import { McpServer, RegisteredTool } from '@modelcontextprotocol/server'; import { ApplyHideToolsByAudienceOptions, PayableHandler, BuildBootstrapPayloadFn, McpToolExtra, SolvaPayToolAnnotations, SolvaPayToolIcon, BuildSolvaPayDescriptorsOptions } from '@solvapay/mcp-core'; import { SolvaPay, FreeLimit } from '@solvapay/server'; import { z, ZodTypeAny } from 'zod'; /** * Shared `McpServer` construction + descriptor-registration loop used * by both the `.` entry (`createSolvaPayMcpServer` in `../server.ts`) * and the `./fetch` entry (`createSolvaPayMcpFetch` in * `../fetch/createSolvaPayMcpFetch.ts`). */ type HideToolsByAudienceConfig = readonly string[] | { audiences: readonly string[]; bypassWhen?: ApplyHideToolsByAudienceOptions['bypassWhen']; }; /** * `registerPayableTool(server, name, options)` — one-liner for registering * a paywall-protected MCP tool on the official `@modelcontextprotocol/server` * `McpServer`. */ type ZodObjectSchema = ReturnType; /** Accepted `schema` forms: a `z.object()` schema or a raw `{ field: z.string() }` shape. */ type InputSchemaOption = ZodObjectSchema | Record | undefined; /** * Projects the tool's `schema` (raw shape or already-constructed schema) into * the `args` type the handler receives. With no schema, falls back to * `Record` so handlers can still destructure. */ type InferHandlerArgs = [InputSchema] extends [undefined] ? Record : InputSchema extends ZodObjectSchema ? z.infer : InputSchema extends Record ? z.infer> : Record; interface RegisterPayableToolOptions { solvaPay: SolvaPay; schema?: InputSchema; product: string; title?: string; description?: string; handler: PayableHandler, TData>; /** * Opt-in structured-output schema. Declaring it converts a nicety * into a spec MUST — the server must then return conforming * `structuredContent`. Never auto-derived. */ outputSchema?: ZodTypeAny; buildBootstrap?: BuildBootstrapPayloadFn; getCustomerRef?: (args: Record, extra?: McpToolExtra) => string | Promise; meta?: Record; annotations?: SolvaPayToolAnnotations; icons?: SolvaPayToolIcon[]; } declare function registerPayableTool(server: McpServer, name: string, options: RegisterPayableToolOptions): RegisteredTool; /** * `registerFreeTool(server, name, options)` — register an MCP tool that * is free up to a per-customer cap declared in code. Exhaustion emits * the same paywall gate as `registerPayable`. * * Prefer `ctx.registerFree` from `createSolvaPayMcpServer` — that path * also enforces that two tools naming the same free meter agree on cap * / scope / windowDays. */ declare const FREE_METER_NAME_PATTERN: RegExp; interface RegisterFreeToolOptions { solvaPay: SolvaPay; schema?: InputSchema; product: string; title?: string; description?: string; limit: Omit & { meter?: string; }; handler: PayableHandler, TData>; outputSchema?: ZodTypeAny; buildBootstrap?: BuildBootstrapPayloadFn; getCustomerRef?: (args: Record, extra?: McpToolExtra) => string | Promise; meta?: Record; annotations?: SolvaPayToolAnnotations; icons?: SolvaPayToolIcon[]; /** Other tools already registered on this meter — used in the description suffix. */ sharedWith?: string[]; } declare function registerFreeTool(server: McpServer, name: string, options: RegisterFreeToolOptions): RegisteredTool; /** * `createSolvaPayMcpServer` — batteries-included factory that * registers the full SolvaPay transport + bootstrap tool surface on a * fresh `McpServer` from the official `@modelcontextprotocol/server`, * plus the UI resource the `open_*` tools reference. * * Internals delegate to `internal/buildMcpServer` (shared with the * `./fetch` subpath entry) so the two factories register the same 12 * tools in the same order off the same `buildSolvaPayDescriptors` * bundle without duplicating the registration loop. */ /** * Callback fired from the `additionalTools` hook with helpers bound for * the current server + `solvaPay` instance. */ interface AdditionalToolsContext { server: McpServer; solvaPay: SolvaPay; resourceUri: string; productRef: string; /** * `registerPayableTool` bound with `solvaPay` + `resourceUri` already * provided, and `product` defaulting to the server's `productRef`. * * Zod `schema` flows through to the handler's `args` parameter so * merchants get inferred arg types without a second declaration. */ registerPayable: (name: string, options: Omit, 'solvaPay' | 'product'> & { product?: string; }) => void; /** * `registerFreeTool` bound with `solvaPay` already provided, and * `product` defaulting to the server's `productRef`. Two tools that * name the same free meter must declare the same cap / scope / * windowDays — a mismatch throws at registration. */ registerFree: (name: string, options: Omit, 'solvaPay' | 'product'> & { product?: string; }) => void; } interface CreateSolvaPayMcpServerOptions extends BuildSolvaPayDescriptorsOptions { /** * Integrator hook to register non-SolvaPay tools. The callback receives * the built server plus `registerPayable` / `registerFree` helpers bound * for this instance. */ additionalTools?: (ctx: AdditionalToolsContext) => void; /** * Register the slash-command prompts (`/upgrade`, `/manage_account`, * `/topup`, `/activate_plan`) built from the descriptor bundle. * Defaults to `true` — the prompts are additive and silently ignored * by hosts without prompt support. */ registerPrompts?: boolean; /** * Register the narrated `docs://solvapay/overview.md` resource so * agents can `resources/read` before trying a tool. Defaults to * `true` — pure narration, no side-effects. */ registerDocsResources?: boolean; /** Overrides the default `McpServer` name. */ serverName?: string; /** Overrides the default `McpServer` version. */ serverVersion?: string; /** * After registration, wrap the `tools/list` handler to drop any * tool whose `_meta.audience` matches one of these values. The * tools stay `enabled: true` so `tools/call` still reaches their * handlers — this option only affects the `tools/list` response * shape. Pass `['ui']` to keep the LLM-facing catalogue narrow to * the four intent tools (`upgrade` / `manage_account` / * `activate_plan` / `topup`) plus your own merchant-registered * data tools, while leaving the eight UI transport tools * (`create_payment_intent`, etc.) callable for the SolvaPay * iframe. * * # ChatGPT auto-bypass * * ChatGPT's Custom Connector gateway re-validates iframe-initiated * `tools/call` against the cached `tools/list` catalog, so any * tool hidden by this option becomes uncallable from the embedded * iframe and surfaces in the UI as `MCP error -32000: MCP Resource * not found`. To preserve the cleaner LLM catalog on every other * host while keeping the iframe working on ChatGPT, the SDK * auto-detects ChatGPT-originated `tools/list` requests (matching * `request.headers['user-agent']` and the post-`initialize` * `clientInfo.name` against `/openai-mcp/i`) and returns the full * catalog to them. The detection is verified live against * `openai-mcp/1.0.0 (ChatGPT)` and the broad pattern survives a UA * version bump. * * To extend the bypass to a future iframe-capable host, pass the * object form: `{ audiences: ['ui'], bypassWhen: ctx => … }`. * * To disable the bypass and apply the filter unconditionally * (e.g. on a known text-only deployment), pass `{ audiences: * ['ui'], bypassWhen: () => false }`. */ hideToolsByAudience?: HideToolsByAudienceConfig; } /** * Build the MCP server and register the full SolvaPay tool surface. */ declare function createSolvaPayMcpServer(options: CreateSolvaPayMcpServerOptions): McpServer; export { type AdditionalToolsContext as A, type CreateSolvaPayMcpServerOptions as C, FREE_METER_NAME_PATTERN as F, type HideToolsByAudienceConfig as H, type RegisterFreeToolOptions as R, type RegisterPayableToolOptions as a, registerPayableTool as b, createSolvaPayMcpServer as c, registerFreeTool as r };