/** * Helper to register `config__open_relay` MCP tool — HTTP-only mode. * * After the stdio-pure + http-multi-user split, the relay config form is * served by the HTTP server itself at ``/authorize``. The * ``config__open_relay`` tool directs the user to that URL. * * When the connected client declares URL-mode elicitation * (``capabilities.elicitation.url``, SEP-1036), the tool asks the client to * present a consent prompt and open the URL via ``Server.elicitInput`` so the * credential form is opened out-of-band without the LLM in the loop. Clients * that do NOT declare the capability fall back to the legacy behaviour: the * tool returns the URL and best-effort opens the user's default browser * server-side. There is no daemon-bridge discovery, no respawn, and no * session deduplication — the HTTP server's own session tracking handles * concurrent setup attempts. * * In stdio mode, the relay form does not exist; the tool returns * ``stdio_unsupported`` so plugin code can render a "switch to HTTP mode" * message instead of misleading the user with an unreachable URL. */ import type { ClientCapabilities, ElicitRequestURLParams, ElicitResult } from '@modelcontextprotocol/sdk/types.js'; export interface OpenRelayResult { url: string; browserOpened: boolean; status: 'configured' | 'unconfigured' | 'expired' | 'session_active' | 'stdio_unsupported'; elicitation?: 'accepted' | 'declined' | 'cancelled'; } /** * Minimal surface required to drive URL-mode elicitation. Satisfied by the * low-level `Server` from `@modelcontextprotocol/sdk` (`mcp.server`), which * exposes both `getClientCapabilities` and `elicitInput`. */ export interface ElicitationServer { getClientCapabilities: () => ClientCapabilities | undefined; elicitInput: (params: ElicitRequestURLParams) => Promise; } export interface OpenRelayHandlerOptions { serverName: string; publicUrl: string | null; elicitation?: ElicitationServer; } /** * Build the `open_relay` handler closure. Tests can call * ``buildOpenRelayHandler({ serverName, publicUrl })`` directly without * needing a real MCP server instance. * * When `elicitation` is supplied AND the client declared URL-mode * elicitation, the handler drives `elicitInput` and returns the accept / * decline / cancel outcome. Otherwise it returns the legacy dict * (`{ url, browserOpened, status }`) unchanged. */ export declare function buildOpenRelayHandler(options: OpenRelayHandlerOptions): () => Promise; /** * Minimal shape we require from the MCP server instance to register the * tool. Both `@modelcontextprotocol/sdk`'s `McpServer.tool` and the * FastMCP-style helpers used in consumer servers conform to this surface. */ export interface ToolRegistrar { tool: (config: { name: string; description?: string; }, handler: () => Promise) => void; } /** * Register `config__open_relay` on the given MCP server instance. * * Consumer servers add this single line in their tool registry after the * other `config__*` registrations: * * ```ts * import { registerOpenRelayTool } from '@n24q02m/mcp-core' * registerOpenRelayTool(mcp, SERVER_NAME, PUBLIC_URL, mcp.server) * ``` * * Pass ``null`` for ``publicUrl`` when the server is running in stdio mode; * the tool will return ``status: 'stdio_unsupported'`` so the caller can * surface a clear "switch to HTTP mode" message. * * Pass the low-level `Server` (`mcp.server`) as ``elicitation`` to enable * URL-mode elicitation for capable clients. When omitted, the tool keeps * the legacy browser-open behaviour for every client. */ export declare function registerOpenRelayTool(mcp: ToolRegistrar, serverName: string, publicUrl: string | null, elicitation?: ElicitationServer): void; //# sourceMappingURL=tool-helpers.d.ts.map