/** * mcpServe — expose your agentfootprint tools AS an MCP server. * * const handle = await mcpServe([lookupTool, refundTool], { * name: 'support-desk', * version: '1.0.0', * }); * * // …later * await handle.close(); * * Over HTTP the handle also reports the socket it bound, so `port: 0` * ("any free port") is usable from the outside: * * const handle = await mcpServe(tools, { * transport: { transport: 'http', port: 0, host: '127.0.0.1' }, * }); * connect(`http://127.0.0.1:${handle.port}/mcp`); * * `mcpClient` pulls someone else's tools in. This pushes yours out, so * the tool you already wrote, tested and governed can be called by any * MCP client — a desktop host, another team's agent, an IDE — without * being rewritten against a second tool interface. * * Pattern: Adapter (GoF), pointed the other way. `mcpClient` translates * MCP → `Tool`; this translates `Tool` → MCP. Same SDK, same * lazy-require discipline, mirrored lifecycle (`close()`). * * ── The one promise worth stating plainly ──────────────────────────── * A served tool is THE SAME OBJECT you passed in. `mcpServe` holds your * `Tool` by reference and calls `tool.execute(args, ctx)` — it never * copies the schema and re-implements the body, never unwraps a * decorator, never reaches past a wrapper to an inner tool. So whatever * governance you composed around that tool — a permission check inside * `execute`, a redaction step, an audit hook — is still the thing that * runs when a remote client calls it. Serving is not a second door into * your tool; it is the same door with a longer corridor. * * Two demands the library CANNOT keep over MCP are refused at * construction rather than silently dropped: * - `checkIn` (human consent before the tool runs) needs a pause * channel that a request/response protocol does not have. * - `needs` (declare-and-push credentials) needs a provider; without * one the tool would run with `ctx.credential` undefined. * * ── Declarations travel; execution does not (9.71.0) ───────────────── * A served tool's DECLARATIONS — `argumentsFrom`, `resultKind`, `owner`, * `resultClass`, `resultCeiling` — are written into MCP's own `_meta` bag * under one namespaced key, so an agentfootprint client arms the checks and * rails that read them exactly as it would for a local `defineTool`. The * execution-side fields never go: see `toolExtras.ts` for the bar and the * reasoning. A tool declaring none of the five lists exactly as before. * * ── Schemas ────────────────────────────────────────────────────────── * Tools already carry JSON Schema in `schema.inputSchema`, and MCP's * `tools/list` wants JSON Schema, so the mapping is the identity * function. That is also why this builds on the SDK's low-level * `Server` rather than its `McpServer` convenience wrapper — the latter * takes zod schemas, which would mean converting a JSON Schema you * already have into zod (a new dependency) to convert it straight back. */ import type { Tool } from '../../core/tools.js'; import type { McpServeHandle, McpServeOptions } from './types.js'; /** * Serve `tools` over MCP. Resolves once the transport is connected (for * `http`, once the socket is listening), so holding the handle means the * server is live. * * @throws at construction when `tools` is empty, when two tools share a * name, when a tool declares `checkIn`, or when a tool declares `needs` * without `opts.credentials` — see the module header. Also throws when * `@modelcontextprotocol/sdk` is not installed. */ export declare function mcpServe(tools: readonly Tool[], opts?: McpServeOptions): Promise; /** * Sentinels handed to an injected `_server` in place of the SDK's zod * schemas. Exported so a test can tell the two handlers apart. * @internal */ export declare const LIST_TOOLS_SENTINEL: Readonly<{ method: "tools/list"; }>; /** @internal @see LIST_TOOLS_SENTINEL */ export declare const CALL_TOOL_SENTINEL: Readonly<{ method: "tools/call"; }>; //# sourceMappingURL=mcpServe.d.ts.map