fastmcp 4.17.1 → 4.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/openapi/index.cjs +662 -0
- package/dist/openapi/index.cjs.map +1 -0
- package/dist/openapi/index.d.cts +181 -0
- package/dist/openapi/index.d.ts +181 -0
- package/dist/openapi/index.js +662 -0
- package/dist/openapi/index.js.map +1 -0
- package/package.json +10 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/openapi/loadSpec.ts","../../src/openapi/naming.ts","../../src/openapi/requestBuilder.ts","../../src/openapi/resourceMapping.ts","../../src/openapi/routes.ts","../../src/openapi/schemas.ts","../../src/openapi/selection.ts","../../src/openapi/fromOpenAPI.ts"],"sourcesContent":["import SwaggerParser from \"@apidevtools/swagger-parser\";\n\nimport type { BundledOpenApiDocument } from \"./types.js\";\n\nexport interface LoadedSpec {\n document: BundledOpenApiDocument;\n /**\n * The spec's own URL, when it was loaded from one. Used to resolve a\n * relative `servers[0].url` against the document's origin.\n */\n origin?: string;\n}\n\n/**\n * Loads and bundles an OpenAPI document, resolving local *and* external\n * `$ref`s (relative paths, absolute URLs, `other.yaml#/fragment`).\n *\n * `spec` is handed to swagger-parser as-is — a URL, file path, or object —\n * rather than being fetched and re-parsed here first. External refs resolve\n * relative to whatever document they were found in, so pre-fetching the\n * entry document and passing its parsed text as an object would resolve\n * every external ref against the wrong base (or none at all).\n */\nexport async function loadSpec(\n spec: Record<string, unknown> | string,\n): Promise<LoadedSpec> {\n const document = (await SwaggerParser.bundle(\n spec as never,\n )) as unknown as BundledOpenApiDocument;\n\n if (!document.openapi?.startsWith(\"3.\")) {\n throw new Error(\n `fromOpenAPI only supports OpenAPI 3.x documents (found ${\n document.openapi ?? document.swagger ?? \"an unrecognized version\"\n }). Swagger 2.0 is not supported.`,\n );\n }\n\n return {\n document,\n origin: typeof spec === \"string\" && isHttpUrl(spec) ? spec : undefined,\n };\n}\n\nfunction isHttpUrl(value: string): boolean {\n return value.startsWith(\"http://\") || value.startsWith(\"https://\");\n}\n","import type { HttpRoute } from \"./types.js\";\n\nconst MAX_NAME_LENGTH = 56;\n// Reserves room for a \"_<n>\" collision suffix so the final name never\n// exceeds MAX_NAME_LENGTH, however many collisions it takes.\nconst MAX_BASE_LENGTH = MAX_NAME_LENGTH - 5;\n\n/**\n * Generates a unique name per route — used both for tools and, when\n * `resources: true`, for the resources/resource templates a `GET` route\n * maps to instead. One pass over the whole selected set keeps names unique\n * regardless of which destination a route ends up at.\n *\n * Ports the Python implementation's naming rule\n * (`server/providers/openapi/provider.py:_generate_default_name`): prefer\n * `mcpNames[operationId]`, then `operationId` (FastAPI-style `__` suffixes\n * stripped), falling back to `summary` or `{method}_{path}`; slugified and\n * capped at 56 characters, with `_2`, `_3`, ... appended on collision.\n *\n * Uniqueness is checked against the final (post-suffix) name, not just the\n * base — otherwise a spec whose own operationIds already look auto-suffixed\n * (e.g. both \"foo\" and \"foo_2\" present) could produce two identically-named\n * tools, one of which `FastMCP.addTool` would silently drop.\n */\nexport function generateNames(\n routes: HttpRoute[],\n mcpNames: Record<string, string> | undefined,\n): Map<HttpRoute, string> {\n const names = new Map<HttpRoute, string>();\n const used = new Set<string>();\n\n for (const route of routes) {\n const base = slugify(baseNameFor(route, mcpNames));\n let candidate = base;\n let suffix = 1;\n\n while (used.has(candidate)) {\n suffix += 1;\n candidate = `${base}_${suffix}`;\n }\n\n used.add(candidate);\n names.set(route, candidate);\n }\n\n return names;\n}\n\nfunction baseNameFor(\n route: HttpRoute,\n mcpNames: Record<string, string> | undefined,\n): string {\n if (route.operationId) {\n return mcpNames?.[route.operationId] ?? route.operationId.split(\"__\")[0];\n }\n\n return route.summary || `${route.method}_${route.path}`;\n}\n\nfunction slugify(value: string): string {\n const slug = value\n .replace(/[^a-zA-Z0-9_]+/g, \"_\")\n .replace(/_+/g, \"_\")\n .replace(/^_|_$/g, \"\")\n .slice(0, MAX_BASE_LENGTH);\n\n return slug || \"operation\";\n}\n","import type { ParameterMapping } from \"./schemas.js\";\nimport type { FromOpenAPIOptions, HttpRoute, OpenApiServer } from \"./types.js\";\n\nimport { UserError } from \"../FastMCP.js\";\n\nexport interface ExecuteRequestOptions {\n args: Record<string, unknown>;\n baseUrlOverride?: string;\n /** How to serialize a request body, if `args` contains any body-mapped values. */\n bodyEncoding?: \"form\" | \"json\";\n fetchImpl: typeof fetch;\n headers?: FromOpenAPIOptions[\"headers\"];\n origin?: string;\n parameterMap: Record<string, ParameterMapping>;\n route: HttpRoute;\n servers: OpenApiServer[] | undefined;\n wholeBodyKey?: string;\n}\n\nexport async function executeRequest(\n options: ExecuteRequestOptions,\n): Promise<string> {\n const baseUrl = resolveBaseUrl(\n options.servers,\n options.origin,\n options.baseUrlOverride,\n );\n\n const pathParams: Record<string, string> = {};\n const query = new URLSearchParams();\n // A plain object keys headers case-sensitively, so a caller-supplied\n // header (e.g. \"Content-Type\") wouldn't be recognized as the same header\n // as one this function sets internally (e.g. \"content-type\") — `Headers`\n // normalizes casing, so `.set()` correctly overrides rather than\n // combining into a comma-joined, malformed value.\n const headers = new Headers(await resolveHeaders(options.headers));\n const bodyProps: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(options.args)) {\n const mapping = options.parameterMap[key];\n\n if (!mapping || value === undefined) {\n continue;\n }\n\n switch (mapping.in) {\n case \"body\":\n bodyProps[mapping.name] = value;\n break;\n case \"cookie\": {\n const existing = headers.get(\"cookie\");\n headers.set(\n \"cookie\",\n existing\n ? `${existing}; ${mapping.name}=${String(value)}`\n : `${mapping.name}=${String(value)}`,\n );\n break;\n }\n case \"header\":\n headers.set(mapping.name, String(value));\n break;\n case \"path\":\n pathParams[mapping.name] = String(value);\n break;\n case \"query\":\n for (const item of Array.isArray(value) ? value : [value]) {\n query.append(mapping.name, String(item));\n }\n break;\n }\n }\n\n let path = options.route.path;\n\n for (const [name, value] of Object.entries(pathParams)) {\n path = path.replace(`{${name}}`, encodeURIComponent(value));\n }\n\n const url = new URL(baseUrl.replace(/\\/$/, \"\") + path);\n url.search = query.toString();\n\n let body: string | undefined;\n\n if (Object.keys(bodyProps).length > 0) {\n const payload = options.wholeBodyKey\n ? bodyProps[options.wholeBodyKey]\n : bodyProps;\n\n if (options.bodyEncoding === \"form\") {\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/x-www-form-urlencoded\");\n }\n\n body = encodeFormBody(payload);\n } else {\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n\n body = JSON.stringify(payload);\n }\n }\n\n const response = await options.fetchImpl(url.toString(), {\n body,\n headers,\n method: options.route.method.toUpperCase(),\n });\n\n const text = await response.text();\n\n if (!response.ok) {\n throw new UserError(\n `${options.route.method.toUpperCase()} ${path} failed with ${response.status}: ${text.slice(0, 2000)}`,\n );\n }\n\n if (response.headers.get(\"content-type\")?.includes(\"json\")) {\n try {\n return JSON.stringify(JSON.parse(text), null, 2);\n } catch {\n return text;\n }\n }\n\n return text;\n}\n\n/**\n * Resolves `servers[0].url` the way a real HTTP client needs it resolved,\n * not just the way a schema validator would accept it: a relative URL (e.g.\n * Petstore's own `\"/api/v3\"`) is joined against the document's own origin,\n * not passed through verbatim.\n */\nexport function resolveBaseUrl(\n servers: OpenApiServer[] | undefined,\n origin: string | undefined,\n overrideUrl: string | undefined,\n): string {\n if (overrideUrl) {\n return overrideUrl.replace(/\\/$/, \"\");\n }\n\n const server = servers?.[0];\n\n if (!server) {\n throw new Error(\n \"The OpenAPI document has no `servers` entry. Pass `baseUrl` to fromOpenAPI() explicitly.\",\n );\n }\n\n let url = server.url;\n\n for (const [name, variable] of Object.entries(server.variables ?? {})) {\n url = url.replaceAll(`{${name}}`, variable.default);\n }\n\n try {\n return new URL(url).toString().replace(/\\/$/, \"\");\n } catch {\n if (!origin) {\n throw new Error(\n `The OpenAPI document's servers[0].url (\"${url}\") is relative, and the spec was not loaded from an http(s) URL, so it cannot be resolved to an absolute address. Pass \\`baseUrl\\` to fromOpenAPI() explicitly.`,\n );\n }\n\n return new URL(url, origin).toString().replace(/\\/$/, \"\");\n }\n}\n\n/**\n * Serializes a flattened body payload as `application/x-www-form-urlencoded`.\n * Array values become repeated keys, matching the existing query-parameter\n * convention. A nested object/array *value* is JSON-stringified into a\n * single form value rather than expanded with bracket notation (e.g.\n * Stripe's own `metadata[key]=value` style) — correct for the flat scalar\n * properties that make up the overwhelming majority of real form-encoded\n * APIs (Stripe, Twilio), not a full form-encoding implementation.\n * `URLSearchParams` handles percent-encoding for free.\n */\nfunction encodeFormBody(payload: unknown): string {\n const params = new URLSearchParams();\n\n if (payload && typeof payload === \"object\" && !Array.isArray(payload)) {\n for (const [key, value] of Object.entries(\n payload as Record<string, unknown>,\n )) {\n if (value === undefined) {\n continue;\n }\n\n for (const item of Array.isArray(value) ? value : [value]) {\n params.append(\n key,\n item !== null && typeof item === \"object\"\n ? JSON.stringify(item)\n : String(item),\n );\n }\n }\n }\n\n return params.toString();\n}\n\nasync function resolveHeaders(\n headers: FromOpenAPIOptions[\"headers\"],\n): Promise<Record<string, string>> {\n if (!headers) {\n return {};\n }\n\n return typeof headers === \"function\" ? await headers() : { ...headers };\n}\n","import type { ParameterMapping } from \"./schemas.js\";\nimport type { HttpRoute } from \"./types.js\";\n\nexport type ResourceMapping =\n | {\n args: { name: string; required: boolean }[];\n kind: \"template\";\n uriTemplate: string;\n }\n | { kind: \"resource\"; uri: string };\n\n/**\n * Builds a static resource URI, or a resource template (URI + `arguments`),\n * for an eligible `GET` route — reusing the `parameterMap` and `required`\n * list `buildFlatSchema` already produced for it (path-always-required,\n * collision-suffixed flat keys) rather than re-deriving parameter\n * flattening from scratch.\n *\n * OpenAPI's `{petId}` path-parameter syntax is already valid RFC 6570 simple\n * string expansion, so the route's own path is reused verbatim except where\n * a flat key was collision-suffixed. Query parameters are appended as an\n * RFC 6570 query-expansion segment (`{?a,b}`), which `uri-templates`\n * (already a FastMCP dependency — see its own resource-template dispatch in\n * FastMCP.ts) parses and fills the same way it does path variables.\n */\nexport function buildResourceMapping(\n route: HttpRoute,\n name: string,\n parameterMap: Record<string, ParameterMapping>,\n requiredKeys: string[] | undefined,\n): ResourceMapping {\n const entries = Object.entries(parameterMap);\n\n if (entries.length === 0) {\n return { kind: \"resource\", uri: `openapi://${name}${route.path}` };\n }\n\n const required = new Set(requiredKeys ?? []);\n const args: { name: string; required: boolean }[] = [];\n const queryKeys: string[] = [];\n let path = route.path;\n\n for (const [flatKey, mapping] of entries) {\n if (mapping.in === \"path\") {\n if (flatKey !== mapping.name) {\n path = path.replace(`{${mapping.name}}`, `{${flatKey}}`);\n }\n } else {\n queryKeys.push(flatKey);\n }\n\n args.push({ name: flatKey, required: required.has(flatKey) });\n }\n\n const uriTemplate =\n `openapi://${name}${path}` +\n (queryKeys.length > 0 ? `{?${queryKeys.join(\",\")}}` : \"\");\n\n return { args, kind: \"template\", uriTemplate };\n}\n\n/**\n * Whether a `GET` route can become an MCP resource/resource template\n * instead of a tool, when `resources: true` is passed to `fromOpenAPI`. See\n * docs/openapi.md \"GET → resources\" for the reasoning behind each carve-out:\n *\n * - `header`/`cookie` parameters can't be expressed in a resource URI, and\n * MCP resource reads have no per-call side channel for them.\n * - An array-typed path/query parameter can't be represented consistently\n * between OpenAPI's query serialization (repeated keys) and RFC 6570's\n * array representation (comma-joined or `*`-exploded).\n *\n * A route failing either check falls through to the existing tool path —\n * this only ever *removes* operations from the tool list in favor of a\n * resource, never breaks one.\n */\nexport function isEligibleForResource(route: HttpRoute): boolean {\n return route.parameters.every((param) => {\n if (param.in === \"header\" || param.in === \"cookie\") {\n return false;\n }\n\n return param.schema?.type !== \"array\";\n });\n}\n","import type {\n BundledOpenApiDocument,\n HttpMethod,\n HttpRoute,\n OpenApiParameter,\n OpenApiParameterRef,\n OpenApiRequestBody,\n} from \"./types.js\";\n\nconst HTTP_METHODS: HttpMethod[] = [\"get\", \"put\", \"post\", \"delete\", \"patch\"];\n\n/**\n * Walks a bundled document's `paths` into a flat list of routes, resolving\n * any structural (non-schema) `$ref`s on parameters and request bodies —\n * e.g. `#/components/parameters/Limit` — against the same document.\n *\n * Bundling (see `loadSpec.ts`) guarantees every remaining `$ref` here is\n * local, so a plain JSON-pointer lookup is enough.\n */\nexport function extractRoutes(document: BundledOpenApiDocument): HttpRoute[] {\n const routes: HttpRoute[] = [];\n\n for (const [path, pathItem] of Object.entries(document.paths ?? {})) {\n const pathLevelParams = (pathItem.parameters ?? []).map((param) =>\n resolveRef<OpenApiParameter>(document, param),\n );\n\n for (const method of HTTP_METHODS) {\n const operation = pathItem[method];\n\n if (!operation) {\n continue;\n }\n\n const operationParams = (operation.parameters ?? []).map((param) =>\n resolveRef<OpenApiParameter>(document, param),\n );\n\n routes.push({\n deprecated: operation.deprecated ?? false,\n method,\n operationId: operation.operationId,\n parameters: mergeParameters(pathLevelParams, operationParams),\n path,\n requestBody: operation.requestBody\n ? resolveRef<OpenApiRequestBody>(document, operation.requestBody)\n : undefined,\n summary: operation.summary,\n tags: operation.tags ?? [],\n });\n }\n }\n\n return routes;\n}\n\nfunction mergeParameters(\n pathLevel: OpenApiParameter[],\n operationLevel: OpenApiParameter[],\n): OpenApiParameter[] {\n const overridden = new Set(\n operationLevel.map((param) => `${param.in}:${param.name}`),\n );\n\n return [\n ...pathLevel.filter(\n (param) => !overridden.has(`${param.in}:${param.name}`),\n ),\n ...operationLevel,\n ];\n}\n\nfunction resolveRef<TValue>(\n document: BundledOpenApiDocument,\n value: OpenApiParameterRef | TValue,\n): TValue {\n if (!value || typeof value !== \"object\" || !(\"$ref\" in value)) {\n return value;\n }\n\n const pointer = value.$ref;\n\n if (!pointer.startsWith(\"#/\")) {\n // Bundling should have already turned every external ref into a local\n // one — if this fires, swagger-parser's output shape has changed.\n throw new Error(`Unexpected external $ref after bundling: ${pointer}`);\n }\n\n // swagger-parser synthesizes these pointers as URI fragments (e.g. a path\n // like \"/pets/{petId}\" becomes \"~1pets~1%7BpetId%7D\"), so each segment\n // needs its \"~1\"/\"~0\" escapes undone *and* percent-decoding, in that order.\n const segments = pointer\n .slice(2)\n .split(\"/\")\n .map((segment) =>\n decodeURIComponent(segment.replaceAll(\"~1\", \"/\").replaceAll(\"~0\", \"~\")),\n );\n\n let node: unknown = document;\n\n for (const segment of segments) {\n node = (node as Record<string, unknown> | undefined)?.[segment];\n }\n\n return node as TValue;\n}\n","import type { JsonSchemaObject } from \"../jsonSchemaAdapter.js\";\nimport type {\n BundledOpenApiDocument,\n HttpRoute,\n OpenApiParameter,\n OpenApiRequestBody,\n OpenApiSchema,\n ParameterLocation,\n} from \"./types.js\";\n\n/**\n * Keys whose values are name-to-schema maps: their child keys are\n * author-chosen names rather than JSON Schema keywords.\n */\nconst SCHEMA_MAP_KEYS = new Set([\n \"$defs\",\n \"definitions\",\n \"dependentSchemas\",\n \"patternProperties\",\n \"properties\",\n]);\n\n/**\n * Keys whose values are arbitrary instance data rather than schemas. A\n * sample payload may well contain a \"$ref\" or \"nullable\" key of its own.\n */\nconst DATA_KEYS = new Set([\"const\", \"default\", \"enum\", \"example\", \"examples\"]);\n\n/**\n * Request body content types this module knows how to flatten and encode.\n * `application/json` wins when a route declares both.\n */\nexport const SUPPORTED_BODY_CONTENT_TYPES = [\n \"application/json\",\n \"application/x-www-form-urlencoded\",\n] as const;\n\nexport interface FlatSchemaResult {\n /** How the request body (if any properties were extracted) must be serialized. */\n bodyEncoding?: \"form\" | \"json\";\n flatSchema: JsonSchemaObject;\n parameterMap: Record<string, ParameterMapping>;\n /**\n * Set when `route.requestBody` declares a body this module can't carry:\n * either only in content type(s) it doesn't support (e.g.\n * `multipart/form-data`, `application/json-patch+json`,\n * `application/octet-stream`), or as `application/x-www-form-urlencoded`\n * with a schema that isn't a flat object, which form encoding can't\n * represent. Holds the content type the body was declared in. The caller\n * should not turn this route into a tool with a payload it can never\n * carry — see `fromOpenAPI.ts`.\n */\n unsupportedBodyContentType?: string;\n /**\n * Set when the request body's schema is not a flat object (e.g. an array,\n * or a bare non-object `$ref`) — the whole body is exposed as a single\n * property under this key, rather than flattened into individual\n * properties.\n */\n wholeBodyKey?: string;\n}\n\nexport interface ParameterMapping {\n in: \"body\" | ParameterLocation;\n name: string;\n}\n\ntype WalkMode = \"data\" | \"schema\" | \"schemaMap\";\n\n/**\n * Flattens a route's path/query/header/cookie parameters and request body\n * into a single tool input schema.\n *\n * Collision precedence ports the Python implementation's rule\n * (`utilities/openapi/schemas.py:_combine_schemas_and_map_params`): a name\n * that collides across path/query/header/cookie gets suffixed\n * `{name}__{location}`; a request body property with a colliding name always\n * keeps its bare name.\n *\n * `GET` never contributes a request body: `fetch` (and the Fetch spec in\n * general) rejects a body on a GET request, so a tool built from a spec's\n * (legal, if unusual) `GET` + `requestBody` operation would be permanently\n * broken. The request body is simply not flattened into the schema for such\n * a route, rather than surfacing a schema that can never actually be called.\n */\nexport function buildFlatSchema(\n route: HttpRoute,\n sharedDefs: Record<string, OpenApiSchema> | undefined,\n): FlatSchemaResult {\n const byName = new Map<string, OpenApiParameter[]>();\n\n for (const param of route.parameters) {\n const list = byName.get(param.name) ?? [];\n list.push(param);\n byName.set(param.name, list);\n }\n\n const {\n bodyEncoding,\n properties: bodyProperties,\n unsupportedBodyContentType,\n wholeBodyKey,\n } = extractBodyProperties(\n route.method === \"get\" ? undefined : route.requestBody,\n sharedDefs,\n );\n\n const properties: Record<string, OpenApiSchema> = {};\n const required: string[] = [];\n const parameterMap: Record<string, ParameterMapping> = {};\n\n for (const [name, occurrences] of byName) {\n const collides = occurrences.length > 1 || bodyProperties.has(name);\n\n for (const param of occurrences) {\n const key = collides ? `${name}__${param.in}` : name;\n\n properties[key] = rewriteComponentRefs(\n param.schema ?? { type: \"string\" },\n );\n parameterMap[key] = { in: param.in, name };\n\n if (param.in === \"path\" || param.required) {\n required.push(key);\n }\n }\n }\n\n for (const [name, { required: isRequired, schema }] of bodyProperties) {\n properties[name] = rewriteComponentRefs(schema);\n parameterMap[name] = { in: \"body\", name };\n\n if (isRequired) {\n required.push(name);\n }\n }\n\n const flatSchema: JsonSchemaObject = {\n additionalProperties: false,\n properties,\n type: \"object\",\n ...(required.length > 0 ? { required } : {}),\n };\n\n // Only the definitions this tool's own schema actually (transitively)\n // references — embedding the whole document's components.schemas into\n // every single tool would multiply the tools/list payload size by the\n // tool count for no benefit.\n const usedDefs = sharedDefs && filterReferencedDefs(properties, sharedDefs);\n\n if (usedDefs) {\n flatSchema.$defs = usedDefs;\n }\n\n return {\n bodyEncoding,\n flatSchema,\n parameterMap,\n unsupportedBodyContentType,\n wholeBodyKey,\n };\n}\n\nexport function buildSharedDefs(\n document: BundledOpenApiDocument,\n): Record<string, OpenApiSchema> | undefined {\n const schemas = document.components?.schemas;\n\n if (!schemas || Object.keys(schemas).length === 0) {\n return undefined;\n }\n\n return rewriteNode(schemas, \"schemaMap\") as Record<string, OpenApiSchema>;\n}\n\n/**\n * Rewrites `$ref`s pointing at `#/components/schemas/...` to `#/$defs/...`,\n * so a per-tool schema that contains one can be handed to AJV standalone,\n * alongside a `$defs` object built from the document's `components.schemas`\n * (see `buildSharedDefs`). Ports the equivalent rewrite from the Python\n * implementation (`utilities/openapi/schemas.py:_replace_ref_with_defs`).\n *\n * Also normalizes OpenAPI 3.0's `nullable` keyword (see `normalizeNullable`),\n * since real specs carry both.\n */\nexport function rewriteComponentRefs<TValue>(value: TValue): TValue {\n return rewriteNode(value, \"schema\") as TValue;\n}\n\nfunction childMode(key: string): WalkMode {\n if (DATA_KEYS.has(key)) {\n return \"data\";\n }\n\n return SCHEMA_MAP_KEYS.has(key) ? \"schemaMap\" : \"schema\";\n}\n\nfunction componentSchemaName(ref: string): string | undefined {\n for (const prefix of [\"#/components/schemas/\", \"#/$defs/\"]) {\n if (ref.startsWith(prefix)) {\n return ref.slice(prefix.length);\n }\n }\n\n return undefined;\n}\n\n/**\n * Picks the request body's content type and flattens its schema.\n *\n * `application/json` wins if a route declares both it and\n * `application/x-www-form-urlencoded` (a fixed preference, not declaration\n * order — the latter isn't a reliable signal). A route whose body is only\n * declared under a content type this module doesn't handle at all (e.g.\n * `multipart/form-data`) reports `unsupportedBodyContentType` instead of\n * silently returning an empty property map — that emptiness is exactly what\n * a real Stripe/Twilio operation (both form-urlencoded-only) looked like\n * before this function read anything but JSON, and it produced a tool with\n * no way to carry its actual payload. A bare `content: {}` (no content\n * types at all) still means \"no body,\" not \"unsupported\" — and so does a\n * supported content type with no `schema` at all (a legal, if unusual,\n * \"any JSON body\" declaration): the content type itself is fine, there's\n * just nothing to flatten.\n *\n * A form-urlencoded body is very often declared as a bare `$ref` to a\n * component schema rather than inline — FastAPI emits\n * `#/components/schemas/Body_<operation>` for every form endpoint, and\n * Box's OAuth token/refresh/revoke operations do the same. The document is\n * bundled, not dereferenced (see `loadSpec.ts`), so that `$ref` is resolved\n * here against `sharedDefs` before deciding whether the body is a flat\n * object. Only the form path needs this: a JSON body that isn't a flat\n * object falls back to a single whole-body property, which a `$ref`\n * satisfies as-is.\n *\n * A non-object body (array, `$ref` to a scalar/array, etc.) can't be\n * form-urlencoded at all — form encoding is inherently flat key/value pairs\n * — so that combination is also reported as unsupported, rather than\n * `encodeFormBody` (requestBuilder.ts) silently sending an empty body for\n * data it has no way to represent.\n */\nfunction extractBodyProperties(\n requestBody: OpenApiRequestBody | undefined,\n sharedDefs: Record<string, OpenApiSchema> | undefined,\n): {\n bodyEncoding?: \"form\" | \"json\";\n properties: Map<string, { required: boolean; schema: OpenApiSchema }>;\n unsupportedBodyContentType?: string;\n wholeBodyKey?: string;\n} {\n const properties = new Map<\n string,\n { required: boolean; schema: OpenApiSchema }\n >();\n\n const content = requestBody?.content;\n\n if (!content) {\n return { properties };\n }\n\n const hasJson = \"application/json\" in content;\n const hasForm = \"application/x-www-form-urlencoded\" in content;\n\n if (!hasJson && !hasForm) {\n const contentTypes = Object.keys(content);\n\n return contentTypes.length > 0\n ? { properties, unsupportedBodyContentType: contentTypes[0] }\n : { properties };\n }\n\n const bodyEncoding: \"form\" | \"json\" = hasJson ? \"json\" : \"form\";\n const declaredSchema = hasJson\n ? content[\"application/json\"]?.schema\n : content[\"application/x-www-form-urlencoded\"]?.schema;\n\n if (!declaredSchema) {\n // The content type is declared and supported; it just has no schema\n // (an unconstrained body) — nothing to flatten, but not unsupported.\n return { bodyEncoding, properties };\n }\n\n const schema =\n bodyEncoding === \"form\"\n ? resolveComponentRef(declaredSchema, sharedDefs)\n : declaredSchema;\n\n const schemaProperties = schema.properties as\n | Record<string, OpenApiSchema>\n | undefined;\n\n if (schema.type === \"object\" && schemaProperties) {\n const requiredNames = new Set(\n (schema.required as string[] | undefined) ?? [],\n );\n\n for (const [name, propertySchema] of Object.entries(schemaProperties)) {\n properties.set(name, {\n required: requiredNames.has(name),\n schema: propertySchema,\n });\n }\n\n return { bodyEncoding, properties };\n }\n\n if (bodyEncoding === \"form\") {\n return {\n properties,\n unsupportedBodyContentType: \"application/x-www-form-urlencoded\",\n };\n }\n\n // Non-object JSON body (array, bare $ref to a scalar/array, etc.) — expose\n // the whole thing as a single \"body\" property rather than flattening it.\n properties.set(\"body\", {\n required: requestBody?.required ?? false,\n schema,\n });\n\n return { bodyEncoding, properties, wholeBodyKey: \"body\" };\n}\n\n/**\n * Walks a schema fragment for `#/$defs/Name` refs and returns just those\n * definitions (transitively — a referenced def may itself reference\n * others), or `undefined` if none are referenced.\n */\nfunction filterReferencedDefs(\n node: unknown,\n allDefs: Record<string, OpenApiSchema>,\n): Record<string, OpenApiSchema> | undefined {\n const referenced = new Set<string>();\n const stack: unknown[] = [node];\n\n while (stack.length > 0) {\n const current = stack.pop();\n\n if (Array.isArray(current)) {\n stack.push(...current);\n continue;\n }\n\n if (!current || typeof current !== \"object\") {\n continue;\n }\n\n for (const [key, value] of Object.entries(\n current as Record<string, unknown>,\n )) {\n if (\n key === \"$ref\" &&\n typeof value === \"string\" &&\n value.startsWith(\"#/$defs/\")\n ) {\n const name = value.slice(\"#/$defs/\".length);\n\n if (allDefs[name] && !referenced.has(name)) {\n referenced.add(name);\n stack.push(allDefs[name]);\n }\n\n continue;\n }\n\n stack.push(value);\n }\n }\n\n if (referenced.size === 0) {\n return undefined;\n }\n\n return Object.fromEntries(\n [...referenced].map((name) => [name, allDefs[name]]),\n );\n}\n\n/**\n * OpenAPI 3.0's `nullable` keyword only makes sense alongside a sibling\n * `type`, which it widens (`nullable: true` + `type: \"string\"` means\n * \"string or null\") — but it is not itself standard JSON Schema. AJV\n * recognizes the keyword and throws ('\"nullable\" cannot be used without\n * \"type\"') if it finds one with no `type` on the same node, which real\n * specs do produce (e.g. `nullable` sibling to `oneOf`/`allOf`/`$ref`\n * instead of `type`, as in Box's API). Folded into `type` where there is\n * one to widen, dropped otherwise.\n */\nfunction normalizeNullable(\n schema: Record<string, unknown>,\n): Record<string, unknown> {\n if (!(\"nullable\" in schema)) {\n return schema;\n }\n\n const { nullable, type, ...rest } = schema;\n\n if (nullable !== true) {\n return rest;\n }\n\n if (typeof type === \"string\") {\n return { ...rest, type: [type, \"null\"] };\n }\n\n if (Array.isArray(type)) {\n return { ...rest, type: [...new Set([\"null\", ...type])] };\n }\n\n return rest;\n}\n\n/**\n * Follows a bare `$ref` into `components.schemas` — or its rewritten\n * `#/$defs/` form, which is what `sharedDefs` entries themselves carry —\n * until it reaches a concrete schema. A dangling or cyclic reference is\n * returned as-is rather than failing the whole conversion.\n */\nfunction resolveComponentRef(\n schema: OpenApiSchema,\n sharedDefs: Record<string, OpenApiSchema> | undefined,\n): OpenApiSchema {\n const seen = new Set<string>();\n let current = schema;\n let ref = current.$ref;\n\n while (typeof ref === \"string\") {\n const name = componentSchemaName(ref);\n const target = name === undefined ? undefined : sharedDefs?.[name];\n\n if (name === undefined || target === undefined || seen.has(name)) {\n break;\n }\n\n seen.add(name);\n current = target;\n ref = current.$ref;\n }\n\n return current;\n}\n\n/**\n * Walks a schema fragment, distinguishing the three kinds of node it can\n * reach — because only one of them is a schema whose keys are JSON Schema\n * keywords:\n *\n * - `\"schema\"` — a schema object. `$ref`/`nullable` here are keywords.\n * - `\"schemaMap\"` — a name-to-schema map (`properties`, `$defs`, ...). Its\n * keys are author-chosen names, so a property literally named `nullable`\n * or `$ref` is a field, not a keyword, and must survive untouched.\n * - `\"data\"` — arbitrary values (`default`, `enum`, `example`, ...). Not\n * schemas at all; passed through verbatim.\n *\n * Walking every node as a schema (as this originally did) silently deletes\n * a property named `nullable` from the generated tool schema, since\n * `normalizeNullable` cannot tell the keyword from a same-named field.\n */\nfunction rewriteNode(value: unknown, mode: WalkMode): unknown {\n if (mode === \"data\") {\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => rewriteNode(item, \"schema\"));\n }\n\n if (!value || typeof value !== \"object\") {\n return value;\n }\n\n const entries = Object.entries(value as Record<string, unknown>).map(\n ([key, entryValue]): [string, unknown] => {\n if (mode === \"schemaMap\") {\n return [key, rewriteNode(entryValue, \"schema\")];\n }\n\n if (\n key === \"$ref\" &&\n typeof entryValue === \"string\" &&\n entryValue.startsWith(\"#/components/schemas/\")\n ) {\n return [key, entryValue.replace(\"#/components/schemas/\", \"#/$defs/\")];\n }\n\n return [key, rewriteNode(entryValue, childMode(key))];\n },\n );\n\n const rewritten = Object.fromEntries(entries) as Record<string, unknown>;\n\n return mode === \"schemaMap\" ? rewritten : normalizeNullable(rewritten);\n}\n","import type {\n FromOpenAPIOptions,\n HttpMethod,\n HttpRoute,\n OperationSummary,\n} from \"./types.js\";\n\n/**\n * If neither `include`/`exclude` nor `maxTools` was given, and a spec still\n * produces more operations than this, `selectRoutes` throws rather than\n * silently generating a wall of tools most clients can't usefully work with.\n */\nexport const DEFAULT_MAX_OPERATIONS = 40;\n\nconst METHOD_PRIORITY: Record<HttpMethod, number> = {\n delete: 4,\n get: 0,\n patch: 3,\n post: 1,\n put: 2,\n};\n\n/**\n * Filters and orders routes into the set that becomes tools.\n *\n * Deprecated operations are excluded by default. Ordering is deterministic\n * (method priority GET→POST→PUT→PATCH→DELETE, then path) so that, combined\n * with `maxTools`, truncation is legible rather than arbitrary.\n */\nexport function selectRoutes(\n routes: HttpRoute[],\n options: Pick<FromOpenAPIOptions, \"exclude\" | \"include\" | \"maxTools\">,\n): HttpRoute[] {\n let selected = routes.filter((route) => !route.deprecated);\n\n if (options.include) {\n const include = options.include;\n selected = selected.filter((route) => include(toSummary(route)));\n }\n\n if (options.exclude) {\n const exclude = options.exclude;\n selected = selected.filter((route) => !exclude(toSummary(route)));\n }\n\n selected = [...selected].sort((a, b) => {\n const byMethod = METHOD_PRIORITY[a.method] - METHOD_PRIORITY[b.method];\n return byMethod !== 0 ? byMethod : a.path.localeCompare(b.path);\n });\n\n const noSelectionGiven = !options.include && !options.exclude;\n\n if (\n noSelectionGiven &&\n options.maxTools === undefined &&\n selected.length > DEFAULT_MAX_OPERATIONS\n ) {\n throw new Error(\n `fromOpenAPI found ${selected.length} operations, which exceeds the default limit of ${DEFAULT_MAX_OPERATIONS}. ` +\n \"This is a deliberate stop, not a bug: turning every operation in a large spec into a tool produces a tool list most MCP clients can't use well. \" +\n \"Pass `include`/`exclude` to choose the operations you actually want, or `maxTools` to raise this limit explicitly.\",\n );\n }\n\n if (options.maxTools !== undefined && selected.length > options.maxTools) {\n throw new Error(\n `fromOpenAPI found ${selected.length} operations, which exceeds maxTools (${options.maxTools}). ` +\n \"Narrow the spec with `include`/`exclude`, or raise `maxTools`.\",\n );\n }\n\n return selected;\n}\n\nfunction toSummary(route: HttpRoute): OperationSummary {\n return {\n deprecated: route.deprecated,\n method: route.method,\n operationId: route.operationId,\n path: route.path,\n tags: route.tags,\n };\n}\n","import type { ResourceResult } from \"../FastMCP.js\";\nimport type { ParameterMapping } from \"./schemas.js\";\nimport type { HttpRoute } from \"./types.js\";\nimport type { FromOpenAPIOptions } from \"./types.js\";\n\nimport { FastMCP } from \"../FastMCP.js\";\nimport { jsonSchemaAdapter } from \"../jsonSchemaAdapter.js\";\nimport { loadSpec } from \"./loadSpec.js\";\nimport { generateNames } from \"./naming.js\";\nimport { executeRequest } from \"./requestBuilder.js\";\nimport {\n buildResourceMapping,\n isEligibleForResource,\n} from \"./resourceMapping.js\";\nimport { extractRoutes } from \"./routes.js\";\nimport { buildFlatSchema, buildSharedDefs } from \"./schemas.js\";\nimport { selectRoutes } from \"./selection.js\";\n\n/**\n * Converts an OpenAPI 3.x document into an MCP server, one tool (or, with\n * `resources: true`, resource/resource template for an eligible `GET`) per\n * operation.\n *\n * See docs/openapi.md for the full option reference and known limitations.\n */\nexport async function fromOpenAPI(\n options: FromOpenAPIOptions,\n): Promise<FastMCP> {\n const { document, origin } = await loadSpec(options.spec);\n const routes = extractRoutes(document);\n const selected = selectRoutes(routes, options);\n const names = generateNames(selected, options.mcpNames);\n const sharedDefs = buildSharedDefs(document);\n\n const server =\n options.server ??\n new FastMCP({\n name: options.name ?? document.info?.title ?? \"OpenAPI Server\",\n version: options.version ?? \"1.0.0\",\n });\n\n const skippedOperations: {\n contentType: string;\n method: string;\n path: string;\n }[] = [];\n\n for (const route of selected) {\n const name = names.get(route);\n\n if (!name) {\n continue;\n }\n\n const {\n bodyEncoding,\n flatSchema,\n parameterMap,\n unsupportedBodyContentType,\n wholeBodyKey,\n } = buildFlatSchema(route, sharedDefs);\n\n const execOptions = {\n baseUrlOverride: options.baseUrl,\n fetchImpl: options.fetch ?? fetch,\n headers: options.headers,\n origin,\n parameterMap,\n route,\n servers: document.servers,\n };\n\n if (\n options.resources &&\n route.method === \"get\" &&\n isEligibleForResource(route)\n ) {\n registerResource(\n server,\n route,\n name,\n parameterMap,\n flatSchema.required,\n execOptions,\n );\n continue;\n }\n\n if (unsupportedBodyContentType) {\n skippedOperations.push({\n contentType: unsupportedBodyContentType,\n method: route.method,\n path: route.path,\n });\n continue;\n }\n\n server.addTool({\n description:\n route.summary ?? `${route.method.toUpperCase()} ${route.path}`,\n execute: async (args) =>\n executeRequest({\n ...execOptions,\n args: args as Record<string, unknown>,\n bodyEncoding,\n wholeBodyKey,\n }),\n name,\n parameters: jsonSchemaAdapter(flatSchema),\n });\n }\n\n if (skippedOperations.length > 0) {\n console.warn(\n \"fromOpenAPI: skipped \" +\n `${skippedOperations.length} operation(s) whose request body can't be turned into tool parameters ` +\n \"(supported: application/json, or application/x-www-form-urlencoded with a flat object schema): \" +\n skippedOperations\n .map(\n (op) => `${op.method.toUpperCase()} ${op.path} (${op.contentType})`,\n )\n .join(\", \"),\n );\n }\n\n return server;\n}\n\nfunction registerResource(\n server: FastMCP,\n route: HttpRoute,\n name: string,\n parameterMap: Record<string, ParameterMapping>,\n requiredKeys: string[] | undefined,\n execOptions: Omit<\n Parameters<typeof executeRequest>[0],\n \"args\" | \"bodyEncoding\" | \"wholeBodyKey\"\n >,\n): void {\n const mapping = buildResourceMapping(route, name, parameterMap, requiredKeys);\n const description = route.summary ?? `GET ${route.path}`;\n\n if (mapping.kind === \"resource\") {\n server.addResource({\n description,\n load: async () =>\n wrapAsResourceResult(\n await executeRequest({ ...execOptions, args: {} }),\n ),\n name,\n uri: mapping.uri,\n });\n\n return;\n }\n\n server.addResourceTemplate({\n arguments: mapping.args,\n description,\n load: async (args) =>\n wrapAsResourceResult(\n await executeRequest({\n ...execOptions,\n args: args as Record<string, unknown>,\n }),\n ),\n name,\n uriTemplate: mapping.uriTemplate,\n });\n}\n\nfunction wrapAsResourceResult(text: string): ResourceResult {\n try {\n JSON.parse(text);\n return { mimeType: \"application/json\", text };\n } catch {\n return { mimeType: \"text/plain\", text };\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastmcp",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.19.0",
|
|
4
4
|
"main": "dist/FastMCP.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsup",
|
|
7
7
|
"lint": "prettier --check . && eslint . && tsc --noEmit && jsr publish --dry-run",
|
|
8
8
|
"test": "vitest run",
|
|
9
|
+
"test:openapi": "OPENAPI_NETWORK=1 vitest run src/openapi/fromOpenAPI.benchmark.test.ts src/openapi/fromOpenAPI.live.test.ts",
|
|
10
|
+
"test:openapi:refresh": "node scripts/refresh-openapi-benchmark-specs.mjs",
|
|
9
11
|
"format": "prettier --write . && eslint --fix ."
|
|
10
12
|
},
|
|
11
13
|
"bin": {
|
|
@@ -36,9 +38,15 @@
|
|
|
36
38
|
"import": "./dist/edge/index.js",
|
|
37
39
|
"types": "./dist/edge/index.d.ts",
|
|
38
40
|
"require": "./dist/edge/index.cjs"
|
|
41
|
+
},
|
|
42
|
+
"./openapi": {
|
|
43
|
+
"import": "./dist/openapi/index.js",
|
|
44
|
+
"types": "./dist/openapi/index.d.ts",
|
|
45
|
+
"require": "./dist/openapi/index.cjs"
|
|
39
46
|
}
|
|
40
47
|
},
|
|
41
48
|
"dependencies": {
|
|
49
|
+
"@apidevtools/swagger-parser": "^12.1.0",
|
|
42
50
|
"@modelcontextprotocol/sdk": "^1.24.3",
|
|
43
51
|
"@standard-schema/spec": "^1.0.0",
|
|
44
52
|
"execa": "^9.6.1",
|
|
@@ -123,6 +131,7 @@
|
|
|
123
131
|
"src/bin/fastmcp.ts",
|
|
124
132
|
"src/auth/index.ts",
|
|
125
133
|
"src/edge/index.ts",
|
|
134
|
+
"src/openapi/index.ts",
|
|
126
135
|
"src/examples/custom-routes.ts"
|
|
127
136
|
],
|
|
128
137
|
"format": [
|