/**
 * @fileoverview Server manifest — the single source of truth consumed by the
 * HTTP transport's three surfaces: the bespoke `/mcp` status JSON, the
 * SEP-1649 Server Card at `/.well-known/mcp.json`, and the HTML landing page
 * at `/`. `buildServerManifest()` is a pure function: feed it config + the
 * definition arrays that were already passed to `createApp()` and it produces
 * everything the surfaces need to render without re-reading registries or
 * inspecting Zod schemas a second time.
 *
 * Landing-page content limits (tagline/logo/links/repoRoot shape) are
 * enforced at build time here and surfaced through the definition linter —
 * surprising input fails loudly at startup instead of quietly at render.
 * @module src/core/serverManifest
 */
import type { Implementation } from '@modelcontextprotocol/sdk/types.js';
import type { AppConfig } from '../config/index.js';
import type { AnyPromptDefinition } from '../mcp-server/prompts/utils/promptDefinition.js';
import type { AnyResourceDefinition } from '../mcp-server/resources/utils/resourceDefinition.js';
import type { AnyToolDef } from '../mcp-server/tools/tool-registration.js';
import { type DisabledMetadata } from '../mcp-server/tools/utils/disabled-tool.js';
/** Entry in `landing.links` — rendered in the footer link cluster. */
export interface LandingLink {
    /** When true, opens with `target="_blank" rel="noopener noreferrer"`. */
    external?: boolean;
    /** Absolute URL or same-origin path. */
    href: string;
    /** Visible label. */
    label: string;
}
/**
 * Tab IDs for the connect card; each may have a derived snippet or operator
 * override. Order here is the render order on the landing page: Claude leads
 * because it's the most common conversion path for MCP visitors; named
 * clients follow alphabetically, then transport/protocol fallbacks. Default
 * selected tab is `claude` (wired in the connect-card renderer, not by index).
 */
export declare const CONNECT_SNIPPET_TABS: readonly ["claude", "codex", "cursor", "gemini", "stdio", "http", "curl"];
export type ConnectSnippetTab = (typeof CONNECT_SNIPPET_TABS)[number];
/** Consumer-supplied landing page configuration. */
export interface LandingConfig {
    /** When true (default), footer shows "Built on @cyanheads/mcp-ts-core". */
    attribution?: boolean;
    /**
     * Full URL to the changelog. Defaults to `${repoRoot}/blob/main/CHANGELOG.md`
     * when `repoRoot` is known. Override for projects with a non-standard location.
     */
    changelogUrl?: string;
    /**
     * Per-tab override for the connect card's snippets. When a tab's value is
     * set, the renderer uses it verbatim and skips derivation for that tab;
     * unset tabs fall back to the derived default. Use to express client
     * shapes the derivation doesn't produce (custom `env` merging, Docker /
     * in-process launchers, alternate commands).
     *
     * @example
     * ```ts
     * connectSnippets: {
     *   stdio: JSON.stringify({
     *     mcpServers: {
     *       'my-server': {
     *         command: 'docker',
     *         args: ['run', '-i', '--rm', '-e', 'MY_KEY', 'my/image'],
     *         env: { MY_KEY: 'your-key' },
     *       },
     *     },
     *   }, null, 2),
     * }
     * ```
     */
    connectSnippets?: Partial<Record<ConnectSnippetTab, string>>;
    /** Default: true when HTTP transport is active. */
    enabled?: boolean;
    /**
     * Example env vars to surface in the connect snippets (STDIO JSON config +
     * Claude CLI `--env` flags). Values are placeholders shown to the user;
     * never put real secrets here — the config renders verbatim in the page
     * HTML. Max 12 entries.
     *
     * @example
     * ```ts
     * envExample: {
     *   MAILCHIMP_API_KEY: 'your-api-key',
     *   MAILCHIMP_SERVER_PREFIX: 'us1',
     * }
     * ```
     */
    envExample?: Record<string, string>;
    /** Footer link cluster. Max 6 entries. */
    links?: LandingLink[];
    /** Data URI (`data:image/...`) or same-origin path. ≤24KB when data URI. */
    logo?: string;
    /**
     * Canonical GitHub repository root, e.g. `https://github.com/owner/repo`.
     * Unlocks per-definition "view source" links, release linking on the
     * version badge, and the GitHub footer cluster (changelog, issues, source).
     * Auto-derived from `mcpServerHomepage` when that URL matches the pattern.
     */
    repoRoot?: string;
    /**
     * Gate the landing page inventory (tool/resource/prompt listings, scope
     * chips, invocation snippets) behind authentication. When true,
     * unauthenticated callers receive a reduced landing body.
     *
     * Defaults to `true` when `MCP_AUTH_MODE` is `jwt` or `oauth`, and `false`
     * when auth is `none` — an auth-gated server shouldn't disclose more through
     * the marketing surface than through `GET /mcp` (which already hides
     * metadata when auth is enabled). Set to `false` explicitly to serve the
     * full inventory on an authenticated deployment (public catalog), or `true`
     * to force the reduced body even without auth.
     */
    requireAuth?: boolean;
    /** One-line tagline under the server name. ≤120 chars. */
    tagline?: string;
    /** Brand accent color (any CSS color); hover/active pairs derived via `color-mix()`. */
    theme?: {
        accent?: string;
    };
}
/** Max tagline length. Longer strings break the hero layout. */
export declare const LANDING_MAX_TAGLINE_LENGTH = 120;
/** Max logo size when supplied as a data URI (bytes). */
export declare const LANDING_MAX_LOGO_BYTES: number;
/** Max footer link count. Beyond this the cluster wraps unreadably. */
export declare const LANDING_MAX_LINKS = 6;
/** Max `envExample` entries. Beyond this the connect card grows awkwardly tall. */
export declare const LANDING_MAX_ENV_EXAMPLE = 12;
/** `repoRoot` must match `https://github.com/{owner}/{repo}` with no trailing path. */
export declare const GITHUB_REPO_ROOT_PATTERN: RegExp;
/** Max length for `landing.theme.accent`. Anything longer is almost certainly an injection attempt. */
export declare const LANDING_ACCENT_MAX_LENGTH = 128;
/**
 * Reject CSS values that could escape the custom-property declaration context
 * (`--accent: ${value};`). The renderer HTML-escapes the value, but that's the
 * wrong escape for a CSS context — `;`, `{`, `}`, comment markers, and
 * backslash escapes all survive HTML escaping and can break out. This is the
 * real defense; it's a content shape check, not a full CSS color parser, so
 * new color spaces (`oklch`, `color-mix`, future additions) pass through
 * without regex churn.
 */
export declare function isSafeCssColor(value: string): boolean;
export interface ManifestServer {
    description?: string;
    environment: string;
    homepage?: string;
    /** Server icon(s) forwarded from `createApp({ icons })`. */
    icons?: Implementation['icons'];
    keywords?: string[];
    name: string;
    /** Human-readable display name forwarded from `createApp({ title })`. */
    title?: string;
    version: string;
    /** Canonical server URL forwarded from `createApp({ websiteUrl })`. */
    websiteUrl?: string;
}
export interface ManifestTransport {
    endpointPath: string;
    /**
     * Public-facing origin override (from `MCP_PUBLIC_URL`). When set, the
     * landing page and Server Card render this as the base URL instead of
     * deriving it from the inbound request — required behind TLS-terminating
     * reverse proxies where the container sees `http://` but users reach it
     * over `https://`.
     */
    publicUrl?: string;
    sessionMode: string;
    type: 'http' | 'stdio';
}
export interface ManifestProtocol {
    latestVersion: string;
    supportedVersions: readonly string[];
}
export interface ManifestCapabilities {
    logging: boolean;
    prompts: boolean;
    resources: boolean;
    tools: boolean;
}
export interface ManifestAuth {
    /** JWKS URI, when configured. */
    jwksUri?: string;
    mode: 'none' | 'jwt' | 'oauth';
    /** OAuth audience, when mode = 'oauth'. */
    oauthAudience?: string;
    /** OAuth issuer URL, when mode = 'oauth'. */
    oauthIssuer?: string;
    /** Resource identifier for RFC 9728 discovery. */
    resourceIdentifier?: string;
}
export interface ManifestFramework {
    homepage: string;
    name: string;
    version: string;
}
/** Detected GitHub repository. */
export interface GitHubRepo {
    owner: string;
    repo: string;
    url: string;
}
/** Pre-release classification derived from semver. */
export interface PreReleaseInfo {
    isPreRelease: boolean;
    /** `beta`, `rc`, `alpha`, `pre-1.0`, or undefined when stable. */
    label?: 'alpha' | 'beta' | 'rc' | 'pre-1.0';
}
export interface DefinitionCounts {
    prompts: number;
    resources: number;
    tools: number;
}
export interface ManifestTool {
    annotations?: Record<string, unknown>;
    /** Auth scopes required by the tool, if any. */
    auth?: string[];
    description: string;
    /**
     * Present when the definition was wrapped with `disabledTool()` — the tool
     * is in the manifest but skipped during MCP server registration. Renderers
     * surface a muted card with the operator-facing reason and optional hint;
     * discovery agents reading the Server Card should treat the tool as
     * present-but-uncallable.
     */
    disabled?: DisabledMetadata;
    /** JSON Schema for the input (when Zod → JSON Schema succeeds). */
    inputSchema?: unknown;
    /** True when `_meta.ui.resourceUri` is set (MCP Apps). */
    isApp: boolean;
    /** True when `task: true` on the definition. */
    isTask: boolean;
    name: string;
    /** JSON Schema for the output (when Zod → JSON Schema succeeds). */
    outputSchema?: unknown;
    /** Required field names from the input schema — used for invocation snippets. */
    requiredFields: string[];
    /** View-source URL; auto-derived from `landing.repoRoot` or per-definition override. */
    sourceUrl?: string;
    title: string;
}
export interface ManifestResource {
    annotations?: Record<string, unknown>;
    auth?: string[];
    description: string;
    mimeType?: string;
    name: string;
    sourceUrl?: string;
    title: string;
    uriTemplate: string;
}
export interface ManifestPromptArg {
    description?: string;
    name: string;
    required: boolean;
}
export interface ManifestPrompt {
    args: ManifestPromptArg[];
    description: string;
    name: string;
    sourceUrl?: string;
    title: string;
}
export interface ManifestDefinitions {
    prompts: ManifestPrompt[];
    resources: ManifestResource[];
    tools: ManifestTool[];
}
/** Derived landing state — what the renderer actually consumes. */
export interface ManifestLanding {
    attribution: boolean;
    changelogUrl?: string;
    /** Operator-supplied per-tab connect snippet overrides; empty object when unset. */
    connectSnippets: Partial<Record<ConnectSnippetTab, string>>;
    enabled: boolean;
    /** Ordered key/value pairs for the STDIO env block and Claude CLI `--env` flags. */
    envExample: Array<{
        key: string;
        value: string;
    }>;
    links: Array<Required<Pick<LandingLink, 'href' | 'label' | 'external'>>>;
    logo?: string;
    /** Registry / scoped npm package auto-link, when derivable. */
    npmPackage?: {
        name: string;
        url: string;
    };
    /** Pre-release classification for version badge. */
    preRelease: PreReleaseInfo;
    repoRoot?: GitHubRepo;
    requireAuth: boolean;
    tagline?: string;
    theme: {
        accent: string;
    };
}
/**
 * Full server manifest — the single source of truth for every HTTP surface.
 * Built once at startup, passed to the transport, consumed by `/mcp`,
 * `/.well-known/mcp.json`, and `/`.
 */
export interface ServerManifest {
    auth: ManifestAuth;
    /** Timestamp the manifest was built (ISO 8601). Informational only. */
    builtAt: string;
    capabilities: ManifestCapabilities;
    definitionCounts: DefinitionCounts;
    definitions: ManifestDefinitions;
    extensions?: Record<string, object>;
    framework: ManifestFramework;
    landing: ManifestLanding;
    protocol: ManifestProtocol;
    server: ManifestServer;
    transport: ManifestTransport;
}
/** Classifies a semver string — anything pre-1.0 or with a `-tag` is a pre-release. */
export declare function classifyPreRelease(version: string): PreReleaseInfo;
/** Parses `https://github.com/{owner}/{repo}` into structured form. */
export declare function detectGitHubRepo(url: string | undefined): GitHubRepo | undefined;
/** Converts snake_case or kebab-case to Title Case. */
export declare function deriveTitleFromName(name: string): string;
/** snake_case → kebab-case (for source-link path derivation). */
export declare function snakeToKebab(name: string): string;
/**
 * Build a canonical source-link URL for a definition by convention:
 *   `${repoRoot}/blob/main/src/mcp-server/<kind>/definitions/<kebab-name>.<suffix>.ts`
 *
 * Returns undefined if `repoRoot` isn't set or the name is empty.
 */
export declare function deriveSourceUrl(repoRoot: GitHubRepo | undefined, kind: 'tools' | 'resources' | 'prompts', name: string): string | undefined;
export interface BuildServerManifestInput {
    config: AppConfig;
    /**
     * Explicit description — overrides `config.mcpServerDescription`
     * (`MCP_SERVER_DESCRIPTION` / `package.json` `description`).
     */
    description?: string;
    extensions?: Record<string, object>;
    /** Server icon(s) forwarded from `createApp({ icons })`. */
    icons?: Implementation['icons'];
    landing?: LandingConfig;
    prompts: AnyPromptDefinition[];
    resources: AnyResourceDefinition[];
    /** Human-readable display name forwarded from `createApp({ title })`. */
    title?: string;
    tools: AnyToolDef[];
    /** Canonical server URL forwarded from `createApp({ websiteUrl })`. */
    websiteUrl?: string;
}
/**
 * Build the server manifest. Pure — same inputs produce the same output.
 * Called once at startup from `composeServices()`.
 */
export declare function buildServerManifest(input: BuildServerManifestInput): ServerManifest;
//# sourceMappingURL=serverManifest.d.ts.map