mcp-from-openapi 2.5.1 → 2.6.1

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 CHANGED
@@ -6,6 +6,7 @@
6
6
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-yellow.svg)](https://opensource.org/license/apache-2-0)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
8
8
  [![Node.js](https://img.shields.io/badge/Node.js-20+-green.svg)](https://nodejs.org/)
9
+ [![CodeQL](https://github.com/agentfront/mcp-from-openapi/actions/workflows/codeql.yml/badge.svg)](https://github.com/agentfront/mcp-from-openapi/actions/workflows/codeql.yml)
9
10
 
10
11
  ## What This Solves
11
12
 
@@ -18,14 +19,14 @@ paths:
18
19
  /users/{id}:
19
20
  post:
20
21
  parameters:
21
- - name: id # path
22
+ - name: id # path
22
23
  in: path
23
24
  requestBody:
24
25
  content:
25
26
  application/json:
26
27
  schema:
27
28
  properties:
28
- id: # body -- CONFLICT!
29
+ id: # body -- CONFLICT!
29
30
  type: string
30
31
  ```
31
32
 
@@ -50,14 +51,20 @@ Now you know exactly how to build the HTTP request.
50
51
 
51
52
  ## Features
52
53
 
53
- - **Smart Parameter Handling** -- Automatic conflict detection and resolution across path, query, header, cookie, and body
54
- - **Complete Schemas** -- Input schema combines all parameters; output schema from responses (with oneOf unions)
55
- - **Security Resolution** -- Framework-agnostic auth for Bearer, Basic, Digest, API Key, OAuth2, OpenID, mTLS, HMAC, AWS Sig V4
56
- - **SSRF Prevention** -- Blocks internal IPs, localhost, and cloud metadata endpoints by default during `$ref` resolution
54
+ - **Built-in Request Builder** -- `buildHttpRequest()` applies the full OpenAPI serialization table (form/deepObject/pipeDelimited queries, label/matrix paths, multipart, binary, `wholeBody`) so you never hand-write request assembly
55
+ - **Client Compatibility Targets** -- `target: 'claude' | 'openai' | 'gemini' | 'strict'` emits schemas each client actually accepts (inlined refs, closed objects, collapsed unions, demoted formats)
56
+ - **Context-Budget Reports** -- `analyzeToolSet()` estimates the token bill per tool and warns at the thresholds where agent accuracy degrades
57
+ - **Overlays & Lint** -- apply [OpenAPI Overlay](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/curation.md) curation files at load time; `lint()` flags the spec gaps that hurt tool-calling accuracy
58
+ - **Curation-Grade Filtering** -- Filter by tag, method, path glob (`/admin/**`), operationId, a `readOnlyOnly` safety switch, and `x-mcp` extension flags with root < path < operation precedence
59
+ - **Smart Parameter Handling** -- Automatic conflict detection and resolution across path, query, header, cookie, and body; `allOf` bodies flatten, union and binary bodies map cleanly (`wholeBody`, `binary` markers)
60
+ - **Complete Schemas** -- Input schema combines all parameters; output schema from responses (with oneOf unions); clean JSON Schema 2020-12 output (`nullable` unions, normalized `examples`)
61
+ - **MCP-Native Tools** -- `title` and tool `annotations` (readOnly/destructive/idempotent hints) inferred from HTTP semantics, overridable via the `x-mcp` extension family; spec-compliant tool names (64-char cap, stable hash truncation, collision dedup); deterministic tool ordering for prompt-cache friendliness; `toSdkTool()` for one-line SDK registration
62
+ - **Security Resolution** -- Framework-agnostic auth for Bearer, Basic, Digest, API Key, OAuth2, OpenID, mTLS, HMAC, AWS Sig V4; per-scheme `includeSecurityInInput`
63
+ - **SSRF Prevention** -- Blocks internal IPs, localhost, and cloud metadata endpoints by default during `$ref` resolution; one-flag `secureDefaults` posture for untrusted specs
57
64
  - **Multiple Input Sources** -- Load from URL, file, YAML string, or JSON object
58
65
  - **Rich Metadata** -- Authentication, servers, tags, deprecation, external docs, `x-frontmcp` extension
59
- - **Production Ready** -- Full TypeScript support, validation, structured errors, 80%+ test coverage
60
- - **MCP Native** -- Designed specifically for Model Context Protocol integration
66
+ - **Production Ready** -- Full TypeScript support, validation, structured errors, 100% test coverage (enforced)
67
+ - **Runtime Agnostic** -- Works on Node and V8 isolates (Cloudflare Workers) alike
61
68
 
62
69
  ## Installation
63
70
 
@@ -72,86 +79,89 @@ pnpm add mcp-from-openapi
72
79
  ## Quick Start
73
80
 
74
81
  ```typescript
75
- import { OpenAPIToolGenerator } from 'mcp-from-openapi';
82
+ import { OpenAPIToolGenerator } from "mcp-from-openapi";
76
83
 
77
84
  // Load an OpenAPI spec
78
- const generator = await OpenAPIToolGenerator.fromURL('https://api.example.com/openapi.json');
85
+ const generator = await OpenAPIToolGenerator.fromURL(
86
+ "https://api.example.com/openapi.json",
87
+ );
79
88
 
80
89
  // Generate MCP tools
81
90
  const tools = await generator.generateTools();
82
91
 
83
92
  // Each tool has everything you need
84
93
  tools.forEach((tool) => {
85
- console.log(tool.name); // "createUser"
86
- console.log(tool.inputSchema); // Combined schema for all params
87
- console.log(tool.outputSchema); // Response schema
88
- console.log(tool.mapper); // How to build the HTTP request
89
- console.log(tool.metadata); // Auth, servers, tags, etc.
94
+ console.log(tool.name); // "createUser"
95
+ console.log(tool.title); // "Create a user" (from summary/extensions)
96
+ console.log(tool.annotations); // { readOnlyHint: false, destructiveHint: true, ... }
97
+ console.log(tool.inputSchema); // Combined schema for all params
98
+ console.log(tool.outputSchema); // Response schema
99
+ console.log(tool.mapper); // How to build the HTTP request
100
+ console.log(tool.metadata); // Auth, servers, tags, etc.
90
101
  });
91
102
  ```
92
103
 
93
- ## Using the Mapper
104
+ ## Building Requests
94
105
 
95
- The mapper tells you how to convert tool inputs into an HTTP request:
106
+ `buildHttpRequest()` turns a tool plus input values into a ready-to-send request — style/explode serialization, deepObject queries, multipart, binary, and `wholeBody` handled correctly:
96
107
 
97
108
  ```typescript
98
- function buildRequest(tool: McpOpenAPITool, input: Record<string, any>) {
99
- let path = tool.metadata.path;
100
- const query = new URLSearchParams();
101
- const headers: Record<string, string> = {};
102
- let body: Record<string, any> | undefined;
103
-
104
- for (const m of tool.mapper) {
105
- const value = input[m.inputKey];
106
- if (value === undefined) continue;
107
-
108
- switch (m.type) {
109
- case 'path':
110
- path = path.replace(`{${m.key}}`, encodeURIComponent(value));
111
- break;
112
- case 'query':
113
- query.set(m.key, String(value));
114
- break;
115
- case 'header':
116
- headers[m.key] = String(value);
117
- break;
118
- case 'body':
119
- if (!body) body = {};
120
- body[m.key] = value;
121
- break;
122
- }
123
- }
109
+ import { buildHttpRequest } from "mcp-from-openapi";
110
+
111
+ const request = buildHttpRequest(tool, { id: "42", filter: { tag: "news" } });
112
+ // { url: 'https://api.example.com/users/42?filter[tag]=news',
113
+ // method: 'GET', headers: {...}, body: undefined, ... }
114
+
115
+ await fetch(request.url, {
116
+ method: request.method,
117
+ headers: request.headers,
118
+ body: request.body as BodyInit,
119
+ });
120
+ ```
124
121
 
125
- const baseUrl = tool.metadata.servers?.[0]?.url ?? '';
126
- const qs = query.toString();
122
+ The `mapper` array stays public for anyone who needs custom request assembly — see [Request Builder](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/request-builder.md) and [Parameter Conflicts](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/parameter-conflicts.md) for its contract.
127
123
 
128
- return {
129
- url: `${baseUrl}${path}${qs ? '?' + qs : ''}`,
130
- method: tool.metadata.method.toUpperCase(),
131
- headers,
132
- body: body ? JSON.stringify(body) : undefined,
133
- };
124
+ ## Serving with the Official MCP SDK
125
+
126
+ ```typescript
127
+ import { toSdkTool, buildHttpRequest } from "mcp-from-openapi";
128
+ import { fromJsonSchema } from "@modelcontextprotocol/server"; // SDK v2
129
+
130
+ for (const tool of await generator.generateTools({ target: "claude" })) {
131
+ server.registerTool(...toSdkTool(tool, { fromJsonSchema }), async (input) => {
132
+ const request = buildHttpRequest(tool, input);
133
+ const response = await fetch(request.url, {
134
+ method: request.method,
135
+ headers: request.headers,
136
+ body: request.body as BodyInit,
137
+ });
138
+ return { content: [{ type: "text", text: await response.text() }] };
139
+ });
134
140
  }
135
141
  ```
136
142
 
137
143
  ## Documentation
138
144
 
139
- | Document | Description |
140
- |----------|-------------|
141
- | [Getting Started](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/getting-started.md) | Loading specs, generating tools, building requests |
142
- | [Configuration](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/configuration.md) | LoadOptions, GenerateOptions, RefResolutionOptions |
143
- | [Parameter Conflicts](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/parameter-conflicts.md) | How conflict detection and resolution works |
144
- | [Response Schemas](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/response-schemas.md) | Output schemas, status codes, oneOf unions |
145
- | [Security](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/security.md) | SecurityResolver, all auth types, custom resolvers |
146
- | [SSRF Prevention](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/ssrf-prevention.md) | Ref resolution security, blocked IPs and hosts |
147
- | [Format Resolution](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/FORMAT_RESOLUTION.md) | Format-to-schema enrichment (uuid, date-time, email, int32, etc.) |
148
- | [Naming Strategies](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/naming-strategies.md) | Custom tool naming and conflict resolvers |
149
- | [SchemaBuilder](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/schema-builder.md) | JSON Schema utility methods |
150
- | [Error Handling](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/error-handling.md) | Error classes, context, and patterns |
151
- | [x-frontmcp Extension](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/x-frontmcp.md) | Custom OpenAPI extension for MCP annotations |
152
- | [API Reference](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/api-reference.md) | Complete types, interfaces, and exports |
153
- | [Examples](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/examples.md) | MCP server, Zod, filtering, security, and more |
154
- | [Architecture](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/architecture.md) | System overview, data flow, design patterns |
145
+ | Document | Description |
146
+ | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
147
+ | [Getting Started](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/getting-started.md) | Loading specs, generating tools, building requests |
148
+ | [Configuration](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/configuration.md) | LoadOptions, GenerateOptions, RefResolutionOptions |
149
+ | [Parameter Conflicts](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/parameter-conflicts.md) | How conflict detection and resolution works |
150
+ | [Request Builder](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/request-builder.md) | `buildHttpRequest` — full OpenAPI parameter serialization |
151
+ | [Client Targets](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/client-targets.md) | Per-client schema dialects (Claude, OpenAI, Gemini) |
152
+ | [Curation](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/curation.md) | Token budgets, overlays, lint, trimming, response hints |
153
+ | [Response Schemas](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/response-schemas.md) | Output schemas, status codes, oneOf unions |
154
+ | [Annotations & Extensions](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/annotations.md) | Tool title, annotation inference, `x-mcp` extension family |
155
+ | [Security](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/security.md) | SecurityResolver, all auth types, custom resolvers |
156
+ | [SSRF Prevention](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/ssrf-prevention.md) | Ref resolution security, blocked IPs and hosts |
157
+ | [Format Resolution](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/FORMAT_RESOLUTION.md) | Format-to-schema enrichment (uuid, date-time, email, int32, etc.) |
158
+ | [Naming Strategies](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/naming-strategies.md) | Custom tool naming and conflict resolvers |
159
+ | [SchemaBuilder](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/schema-builder.md) | JSON Schema utility methods |
160
+ | [Error Handling](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/error-handling.md) | Error classes, context, and patterns |
161
+ | [x-frontmcp Extension](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/x-frontmcp.md) | Custom OpenAPI extension for MCP annotations |
162
+ | [API Reference](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/api-reference.md) | Complete types, interfaces, and exports |
163
+ | [Examples](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/examples.md) | MCP server, Zod, filtering, security, and more |
164
+ | [Architecture](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/architecture.md) | System overview, data flow, design patterns |
155
165
 
156
166
  ## Requirements
157
167
 
@@ -161,7 +171,18 @@ function buildRequest(tool: McpOpenAPITool, input: Record<string, any>) {
161
171
 
162
172
  ## Contributing
163
173
 
164
- Contributions are welcome! Please see our [issues page](https://github.com/agentfront/mcp-from-openapi/issues).
174
+ Contributions are welcome! Start with the
175
+ [contributing guide](https://github.com/agentfront/mcp-from-openapi/blob/main/CONTRIBUTING.md);
176
+ this project follows the
177
+ [Contributor Covenant](https://github.com/agentfront/mcp-from-openapi/blob/main/CODE_OF_CONDUCT.md).
178
+ Bug reports and feature requests go through the
179
+ [issue templates](https://github.com/agentfront/mcp-from-openapi/issues/new/choose).
180
+
181
+ ## Security
182
+
183
+ Report vulnerabilities privately — see the
184
+ [security policy](https://github.com/agentfront/mcp-from-openapi/blob/main/SECURITY.md).
185
+ When loading untrusted specs, use `secureDefaults: true`.
165
186
 
166
187
  ## Related Projects
167
188
 
@@ -0,0 +1,57 @@
1
+ import type { HTTPMethod, OperationObject, ToolAnnotations } from './types';
2
+ /**
3
+ * Tool-level overrides read from the `x-mcp` extension family on an operation.
4
+ */
5
+ export interface ExtensionToolOverrides {
6
+ /**
7
+ * Operation explicitly excluded from tool generation
8
+ * (`x-mcp: false`, `x-mcp: { enabled: false }`, or
9
+ * `x-speakeasy-mcp: { disabled: true }`).
10
+ */
11
+ disabled?: boolean;
12
+ /**
13
+ * Tool name override (still normalized to MCP name rules).
14
+ */
15
+ name?: string;
16
+ /**
17
+ * Display title override.
18
+ */
19
+ title?: string;
20
+ /**
21
+ * LLM-facing description override.
22
+ */
23
+ description?: string;
24
+ /**
25
+ * Annotation overrides, merged field-by-field over inferred values.
26
+ */
27
+ annotations?: ToolAnnotations;
28
+ }
29
+ /**
30
+ * Default MCP tool annotations per HTTP method, derived from HTTP semantics
31
+ * (RFC 9110 safety/idempotency): safe methods are read-only and idempotent;
32
+ * PUT/DELETE are idempotent but may destroy state; POST/PATCH are neither
33
+ * safe nor idempotent. `openWorldHint` is false throughout — tools generated
34
+ * from a spec target one known API backend, a closed world.
35
+ */
36
+ export declare function inferAnnotationsFromMethod(method: HTTPMethod): ToolAnnotations;
37
+ /**
38
+ * Resolve whether an operation is enabled for tool generation, honoring the
39
+ * `x-mcp` extension at every level with harsha-compatible precedence:
40
+ * root (document) < path item < operation. A root-level `x-mcp: false` flips
41
+ * the whole spec to opt-in; a path or operation level `x-mcp: true` (or
42
+ * `{ enabled: true }`) re-enables its subtree. At the operation level the
43
+ * whole extension family participates (`x-speakeasy-mcp: { disabled }` too),
44
+ * with the family's own precedence.
45
+ */
46
+ export declare function resolveExtensionEnabled(document: object, pathItem: object, operation: OperationObject): boolean;
47
+ /**
48
+ * Extract tool overrides from the `x-mcp` extension family on an operation.
49
+ *
50
+ * Precedence (ascending — later overrides earlier, field-by-field):
51
+ * 1. `x-speakeasy-mcp` — `{ disabled, name, title, description, readOnlyHint, ... }`
52
+ * (Speakeasy places annotation hints at the top level of the object)
53
+ * 2. `x-mcp` — `false` to exclude, or `{ enabled, name, title, description, annotations }`
54
+ * 3. `x-frontmcp` — the canonical extension for this stack; its `annotations`
55
+ * (including `annotations.title`) win over the generic variants
56
+ */
57
+ export declare function extractExtensionOverrides(operation: OperationObject): ExtensionToolOverrides;
@@ -0,0 +1,55 @@
1
+ import type { JsonSchema } from './types';
2
+ /**
3
+ * Client dialect targets. Every MCP client accepts a different JSON Schema
4
+ * subset; a target applies the transforms that make schemas valid for it:
5
+ *
6
+ * - `strict` — the safe baseline for all clients: local `$ref`/`$defs`
7
+ * inlined, arrays always carry `items`, root-level compositions collapsed
8
+ * - `claude` — `strict` (Claude additionally rejects top-level unions on
9
+ * `input_schema` and caps tool names at 64 chars — both already covered by
10
+ * the generator's defaults)
11
+ * - `openai` — `strict` + every object closed (`additionalProperties: false`,
12
+ * required by OpenAI strict function calling)
13
+ * - `gemini` — `strict` + unions collapsed at every level and unsupported
14
+ * `format` values demoted to descriptions (Gemini rejects `$ref`/`$defs`,
15
+ * union-heavy schemas, and most string formats)
16
+ */
17
+ export type ClientTarget = 'claude' | 'openai' | 'gemini' | 'strict';
18
+ /**
19
+ * Resolve local `$ref` pointers against the schema's own `$defs`/`definitions`
20
+ * and strip the definition blocks. Cycles and unresolvable pointers become
21
+ * permissive `{}` nodes with an explanatory description. (Generated schemas
22
+ * are usually fully dereferenced already — this covers `dereference: false`
23
+ * flows and hand-fed schemas.)
24
+ */
25
+ export declare function inlineLocalRefs(schema: JsonSchema): JsonSchema;
26
+ /** Ensure every array schema carries an `items` schema (permissive when absent). */
27
+ export declare function ensureArrayItems(schema: JsonSchema): JsonSchema;
28
+ /**
29
+ * Collapse ROOT-level compositions only: `allOf` merges; `oneOf`/`anyOf`
30
+ * become a permissive node that documents the variants and preserves them
31
+ * under `x-variants`. The nullable wrapper unwraps to its non-null member.
32
+ */
33
+ export declare function collapseRootCompositions(schema: JsonSchema): JsonSchema;
34
+ /**
35
+ * Collapse unions at EVERY level (Gemini): nullable wrappers unwrap with a
36
+ * note; other `oneOf`/`anyOf` keep their first variant and document the
37
+ * omitted alternatives; `allOf` merges.
38
+ */
39
+ export declare function collapseNestedUnions(schema: JsonSchema): JsonSchema;
40
+ /** Demote unsupported `format` values into descriptions (Gemini). */
41
+ export declare function demoteFormats(schema: JsonSchema, supported?: Set<string>): JsonSchema;
42
+ /** Close every object node (`additionalProperties: false`) — OpenAI strict mode. */
43
+ export declare function enforceClosedObjects(schema: JsonSchema): JsonSchema;
44
+ /**
45
+ * OpenAI strict function calling requires EVERY property to be listed in
46
+ * `required`; optional fields are expressed as required-but-nullable. This
47
+ * rewrites each object node accordingly (typed optionals gain a `null` type;
48
+ * untyped optionals are already permissive).
49
+ */
50
+ export declare function requireAllProperties(schema: JsonSchema): JsonSchema;
51
+ /**
52
+ * Apply a client target's transform pipeline to a schema. Also exported for
53
+ * standalone use on schemas that did not come from the generator.
54
+ */
55
+ export declare function applyClientTarget(schema: JsonSchema, target: ClientTarget): JsonSchema;
package/errors.d.ts CHANGED
@@ -43,6 +43,20 @@ export declare class ValidationError extends OpenAPIToolError {
43
43
  export declare class GenerationError extends OpenAPIToolError {
44
44
  constructor(message: string, context?: Record<string, any>);
45
45
  }
46
+ /**
47
+ * Error thrown when an OpenAPI Overlay document is malformed or its JSONPath
48
+ * target uses unsupported syntax
49
+ */
50
+ export declare class OverlayError extends OpenAPIToolError {
51
+ constructor(message: string, context?: Record<string, any>);
52
+ }
53
+ /**
54
+ * Error thrown when an HTTP request cannot be built from a tool's mapper
55
+ * (missing required parameters, unserializable values, injection attempts)
56
+ */
57
+ export declare class RequestBuildError extends OpenAPIToolError {
58
+ constructor(message: string, context?: Record<string, any>);
59
+ }
46
60
  /**
47
61
  * Error thrown when a schema is invalid
48
62
  */