mcp-from-openapi 2.5.0 → 2.6.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 +73 -67
- package/annotations.d.ts +57 -0
- package/client-targets.d.ts +55 -0
- package/errors.d.ts +7 -0
- package/esm/index.mjs +2359 -1112
- package/esm/package.json +1 -1
- package/generator.d.ts +1 -1
- package/index.d.ts +10 -2
- package/index.js +2374 -1113
- package/package.json +1 -1
- package/parameter-resolver.d.ts +23 -2
- package/request-builder.d.ts +52 -0
- package/response-builder.d.ts +1 -0
- package/schema-builder.d.ts +17 -0
- package/sdk.d.ts +22 -0
- package/ssrf.d.ts +76 -14
- package/types.d.ts +164 -19
package/README.md
CHANGED
|
@@ -18,14 +18,14 @@ paths:
|
|
|
18
18
|
/users/{id}:
|
|
19
19
|
post:
|
|
20
20
|
parameters:
|
|
21
|
-
- name: id
|
|
21
|
+
- name: id # path
|
|
22
22
|
in: path
|
|
23
23
|
requestBody:
|
|
24
24
|
content:
|
|
25
25
|
application/json:
|
|
26
26
|
schema:
|
|
27
27
|
properties:
|
|
28
|
-
id:
|
|
28
|
+
id: # body -- CONFLICT!
|
|
29
29
|
type: string
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -50,14 +50,18 @@ Now you know exactly how to build the HTTP request.
|
|
|
50
50
|
|
|
51
51
|
## Features
|
|
52
52
|
|
|
53
|
-
- **
|
|
54
|
-
- **
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
53
|
+
- **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
|
|
54
|
+
- **Client Compatibility Targets** -- `target: 'claude' | 'openai' | 'gemini' | 'strict'` emits schemas each client actually accepts (inlined refs, closed objects, collapsed unions, demoted formats)
|
|
55
|
+
- **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
|
|
56
|
+
- **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)
|
|
57
|
+
- **Complete Schemas** -- Input schema combines all parameters; output schema from responses (with oneOf unions); clean JSON Schema 2020-12 output (`nullable` unions, normalized `examples`)
|
|
58
|
+
- **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
|
|
59
|
+
- **Security Resolution** -- Framework-agnostic auth for Bearer, Basic, Digest, API Key, OAuth2, OpenID, mTLS, HMAC, AWS Sig V4; per-scheme `includeSecurityInInput`
|
|
60
|
+
- **SSRF Prevention** -- Blocks internal IPs, localhost, and cloud metadata endpoints by default during `$ref` resolution; one-flag `secureDefaults` posture for untrusted specs
|
|
57
61
|
- **Multiple Input Sources** -- Load from URL, file, YAML string, or JSON object
|
|
58
62
|
- **Rich Metadata** -- Authentication, servers, tags, deprecation, external docs, `x-frontmcp` extension
|
|
59
|
-
- **Production Ready** -- Full TypeScript support, validation, structured errors,
|
|
60
|
-
- **
|
|
63
|
+
- **Production Ready** -- Full TypeScript support, validation, structured errors, 100% test coverage (enforced)
|
|
64
|
+
- **Runtime Agnostic** -- Works on Node and V8 isolates (Cloudflare Workers) alike
|
|
61
65
|
|
|
62
66
|
## Installation
|
|
63
67
|
|
|
@@ -72,86 +76,88 @@ pnpm add mcp-from-openapi
|
|
|
72
76
|
## Quick Start
|
|
73
77
|
|
|
74
78
|
```typescript
|
|
75
|
-
import { OpenAPIToolGenerator } from
|
|
79
|
+
import { OpenAPIToolGenerator } from "mcp-from-openapi";
|
|
76
80
|
|
|
77
81
|
// Load an OpenAPI spec
|
|
78
|
-
const generator = await OpenAPIToolGenerator.fromURL(
|
|
82
|
+
const generator = await OpenAPIToolGenerator.fromURL(
|
|
83
|
+
"https://api.example.com/openapi.json",
|
|
84
|
+
);
|
|
79
85
|
|
|
80
86
|
// Generate MCP tools
|
|
81
87
|
const tools = await generator.generateTools();
|
|
82
88
|
|
|
83
89
|
// Each tool has everything you need
|
|
84
90
|
tools.forEach((tool) => {
|
|
85
|
-
console.log(tool.name);
|
|
86
|
-
console.log(tool.
|
|
87
|
-
console.log(tool.
|
|
88
|
-
console.log(tool.
|
|
89
|
-
console.log(tool.
|
|
91
|
+
console.log(tool.name); // "createUser"
|
|
92
|
+
console.log(tool.title); // "Create a user" (from summary/extensions)
|
|
93
|
+
console.log(tool.annotations); // { readOnlyHint: false, destructiveHint: true, ... }
|
|
94
|
+
console.log(tool.inputSchema); // Combined schema for all params
|
|
95
|
+
console.log(tool.outputSchema); // Response schema
|
|
96
|
+
console.log(tool.mapper); // How to build the HTTP request
|
|
97
|
+
console.log(tool.metadata); // Auth, servers, tags, etc.
|
|
90
98
|
});
|
|
91
99
|
```
|
|
92
100
|
|
|
93
|
-
##
|
|
101
|
+
## Building Requests
|
|
94
102
|
|
|
95
|
-
|
|
103
|
+
`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
104
|
|
|
97
105
|
```typescript
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
}
|
|
106
|
+
import { buildHttpRequest } from "mcp-from-openapi";
|
|
107
|
+
|
|
108
|
+
const request = buildHttpRequest(tool, { id: "42", filter: { tag: "news" } });
|
|
109
|
+
// { url: 'https://api.example.com/users/42?filter[tag]=news',
|
|
110
|
+
// method: 'GET', headers: {...}, body: undefined, ... }
|
|
124
111
|
|
|
125
|
-
|
|
126
|
-
|
|
112
|
+
await fetch(request.url, {
|
|
113
|
+
method: request.method,
|
|
114
|
+
headers: request.headers,
|
|
115
|
+
body: request.body as BodyInit,
|
|
116
|
+
});
|
|
117
|
+
```
|
|
127
118
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
119
|
+
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.
|
|
120
|
+
|
|
121
|
+
## Serving with the Official MCP SDK
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { toSdkTool, buildHttpRequest } from "mcp-from-openapi";
|
|
125
|
+
import { fromJsonSchema } from "@modelcontextprotocol/server"; // SDK v2
|
|
126
|
+
|
|
127
|
+
for (const tool of await generator.generateTools({ target: "claude" })) {
|
|
128
|
+
server.registerTool(...toSdkTool(tool, { fromJsonSchema }), async (input) => {
|
|
129
|
+
const request = buildHttpRequest(tool, input);
|
|
130
|
+
const response = await fetch(request.url, {
|
|
131
|
+
method: request.method,
|
|
132
|
+
headers: request.headers,
|
|
133
|
+
body: request.body as BodyInit,
|
|
134
|
+
});
|
|
135
|
+
return { content: [{ type: "text", text: await response.text() }] };
|
|
136
|
+
});
|
|
134
137
|
}
|
|
135
138
|
```
|
|
136
139
|
|
|
137
140
|
## Documentation
|
|
138
141
|
|
|
139
|
-
| Document
|
|
140
|
-
|
|
141
|
-
| [Getting Started](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/getting-started.md)
|
|
142
|
-
| [Configuration](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/configuration.md)
|
|
143
|
-
| [Parameter Conflicts](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/parameter-conflicts.md) | How conflict detection and resolution works
|
|
144
|
-
| [
|
|
145
|
-
| [
|
|
146
|
-
| [
|
|
147
|
-
| [
|
|
148
|
-
| [
|
|
149
|
-
| [
|
|
150
|
-
| [
|
|
151
|
-
| [
|
|
152
|
-
| [
|
|
153
|
-
| [
|
|
154
|
-
| [
|
|
142
|
+
| Document | Description |
|
|
143
|
+
| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
144
|
+
| [Getting Started](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/getting-started.md) | Loading specs, generating tools, building requests |
|
|
145
|
+
| [Configuration](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/configuration.md) | LoadOptions, GenerateOptions, RefResolutionOptions |
|
|
146
|
+
| [Parameter Conflicts](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/parameter-conflicts.md) | How conflict detection and resolution works |
|
|
147
|
+
| [Request Builder](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/request-builder.md) | `buildHttpRequest` — full OpenAPI parameter serialization |
|
|
148
|
+
| [Client Targets](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/client-targets.md) | Per-client schema dialects (Claude, OpenAI, Gemini) |
|
|
149
|
+
| [Response Schemas](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/response-schemas.md) | Output schemas, status codes, oneOf unions |
|
|
150
|
+
| [Annotations & Extensions](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/annotations.md) | Tool title, annotation inference, `x-mcp` extension family |
|
|
151
|
+
| [Security](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/security.md) | SecurityResolver, all auth types, custom resolvers |
|
|
152
|
+
| [SSRF Prevention](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/ssrf-prevention.md) | Ref resolution security, blocked IPs and hosts |
|
|
153
|
+
| [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.) |
|
|
154
|
+
| [Naming Strategies](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/naming-strategies.md) | Custom tool naming and conflict resolvers |
|
|
155
|
+
| [SchemaBuilder](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/schema-builder.md) | JSON Schema utility methods |
|
|
156
|
+
| [Error Handling](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/error-handling.md) | Error classes, context, and patterns |
|
|
157
|
+
| [x-frontmcp Extension](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/x-frontmcp.md) | Custom OpenAPI extension for MCP annotations |
|
|
158
|
+
| [API Reference](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/api-reference.md) | Complete types, interfaces, and exports |
|
|
159
|
+
| [Examples](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/examples.md) | MCP server, Zod, filtering, security, and more |
|
|
160
|
+
| [Architecture](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/architecture.md) | System overview, data flow, design patterns |
|
|
155
161
|
|
|
156
162
|
## Requirements
|
|
157
163
|
|
package/annotations.d.ts
ADDED
|
@@ -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,13 @@ 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 HTTP request cannot be built from a tool's mapper
|
|
48
|
+
* (missing required parameters, unserializable values, injection attempts)
|
|
49
|
+
*/
|
|
50
|
+
export declare class RequestBuildError extends OpenAPIToolError {
|
|
51
|
+
constructor(message: string, context?: Record<string, any>);
|
|
52
|
+
}
|
|
46
53
|
/**
|
|
47
54
|
* Error thrown when a schema is invalid
|
|
48
55
|
*/
|