import type { FunctionReference } from "convex/server"; import type { GenericValidator, Infer, PropertyValidators, Validator, VAny, VArray, VBoolean, VBytes, VFloat64, VId, VInt64, VLiteral, VNull, VObject, VRecord, VString, VUnion } from "convex/values"; export type JsonSchema = { type: "string"; enum?: string[]; format?: string; contentEncoding?: string; description?: string; [key: string]: unknown; } | { type: "number"; description?: string; [key: string]: unknown; } | { type: "integer"; format?: string; description?: string; [key: string]: unknown; } | { type: "boolean"; description?: string; [key: string]: unknown; } | { type: "null"; description?: string; [key: string]: unknown; } | { type: "array"; items: JsonSchema; description?: string; [key: string]: unknown; } | { type: "object"; properties?: Record; required?: string[]; additionalProperties?: JsonSchema | boolean; description?: string; [key: string]: unknown; } | { const: unknown; description?: string; [key: string]: unknown; } | { anyOf: JsonSchema[]; description?: string; [key: string]: unknown; } | { description?: string; [key: string]: unknown; }; export type McpToolKind = "query" | "mutation" | "action"; export interface McpToolAnnotations { title?: string; readOnlyHint?: boolean; destructiveHint?: boolean; idempotentHint?: boolean; openWorldHint?: boolean; [key: string]: unknown; } /** * Names of tool arguments reserved for gateway-injected MRTR data. Only * the idempotency key is ever injected: continuation state and input * responses stay inside the `beforeCall` hook, so the underlying Convex * function remains MCP-unaware. */ export interface McpMrtrArgs { idempotencyKey: string; } /** * A host-side MRTR decision. The gateway signs `state` but does not encrypt * it, so it must not contain credentials. */ /** Terminal hook results accepted as an `inputRequired()` fallback. */ export type McpInputRequiredFallback = McpCompleteCallResult | McpCompleteReadResult | McpDeclineReadResult; export type McpInputRequiredResult = { __mcpInputRequired: true; inputRequests?: Record; state?: unknown; onUnsupported?: TFallback; }; /** * A host-side `beforeCall` decision that ends the call without invoking * the underlying Convex function. `result` is the literal MCP * `tools/call` result the client receives (`content`, optional * `structuredContent`, optional `isError`), e.g. "Invoice was not * archived." after a declined confirmation. */ export type McpCompleteCallResult = { __mcpCompleteCall: true; result: Record; }; export type McpBeforeCallResult = McpInputRequiredResult | McpCompleteCallResult | null | undefined; /** * A host-side `beforeResourceRead` decision that ends the read by serving * `contents` itself, without consulting any provider or template. The * read counterpart of `completeCall`: a `resources/read` result is * `{ contents }` rather than a `CallToolResult`, so the two cannot share * one shape. */ export type McpCompleteReadResult = { __mcpCompleteRead: true; contents: unknown[]; }; /** * A host-side `beforeResourceRead` decision that refuses the read after * the caller answered. Distinct from returning substitute `contents`: * the client asked for a resource and is getting none, so it belongs on * the error channel, in the same family as an `authorizeResource` denial. */ export type McpDeclineReadResult = { __mcpDeclineRead: true; reason: string; }; export type McpBeforeResourceReadResult = McpInputRequiredResult | McpCompleteReadResult | McpDeclineReadResult | null | undefined; /** * Create a host-side result that requests another round trip. `onUnsupported` * is returned when the gateway cannot satisfy the requested MRTR capabilities. */ export declare function inputRequired(inputRequests?: Record, state?: unknown, options?: { onUnsupported?: TFallback; }): McpInputRequiredResult; /** * Create a host-side `beforeResourceRead` result that serves `contents` * directly, e.g. a redacted summary after the owner declined to share the * full document. Contents are validated exactly like a provider's, so a * malformed block fails loudly instead of shipping invalid JSON-RPC. */ export declare function completeRead(contents: unknown[]): McpCompleteReadResult; /** * Create a host-side `beforeResourceRead` result that refuses the read. * `reason` is host-authored and reaches the caller verbatim, like an * `authorizeResource` denial reason; it must not carry anything the caller * may not see. */ export declare function declineRead(reason: string): McpDeclineReadResult; /** * Create a host-side `beforeCall` result that terminates the call with * the given MCP tool result, without dispatching the Convex function. */ export declare function completeCall(result: Record): McpCompleteCallResult; /** * An icon a client may display next to a tool, resource, or template. `src` * is host-supplied and reaches the client verbatim: the gateway advertises * it and never fetches it, so the consumer-side precautions the spec * describes (same-domain checks, care with SVG) belong to the client. * * Advertised to every client, on both transport eras, and that is * correct: `icons` arrived in `2025-11-25`, which is the gateway's own * DEFAULT revision, and `2026-07-28` changed nothing about it beyond a * doc-comment typo. There is no era split to apply here, so do not go * looking for the missing one. Even a client predating the field is * safe, because the reference SDK's descriptor schemas are plain * objects that strip unknown keys rather than rejecting the response. * * The shape is worth respecting exactly. `sizes` is an array of strings * and `theme` is a closed union, and a client that validates rejects the * WHOLE list response over one bad entry rather than dropping one icon. * That is what `describeIconsProblem` is guarding against; SDK builds * 1.18.0 through 1.18.2 typed `sizes` as a bare string and hard-fail on * the spec-mandated array form. * * The spec puts `icons` on one further type this gateway does not carry * it on: `Prompt`. That is a gap rather than a decision, and it stays one * until there is a prompts feature to hang it off. `Implementation` is * covered, see `McpServerInfo`. */ export interface McpIcon { src: string; mimeType?: string; /** WxH strings (`"48x48"`), or `"any"` for a scalable format. */ sizes?: string[]; theme?: "light" | "dark"; } /** * The spec's `Implementation`, which the gateway returns as `serverInfo` * on `initialize` and in the `io.modelcontextprotocol/serverInfo` `_meta` * block of every stateless result. * * `name` and `version` identify the build; the other four are display * metadata a white-labelling host may want. All of them reach the client * verbatim, so the same reasoning as `McpIcon` applies: nothing here is * fetched by the gateway, and nothing here is era-gated. `title` predates * the gateway's DEFAULT revision and the rest arrived with it, and the * three string fields are measured safe on a client older than all of * them: SDK 1.18.0 keeps them rather than rejecting the response. * * `icons` is the exception, and not in the direction the validator * covers. `describeServerInfoProblem` stops a MALFORMED block reaching * the wire, because a spec-conformant client rejects the whole response * over one bad entry, and for `initialize` that means it never connects. * But the input that breaks SDK 1.18.0 through 1.18.2 is the WELL-FORMED * one: they typed `sizes` as a bare string, so the spec-mandated array * fails their parse and no validator can help. See the `serverInfo` * option docs for the measurements and the one lever a host has. */ export interface McpServerInfo { name: string; /** Display name, where `name` is the identifier. */ title?: string; version: string; description?: string; websiteUrl?: string; icons?: McpIcon[]; } /** * A single entry of a tool's `securitySchemes`. The field is still a * draft addition to the MCP Tool spec and the gateway only passes it * through, so the shape stays open: `type` plus whatever the scheme * carries (`scopes` for `oauth2`, nothing for `noauth`). Pinning the * union here would reject schemes the spec adds later without buying * any runtime safety. */ export interface McpToolSecurityScheme { type: string; [key: string]: unknown; } export interface McpToolDefinition { name: string; description: string; kind: McpToolKind; functionReference: unknown; inputSchema: JsonSchema; /** * Optional MCP `outputSchema` (JSON Schema). When set, the gateway * also includes `structuredContent` in every `tools/call` response * for this tool, alongside the existing text-JSON `content` block. * Most commonly populated by passing `returns:` to * `defineMcp{Query,Mutation,Action}`. */ outputSchema?: JsonSchema; title?: string; annotations?: McpToolAnnotations; _meta?: Record; securitySchemes?: McpToolSecurityScheme[]; /** * Optional icons a client may display next to this tool in a picker. * Advertised verbatim in `tools/list`; the gateway never dereferences an * icon `src`. Same shape the spec puts on resources and templates. */ icons?: McpIcon[]; /** * Name of the tool function argument the gateway fills server-side * with the resolved caller identity (`{ subject, claims }`). When set: * the arg is removed from the advertised `inputSchema` (clients never * see it), stripped from caller-supplied arguments (no spoofing), and * injected from the identity resolved at the gateway boundary right * before dispatch. Lets identity-scoped tools read the caller without * `ctx.auth` (which Convex strips across the component boundary). Use * `mcpCallerValidator` for the arg's validator. */ identityArg?: string; /** * Name of the tool argument the gateway fills with the continuation's * stable idempotency key on a verified MRTR retry that continues to * dispatch. Removed from the advertised input schema and stripped from * every client request. Optional: a tool without durable side effects * (or one only used for gateway-side confirmation) does not need it. * * Also filled from the task row's own idempotency key when the tool is * run by the BUILT-IN task executor, so a tool that dedupes on it keeps * receiving it on that path too. A host executor (`tasks.execute`) gets * no injection: it must thread `task.idempotencyKey` through itself. */ mrtrArgs?: McpMrtrArgs; /** * The host-side MRTR state machine, run in the host HTTP action before * the underlying Convex tool on the first call AND on every verified * continuation (where it additionally receives the decoded state, the * client's untrusted `inputResponses`, and the stable idempotency key). * Returns `inputRequired()` for another round (optionally with an * `onUnsupported` fallback), `completeCall()` to end * the call without dispatching, or `null`/`undefined` to continue to * the Convex function. Supported only by the declarative `tools` * option of `handleMcpRequest`. * * Composes with `taskSupport`: the hook runs at task-creation time, so * a task is only created once it approves, and a durable task can * never execute with the confirmation skipped. */ beforeCall?: McpBeforeCallHandler; /** * Opt-in MCP Tasks support (`io.modelcontextprotocol/tasks`). Only a * tool that sets this may be invoked as a task-augmented modern * `tools/call`. Task execution defers the function: it must be safe to * run after the HTTP request completed, and it must persist the * gateway-issued idempotency key around its side effect so workflow * retries and duplicate client updates cannot double-apply. */ taskSupport?: boolean | "forbidden" | "optional" | "required"; metadata?: Record; } /** * A Convex function reference usable as an MCP tool: a query, mutation, * or action of either visibility. The arg/return generics are `any` * here on purpose, the per-tool arg/return type-checking happens in the * `defineMcp*` config parameter, not at this widened element type. */ export type McpToolFunctionReference = FunctionReference; /** * Element type of a declarative tool catalog: the result of * `defineMcp{Query,Mutation,Action}`. Use it to annotate an exported * `tools` array so it can be passed to `gateway.handleMcpRequest` or * `gateway.register`: * * ```ts * export const tools: McpToolRegistration[] = [defineMcpQuery({ ... })]; * ``` * * The annotation is only needed when the array is **exported from a * Convex module** (one under your `convex/` functions dir): without it, * the inferred type reads `api.*` from the tool `fn`s while `api` itself * includes that module, and Convex's generated `api.d.ts` hits a * circular-reference error. A non-exported `const tools = [...]` (e.g. * declared inline in `http.ts`) needs no annotation. * * Annotating does **not** weaken per-tool type safety: `args` / `returns` * are validated at the `defineMcp*` call against the function's actual * signature, independent of how the resulting array is typed. */ export type McpToolRegistration = McpToolDefinition & { fn: McpToolFunctionReference; }; /** * Validator for the caller identity the gateway injects into a tool's * `identityArg`. Declare the receiving argument with this validator so * the tool's compile-time `args` check still matches its function: * * ```ts * export const whoami = query({ * args: { caller: mcpCallerValidator }, * handler: async (_ctx, { caller }) => ({ subject: caller.subject }), * }); * * defineMcpQuery({ * name: "whoami", * fn: api.x.whoami, * args: { caller: mcpCallerValidator }, * identityArg: "caller", * }); * ``` * * `subject` is the caller's stable id; `claims` is whatever the * boundary resolved (the upstream userinfo doc in bridge mode, or the * Convex JWT identity otherwise). */ export declare const mcpCallerValidator: VObject<{ claims?: any; subject: string; }, { subject: VString; claims: VAny; }, "required", "subject" | "claims" | `claims.${string}`>; export type McpCaller = Infer; /** * What a `beforeCall` hook receives. On the first call only `args` and * `identity` are present. On a verified continuation the gateway adds * the decoded `state` the hook sealed in the previous round, the * client's untrusted `inputResponses` (validate every field before * acting on it), the chain's stable `idempotencyKey`, and the 1-based * `round` number of the continuation being answered. */ export type McpBeforeCallArgs = { args: Record; identity: McpCaller; state?: unknown; inputResponses?: Record; idempotencyKey?: string; round?: number; }; /** * The context every host callback receives: the host's own Convex * context, unchanged. * * These callbacks run in the HOST, not inside the component, which is * what lets them read and write the host's tables. An authorizer that * looks a role up in a table, or a `beforeCall` hook that names the * records a confirmation is about, both need `runQuery` here. * * The index signature is kept so a host may reach anything else its * runtime provides; the named members exist so the common ones do not * have to be cast first. */ export type McpHostCallbackCtx = { runQuery: (ref: any, args: any) => Promise; runMutation: (ref: any, args: any) => Promise; runAction: (ref: any, args: any) => Promise; auth: { getUserIdentity: () => Promise; }; } & Record; export type McpBeforeCallHandler = (ctx: McpHostCallbackCtx, args: McpBeforeCallArgs) => McpBeforeCallResult | Promise; /** * Args the gateway passes to the host's `beforeResourceRead` hook, on the * first read and on every verified continuation of it. Mirrors * `McpBeforeCallArgs`, with the resource identity in place of the tool's * arguments: a read has no arguments, and its `uri` is what the sealed * continuation binds. * * `resourceMetadata` is the registry `metadata` of the concrete resource * when the URI names one, `null` otherwise (a template expansion, or a * provider-served URI that is not persisted). Same value the host's * `authorizeResource` receives, so one policy can inform both. */ export type McpBeforeResourceReadArgs = { uri: string; resourceMetadata: Record | null; identity: McpCaller; state?: unknown; inputResponses?: Record; round?: number; }; export type McpBeforeResourceReadHandler = (ctx: { auth: { getUserIdentity: () => Promise; }; } & Record, args: McpBeforeResourceReadArgs) => McpBeforeResourceReadResult | Promise; /** * Args that the gateway passes to the host's `authorize` callback for * each `tools/call` and each filtered `tools/list` evaluation. * * The authorizer is a regular JS function the host hands to * `gateway.handleMcpRequest({ authorize })`, **not** a registered * Convex query: Convex doesn't propagate `ctx.auth` into component * code, so the policy decision must run host-side where * `ctx.auth.getUserIdentity()` works. */ export interface McpAuthorizerArgs { toolName: string; toolKind: McpToolKind; args: Record; /** * `"call"` for an actual `tools/call` dispatch, `"list"` when the * gateway is filtering `tools/list` per tool. `args` for `"list"` * is always an empty object. */ mode: "call" | "list"; /** * Free-form metadata the host attached to the tool via * `defineMcp*({ metadata })`. The component never inspects this; * the authorizer reads it for scope/role / public-flag checks. */ toolMetadata: unknown; /** * The caller's identity, resolved once at the gateway boundary * before this callback runs. Source depends on configuration: * - With `resolveIdentity` set: whatever the validator returned * (typically userinfo-endpoint claims). * - Without `resolveIdentity`: the result of * `ctx.auth.getUserIdentity()`, with `iss/aud` mismatches treated * as null instead of throwing. * * `null` for anonymous calls (no Bearer, invalid token, etc.). * * Prefer this field over calling `ctx.auth.getUserIdentity()` * inside the callback: it works in both pure-JWT and bridge modes, * and you save a call. */ identity: { subject: string; claims?: Record; } | null; } export interface McpAuthorizerDecision { allowed: boolean; reason?: string; } /** * Is this a `ConvexError`, i.e. a message the host threw on purpose? * * The gateway treats `ConvexError` as the deliberate caller-facing * channel: its message reaches the MCP client verbatim. Every other * throw is an accident (a failed `fetch` quoting a signed URL, a driver * error echoing a connection string) and only ever reaches the client * as a generic message. * * The `instanceof` check covers the in-process case; the * `name === "ConvexError"` fallback catches errors that crossed a Convex * function boundary (`ctx.runQuery` / `runMutation` / `runAction` * reconstruct the error with the proper `name`, but the class identity * can differ across module resolution boundaries inside `convex-test`). * * Lives in `shared.ts` because the component (`dispatch.runTool`) and the * host (`mcp-handler`'s resource paths) must classify errors identically; * two copies of this predicate would be two chances to drift. */ export declare function isDeliberateConvexError(err: unknown): boolean; /** * The reason a malformed authorizer return is denied with. Named so the * gateway's own call sites can tell it apart from a deliberate policy * denial and log it rather than shipping it: a host that forgets a * `return` on one branch produces exactly this, and it is the likeliest * first-day failure of a new authorizer branch. Not part of the package's * public surface; `src/client/index.ts` does not re-export it. */ export declare const AUTHORIZER_INVALID_SHAPE_REASON = "Authorizer returned an invalid shape. Expected `{ allowed: boolean, reason?: string }`."; /** * Runtime validation of the host's authorize-callback return value. * Lenient on extra fields (forward-compat); strict on the required * `allowed` boolean. Lives in `shared.ts` so both the host (`mcp-handler`) * and the component (`dispatch`, via re-export) can defend against * authorize callbacks that return malformed shapes. */ export declare function parseAuthorizerDecision(decision: unknown): McpAuthorizerDecision; /** * Authorizer signature: a regular async (or sync) function. It runs in * the host's HTTP-action context, so `ctx.auth.getUserIdentity()` * returns the JWT-validated identity here. * * ```ts * import type { McpAuthorizerHandler } from "convex-mcp-gateway"; * * export const authorize: McpAuthorizerHandler = async (ctx, args) => { * const identity = await ctx.auth.getUserIdentity(); * if (!identity) return { allowed: false, reason: "Unauthorized" }; * // ... your scope / role / metadata check ... * return { allowed: true }; * }; * ``` */ export type McpAuthorizerHandler = (ctx: McpHostCallbackCtx, args: McpAuthorizerArgs) => Promise | McpAuthorizerDecision; /** * Convert a Convex validator (single value or args-object) into a JSON Schema * fragment that satisfies MCP `tools.inputSchema`. * * MCP tools always present an object-typed input schema. If you pass a * `PropertyValidators` record, the result is `{ type: "object", properties, required }`. * If you pass a single validator, it returns that fragment unwrapped. */ export declare function convexValidatorToJsonSchema(validator: GenericValidator | PropertyValidators): JsonSchema; export declare function propertyValidatorsToObjectSchema(validators: PropertyValidators): JsonSchema; export type { GenericValidator, PropertyValidators, Validator, VAny, VArray, VBoolean, VBytes, VFloat64, VId, VInt64, VLiteral, VNull, VObject, VRecord, VString, VUnion, }; /** * Compute the RFC 9728 protected-resource metadata URL for an MCP gateway * mounted at `mcpPath` on `origin`. The canonical (path-prefix) form * places the well-known segment between host and path: * * `/.well-known/oauth-protected-resource` * * For example, an MCP endpoint at `https://app.example.com/mcp/` has * metadata at `https://app.example.com/.well-known/oauth-protected-resource/mcp`. * * Pure function so the gateway can compute the URL from inside an * httpAction without re-parsing intermediate URLs, and so it is unit * testable independently of any framework. * * Spec: RFC 9728 ยง3.1 ("Well-Known URI"). The host is expected to mount * the discovery handler at exactly this path; the gateway component * does not own any HTTP routes (Convex doesn't propagate `ctx.auth` * into component code, so all routes live in the host). */ export declare function buildProtectedResourceMetadataUrl(origin: string, mcpPath: string): string; /** * Compute the canonical resource URL for an MCP gateway from a request * URL plus an optional override. Used by both the 401 path (where the * request hits ``) and by host-mounted discovery handlers * (which call this with the path stripped of the well-known prefix). */ export declare function buildResourceUrl(origin: string, mcpPath: string, override: string | null | undefined): string; /** * Strip the `/.well-known/oauth-protected-resource` prefix from a * request path to recover the resource path the metadata document * describes. Used by the host's discovery-route handler. * * Returns `"/"` if nothing follows the well-known segment, matching the * RFC 9728 example for resources mounted at the host root. */ export declare function resourcePathFromWellKnownRequest(pathname: string): string; /** * Budgets for `resolveJsonSchemaBounded`. Hard limits with named * errors: silently truncating a schema would advertise a contract the * tool does not have, which is worse than rejecting it at registration. */ export declare const SCHEMA_MAX_STRUCTURAL_DEPTH = 64; export declare const SCHEMA_MAX_REF_EXPANSIONS = 64; export declare const SCHEMA_MAX_RESOLVED_BYTES: number; /** * Version of the resolution semantics. Folded into the declarative * catalog fingerprint so a change here re-syncs every registry that was * written under the old rules, instead of leaving deployments * advertising stale resolutions until someone edits a tool. Bump on any * behavior change (new supported ref position, different budget * accounting, changed drop rules). */ export declare const SCHEMA_RESOLVER_VERSION = 3; /** UTF-8 byte length without `TextEncoder` (unavailable in some Convex runtimes). */ export declare function utf8ByteLength(value: string): number; export type ResolvedJsonSchema = { resolved: unknown; problem?: undefined; } | { resolved?: undefined; problem: string; }; /** * Resolve a tool schema's local `$ref`s within hard budgets, producing * a self-contained schema suitable for storage and advertisement. * * The contract, deliberately narrow: * * - A schema with no `$ref` at any SCHEMA position is returned * **verbatim** (the same reference), so every schema that registers * today keeps advertising byte-identically. Detection and expansion * are position-aware: `$ref` is only a reference where a schema is * expected, never inside data keywords (`enum`, `const`, `default`, * `examples`), unknown vendor keywords, or as a property NAME. Note * this is about how the resolver INTERPRETS such values, not a * promise that they are storable: Convex rejects `$`-prefixed field * names at the storage boundary, so a schema declaring a property * named `$ref` cannot be registered whatever this function returns. * - Only root-relative `#/$defs/` references are supported * (single JSON Pointer token, RFC 6901 unescaped). Remote (`https:`) * references, anchors, and pointers into arbitrary schema locations * are rejected by name -- the gateway must never fetch, and a ref * into the middle of another schema has no stable meaning once the * target is rewritten. * - `$ref` must be the only key of its schema object. JSON Schema * 2020-12 gives adjacent keywords `allOf`-like semantics; merging * them correctly is a composition problem, and composition is * exactly where static reachability (and with it the `x-mcp-header` * binding guarantee) ends. * - Resolution is **reachability-driven**: definition containers * (`$defs`, `definitions`) are never walked as output, only pulled * from when something references them. An unused definition (a * self-referential type or a remote `$ref` in a generated bundle) * therefore cannot fail a schema whose resolved form is fine, and the * expansion budget counts only definitions that end up in the output. * - Expansion is bounded three ways: traversal depth (each nesting * level of the schema tree charges one), total `$ref` expansions, and * the UTF-8 size of the result. Cycles are detected via the active * reference chain, not left to the depth budget, so the error names * the cycle. * - On success the root definition containers are dropped: every * reference into them has been inlined, and advertising dead * definitions would only confuse clients that do not resolve * references (which is why the gateway inlines rather than passes * `$ref` through: the advertised schema works for every client, and * the runtime `Mcp-Param-*` walk sees exactly what was validated at * registration). A reference that survives resolution anywhere in the * output (e.g. under a keyword the walker does not treat as a schema * position, or inside a nested definition container) is rejected by * name rather than shipped dangling. */ export declare function resolveJsonSchemaBounded(schema: unknown): ResolvedJsonSchema; /** * Make a resolved schema storable as a Convex object. * * Convex reserves field names beginning with `$`, which is fatal for a * schema that declares its dialect: the write throws from inside Convex * and takes every request to the mount with it, `initialize` included. * In a keyword position a `$` name is JSON Schema vocabulary rather than * anything the gateway routes on, so the stored copy drops it and the * authored copy kept alongside it carries it to the client intact. * * That drop covers data keywords too (`const`, `enum`), where `$ref` is * plain data rather than a reference. It is a deliberate narrowing of the * INTERNAL copy, which is read only to walk `x-mcp-header` annotations; * the advertised schema is unaffected. * * A PROPERTY name is never dropped. It is a `problem` instead, because * the advertised schema keeps it either way, and a property the runtime * walk cannot see is an annotation declared to the client and enforced * against nobody. */ export declare function prepareSchemaForStorage(schema: unknown): { storable?: unknown; problem?: string; }; /** * A tool's task support, normalized to the three SEP-2663 levels. * * This gateway shipped a boolean first, and rows written by an older * version still carry one, so both spellings are read and only the * string is written. `true` means `"optional"`, which is what it meant. * * Lives here because the client decides with it and the component's * executor re-checks it at run time, and the two must not drift: a task * created while a tool was task-capable must not still execute after the * tool was withdrawn, and that comparison is only sound if both sides * read the same field the same way. */ export declare function mcpTaskSupportLevel(tool: { taskSupport?: boolean | string | null; }): "forbidden" | "optional" | "required"; //# sourceMappingURL=shared.d.ts.map