mcp-from-openapi 2.5.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-from-openapi",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "description": "Production-ready library for converting OpenAPI specifications into MCP tool definitions",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
@@ -2,12 +2,23 @@ import type { JSONSchema } from 'zod/v4/core';
2
2
  /** JSON Schema type from Zod v4 */
3
3
  type JsonSchema = JSONSchema.JSONSchema;
4
4
  import type { ParameterMapper, ParameterObject, NamingStrategy, SecurityRequirement } from './types';
5
+ /**
6
+ * Options controlling parameter resolution behavior
7
+ */
8
+ export interface ParameterResolverOptions {
9
+ /**
10
+ * Include parameter-level and media-type-level example(s) in the
11
+ * generated input schema (as JSON Schema `examples` arrays).
12
+ */
13
+ includeExamples?: boolean;
14
+ }
5
15
  /**
6
16
  * Resolves parameters and handles naming conflicts
7
17
  */
8
18
  export declare class ParameterResolver {
9
19
  private namingStrategy;
10
- constructor(namingStrategy?: NamingStrategy);
20
+ private includeExamples;
21
+ constructor(namingStrategy?: NamingStrategy, options?: ParameterResolverOptions);
11
22
  /**
12
23
  * Default conflict resolver: prefix with location
13
24
  */
@@ -15,7 +26,7 @@ export declare class ParameterResolver {
15
26
  /**
16
27
  * Resolve all parameters for an operation
17
28
  */
18
- resolve(operation: any, pathParameters?: ParameterObject[], securityRequirements?: SecurityRequirement[], includeSecurityInInput?: boolean): {
29
+ resolve(operation: any, pathParameters?: ParameterObject[], securityRequirements?: SecurityRequirement[], includeSecurityInInput?: boolean | string[]): {
19
30
  inputSchema: JsonSchema;
20
31
  mapper: ParameterMapper[];
21
32
  };
@@ -36,4 +47,14 @@ export declare class ParameterResolver {
36
47
  */
37
48
  private processSecurityRequirements;
38
49
  }
50
+ /**
51
+ * Collect concrete example values from OpenAPI `example` / `examples` fields
52
+ * (parameter or media-type level). The `examples` map wins over the singular
53
+ * `example` (they are mutually exclusive per OpenAPI); `$ref` entries are
54
+ * skipped because example refs are not dereferenced into values here.
55
+ * Returns undefined when nothing usable is present.
56
+ *
57
+ * Internal helper shared with ResponseBuilder (not part of the public barrel).
58
+ */
59
+ export declare function collectExampleValues(example: unknown, examples?: Record<string, unknown> | unknown[]): unknown[] | undefined;
39
60
  export {};
@@ -0,0 +1,52 @@
1
+ import type { McpOpenAPITool } from './types';
2
+ /**
3
+ * Options for {@link buildHttpRequest}.
4
+ */
5
+ export interface BuildHttpRequestOptions {
6
+ /**
7
+ * Base URL for the request. Overrides the tool's `metadata.servers[0].url`.
8
+ * Must be empty (relative request) or an http/https URL.
9
+ */
10
+ baseUrl?: string;
11
+ }
12
+ /**
13
+ * The composed HTTP request. Pure data — nothing has been sent.
14
+ */
15
+ export interface BuiltHttpRequest {
16
+ /** Fully composed URL: base + expanded path + encoded query string */
17
+ url: string;
18
+ /** Uppercase HTTP method */
19
+ method: string;
20
+ /**
21
+ * Request headers, including a composed `Cookie` header (when cookie
22
+ * parameters exist) and `content-type` (when the body is not multipart —
23
+ * multipart bodies must let the HTTP client set the boundary itself).
24
+ */
25
+ headers: Record<string, string>;
26
+ /** Query parameters as sent (unencoded values, one array per key) */
27
+ query: Record<string, string[]>;
28
+ /** Cookie parameters (also folded into the `Cookie` header) */
29
+ cookies: Record<string, string>;
30
+ /** Selected request body content type (also in headers, except multipart) */
31
+ contentType?: string;
32
+ /**
33
+ * Serialized body ready for fetch: a JSON/form-urlencoded/text string, a
34
+ * `FormData` for multipart, the raw value for binary bodies, or undefined.
35
+ */
36
+ body?: unknown;
37
+ /** Structured body value before serialization (object/array/primitive) */
38
+ rawBody?: unknown;
39
+ }
40
+ /**
41
+ * Build an HTTP request from a generated tool and its input values — the
42
+ * mapper applied in full: style/explode serialization (form, spaceDelimited,
43
+ * pipeDelimited, deepObject, simple, label, matrix), `allowReserved`,
44
+ * whole-body and binary bodies, JSON / form-urlencoded / multipart / text
45
+ * serialization, cookies, and header-injection guards.
46
+ *
47
+ * Pure function: nothing is sent, no runtime context is consulted. Security
48
+ * mapper entries are applied only when their value is present in `input`
49
+ * (with scheme-aware formatting); missing security values never throw —
50
+ * frameworks resolve credentials separately (see SecurityResolver).
51
+ */
52
+ export declare function buildHttpRequest(tool: McpOpenAPITool, input: Record<string, unknown>, options?: BuildHttpRequestOptions): BuiltHttpRequest;
@@ -8,6 +8,7 @@ import type { GenerateOptions, ResponsesObject } from './types';
8
8
  export declare class ResponseBuilder {
9
9
  private preferredStatusCodes;
10
10
  private includeAllResponses;
11
+ private includeExamples;
11
12
  constructor(options?: GenerateOptions);
12
13
  /**
13
14
  * Build output schema from responses
@@ -110,6 +110,23 @@ export declare class SchemaBuilder {
110
110
  * Flatten nested oneOf/anyOf/allOf schemas
111
111
  */
112
112
  static flatten(schema: JsonSchema, maxDepth?: number): JsonSchema;
113
+ /**
114
+ * Truncate a schema tree to a maximum nesting depth.
115
+ *
116
+ * The root sits at depth 0; descending into `properties` values, `items`,
117
+ * `additionalProperties`, composition members (`allOf`/`anyOf`/`oneOf`), or
118
+ * `not` increments the depth. Nodes at `maxDepth` keep their scalar keywords
119
+ * (type, description, format, ...) but have their child schemas stripped and
120
+ * a truncation note appended to the description.
121
+ */
122
+ static truncateDepth(schema: JsonSchema, maxDepth: number): JsonSchema;
123
+ /** Keys whose value is a map of schemas (JSON Schema 2020-12) */
124
+ private static readonly TRUNCATE_MAP_KEYS;
125
+ /** Keys whose value is a single schema (or, for `items`, a tuple array) */
126
+ private static readonly TRUNCATE_SCHEMA_KEYS;
127
+ /** Keys whose value is an array of schemas */
128
+ private static readonly TRUNCATE_LIST_KEYS;
129
+ private static truncateDepthRecursive;
113
130
  /**
114
131
  * Simplify schema by removing unnecessary fields
115
132
  */
package/sdk.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { JsonSchema, McpOpenAPITool, ToolAnnotations } from './types';
2
+ /**
3
+ * A `registerTool`-shaped config for the official MCP TypeScript SDK.
4
+ * `TSchema` is whatever the schema wrapper returns — the raw `JsonSchema`
5
+ * when no wrapper is used, or the SDK's wrapped schema type.
6
+ */
7
+ export interface SdkToolConfig<TSchema = JsonSchema> {
8
+ title?: string;
9
+ description: string;
10
+ inputSchema: TSchema;
11
+ outputSchema?: TSchema;
12
+ annotations?: ToolAnnotations;
13
+ }
14
+ /**
15
+ * Schema wrapper — pass the SDK v2 `fromJsonSchema` here so schemas are
16
+ * advertised verbatim and validated by the SDK's JSON Schema validator.
17
+ */
18
+ export interface SdkSchemaWrapper<TSchema> {
19
+ fromJsonSchema: (schema: JsonSchema) => TSchema;
20
+ }
21
+ export declare function toSdkTool(tool: McpOpenAPITool): [name: string, config: SdkToolConfig];
22
+ export declare function toSdkTool<TSchema>(tool: McpOpenAPITool, wrapper: SdkSchemaWrapper<TSchema>): [name: string, config: SdkToolConfig<TSchema>];
package/types.d.ts CHANGED
@@ -49,20 +49,68 @@ export declare function isReferenceObject(obj: any): obj is ReferenceObject;
49
49
  * Convert OpenAPI schema to JsonSchema
50
50
  * Note: OpenAPI 3.0 uses a subset of JSON Schema Draft 4
51
51
  * OpenAPI 3.1 uses JSON Schema Draft 2020-12
52
+ *
53
+ * Normalizations applied for clean JSON Schema 2020-12 output (MCP's default
54
+ * dialect since spec revision 2025-11-25):
55
+ * - OpenAPI 3.0 `nullable: true` -> `type: [..., 'null']` union
56
+ * - OpenAPI 3.0 boolean `exclusiveMinimum`/`exclusiveMaximum` -> numeric form
57
+ * - OpenAPI `example` (singular) -> `examples` array (2020-12 keyword)
58
+ * - OpenAPI-only `xml` metadata is dropped
52
59
  */
53
60
  export declare function toJsonSchema(schema: SchemaObject | ReferenceObject): JsonSchema;
54
61
  /**
55
- * Main MCP Tool definition generated from OpenAPI
62
+ * MCP tool annotations — behavior hints for clients (MCP spec 2025-03-26).
63
+ * Hints are advisory: clients must not treat them as security guarantees.
64
+ */
65
+ export interface ToolAnnotations {
66
+ /**
67
+ * Legacy display-name slot inside annotations. Prefer the tool-level `title`.
68
+ */
69
+ title?: string;
70
+ /**
71
+ * Tool only reads data, never modifies state.
72
+ */
73
+ readOnlyHint?: boolean;
74
+ /**
75
+ * Tool may perform destructive updates (delete, overwrite).
76
+ */
77
+ destructiveHint?: boolean;
78
+ /**
79
+ * Calling repeatedly with the same arguments has no additional effect.
80
+ */
81
+ idempotentHint?: boolean;
82
+ /**
83
+ * Tool interacts with an open world of external entities.
84
+ */
85
+ openWorldHint?: boolean;
86
+ }
87
+ /**
88
+ * Main MCP Tool definition generated from OpenAPI.
89
+ *
90
+ * `TMeta` lets embedding frameworks extend the metadata contract without
91
+ * casting — e.g. `McpOpenAPITool<ToolMetadata & { adapter: AdapterState }>`.
56
92
  */
57
- export interface McpOpenAPITool {
93
+ export interface McpOpenAPITool<TMeta extends ToolMetadata = ToolMetadata> {
58
94
  /**
59
95
  * Unique tool name (from operationId or generated)
60
96
  */
61
97
  name: string;
98
+ /**
99
+ * Human-readable display name (MCP `Tool.title`, spec 2025-06-18).
100
+ * From extension overrides or the operation summary.
101
+ */
102
+ title?: string;
62
103
  /**
63
104
  * Tool description (from operation summary/description)
64
105
  */
65
106
  description: string;
107
+ /**
108
+ * MCP tool annotations. Inferred from HTTP method semantics by default
109
+ * (see `GenerateOptions.inferAnnotations`) and overridable via the
110
+ * `x-speakeasy-mcp` / `x-mcp` / `x-frontmcp` extensions (in ascending
111
+ * precedence).
112
+ */
113
+ annotations?: ToolAnnotations;
66
114
  /**
67
115
  * Combined input schema including all parameters
68
116
  * (path, query, header, cookie, body)
@@ -80,7 +128,7 @@ export interface McpOpenAPITool {
80
128
  /**
81
129
  * Additional metadata about the tool
82
130
  */
83
- metadata: ToolMetadata;
131
+ metadata: TMeta;
84
132
  }
85
133
  /**
86
134
  * Maps input schema properties to their actual request locations
@@ -110,10 +158,23 @@ export interface ParameterMapper {
110
158
  * Whether to explode arrays/objects
111
159
  */
112
160
  explode?: boolean;
161
+ /**
162
+ * Whether RFC 3986 reserved characters may appear unencoded in the value
163
+ * (query parameters only, OpenAPI `allowReserved`)
164
+ */
165
+ allowReserved?: boolean;
113
166
  /**
114
167
  * Custom serialization info
115
168
  */
116
169
  serialization?: SerializationInfo;
170
+ /**
171
+ * When true, this input value IS the entire request body — set for
172
+ * non-object bodies (arrays, primitives, binary) and for `oneOf`/`anyOf`
173
+ * union bodies that cannot be flattened into named properties. Consumers
174
+ * building requests must send the value directly as the body instead of
175
+ * wrapping it in an object keyed by `key`.
176
+ */
177
+ wholeBody?: boolean;
117
178
  /**
118
179
  * Security scheme information (if this is an auth parameter)
119
180
  * This allows frameworks to resolve auth from context, env vars, etc.
@@ -129,9 +190,16 @@ export interface SerializationInfo {
129
190
  */
130
191
  contentType?: string;
131
192
  /**
132
- * Encoding rules
193
+ * Encoding rules from the request body's media type (OpenAPI `encoding`).
194
+ * For a flattened body-property parameter this contains only that
195
+ * property's entry; for a whole-body parameter it is the full map.
133
196
  */
134
197
  encoding?: Record<string, EncodingObject>;
198
+ /**
199
+ * File-upload marker: the parameter schema declares binary content
200
+ * (`format: binary`), e.g. a multipart file part or a raw binary body.
201
+ */
202
+ binary?: boolean;
135
203
  }
136
204
  /**
137
205
  * Security parameter information for framework-agnostic auth resolution
@@ -231,15 +299,10 @@ export interface ToolMetadata {
231
299
  */
232
300
  export interface FrontMcpExtensionData {
233
301
  /**
234
- * Tool annotations for AI behavior hints.
302
+ * Tool annotations for AI behavior hints (same contract as the tool-level
303
+ * `annotations` field).
235
304
  */
236
- annotations?: {
237
- title?: string;
238
- readOnlyHint?: boolean;
239
- destructiveHint?: boolean;
240
- idempotentHint?: boolean;
241
- openWorldHint?: boolean;
242
- };
305
+ annotations?: ToolAnnotations;
243
306
  /**
244
307
  * Cache configuration for response caching.
245
308
  */
@@ -395,9 +458,18 @@ export interface LoadOptions {
395
458
  * Whether to follow HTTP redirects when fetching the spec URL. Each redirect
396
459
  * hop is re-validated against the SSRF guard before being followed (a 3xx to
397
460
  * an internal target is refused), so following is safe by default.
398
- * @default true
461
+ * @default true (false when `secureDefaults` is set)
399
462
  */
400
463
  followRedirects?: boolean;
464
+ /**
465
+ * Opt into the strictest loading posture in one flag: redirects are not
466
+ * followed and external `$ref` resolution is disabled entirely
467
+ * (`refResolution.allowedProtocols: []`) — the right default when loading
468
+ * untrusted specs. Explicitly-set `followRedirects`/`refResolution` values
469
+ * still win over the preset.
470
+ * @default false
471
+ */
472
+ secureDefaults?: boolean;
401
473
  /**
402
474
  * Controls spec-loading security: external `$ref` resolution AND the host
403
475
  * policy for the initial spec-URL fetch. By default `file://` is blocked,
@@ -430,6 +502,38 @@ export interface GenerateOptions {
430
502
  * Custom filter function
431
503
  */
432
504
  filterFn?: (operation: OperationWithContext) => boolean;
505
+ /**
506
+ * Include only operations carrying at least one of these OpenAPI tags
507
+ */
508
+ includeTags?: string[];
509
+ /**
510
+ * Exclude operations carrying any of these OpenAPI tags
511
+ */
512
+ excludeTags?: string[];
513
+ /**
514
+ * Include only these HTTP methods
515
+ */
516
+ includeMethods?: HTTPMethod[];
517
+ /**
518
+ * Exclude these HTTP methods
519
+ */
520
+ excludeMethods?: HTTPMethod[];
521
+ /**
522
+ * Include only paths matching at least one of these globs.
523
+ * `*` matches within a path segment, `**` across segments, `?` one character
524
+ * (e.g. `/users/*`, `/admin/**`).
525
+ */
526
+ includePaths?: string[];
527
+ /**
528
+ * Exclude paths matching any of these globs
529
+ */
530
+ excludePaths?: string[];
531
+ /**
532
+ * Safety switch: include only operations whose effective annotations say
533
+ * `readOnlyHint: true` (HTTP-method inference merged with extension
534
+ * overrides, regardless of `inferAnnotations`).
535
+ */
536
+ readOnlyOnly?: boolean;
433
537
  /**
434
538
  * Naming strategy for resolving conflicts
435
539
  */
@@ -451,22 +555,63 @@ export interface GenerateOptions {
451
555
  */
452
556
  includeAllResponses?: boolean;
453
557
  /**
454
- * Maximum depth for dereferencing schemas
558
+ * Maximum schema nesting depth retained in generated input/output schemas.
559
+ * Structures nested deeper than this are truncated: child schemas are
560
+ * stripped and a truncation note is appended to the node's description.
561
+ * Clamped to a minimum of 1 so the root schema always keeps its properties.
455
562
  * @default 10
456
563
  */
457
564
  maxSchemaDepth?: number;
458
565
  /**
459
- * Whether to include examples in schemas
566
+ * Include OpenAPI parameter-level and media-type-level `example`/`examples`
567
+ * values in generated schemas (as JSON Schema `examples` arrays). These
568
+ * override schema-level examples where present. Schema-level `example`
569
+ * keywords are always normalized to `examples` regardless of this option.
460
570
  * @default false
461
571
  */
462
572
  includeExamples?: boolean;
463
573
  /**
464
- * Whether to include security requirements as input parameters
465
- * If false, security is only in mapper (frameworks resolve from context/env/etc.)
466
- * If true, security is added to inputSchema as explicit parameters
574
+ * Whether to include security requirements as input parameters.
575
+ * - `false` (default): security lives only in the mapper (frameworks
576
+ * resolve credentials from context/env/vaults)
577
+ * - `true`: every security scheme is added to inputSchema as a required
578
+ * string property
579
+ * - `string[]`: only the named schemes appear in inputSchema; the rest stay
580
+ * mapper-only (all schemes are always present in the mapper)
467
581
  * @default false
468
582
  */
469
- includeSecurityInInput?: boolean;
583
+ includeSecurityInInput?: boolean | string[];
584
+ /**
585
+ * Target client schema dialect. Every MCP client accepts a different JSON
586
+ * Schema subset; setting a target applies the transforms that make the
587
+ * generated input/output schemas valid for it: `strict` (safe baseline —
588
+ * local $refs inlined, arrays get `items`, root compositions collapsed),
589
+ * `claude` (= strict), `openai` (strict + closed objects), `gemini`
590
+ * (strict + all unions collapsed + unsupported formats demoted).
591
+ * See `applyClientTarget` for standalone use.
592
+ */
593
+ target?: import('./client-targets').ClientTarget;
594
+ /**
595
+ * Infer MCP tool annotations from HTTP method semantics:
596
+ * GET/HEAD/OPTIONS/TRACE -> read-only + idempotent; PUT/DELETE ->
597
+ * destructive + idempotent; POST/PATCH -> destructive, not idempotent.
598
+ * `openWorldHint` defaults to false (a known API backend is a closed world).
599
+ * Extension overrides (`x-speakeasy-mcp`, `x-mcp`, `x-frontmcp`) are applied
600
+ * on top of the inferred values regardless of this flag.
601
+ * @default true
602
+ */
603
+ inferAnnotations?: boolean;
604
+ /**
605
+ * Maximum length for generated tool names. Names longer than this are
606
+ * truncated and given a short hash suffix derived from the full name, so
607
+ * truncated names stay unique and stable across regenerations.
608
+ *
609
+ * MCP tool names may be 1-128 characters of `[A-Za-z0-9_.-]` (values above
610
+ * 128 are clamped to 128). The default of 64 matches the strictest common
611
+ * client limits (Claude / Bedrock cap tool names at 64 characters).
612
+ * @default 64
613
+ */
614
+ maxToolNameLength?: number;
470
615
  /**
471
616
  * Enable built-in format-to-schema resolution.
472
617
  * Enriches schemas with concrete constraints (patterns, descriptions, min/max)