mcp-from-openapi 2.6.1 → 2.8.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 CHANGED
@@ -2,11 +2,14 @@
2
2
 
3
3
  > Convert OpenAPI specifications into MCP tool definitions with automatic parameter conflict resolution
4
4
 
5
- [![npm version](https://badge.fury.io/js/mcp-from-openapi.svg)](https://www.npmjs.com/package/mcp-from-openapi)
5
+ [![npm version](https://img.shields.io/npm/v/mcp-from-openapi.svg)](https://www.npmjs.com/package/mcp-from-openapi)
6
+ [![npm downloads](https://img.shields.io/npm/dm/mcp-from-openapi.svg)](https://www.npmjs.com/package/mcp-from-openapi)
7
+ [![CI](https://github.com/agentfront/mcp-from-openapi/actions/workflows/push.yml/badge.svg)](https://github.com/agentfront/mcp-from-openapi/actions/workflows/push.yml)
8
+ [![coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/agentfront/mcp-from-openapi/actions/workflows/push.yml)
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)
6
10
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-yellow.svg)](https://opensource.org/license/apache-2-0)
7
11
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
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)
12
+ [![node](https://img.shields.io/node/v/mcp-from-openapi.svg)](https://nodejs.org/)
10
13
 
11
14
  ## What This Solves
12
15
 
@@ -150,6 +153,10 @@ for (const tool of await generator.generateTools({ target: "claude" })) {
150
153
  | [Request Builder](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/request-builder.md) | `buildHttpRequest` — full OpenAPI parameter serialization |
151
154
  | [Client Targets](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/client-targets.md) | Per-client schema dialects (Claude, OpenAI, Gemini) |
152
155
  | [Curation](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/curation.md) | Token budgets, overlays, lint, trimming, response hints |
156
+ | [Type Signatures](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/type-signatures.md) | TypeScript call contracts for code-execution surfaces |
157
+ | [Modern MCP Fields](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/modern-mcp-fields.md) | Tool `_meta`, icons, `x-mcp-header`, elicitation descriptors |
158
+ | [Arazzo Workflows](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/arazzo.md) | fromArazzo() — Arazzo 1.0 workflows as consolidated MCP tools |
159
+ | [Tested Examples](https://github.com/agentfront/mcp-from-openapi/tree/main/examples) | Runnable examples, each executed as an e2e test on every CI run |
153
160
  | [Response Schemas](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/response-schemas.md) | Output schemas, status codes, oneOf unions |
154
161
  | [Annotations & Extensions](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/annotations.md) | Tool title, annotation inference, `x-mcp` extension family |
155
162
  | [Security](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/security.md) | SecurityResolver, all auth types, custom resolvers |
package/annotations.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { HTTPMethod, OperationObject, ToolAnnotations } from './types';
1
+ import type { HTTPMethod, OperationObject, ToolAnnotations, ToolIcon } from './types';
2
2
  /**
3
3
  * Tool-level overrides read from the `x-mcp` extension family on an operation.
4
4
  */
@@ -25,6 +25,15 @@ export interface ExtensionToolOverrides {
25
25
  * Annotation overrides, merged field-by-field over inferred values.
26
26
  */
27
27
  annotations?: ToolAnnotations;
28
+ /**
29
+ * MCP `_meta` entries supplied by the extension (merged key-by-key across
30
+ * layers, emitted on the tool's `_meta` even when `emitMeta` is off).
31
+ */
32
+ meta?: Record<string, unknown>;
33
+ /**
34
+ * Tool icons supplied by the extension (later layers replace wholesale).
35
+ */
36
+ icons?: ToolIcon[];
28
37
  }
29
38
  /**
30
39
  * Default MCP tool annotations per HTTP method, derived from HTTP semantics
@@ -34,6 +43,12 @@ export interface ExtensionToolOverrides {
34
43
  * from a spec target one known API backend, a closed world.
35
44
  */
36
45
  export declare function inferAnnotationsFromMethod(method: HTTPMethod): ToolAnnotations;
46
+ /**
47
+ * Whether an icon source URI matches the documented `ToolIcon.src` scheme
48
+ * contract (`https:` or `data:` only, case-insensitive). Shared by extension
49
+ * icon sanitization and the generator's `info['x-logo']` inheritance.
50
+ */
51
+ export declare function isAllowedIconSrc(src: string): boolean;
37
52
  /**
38
53
  * Resolve whether an operation is enabled for tool generation, honoring the
39
54
  * `x-mcp` extension at every level with harsha-compatible precedence:
@@ -0,0 +1,19 @@
1
+ import type { ExpressionValueIR, PayloadExpressionIR, RuntimeExpressionAST } from './arazzo-types';
2
+ /**
3
+ * Parse a runtime expression into its structured form. Throws `ArazzoError`
4
+ * (with the document path in `context.path`) on any grammar violation.
5
+ */
6
+ export declare function parseRuntimeExpression(raw: string, docPath?: string): RuntimeExpressionAST;
7
+ /**
8
+ * Interpret a step/parameter value: non-strings are literals; strings that
9
+ * start with a known expression root must parse as expressions; strings with
10
+ * embedded `{$...}` become templates; everything else is a literal (`"$50"`
11
+ * has no known root and stays literal).
12
+ */
13
+ export declare function parseExpressionValue(value: unknown, docPath?: string): ExpressionValueIR;
14
+ /**
15
+ * Walk a request-body payload and record every string that parses to an
16
+ * expression or template, keyed by its RFC 6901 pointer (`''` = the payload
17
+ * itself is the value).
18
+ */
19
+ export declare function collectPayloadExpressions(payload: unknown, docPath?: string): PayloadExpressionIR[];
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Arazzo 1.0 document and workflow-IR type definitions.
3
+ *
4
+ * The document types cover the subset of the Arazzo Specification 1.0
5
+ * (https://spec.openapis.org/arazzo/v1.0.0.html) that `fromArazzo()` reads.
6
+ * The IR types describe the pure, JSON-serializable workflow representation
7
+ * embedded on `metadata.workflow` — executors drive HTTP from it and never
8
+ * need a second spec pass. This library never executes steps or evaluates
9
+ * criteria.
10
+ */
11
+ import type { HTTPMethod, JsonSchema, ParameterMapper, SchemaObject, SecurityRequirement, ServerInfo } from './types';
12
+ /** Arazzo `info` object. */
13
+ export interface ArazzoInfo {
14
+ title: string;
15
+ summary?: string;
16
+ description?: string;
17
+ version: string;
18
+ }
19
+ /** A source description entry (`sourceDescriptions[]`). */
20
+ export interface ArazzoSourceDescription {
21
+ /** Unique name matching `[A-Za-z0-9_-]+`. */
22
+ name: string;
23
+ /** URL/location of the source document — never fetched by this library. */
24
+ url: string;
25
+ type?: 'openapi' | 'arazzo';
26
+ }
27
+ /** Root Arazzo 1.0 document. */
28
+ export interface ArazzoDocument {
29
+ /** Version string matching `1.0.x`. */
30
+ arazzo: string;
31
+ info: ArazzoInfo;
32
+ sourceDescriptions: ArazzoSourceDescription[];
33
+ workflows: ArazzoWorkflow[];
34
+ components?: ArazzoComponents;
35
+ }
36
+ /** A workflow (`workflows[]`). */
37
+ export interface ArazzoWorkflow {
38
+ /** Unique id matching `[A-Za-z0-9_-]+`. */
39
+ workflowId: string;
40
+ summary?: string;
41
+ description?: string;
42
+ /** JSON Schema for workflow inputs; may `$ref` into `#/components/inputs`. */
43
+ inputs?: SchemaObject;
44
+ dependsOn?: string[];
45
+ steps: ArazzoStep[];
46
+ successActions?: Array<ArazzoSuccessAction | ArazzoReusableObject>;
47
+ failureActions?: Array<ArazzoFailureAction | ArazzoReusableObject>;
48
+ /** Output name → runtime expression. */
49
+ outputs?: Record<string, string>;
50
+ parameters?: Array<ArazzoParameter | ArazzoReusableObject>;
51
+ }
52
+ /** A step: exactly one of `operationId` / `operationPath` / `workflowId`. */
53
+ export interface ArazzoStep {
54
+ /** Unique id within the workflow, matching `[A-Za-z0-9_-]+`. */
55
+ stepId: string;
56
+ description?: string;
57
+ operationId?: string;
58
+ operationPath?: string;
59
+ workflowId?: string;
60
+ parameters?: Array<ArazzoParameter | ArazzoReusableObject>;
61
+ requestBody?: ArazzoRequestBody;
62
+ successCriteria?: ArazzoCriterion[];
63
+ onSuccess?: Array<ArazzoSuccessAction | ArazzoReusableObject>;
64
+ onFailure?: Array<ArazzoFailureAction | ArazzoReusableObject>;
65
+ /** Output name → runtime expression. */
66
+ outputs?: Record<string, string>;
67
+ }
68
+ /** A parameter applied to a step or workflow. */
69
+ export interface ArazzoParameter {
70
+ name: string;
71
+ /** Required for operation steps; forbidden on workflowId steps. */
72
+ in?: 'path' | 'query' | 'header' | 'cookie';
73
+ /** Literal value or runtime expression (string form). */
74
+ value: unknown;
75
+ }
76
+ /** Step request body. */
77
+ export interface ArazzoRequestBody {
78
+ contentType?: string;
79
+ /** Literal payload; strings may embed `{$...}` template expressions. */
80
+ payload?: unknown;
81
+ replacements?: ArazzoPayloadReplacement[];
82
+ }
83
+ /** A targeted replacement inside `payload`. */
84
+ export interface ArazzoPayloadReplacement {
85
+ /** JSON Pointer (or XPath for XML payloads) into the payload. */
86
+ target: string;
87
+ value: unknown;
88
+ }
89
+ /** Criterion `type`: shorthand or the Criterion Expression Type Object. */
90
+ export type ArazzoCriterionType = 'simple' | 'regex' | 'jsonpath' | 'xpath' | {
91
+ type: 'jsonpath' | 'xpath';
92
+ version: string;
93
+ };
94
+ /** A success criterion — this library never evaluates conditions. */
95
+ export interface ArazzoCriterion {
96
+ /** Runtime expression providing evaluation context (required for non-simple types). */
97
+ context?: string;
98
+ condition: string;
99
+ type?: ArazzoCriterionType;
100
+ }
101
+ /** `onSuccess` / workflow `successActions` entry. */
102
+ export interface ArazzoSuccessAction {
103
+ name: string;
104
+ type: 'end' | 'goto';
105
+ workflowId?: string;
106
+ stepId?: string;
107
+ criteria?: ArazzoCriterion[];
108
+ }
109
+ /** `onFailure` / workflow `failureActions` entry. */
110
+ export interface ArazzoFailureAction {
111
+ name: string;
112
+ type: 'end' | 'retry' | 'goto';
113
+ workflowId?: string;
114
+ stepId?: string;
115
+ /** Seconds to wait before retrying. */
116
+ retryAfter?: number;
117
+ retryLimit?: number;
118
+ criteria?: ArazzoCriterion[];
119
+ }
120
+ /** Reusable Object: a `$components.…` reference with an optional value override. */
121
+ export interface ArazzoReusableObject {
122
+ /** Runtime expression, e.g. `$components.parameters.page`. */
123
+ reference: string;
124
+ /** Overrides the referenced parameter's `value`. */
125
+ value?: unknown;
126
+ }
127
+ /** Arazzo `components`. */
128
+ export interface ArazzoComponents {
129
+ inputs?: Record<string, SchemaObject>;
130
+ parameters?: Record<string, ArazzoParameter>;
131
+ successActions?: Record<string, ArazzoSuccessAction>;
132
+ failureActions?: Record<string, ArazzoFailureAction>;
133
+ }
134
+ /** Root of a parsed runtime expression. */
135
+ export type RuntimeExpressionType = 'url' | 'method' | 'statusCode' | 'request' | 'response' | 'message' | 'inputs' | 'outputs' | 'steps' | 'workflows' | 'sourceDescriptions' | 'components';
136
+ /**
137
+ * Structured form of an Arazzo runtime expression. `raw` always preserves
138
+ * the exact original text.
139
+ */
140
+ export interface RuntimeExpressionAST {
141
+ type: RuntimeExpressionType;
142
+ raw: string;
143
+ /** Dot segments after the root: `$steps.s1.outputs.id` → `['s1','outputs','id']`. */
144
+ path: string[];
145
+ /** For `request` / `response` roots: which part is referenced. */
146
+ source?: 'header' | 'query' | 'path' | 'body';
147
+ /** Header/query/path parameter name for `request` / `response` source refs. */
148
+ name?: string;
149
+ /** JSON Pointer after `#` on body refs: `$response.body#/items/0/id` → `/items/0/id`. */
150
+ pointer?: string;
151
+ }
152
+ /** A value that is a literal, a whole expression, or a `{$...}`-templated string. */
153
+ export type ExpressionValueIR = {
154
+ kind: 'literal';
155
+ value: unknown;
156
+ } | {
157
+ kind: 'expression';
158
+ expression: RuntimeExpressionAST;
159
+ } | {
160
+ kind: 'template';
161
+ raw: string;
162
+ parts: Array<string | RuntimeExpressionAST>;
163
+ };
164
+ /** A parameter in the IR — components inlined, value parsed. */
165
+ export interface StepParameterIR {
166
+ name: string;
167
+ in?: 'path' | 'query' | 'header' | 'cookie';
168
+ value: ExpressionValueIR;
169
+ }
170
+ /** A criterion in the IR — the condition is raw text, never evaluated. */
171
+ export interface CriterionIR {
172
+ context?: RuntimeExpressionAST;
173
+ condition: string;
174
+ type: 'simple' | 'regex' | 'jsonpath' | 'xpath';
175
+ /** Present when the document used a Criterion Expression Type Object. */
176
+ version?: string;
177
+ }
178
+ /** A flow action in the IR (success or failure family). */
179
+ export interface ActionIR {
180
+ name: string;
181
+ kind: 'success' | 'failure';
182
+ type: 'end' | 'goto' | 'retry';
183
+ workflowId?: string;
184
+ stepId?: string;
185
+ retryAfter?: number;
186
+ retryLimit?: number;
187
+ criteria?: CriterionIR[];
188
+ }
189
+ /** An expression located inside a request payload (RFC 6901 pointer). */
190
+ export interface PayloadExpressionIR {
191
+ /** `''` means the whole payload is the expression value. */
192
+ pointer: string;
193
+ value: ExpressionValueIR;
194
+ }
195
+ /** A `replacements[]` entry in the IR. */
196
+ export interface PayloadReplacementIR {
197
+ target: string;
198
+ value: ExpressionValueIR;
199
+ }
200
+ /** Step request body in the IR: verbatim payload + located substitutions. */
201
+ export interface StepRequestBodyIR {
202
+ contentType?: string;
203
+ payload?: unknown;
204
+ payloadExpressions?: PayloadExpressionIR[];
205
+ replacements?: PayloadReplacementIR[];
206
+ }
207
+ /**
208
+ * Embedded essentials of a step's resolved operation — the subset of the
209
+ * per-operation tool an executor needs (`mapper` feeds `buildHttpRequest`).
210
+ */
211
+ export interface StepOperationIR {
212
+ inputSchema: JsonSchema;
213
+ outputSchema?: JsonSchema;
214
+ mapper: ParameterMapper[];
215
+ security?: SecurityRequirement[];
216
+ servers?: ServerInfo[];
217
+ }
218
+ interface StepIRBase {
219
+ stepId: string;
220
+ description?: string;
221
+ parameters?: StepParameterIR[];
222
+ successCriteria?: CriterionIR[];
223
+ onSuccess?: ActionIR[];
224
+ onFailure?: ActionIR[];
225
+ outputs?: Record<string, RuntimeExpressionAST>;
226
+ }
227
+ /** A step that invokes one HTTP operation from a source description. */
228
+ export interface OperationStepIR extends StepIRBase {
229
+ kind: 'operation';
230
+ /** Source description name the operation was resolved from. */
231
+ source: string;
232
+ /** OpenAPI path in that source. */
233
+ path: string;
234
+ method: HTTPMethod;
235
+ operationId?: string;
236
+ operation: StepOperationIR;
237
+ requestBody?: StepRequestBodyIR;
238
+ }
239
+ /** A step that invokes another workflow in the same Arazzo document. */
240
+ export interface NestedWorkflowStepIR extends StepIRBase {
241
+ kind: 'workflow';
242
+ workflowId: string;
243
+ }
244
+ /** Discriminated step union (`kind`). */
245
+ export type WorkflowStepIR = OperationStepIR | NestedWorkflowStepIR;
246
+ /** The complete serializable workflow IR carried on `metadata.workflow`. */
247
+ export interface WorkflowIR {
248
+ /** The document's `arazzo` version, e.g. `'1.0.0'`. */
249
+ arazzoVersion: string;
250
+ workflowId: string;
251
+ summary?: string;
252
+ description?: string;
253
+ /** Normalized workflow inputs (components `$ref`s resolved). */
254
+ inputSchema?: JsonSchema;
255
+ dependsOn?: string[];
256
+ parameters?: StepParameterIR[];
257
+ steps: WorkflowStepIR[];
258
+ successActions?: ActionIR[];
259
+ failureActions?: ActionIR[];
260
+ outputs?: Record<string, RuntimeExpressionAST>;
261
+ }
262
+ export {};
package/arazzo.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Arazzo 1.0 → consolidated MCP tools.
3
+ *
4
+ * `fromArazzo()` parses an Arazzo workflow document against caller-supplied
5
+ * OpenAPI sources and emits ONE `McpOpenAPITool` per workflow: the workflow
6
+ * inputs become the tool's input schema, the workflow outputs derive the
7
+ * output schema, and a pure, JSON-serializable IR (`metadata.workflow`)
8
+ * carries the step sequence — each operation step embedding its resolved
9
+ * schemas and mapper so an executor needs no second spec pass. This library
10
+ * never fetches source URLs, performs HTTP, or evaluates expressions.
11
+ */
12
+ import { OpenAPIToolGenerator } from './generator';
13
+ import type { GenerateOptions, LoadOptions, McpOpenAPITool, OpenAPIDocument } from './types';
14
+ import type { ArazzoDocument } from './arazzo-types';
15
+ /**
16
+ * The `GenerateOptions` subset that applies to Arazzo output — schema-shaping
17
+ * and naming options. Operation-filtering options have no meaning here.
18
+ */
19
+ export type ArazzoGenerateOptions = Pick<GenerateOptions, 'target' | 'maxSchemaDepth' | 'maxProperties' | 'maxDescriptionLength' | 'stripExamples' | 'includeExamples' | 'resolveFormats' | 'formatResolvers' | 'preferredStatusCodes' | 'includeAllResponses' | 'maxToolNameLength' | 'includeSecurityInInput' | 'emitTypeSignatures'>;
20
+ /** Options for {@link fromArazzo}. */
21
+ export interface FromArazzoOptions {
22
+ /**
23
+ * Source description name → resolved OpenAPI document or pre-built
24
+ * generator. Source URLs are NEVER fetched — the caller supplies resolved
25
+ * documents for every source the workflows use.
26
+ */
27
+ sources: Record<string, OpenAPIDocument | OpenAPIToolGenerator>;
28
+ /**
29
+ * Schema-affecting options, applied to the per-step embedded schemas AND
30
+ * the consolidated workflow schemas.
31
+ */
32
+ generateOptions?: ArazzoGenerateOptions;
33
+ /**
34
+ * Load options for internally-constructed generators (raw documents only).
35
+ */
36
+ loadOptions?: Pick<LoadOptions, 'dereference' | 'validate' | 'baseUrl' | 'overlays'>;
37
+ }
38
+ /**
39
+ * Convert an Arazzo 1.0 workflow document (object or YAML/JSON string) into
40
+ * consolidated MCP tools — one per workflow, in document order. Source URLs
41
+ * are never fetched; supply every used source via `options.sources`. Throws
42
+ * `ArazzoError` (with a JSON-Pointer `path`) on malformed documents,
43
+ * unresolvable references, or cyclic workflows.
44
+ */
45
+ export declare function fromArazzo(document: ArazzoDocument | string, options: FromArazzoOptions): Promise<McpOpenAPITool[]>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Security elicitation descriptors.
3
+ *
4
+ * Derives MCP-elicitation-compatible `{ message, requestedSchema }` request
5
+ * descriptors from a tool's resolved security data, so a server can ask the
6
+ * user for missing credentials in the shape `elicitInput` expects. Pure data
7
+ * derivation — transport policy is the consumer's. Note the MCP guidance:
8
+ * servers SHOULD NOT elicit secrets over untrusted paths; prefer dedicated
9
+ * credential flows where available.
10
+ */
11
+ import type { McpOpenAPITool } from './types';
12
+ /** A flat string property in an elicitation `requestedSchema`. */
13
+ export interface ElicitationField {
14
+ type: 'string';
15
+ title?: string;
16
+ description?: string;
17
+ }
18
+ /** MCP elicitation request descriptor derived from a tool's security data. */
19
+ export interface SecurityElicitation {
20
+ /**
21
+ * OpenAPI security scheme name (as declared in `components.securitySchemes`).
22
+ */
23
+ scheme: string;
24
+ /**
25
+ * Human-readable prompt (`ElicitRequest.message`).
26
+ */
27
+ message: string;
28
+ /**
29
+ * Flat requested schema — primitive string properties only, per MCP
30
+ * elicitation rules.
31
+ */
32
+ requestedSchema: {
33
+ type: 'object';
34
+ properties: Record<string, ElicitationField>;
35
+ required: string[];
36
+ };
37
+ }
38
+ /**
39
+ * Derive credential-elicitation descriptors from a generated tool — one per
40
+ * distinct security scheme, in mapper order. Falls back to
41
+ * `metadata.security` for hand-built tools without security mapper entries.
42
+ * Returns `[]` when the tool declares no security.
43
+ */
44
+ export declare function deriveSecurityElicitations(tool: McpOpenAPITool): SecurityElicitation[];
package/errors.d.ts CHANGED
@@ -57,6 +57,14 @@ export declare class OverlayError extends OpenAPIToolError {
57
57
  export declare class RequestBuildError extends OpenAPIToolError {
58
58
  constructor(message: string, context?: Record<string, any>);
59
59
  }
60
+ /**
61
+ * Error thrown when an Arazzo document is malformed or cannot be resolved
62
+ * against its sources. `path` is a JSON Pointer into the Arazzo document.
63
+ */
64
+ export declare class ArazzoError extends OpenAPIToolError {
65
+ readonly path?: string;
66
+ constructor(message: string, context?: Record<string, any>);
67
+ }
60
68
  /**
61
69
  * Error thrown when a schema is invalid
62
70
  */