@ttoss/http-server-mcp-openapi 0.3.0 → 0.4.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
@@ -69,6 +69,10 @@ body property declared as a single-entry `allOf` (usually `allOf: [{ $ref }]`
69
69
  beside its own `description`) takes `type`, `nullable` and `items` from the
70
70
  referenced schema; a multi-entry `allOf` is forwarded verbatim, and a property
71
71
  with no declared type is advertised untyped so it accepts any value.
72
+ OpenAPI's `nullable` becomes JSON Schema at every depth — inside `items`,
73
+ `properties`, `additionalProperties` and `oneOf` / `anyOf` / `allOf`
74
+ alternatives: `nullable: true` adds `'null'` to the `type`, and the keyword is
75
+ dropped.
72
76
  Parameters declared at the **path-item level** (shared by every operation on a
73
77
  path) are merged into each operation; an operation-level parameter overrides a
74
78
  path-item one with the same `name`+`in`.
@@ -130,7 +134,7 @@ registerOpenApiTools({
130
134
  callApi,
131
135
  options: {
132
136
  excludeExtension: 'x-mcp-exclude', // operations flagged truthy are skipped
133
- serverManagedExtension: 'x-mcp-server-managed', // values hidden from the input schema
137
+ serverManagedExtension: 'x-mcp-server-managed', // or several: ['x-a', 'x-b']
134
138
  argumentNames: 'camelCase', // or 'verbatim'
135
139
  documents: { './tags.yaml': tagsDocument }, // targets of cross-file $refs
136
140
  },
@@ -139,8 +143,8 @@ registerOpenApiTools({
139
143
 
140
144
  - **`excludeExtension`** (default `x-mcp-exclude`) — an operation with this
141
145
  extension set truthy is omitted from the tool surface.
142
- - **`serverManagedExtension`** (default `x-mcp-server-managed`) — see
143
- [Server-managed values](#server-managed-values).
146
+ - **`serverManagedExtension`** (default `x-mcp-server-managed`) — one name or
147
+ an array of names; see [Server-managed values](#server-managed-values).
144
148
  - **`argumentNames`** (default `camelCase`) — `verbatim` keeps the spec's
145
149
  parameter and property names as tool argument names.
146
150
  - **`documents`** — sibling documents for `$ref`s with a file part, keyed by
@@ -173,6 +177,12 @@ registerOpenApiTools({
173
177
  With `openApiToToolDefinitions`, set each entry's `argName` in the args before
174
178
  calling `tool.path` / `tool.query`.
175
179
 
180
+ A **string** extension value pins the parameter: `wait` declared with
181
+ `x-mcp-server-managed: 'true'` is always sent as `wait=true`. `tool.path` and
182
+ `tool.query` apply pinned values themselves, over anything in the args or
183
+ `serverParameters`, and the entry in `serverManagedParameters` carries it as
184
+ `value`.
185
+
176
186
  ### Reading custom extensions
177
187
 
178
188
  Every `x-` prefixed extension on an operation is forwarded verbatim on
package/dist/index.cjs CHANGED
@@ -319,6 +319,85 @@ var buildBodyFn = bodyProps => {
319
319
  };
320
320
  };
321
321
 
322
+ //#endregion
323
+ //#region src/serverManaged.ts
324
+ /**
325
+ * Whether a parameter or body property carries one of the server-managed
326
+ * extensions, and the value it pins when the extension is a string.
327
+ *
328
+ * A string pins the value (`x-mcp-server-managed: 'true'` always sends
329
+ * `true`); any other truthy value only hides it. The first matching name wins.
330
+ */
331
+ var readServerManaged = args => {
332
+ const names = Array.isArray(args.extension) ? args.extension : [args.extension];
333
+ for (const name of names) {
334
+ const flag = args.node[name];
335
+ if (typeof flag === "string") return {
336
+ managed: true,
337
+ value: flag
338
+ };
339
+ if (flag) return {
340
+ managed: true
341
+ };
342
+ }
343
+ return {
344
+ managed: false
345
+ };
346
+ };
347
+ /** The args each pinned parameter is always sent with, keyed by `argName`. */
348
+ var pinnedArgs = parameters => {
349
+ const pinned = {};
350
+ for (const parameter of parameters) if (parameter.value !== void 0) pinned[parameter.argName] = parameter.value;
351
+ return pinned;
352
+ };
353
+ /**
354
+ * Wraps a `path` / `query` builder so pinned values replace whatever the args
355
+ * carry. Applied in the builder itself, so every consumer of the tool
356
+ * definition sends them, not only `registerOpenApiTools`.
357
+ */
358
+ var withPinned = args => {
359
+ const {
360
+ build,
361
+ pinned
362
+ } = args;
363
+ if (!build || Object.keys(pinned).length === 0) return build;
364
+ return values => {
365
+ return build({
366
+ ...values,
367
+ ...pinned
368
+ });
369
+ };
370
+ };
371
+ var isPlainObject$1 = value => {
372
+ return typeof value === "object" && value !== null && !Array.isArray(value);
373
+ };
374
+ var mergeNullIntoType = schema => {
375
+ const {
376
+ type
377
+ } = schema;
378
+ if (typeof type === "string") schema.type = [type, "null"];else if (Array.isArray(type) && !type.includes("null")) schema.type = [...type, "null"];
379
+ };
380
+ /**
381
+ * Turns OpenAPI's `nullable` into JSON Schema at every depth: `nullable: true`
382
+ * merges `'null'` into a sibling `type` and is dropped where there is none.
383
+ * JSON Schema has no `nullable`, so a validator or model reading it would
384
+ * refuse `null` where the API accepts it.
385
+ *
386
+ * Only a boolean `nullable` is the keyword; a property *named* `nullable`
387
+ * inside `properties` is a schema and is kept.
388
+ */
389
+ var normalizeNullable = value => {
390
+ if (Array.isArray(value)) return value.map(normalizeNullable);
391
+ if (!isPlainObject$1(value)) return value;
392
+ const result = {};
393
+ for (const [key, nested] of Object.entries(value)) {
394
+ if (key === "nullable" && typeof nested === "boolean") continue;
395
+ result[key] = normalizeNullable(nested);
396
+ }
397
+ if (value.nullable === true) mergeNullIntoType(result);
398
+ return result;
399
+ };
400
+
322
401
  //#endregion
323
402
  //#region src/types.ts
324
403
  var DEFAULT_EXCLUDE_EXTENSION = "x-mcp-exclude";
@@ -352,6 +431,14 @@ var dedupeByName = items => {
352
431
  for (const item of items) byName.set(item.name, item);
353
432
  return [...byName.values()];
354
433
  };
434
+ var managedFields = flag => {
435
+ return flag.value === void 0 ? {
436
+ serverManaged: flag.managed
437
+ } : {
438
+ serverManaged: true,
439
+ pinnedValue: flag.value
440
+ };
441
+ };
355
442
  var extractPathParams = args => {
356
443
  const toArgName = args.toArgName ?? snakeToCamel;
357
444
  const flag = args.serverManagedExtension ?? "x-mcp-server-managed";
@@ -363,7 +450,10 @@ var extractPathParams = args => {
363
450
  return {
364
451
  name: p.name || "",
365
452
  argName: toArgName(p.name || ""),
366
- serverManaged: Boolean(p[flag])
453
+ ...managedFields(readServerManaged({
454
+ node: p,
455
+ extension: flag
456
+ }))
367
457
  };
368
458
  }));
369
459
  };
@@ -383,11 +473,13 @@ var extractQueryParams = args => {
383
473
  type: p.schema?.type || "string",
384
474
  style: p.style,
385
475
  explode: p.explode,
386
- serverManaged: Boolean(p[flag])
476
+ ...managedFields(readServerManaged({
477
+ node: p,
478
+ extension: flag
479
+ }))
387
480
  };
388
481
  }));
389
482
  };
390
- /** Lists the path and query params flagged as server-managed. */
391
483
  var collectServerManagedParameters = args => {
392
484
  return [...args.pathParams.map(p => {
393
485
  return {
@@ -405,7 +497,10 @@ var collectServerManagedParameters = args => {
405
497
  return {
406
498
  name: p.name,
407
499
  in: p.in,
408
- argName: p.argName
500
+ argName: p.argName,
501
+ ...(p.pinnedValue === void 0 ? {} : {
502
+ value: p.pinnedValue
503
+ })
409
504
  };
410
505
  });
411
506
  };
@@ -498,7 +593,7 @@ var buildInputSchema = (pathParams, queryParams, bodyProps) => {
498
593
  return p.argName;
499
594
  })];
500
595
  const properties = {};
501
- for (const param of allParams) properties[param.argName] = "description" in param ? buildTypedProperty(param) : {
596
+ for (const param of allParams) properties[param.argName] = "description" in param ? normalizeNullable(buildTypedProperty(param)) : {
502
597
  type: "string",
503
598
  description: ""
504
599
  };
@@ -550,7 +645,10 @@ var extractBodyProps = args => {
550
645
  const bodySchema = resolveBodySchema(args);
551
646
  if (!bodySchema?.properties) return [];
552
647
  return Object.entries(bodySchema.properties).filter(([, value]) => {
553
- return !value[args.serverManagedExtension];
648
+ return !readServerManaged({
649
+ node: value,
650
+ extension: args.serverManagedExtension
651
+ }).managed;
554
652
  }).map(([key, value]) => {
555
653
  const val = flattenSingleAllOf(value);
556
654
  return {
@@ -607,6 +705,11 @@ var processOperation = args => {
607
705
  toArgName
608
706
  });
609
707
  const inputSchema = buildInputSchema(pathParams, queryParams, bodyProps);
708
+ const serverManagedParameters = collectServerManagedParameters({
709
+ pathParams,
710
+ queryParams
711
+ });
712
+ const pinned = pinnedArgs(serverManagedParameters);
610
713
  const acceptedBodyFields = extractAcceptedBodyFields({
611
714
  requestBody: args.operation.requestBody,
612
715
  spec: args.spec,
@@ -619,15 +722,18 @@ var processOperation = args => {
619
722
  method: httpMethod,
620
723
  pathTemplate: args.pathTemplate,
621
724
  operationId: args.operation.operationId,
622
- path: buildPathFn(args.pathTemplate, pathParams),
623
- query: buildQueryFn(queryParams),
725
+ path: withPinned({
726
+ build: buildPathFn(args.pathTemplate, pathParams),
727
+ pinned
728
+ }),
729
+ query: withPinned({
730
+ build: buildQueryFn(queryParams),
731
+ pinned
732
+ }),
624
733
  body: buildBodyFn(bodyProps),
625
734
  acceptedBodyFields,
626
735
  extensions: extractExtensions(args.operation),
627
- serverManagedParameters: collectServerManagedParameters({
628
- pathParams,
629
- queryParams
630
- })
736
+ serverManagedParameters
631
737
  };
632
738
  };
633
739
  var processPath = args => {
package/dist/index.d.cts CHANGED
@@ -84,6 +84,11 @@ interface ServerManagedParameter {
84
84
  in: 'path' | 'query';
85
85
  /** The args key `path` / `query` read the value from. */
86
86
  argName: string;
87
+ /**
88
+ * The value the spec pins, when the extension is a string. `path` / `query`
89
+ * always send it, whatever the args or `serverParameters` carry.
90
+ */
91
+ value?: string;
87
92
  }
88
93
  /** Minimal shape of an OpenAPI document consumed by the generator. */
89
94
  interface OpenApiSpec {
@@ -150,11 +155,14 @@ interface OpenApiToToolsOptions {
150
155
  * - On a **request-body property**, the property stays in
151
156
  * `acceptedBodyFields` and is never sent (the API sets it itself).
152
157
  * - On a **path or query parameter**, the parameter is listed in
153
- * `serverManagedParameters` and the consumer supplies its value.
158
+ * `serverManagedParameters` and the consumer supplies its value. A string
159
+ * extension value (`'true'`) pins it: the builders always send that value.
160
+ *
161
+ * Several names may be given; a node flagged by any of them is managed.
154
162
  *
155
163
  * @default 'x-mcp-server-managed'
156
164
  */
157
- serverManagedExtension?: string;
165
+ serverManagedExtension?: string | string[];
158
166
  /**
159
167
  * How tool argument names are derived from the spec's parameter and
160
168
  * body-property names.
@@ -181,6 +189,10 @@ type ResolvedToolOptions = Required<Omit<OpenApiToToolsOptions, 'documents'>> &
181
189
  declare const DEFAULT_EXCLUDE_EXTENSION = "x-mcp-exclude";
182
190
  declare const DEFAULT_SERVER_MANAGED_EXTENSION = "x-mcp-server-managed";
183
191
  //#endregion
192
+ //#region src/serverManaged.d.ts
193
+ /** One extension name, or several that all mean "the server sets this". */
194
+ type ServerManagedExtension = string | string[];
195
+ //#endregion
184
196
  //#region src/parameters.d.ts
185
197
  /**
186
198
  * Folds `_` and `-` separators into camelCase. OpenAPI operation and parameter
@@ -200,12 +212,13 @@ type ExtractParamsArgs = {
200
212
  spec: OpenApiSpec; /** Sibling documents cross-file `$ref`s resolve against. */
201
213
  documents?: OpenApiDocuments; /** Maps a spec name to its tool argument name. @default snakeToCamel */
202
214
  toArgName?: ToArgName; /** @default DEFAULT_SERVER_MANAGED_EXTENSION */
203
- serverManagedExtension?: string;
215
+ serverManagedExtension?: ServerManagedExtension;
204
216
  };
205
217
  declare const extractPathParams: (args: ExtractParamsArgs) => Array<{
206
218
  name: string;
207
219
  argName: string;
208
220
  serverManaged: boolean;
221
+ pinnedValue?: string;
209
222
  }>;
210
223
  declare const extractQueryParams: (args: ExtractParamsArgs) => Array<{
211
224
  name: string;
@@ -216,6 +229,7 @@ declare const extractQueryParams: (args: ExtractParamsArgs) => Array<{
216
229
  style?: string;
217
230
  explode?: boolean;
218
231
  serverManaged: boolean;
232
+ pinnedValue?: string;
219
233
  }>;
220
234
  //#endregion
221
235
  //#region src/registerOpenApiTools.d.ts
@@ -415,7 +429,7 @@ declare const extractAcceptedBodyFields: (args: {
415
429
  declare const extractBodyProps: (args: {
416
430
  requestBody?: RequestBodySpec;
417
431
  spec: OpenApiSpec;
418
- serverManagedExtension: string;
432
+ serverManagedExtension: ServerManagedExtension;
419
433
  documents?: OpenApiDocuments; /** Maps a spec name to its tool argument name. @default snakeToCamel */
420
434
  toArgName?: ToArgName;
421
435
  }) => Array<{
package/dist/index.d.mts CHANGED
@@ -84,6 +84,11 @@ interface ServerManagedParameter {
84
84
  in: 'path' | 'query';
85
85
  /** The args key `path` / `query` read the value from. */
86
86
  argName: string;
87
+ /**
88
+ * The value the spec pins, when the extension is a string. `path` / `query`
89
+ * always send it, whatever the args or `serverParameters` carry.
90
+ */
91
+ value?: string;
87
92
  }
88
93
  /** Minimal shape of an OpenAPI document consumed by the generator. */
89
94
  interface OpenApiSpec {
@@ -150,11 +155,14 @@ interface OpenApiToToolsOptions {
150
155
  * - On a **request-body property**, the property stays in
151
156
  * `acceptedBodyFields` and is never sent (the API sets it itself).
152
157
  * - On a **path or query parameter**, the parameter is listed in
153
- * `serverManagedParameters` and the consumer supplies its value.
158
+ * `serverManagedParameters` and the consumer supplies its value. A string
159
+ * extension value (`'true'`) pins it: the builders always send that value.
160
+ *
161
+ * Several names may be given; a node flagged by any of them is managed.
154
162
  *
155
163
  * @default 'x-mcp-server-managed'
156
164
  */
157
- serverManagedExtension?: string;
165
+ serverManagedExtension?: string | string[];
158
166
  /**
159
167
  * How tool argument names are derived from the spec's parameter and
160
168
  * body-property names.
@@ -181,6 +189,10 @@ type ResolvedToolOptions = Required<Omit<OpenApiToToolsOptions, 'documents'>> &
181
189
  declare const DEFAULT_EXCLUDE_EXTENSION = "x-mcp-exclude";
182
190
  declare const DEFAULT_SERVER_MANAGED_EXTENSION = "x-mcp-server-managed";
183
191
  //#endregion
192
+ //#region src/serverManaged.d.ts
193
+ /** One extension name, or several that all mean "the server sets this". */
194
+ type ServerManagedExtension = string | string[];
195
+ //#endregion
184
196
  //#region src/parameters.d.ts
185
197
  /**
186
198
  * Folds `_` and `-` separators into camelCase. OpenAPI operation and parameter
@@ -200,12 +212,13 @@ type ExtractParamsArgs = {
200
212
  spec: OpenApiSpec; /** Sibling documents cross-file `$ref`s resolve against. */
201
213
  documents?: OpenApiDocuments; /** Maps a spec name to its tool argument name. @default snakeToCamel */
202
214
  toArgName?: ToArgName; /** @default DEFAULT_SERVER_MANAGED_EXTENSION */
203
- serverManagedExtension?: string;
215
+ serverManagedExtension?: ServerManagedExtension;
204
216
  };
205
217
  declare const extractPathParams: (args: ExtractParamsArgs) => Array<{
206
218
  name: string;
207
219
  argName: string;
208
220
  serverManaged: boolean;
221
+ pinnedValue?: string;
209
222
  }>;
210
223
  declare const extractQueryParams: (args: ExtractParamsArgs) => Array<{
211
224
  name: string;
@@ -216,6 +229,7 @@ declare const extractQueryParams: (args: ExtractParamsArgs) => Array<{
216
229
  style?: string;
217
230
  explode?: boolean;
218
231
  serverManaged: boolean;
232
+ pinnedValue?: string;
219
233
  }>;
220
234
  //#endregion
221
235
  //#region src/registerOpenApiTools.d.ts
@@ -415,7 +429,7 @@ declare const extractAcceptedBodyFields: (args: {
415
429
  declare const extractBodyProps: (args: {
416
430
  requestBody?: RequestBodySpec;
417
431
  spec: OpenApiSpec;
418
- serverManagedExtension: string;
432
+ serverManagedExtension: ServerManagedExtension;
419
433
  documents?: OpenApiDocuments; /** Maps a spec name to its tool argument name. @default snakeToCamel */
420
434
  toArgName?: ToArgName;
421
435
  }) => Array<{
package/dist/index.mjs CHANGED
@@ -316,6 +316,85 @@ var buildBodyFn = bodyProps => {
316
316
  };
317
317
  };
318
318
 
319
+ //#endregion
320
+ //#region src/serverManaged.ts
321
+ /**
322
+ * Whether a parameter or body property carries one of the server-managed
323
+ * extensions, and the value it pins when the extension is a string.
324
+ *
325
+ * A string pins the value (`x-mcp-server-managed: 'true'` always sends
326
+ * `true`); any other truthy value only hides it. The first matching name wins.
327
+ */
328
+ var readServerManaged = args => {
329
+ const names = Array.isArray(args.extension) ? args.extension : [args.extension];
330
+ for (const name of names) {
331
+ const flag = args.node[name];
332
+ if (typeof flag === "string") return {
333
+ managed: true,
334
+ value: flag
335
+ };
336
+ if (flag) return {
337
+ managed: true
338
+ };
339
+ }
340
+ return {
341
+ managed: false
342
+ };
343
+ };
344
+ /** The args each pinned parameter is always sent with, keyed by `argName`. */
345
+ var pinnedArgs = parameters => {
346
+ const pinned = {};
347
+ for (const parameter of parameters) if (parameter.value !== void 0) pinned[parameter.argName] = parameter.value;
348
+ return pinned;
349
+ };
350
+ /**
351
+ * Wraps a `path` / `query` builder so pinned values replace whatever the args
352
+ * carry. Applied in the builder itself, so every consumer of the tool
353
+ * definition sends them, not only `registerOpenApiTools`.
354
+ */
355
+ var withPinned = args => {
356
+ const {
357
+ build,
358
+ pinned
359
+ } = args;
360
+ if (!build || Object.keys(pinned).length === 0) return build;
361
+ return values => {
362
+ return build({
363
+ ...values,
364
+ ...pinned
365
+ });
366
+ };
367
+ };
368
+ var isPlainObject$1 = value => {
369
+ return typeof value === "object" && value !== null && !Array.isArray(value);
370
+ };
371
+ var mergeNullIntoType = schema => {
372
+ const {
373
+ type
374
+ } = schema;
375
+ if (typeof type === "string") schema.type = [type, "null"];else if (Array.isArray(type) && !type.includes("null")) schema.type = [...type, "null"];
376
+ };
377
+ /**
378
+ * Turns OpenAPI's `nullable` into JSON Schema at every depth: `nullable: true`
379
+ * merges `'null'` into a sibling `type` and is dropped where there is none.
380
+ * JSON Schema has no `nullable`, so a validator or model reading it would
381
+ * refuse `null` where the API accepts it.
382
+ *
383
+ * Only a boolean `nullable` is the keyword; a property *named* `nullable`
384
+ * inside `properties` is a schema and is kept.
385
+ */
386
+ var normalizeNullable = value => {
387
+ if (Array.isArray(value)) return value.map(normalizeNullable);
388
+ if (!isPlainObject$1(value)) return value;
389
+ const result = {};
390
+ for (const [key, nested] of Object.entries(value)) {
391
+ if (key === "nullable" && typeof nested === "boolean") continue;
392
+ result[key] = normalizeNullable(nested);
393
+ }
394
+ if (value.nullable === true) mergeNullIntoType(result);
395
+ return result;
396
+ };
397
+
319
398
  //#endregion
320
399
  //#region src/types.ts
321
400
  var DEFAULT_EXCLUDE_EXTENSION = "x-mcp-exclude";
@@ -349,6 +428,14 @@ var dedupeByName = items => {
349
428
  for (const item of items) byName.set(item.name, item);
350
429
  return [...byName.values()];
351
430
  };
431
+ var managedFields = flag => {
432
+ return flag.value === void 0 ? {
433
+ serverManaged: flag.managed
434
+ } : {
435
+ serverManaged: true,
436
+ pinnedValue: flag.value
437
+ };
438
+ };
352
439
  var extractPathParams = args => {
353
440
  const toArgName = args.toArgName ?? snakeToCamel;
354
441
  const flag = args.serverManagedExtension ?? "x-mcp-server-managed";
@@ -360,7 +447,10 @@ var extractPathParams = args => {
360
447
  return {
361
448
  name: p.name || "",
362
449
  argName: toArgName(p.name || ""),
363
- serverManaged: Boolean(p[flag])
450
+ ...managedFields(readServerManaged({
451
+ node: p,
452
+ extension: flag
453
+ }))
364
454
  };
365
455
  }));
366
456
  };
@@ -380,11 +470,13 @@ var extractQueryParams = args => {
380
470
  type: p.schema?.type || "string",
381
471
  style: p.style,
382
472
  explode: p.explode,
383
- serverManaged: Boolean(p[flag])
473
+ ...managedFields(readServerManaged({
474
+ node: p,
475
+ extension: flag
476
+ }))
384
477
  };
385
478
  }));
386
479
  };
387
- /** Lists the path and query params flagged as server-managed. */
388
480
  var collectServerManagedParameters = args => {
389
481
  return [...args.pathParams.map(p => {
390
482
  return {
@@ -402,7 +494,10 @@ var collectServerManagedParameters = args => {
402
494
  return {
403
495
  name: p.name,
404
496
  in: p.in,
405
- argName: p.argName
497
+ argName: p.argName,
498
+ ...(p.pinnedValue === void 0 ? {} : {
499
+ value: p.pinnedValue
500
+ })
406
501
  };
407
502
  });
408
503
  };
@@ -495,7 +590,7 @@ var buildInputSchema = (pathParams, queryParams, bodyProps) => {
495
590
  return p.argName;
496
591
  })];
497
592
  const properties = {};
498
- for (const param of allParams) properties[param.argName] = "description" in param ? buildTypedProperty(param) : {
593
+ for (const param of allParams) properties[param.argName] = "description" in param ? normalizeNullable(buildTypedProperty(param)) : {
499
594
  type: "string",
500
595
  description: ""
501
596
  };
@@ -547,7 +642,10 @@ var extractBodyProps = args => {
547
642
  const bodySchema = resolveBodySchema(args);
548
643
  if (!bodySchema?.properties) return [];
549
644
  return Object.entries(bodySchema.properties).filter(([, value]) => {
550
- return !value[args.serverManagedExtension];
645
+ return !readServerManaged({
646
+ node: value,
647
+ extension: args.serverManagedExtension
648
+ }).managed;
551
649
  }).map(([key, value]) => {
552
650
  const val = flattenSingleAllOf(value);
553
651
  return {
@@ -604,6 +702,11 @@ var processOperation = args => {
604
702
  toArgName
605
703
  });
606
704
  const inputSchema = buildInputSchema(pathParams, queryParams, bodyProps);
705
+ const serverManagedParameters = collectServerManagedParameters({
706
+ pathParams,
707
+ queryParams
708
+ });
709
+ const pinned = pinnedArgs(serverManagedParameters);
607
710
  const acceptedBodyFields = extractAcceptedBodyFields({
608
711
  requestBody: args.operation.requestBody,
609
712
  spec: args.spec,
@@ -616,15 +719,18 @@ var processOperation = args => {
616
719
  method: httpMethod,
617
720
  pathTemplate: args.pathTemplate,
618
721
  operationId: args.operation.operationId,
619
- path: buildPathFn(args.pathTemplate, pathParams),
620
- query: buildQueryFn(queryParams),
722
+ path: withPinned({
723
+ build: buildPathFn(args.pathTemplate, pathParams),
724
+ pinned
725
+ }),
726
+ query: withPinned({
727
+ build: buildQueryFn(queryParams),
728
+ pinned
729
+ }),
621
730
  body: buildBodyFn(bodyProps),
622
731
  acceptedBodyFields,
623
732
  extensions: extractExtensions(args.operation),
624
- serverManagedParameters: collectServerManagedParameters({
625
- pathParams,
626
- queryParams
627
- })
733
+ serverManagedParameters
628
734
  };
629
735
  };
630
736
  var processPath = args => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp-openapi",
3
- "version": "0.3.0",
3
+ "version": "0.4.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",
@@ -42,8 +42,8 @@
42
42
  "jest": "^30.4.2",
43
43
  "supertest": "^7.2.2",
44
44
  "tsdown": "^0.22.2",
45
- "@ttoss/http-server": "^0.8.1",
46
- "@ttoss/config": "^1.38.0"
45
+ "@ttoss/config": "^1.38.0",
46
+ "@ttoss/http-server": "^0.8.1"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public",