@ttoss/http-server-mcp-openapi 0.2.15 → 0.3.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/dist/index.mjs CHANGED
@@ -1,7 +1,10 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- import { registerToolFromSchema } from "@ttoss/http-server-mcp";
2
+ import { getApiHeaders, registerToolFromSchema } from "@ttoss/http-server-mcp";
3
3
 
4
4
  //#region src/schema.ts
5
+ var isRecord = value => {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ };
5
8
  var getAlternativeSchemas = schema => {
6
9
  if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) return schema.oneOf;
7
10
  if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) return schema.anyOf;
@@ -23,36 +26,96 @@ var mergeResolvedSchemas = resolvedAlternatives => {
23
26
  required: requiredIntersection && requiredIntersection.length > 0 ? requiredIntersection : void 0
24
27
  };
25
28
  };
29
+ var stripDotSlash = file => {
30
+ return file.replace(/^\.\//, "");
31
+ };
32
+ var findDocument = args => {
33
+ if (!args.documents) return void 0;
34
+ const wanted = stripDotSlash(args.file);
35
+ for (const [key, document] of Object.entries(args.documents)) if (stripDotSlash(key) === wanted) return document;
36
+ };
37
+ /** Follows an RFC 6901 JSON pointer (`/components/schemas/Tag`) into a value. */
38
+ var followPointer = args => {
39
+ const tokens = args.pointer.split("/").slice(1);
40
+ let current = args.root;
41
+ for (const rawToken of tokens) {
42
+ if (!isRecord(current) && !Array.isArray(current)) return void 0;
43
+ const token = decodeURIComponent(rawToken).replace(/~1/g, "/").replace(/~0/g, "~");
44
+ current = current[token];
45
+ }
46
+ return current;
47
+ };
48
+ /** Stable identity for each document, so cycle keys never collide across files. */
49
+ var documentIds = /* @__PURE__ */new WeakMap();
50
+ var nextDocumentId = 0;
51
+ var documentId = spec => {
52
+ const known = documentIds.get(spec);
53
+ if (known !== void 0) return known;
54
+ nextDocumentId += 1;
55
+ documentIds.set(spec, nextDocumentId);
56
+ return nextDocumentId;
57
+ };
58
+ /**
59
+ * Resolves a `$ref` to its target and the document the target lives in (the
60
+ * scope its own nested refs resolve against). A ref without a file part
61
+ * (`#/components/schemas/X`) points into the current document; one with a
62
+ * file part (`./tags.yaml#/components/schemas/Tag`) points into the matching
63
+ * entry of `documents`. Returns `undefined` when the target does not exist.
64
+ */
65
+ var resolveRef = args => {
66
+ const hashIndex = args.ref.indexOf("#");
67
+ const file = hashIndex === -1 ? args.ref : args.ref.slice(0, hashIndex);
68
+ const pointer = hashIndex === -1 ? "" : args.ref.slice(hashIndex + 1);
69
+ const spec = file === "" ? args.scope.spec : findDocument({
70
+ file,
71
+ documents: args.scope.documents
72
+ });
73
+ if (!spec) return void 0;
74
+ const value = followPointer({
75
+ root: spec,
76
+ pointer
77
+ });
78
+ if (value === void 0) return void 0;
79
+ return {
80
+ value,
81
+ scope: {
82
+ spec,
83
+ documents: args.scope.documents
84
+ },
85
+ key: `${documentId(spec)}#${pointer}`
86
+ };
87
+ };
26
88
  var dereferenceValue = args => {
27
89
  const {
28
90
  value,
29
- spec,
91
+ scope,
30
92
  seenRefs
31
93
  } = args;
32
94
  if (Array.isArray(value)) return value.map(item => {
33
95
  return dereferenceValue({
34
96
  value: item,
35
- spec,
97
+ scope,
36
98
  seenRefs
37
99
  });
38
100
  });
39
- if (value && typeof value === "object") {
40
- const obj = value;
41
- if (typeof obj.$ref === "string") {
42
- const refName = obj.$ref.replace("#/components/schemas/", "");
43
- if (seenRefs.has(refName)) return {};
44
- const resolved = spec.components?.schemas?.[refName];
45
- if (resolved === void 0) return {};
101
+ if (isRecord(value)) {
102
+ if (typeof value.$ref === "string") {
103
+ const target = resolveRef({
104
+ ref: value.$ref,
105
+ scope
106
+ });
107
+ if (!target) return {};
108
+ if (seenRefs.has(target.key)) return {};
46
109
  return dereferenceValue({
47
- value: resolved,
48
- spec,
49
- seenRefs: new Set(seenRefs).add(refName)
110
+ value: target.value,
111
+ scope: target.scope,
112
+ seenRefs: new Set(seenRefs).add(target.key)
50
113
  });
51
114
  }
52
115
  const result = {};
53
- for (const [key, entryValue] of Object.entries(obj)) result[key] = dereferenceValue({
116
+ for (const [key, entryValue] of Object.entries(value)) result[key] = dereferenceValue({
54
117
  value: entryValue,
55
- spec,
118
+ scope,
56
119
  seenRefs
57
120
  });
58
121
  return result;
@@ -64,12 +127,17 @@ var dereferenceValue = args => {
64
127
  * `properties`, `items`, `oneOf`, `anyOf`, etc.), producing a self-contained
65
128
  * schema safe to hand to an MCP client or LLM provider as a tool definition —
66
129
  * provider tool schemas have no `components` section to resolve refs against.
130
+ *
131
+ * Refs into other files resolve against `documents`; see {@link OpenApiDocuments}.
67
132
  */
68
- var dereferenceSchema = (schema, spec) => {
133
+ var dereferenceSchema = (schema, spec, documents) => {
69
134
  if (!schema) return schema;
70
135
  return dereferenceValue({
71
136
  value: schema,
72
- spec,
137
+ scope: {
138
+ spec,
139
+ documents
140
+ },
73
141
  seenRefs: /* @__PURE__ */new Set()
74
142
  });
75
143
  };
@@ -78,25 +146,39 @@ var dereferenceSchema = (schema, spec) => {
78
146
  * and merges `oneOf` / `anyOf` alternatives (union of properties, intersection
79
147
  * of `required`) so the caller sees one flat property set.
80
148
  */
81
- var resolveSchema = (schema, spec) => {
149
+ var resolveSchema = (schema, spec, documents) => {
82
150
  if (!schema) return {};
83
151
  if (typeof schema.$ref === "string") {
84
- const refName = schema.$ref.replace("#/components/schemas/", "");
85
- const resolved = spec.components?.schemas?.[refName];
86
- return resolveSchema(resolved, spec);
152
+ const target = resolveRef({
153
+ ref: schema.$ref,
154
+ scope: {
155
+ spec,
156
+ documents
157
+ }
158
+ });
159
+ return resolveSchema(target?.value, target?.scope.spec ?? spec, documents);
87
160
  }
88
161
  const alternatives = getAlternativeSchemas(schema);
89
162
  if (alternatives) return mergeResolvedSchemas(alternatives.map(candidate => {
90
- return resolveSchema(candidate, spec);
163
+ return resolveSchema(candidate, spec, documents);
91
164
  }));
92
165
  return schema;
93
166
  };
94
- /** Follows a parameter `$ref` into `components.parameters`, if present. */
95
- var resolveParameter = (param, spec) => {
167
+ /**
168
+ * Follows a parameter `$ref` — into `components.parameters`, or into another
169
+ * file through `documents` — if present.
170
+ */
171
+ var resolveParameter = (param, spec, documents) => {
96
172
  if (!param) return {};
97
173
  if (typeof param.$ref === "string") {
98
- const refName = param.$ref.replace("#/components/parameters/", "");
99
- return spec.components?.parameters?.[refName] || {};
174
+ const target = resolveRef({
175
+ ref: param.$ref,
176
+ scope: {
177
+ spec,
178
+ documents
179
+ }
180
+ });
181
+ return isRecord(target?.value) ? target.value : {};
100
182
  }
101
183
  return param;
102
184
  };
@@ -106,9 +188,9 @@ var buildPathFn = (pathTemplate, pathParams) => {
106
188
  let result = pathTemplate;
107
189
  for (const {
108
190
  name,
109
- camelName
191
+ argName
110
192
  } of pathParams) {
111
- const value = args[camelName];
193
+ const value = args[argName];
112
194
  if (value !== void 0) result = result.replace(`{${name}}`, encodeURIComponent(String(value)));
113
195
  }
114
196
  return result;
@@ -119,9 +201,6 @@ var NON_EXPLODED_DELIMITERS = {
119
201
  spaceDelimited: " ",
120
202
  pipeDelimited: "|"
121
203
  };
122
- var isRecord = value => {
123
- return typeof value === "object" && value !== null && !Array.isArray(value);
124
- };
125
204
  /**
126
205
  * Appends a `deepObject` value as bracketed keys — `filters[documentId][$eq]`.
127
206
  * OpenAPI only defines one level, but the APIs that ask for `deepObject`
@@ -209,7 +288,7 @@ var buildQueryFn = queryParams => {
209
288
  return args => {
210
289
  const search = new URLSearchParams();
211
290
  for (const param of queryParams) {
212
- const value = args[param.camelName];
291
+ const value = args[param.argName];
213
292
  if (value === void 0 || value === null) continue;
214
293
  appendQueryValue({
215
294
  search,
@@ -222,8 +301,8 @@ var buildQueryFn = queryParams => {
222
301
  };
223
302
  };
224
303
  /**
225
- * Builds a function that maps camelCase args back to a snake_case request
226
- * body, skipping `undefined` args. Returns `undefined` when the op has no body.
304
+ * Builds a function that maps tool args back to a request body keyed by the
305
+ * spec's property names, skipping `undefined` args. Returns `undefined` when the op has no body.
227
306
  */
228
307
  var buildBodyFn = bodyProps => {
229
308
  if (bodyProps.length === 0) return void 0;
@@ -231,8 +310,8 @@ var buildBodyFn = bodyProps => {
231
310
  const body = {};
232
311
  for (const {
233
312
  snakeName,
234
- camelName
235
- } of bodyProps) if (args[camelName] !== void 0) body[snakeName] = args[camelName];
313
+ argName
314
+ } of bodyProps) if (args[argName] !== void 0) body[snakeName] = args[argName];
236
315
  return body;
237
316
  };
238
317
  };
@@ -243,17 +322,93 @@ var DEFAULT_EXCLUDE_EXTENSION = "x-mcp-exclude";
243
322
  var DEFAULT_SERVER_MANAGED_EXTENSION = "x-mcp-server-managed";
244
323
 
245
324
  //#endregion
246
- //#region src/toolDefinitions.ts
325
+ //#region src/parameters.ts
247
326
  /**
248
327
  * Folds `_` and `-` separators into camelCase. OpenAPI operation and parameter
249
- * names may be snake_case (`agent_id`) or kebab-case (`list-tools`), and MCP
250
- * tool inputs are camelCase by convention, so both are folded here.
328
+ * names may be snake_case (`agent_id`) or kebab-case (`list-tools`); with the
329
+ * default `argumentNames: 'camelCase'` both are folded into tool arguments.
251
330
  */
252
331
  var snakeToCamel = str => {
253
332
  return str.replace(/[_-]([a-z])/g, (_, letter) => {
254
333
  return letter.toUpperCase();
255
334
  });
256
335
  };
336
+ var verbatim = name => {
337
+ return name;
338
+ };
339
+ var argNameMapper = argumentNames => {
340
+ return argumentNames === "verbatim" ? verbatim : snakeToCamel;
341
+ };
342
+ /**
343
+ * Deduplicates parameter entries by `name`, keeping the last occurrence. When
344
+ * path-item-level and operation-level parameters are concatenated (operation
345
+ * last), this makes the operation-level entry win — as the OpenAPI spec requires.
346
+ */
347
+ var dedupeByName = items => {
348
+ const byName = /* @__PURE__ */new Map();
349
+ for (const item of items) byName.set(item.name, item);
350
+ return [...byName.values()];
351
+ };
352
+ var extractPathParams = args => {
353
+ const toArgName = args.toArgName ?? snakeToCamel;
354
+ const flag = args.serverManagedExtension ?? "x-mcp-server-managed";
355
+ return dedupeByName((args.parameters || []).map(p => {
356
+ return resolveParameter(p, args.spec, args.documents);
357
+ }).filter(p => {
358
+ return p.in === "path";
359
+ }).map(p => {
360
+ return {
361
+ name: p.name || "",
362
+ argName: toArgName(p.name || ""),
363
+ serverManaged: Boolean(p[flag])
364
+ };
365
+ }));
366
+ };
367
+ var extractQueryParams = args => {
368
+ const toArgName = args.toArgName ?? snakeToCamel;
369
+ const flag = args.serverManagedExtension ?? "x-mcp-server-managed";
370
+ return dedupeByName((args.parameters || []).map(p => {
371
+ return resolveParameter(p, args.spec, args.documents);
372
+ }).filter(p => {
373
+ return p.in === "query";
374
+ }).map(p => {
375
+ return {
376
+ name: p.name || "",
377
+ argName: toArgName(p.name || ""),
378
+ description: p.description || "",
379
+ required: p.required || false,
380
+ type: p.schema?.type || "string",
381
+ style: p.style,
382
+ explode: p.explode,
383
+ serverManaged: Boolean(p[flag])
384
+ };
385
+ }));
386
+ };
387
+ /** Lists the path and query params flagged as server-managed. */
388
+ var collectServerManagedParameters = args => {
389
+ return [...args.pathParams.map(p => {
390
+ return {
391
+ ...p,
392
+ in: "path"
393
+ };
394
+ }), ...args.queryParams.map(p => {
395
+ return {
396
+ ...p,
397
+ in: "query"
398
+ };
399
+ })].filter(p => {
400
+ return p.serverManaged;
401
+ }).map(p => {
402
+ return {
403
+ name: p.name,
404
+ in: p.in,
405
+ argName: p.argName
406
+ };
407
+ });
408
+ };
409
+
410
+ //#endregion
411
+ //#region src/toolDefinitions.ts
257
412
  /** Converts a camelCase `operationId` to a kebab-case tool name. */
258
413
  var operationIdToToolName = operationId => {
259
414
  return operationId.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
@@ -318,23 +473,29 @@ var buildTypedProperty = param => {
318
473
  };
319
474
  };
320
475
  var buildInputSchema = (pathParams, queryParams, bodyProps) => {
321
- const allParams = [...pathParams, ...queryParams, ...bodyProps];
476
+ const modelPathParams = pathParams.filter(p => {
477
+ return !p.serverManaged;
478
+ });
479
+ const modelQueryParams = queryParams.filter(p => {
480
+ return !p.serverManaged;
481
+ });
482
+ const allParams = [...modelPathParams, ...modelQueryParams, ...bodyProps];
322
483
  if (allParams.length === 0) return {
323
484
  type: "object"
324
485
  };
325
- const requiredFields = [...pathParams.map(p => {
326
- return p.camelName;
327
- }), ...queryParams.filter(p => {
486
+ const requiredFields = [...modelPathParams.map(p => {
487
+ return p.argName;
488
+ }), ...modelQueryParams.filter(p => {
328
489
  return p.required;
329
490
  }).map(p => {
330
- return p.camelName;
491
+ return p.argName;
331
492
  }), ...bodyProps.filter(p => {
332
493
  return p.required;
333
494
  }).map(p => {
334
- return p.camelName;
495
+ return p.argName;
335
496
  })];
336
497
  const properties = {};
337
- for (const param of allParams) properties[param.camelName] = "description" in param ? buildTypedProperty(param) : {
498
+ for (const param of allParams) properties[param.argName] = "description" in param ? buildTypedProperty(param) : {
338
499
  type: "string",
339
500
  description: ""
340
501
  };
@@ -346,48 +507,9 @@ var buildInputSchema = (pathParams, queryParams, bodyProps) => {
346
507
  } : {})
347
508
  };
348
509
  };
349
- /**
350
- * Deduplicates parameter entries by `name`, keeping the last occurrence. When
351
- * path-item-level and operation-level parameters are concatenated (operation
352
- * last), this makes the operation-level entry win — as the OpenAPI spec requires.
353
- */
354
- var dedupeByName = items => {
355
- const byName = /* @__PURE__ */new Map();
356
- for (const item of items) byName.set(item.name, item);
357
- return [...byName.values()];
358
- };
359
- var extractPathParams = args => {
360
- return dedupeByName((args.parameters || []).map(p => {
361
- return resolveParameter(p, args.spec);
362
- }).filter(p => {
363
- return p.in === "path";
364
- }).map(p => {
365
- return {
366
- name: p.name || "",
367
- camelName: snakeToCamel(p.name || "")
368
- };
369
- }));
370
- };
371
- var extractQueryParams = args => {
372
- return dedupeByName((args.parameters || []).map(p => {
373
- return resolveParameter(p, args.spec);
374
- }).filter(p => {
375
- return p.in === "query";
376
- }).map(p => {
377
- return {
378
- name: p.name || "",
379
- camelName: snakeToCamel(p.name || ""),
380
- description: p.description || "",
381
- required: p.required || false,
382
- type: p.schema?.type || "string",
383
- style: p.style,
384
- explode: p.explode
385
- };
386
- }));
387
- };
388
510
  var resolveBodySchema = args => {
389
511
  const rawBodySchema = args.requestBody?.content?.["application/json"]?.schema;
390
- return resolveSchema(dereferenceSchema(rawBodySchema, args.spec), args.spec);
512
+ return resolveSchema(dereferenceSchema(rawBodySchema, args.spec, args.documents), args.spec, args.documents);
391
513
  };
392
514
  /**
393
515
  * snake_case names of every top-level property an operation's request schema
@@ -421,6 +543,7 @@ var flattenSingleAllOf = schema => {
421
543
  };
422
544
  };
423
545
  var extractBodyProps = args => {
546
+ const toArgName = args.toArgName ?? snakeToCamel;
424
547
  const bodySchema = resolveBodySchema(args);
425
548
  if (!bodySchema?.properties) return [];
426
549
  return Object.entries(bodySchema.properties).filter(([, value]) => {
@@ -429,7 +552,7 @@ var extractBodyProps = args => {
429
552
  const val = flattenSingleAllOf(value);
430
553
  return {
431
554
  snakeName: key,
432
- camelName: snakeToCamel(key),
555
+ argName: toArgName(key),
433
556
  description: typeof val.description === "string" ? val.description : "",
434
557
  required: (bodySchema.required || []).includes(key),
435
558
  type: typeof val.type === "string" ? val.type : void 0,
@@ -454,23 +577,37 @@ var processOperation = args => {
454
577
  if (args.operation[args.options.excludeExtension]) return null;
455
578
  const toolName = operationIdToToolName(args.operation.operationId);
456
579
  const parameters = [...(args.pathItemParameters ?? []), ...(args.operation.parameters ?? [])];
580
+ const {
581
+ documents,
582
+ serverManagedExtension
583
+ } = args.options;
584
+ const toArgName = argNameMapper(args.options.argumentNames);
457
585
  const pathParams = extractPathParams({
458
586
  parameters,
459
- spec: args.spec
587
+ spec: args.spec,
588
+ documents,
589
+ toArgName,
590
+ serverManagedExtension
460
591
  });
461
592
  const queryParams = extractQueryParams({
462
593
  parameters,
463
- spec: args.spec
594
+ spec: args.spec,
595
+ documents,
596
+ toArgName,
597
+ serverManagedExtension
464
598
  });
465
599
  const bodyProps = extractBodyProps({
466
600
  requestBody: args.operation.requestBody,
467
601
  spec: args.spec,
468
- serverManagedExtension: args.options.serverManagedExtension
602
+ serverManagedExtension,
603
+ documents,
604
+ toArgName
469
605
  });
470
606
  const inputSchema = buildInputSchema(pathParams, queryParams, bodyProps);
471
607
  const acceptedBodyFields = extractAcceptedBodyFields({
472
608
  requestBody: args.operation.requestBody,
473
- spec: args.spec
609
+ spec: args.spec,
610
+ documents
474
611
  });
475
612
  return {
476
613
  name: toolName,
@@ -483,7 +620,11 @@ var processOperation = args => {
483
620
  query: buildQueryFn(queryParams),
484
621
  body: buildBodyFn(bodyProps),
485
622
  acceptedBodyFields,
486
- extensions: extractExtensions(args.operation)
623
+ extensions: extractExtensions(args.operation),
624
+ serverManagedParameters: collectServerManagedParameters({
625
+ pathParams,
626
+ queryParams
627
+ })
487
628
  };
488
629
  };
489
630
  var processPath = args => {
@@ -504,6 +645,15 @@ var processPath = args => {
504
645
  }
505
646
  return tools;
506
647
  };
648
+ /** Applies the defaults to {@link OpenApiToToolsOptions}. */
649
+ var resolveOptions = (options = {}) => {
650
+ return {
651
+ excludeExtension: options.excludeExtension ?? "x-mcp-exclude",
652
+ serverManagedExtension: options.serverManagedExtension ?? "x-mcp-server-managed",
653
+ argumentNames: options.argumentNames ?? "camelCase",
654
+ documents: options.documents
655
+ };
656
+ };
507
657
  /**
508
658
  * Translates one or more OpenAPI documents into REST-backed MCP tool
509
659
  * definitions. Each translatable operation (has an `operationId`, a supported
@@ -517,10 +667,7 @@ var processPath = args => {
517
667
  * ```
518
668
  */
519
669
  var openApiToToolDefinitions = args => {
520
- const options = {
521
- excludeExtension: args.options?.excludeExtension ?? "x-mcp-exclude",
522
- serverManagedExtension: args.options?.serverManagedExtension ?? "x-mcp-server-managed"
523
- };
670
+ const options = resolveOptions(args.options);
524
671
  const specs = Array.isArray(args.spec) ? args.spec : [args.spec];
525
672
  const tools = [];
526
673
  for (const spec of specs) {
@@ -537,13 +684,34 @@ var openApiToToolDefinitions = args => {
537
684
 
538
685
  //#endregion
539
686
  //#region src/registerOpenApiTools.ts
687
+ /** The text the default `toText` answers when the API returned no body. */
688
+ var NO_CONTENT_TEXT = "Succeeded. The operation returned no content.";
540
689
  var defaultToText = data => {
690
+ if (data === void 0 || data === "") return NO_CONTENT_TEXT;
541
691
  return typeof data === "string" ? data : JSON.stringify(data, null, 2);
542
692
  };
543
693
  /**
694
+ * Replaces whatever the model sent for server-managed parameters with the
695
+ * values `serverParameters` supplies, so the model can never set them.
696
+ */
697
+ var applyServerParameters = async args => {
698
+ const managed = args.tool.serverManagedParameters;
699
+ if (managed.length === 0) return args.handlerArgs;
700
+ const result = {
701
+ ...args.handlerArgs
702
+ };
703
+ for (const param of managed) delete result[param.argName];
704
+ const values = args.serverParameters ? await args.serverParameters({
705
+ tool: args.tool,
706
+ headers: args.headers
707
+ }) : {};
708
+ for (const param of managed) if (values[param.name] !== void 0) result[param.argName] = values[param.name];
709
+ return result;
710
+ };
711
+ /**
544
712
  * Derives MCP tools from OpenAPI document(s) and registers each on the given
545
- * MCP server. Every tool's handler resolves the incoming camelCase args into a
546
- * concrete HTTP request and delegates execution to `callApi`.
713
+ * MCP server. Every tool's handler resolves the incoming args into a concrete
714
+ * HTTP request and delegates execution to `callApi`.
547
715
  *
548
716
  * @returns The list of {@link ToolDefinition} that were registered.
549
717
  *
@@ -557,10 +725,10 @@ var defaultToText = data => {
557
725
  * registerOpenApiTools({
558
726
  * server,
559
727
  * spec: myOpenApiDocument,
560
- * callApi: async ({ method, url, body }) => {
728
+ * callApi: async ({ method, url, body, headers }) => {
561
729
  * const res = await fetch(`https://api.example.com${url}`, {
562
730
  * method,
563
- * headers: { 'Content-Type': 'application/json' },
731
+ * headers: { ...headers, 'Content-Type': 'application/json' },
564
732
  * body: body ? JSON.stringify(body) : undefined,
565
733
  * });
566
734
  * return res.json();
@@ -578,7 +746,14 @@ var registerOpenApiTools = args => {
578
746
  name: tool.name,
579
747
  description: tool.description,
580
748
  inputSchema: tool.inputSchema,
581
- handler: async handlerArgs => {
749
+ handler: async rawArgs => {
750
+ const headers = getApiHeaders();
751
+ const handlerArgs = await applyServerParameters({
752
+ tool,
753
+ handlerArgs: rawArgs,
754
+ headers,
755
+ serverParameters: args.serverParameters
756
+ });
582
757
  const url = tool.path(handlerArgs) + (tool.query ? tool.query(handlerArgs) : "");
583
758
  return {
584
759
  content: [{
@@ -587,7 +762,8 @@ var registerOpenApiTools = args => {
587
762
  method: tool.method,
588
763
  url,
589
764
  body: tool.body ? tool.body(handlerArgs) : void 0,
590
- tool
765
+ tool,
766
+ headers
591
767
  }))
592
768
  }]
593
769
  };
@@ -597,4 +773,4 @@ var registerOpenApiTools = args => {
597
773
  };
598
774
 
599
775
  //#endregion
600
- export { DEFAULT_EXCLUDE_EXTENSION, DEFAULT_SERVER_MANAGED_EXTENSION, buildBodyFn, buildInputSchema, buildPathFn, buildQueryFn, dereferenceSchema, extractAcceptedBodyFields, extractBodyProps, extractPathParams, extractQueryParams, getJsonSchemaType, openApiToToolDefinitions, operationIdToToolName, processOperation, processPath, registerOpenApiTools, resolveParameter, resolveSchema, snakeToCamel };
776
+ export { DEFAULT_EXCLUDE_EXTENSION, DEFAULT_SERVER_MANAGED_EXTENSION, NO_CONTENT_TEXT, buildBodyFn, buildInputSchema, buildPathFn, buildQueryFn, dereferenceSchema, extractAcceptedBodyFields, extractBodyProps, extractPathParams, extractQueryParams, getJsonSchemaType, openApiToToolDefinitions, operationIdToToolName, processOperation, processPath, registerOpenApiTools, resolveParameter, resolveSchema, snakeToCamel };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp-openapi",
3
- "version": "0.2.15",
3
+ "version": "0.3.0",
4
4
  "description": "Generate Model Context Protocol (MCP) tools from an OpenAPI specification for @ttoss/http-server-mcp",
5
5
  "keywords": [
6
6
  "ai",
@@ -35,15 +35,15 @@
35
35
  "dist"
36
36
  ],
37
37
  "dependencies": {
38
- "@ttoss/http-server-mcp": "^0.28.2"
38
+ "@ttoss/http-server-mcp": "^0.29.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@modelcontextprotocol/server": "^2.0.0",
42
42
  "jest": "^30.4.2",
43
43
  "supertest": "^7.2.2",
44
44
  "tsdown": "^0.22.2",
45
- "@ttoss/config": "^1.38.0",
46
- "@ttoss/http-server": "^0.8.1"
45
+ "@ttoss/http-server": "^0.8.1",
46
+ "@ttoss/config": "^1.38.0"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public",