@ttoss/http-server-mcp-openapi 0.1.0 → 0.1.2

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
@@ -62,6 +62,9 @@ Each OpenAPI operation with an `operationId` and a supported HTTP method
62
62
 
63
63
  Path params are always required strings. Query and body params carry their
64
64
  declared type and `required` flag. Array params keep their `items` schema.
65
+ Parameters declared at the **path-item level** (shared by every operation on a
66
+ path) are merged into each operation; an operation-level parameter overrides a
67
+ path-item one with the same `name`+`in`.
65
68
 
66
69
  Tool arguments are **camelCase** (`agentId`, `projectId`); the generated
67
70
  request path, query string, and body use the original **snake_case** names.
package/dist/index.cjs CHANGED
@@ -227,8 +227,18 @@ var buildInputSchema = (pathParams, queryParams, bodyProps) => {
227
227
  required: requiredFields.length > 0 ? requiredFields : void 0
228
228
  };
229
229
  };
230
+ /**
231
+ * Deduplicates parameter entries by `name`, keeping the last occurrence. When
232
+ * path-item-level and operation-level parameters are concatenated (operation
233
+ * last), this makes the operation-level entry win — as the OpenAPI spec requires.
234
+ */
235
+ var dedupeByName = items => {
236
+ const byName = /* @__PURE__ */new Map();
237
+ for (const item of items) byName.set(item.name, item);
238
+ return [...byName.values()];
239
+ };
230
240
  var extractPathParams = args => {
231
- return (args.parameters || []).map(p => {
241
+ return dedupeByName((args.parameters || []).map(p => {
232
242
  return resolveParameter(p, args.spec);
233
243
  }).filter(p => {
234
244
  return p.in === "path";
@@ -237,10 +247,10 @@ var extractPathParams = args => {
237
247
  name: p.name || "",
238
248
  camelName: snakeToCamel(p.name || "")
239
249
  };
240
- });
250
+ }));
241
251
  };
242
252
  var extractQueryParams = args => {
243
- return (args.parameters || []).map(p => {
253
+ return dedupeByName((args.parameters || []).map(p => {
244
254
  return resolveParameter(p, args.spec);
245
255
  }).filter(p => {
246
256
  return p.in === "query";
@@ -252,7 +262,7 @@ var extractQueryParams = args => {
252
262
  required: p.required || false,
253
263
  type: p.schema?.type || "string"
254
264
  };
255
- });
265
+ }));
256
266
  };
257
267
  var resolveBodySchema = args => {
258
268
  const rawBodySchema = args.requestBody?.content?.["application/json"]?.schema;
@@ -295,12 +305,13 @@ var processOperation = args => {
295
305
  if (!args.operation.operationId) return null;
296
306
  if (args.operation[args.options.excludeExtension]) return null;
297
307
  const toolName = operationIdToToolName(args.operation.operationId);
308
+ const parameters = [...(args.pathItemParameters ?? []), ...(args.operation.parameters ?? [])];
298
309
  const pathParams = extractPathParams({
299
- parameters: args.operation.parameters || [],
310
+ parameters,
300
311
  spec: args.spec
301
312
  });
302
313
  const queryParams = extractQueryParams({
303
- parameters: args.operation.parameters || [],
314
+ parameters,
304
315
  spec: args.spec
305
316
  });
306
317
  const bodyProps = extractBodyProps({
@@ -328,14 +339,18 @@ var processOperation = args => {
328
339
  };
329
340
  };
330
341
  var processPath = args => {
342
+ const rawPathItemParameters = args.pathItem.parameters;
343
+ const pathItemParameters = Array.isArray(rawPathItemParameters) ? rawPathItemParameters : [];
331
344
  const tools = [];
332
345
  for (const [method, operation] of Object.entries(args.pathItem)) {
346
+ if (method === "parameters") continue;
333
347
  const tool = processOperation({
334
348
  pathTemplate: args.pathTemplate,
335
349
  method,
336
350
  operation,
337
351
  spec: args.spec,
338
- options: args.options
352
+ options: args.options,
353
+ pathItemParameters
339
354
  });
340
355
  if (tool) tools.push(tool);
341
356
  }
package/dist/index.d.cts CHANGED
@@ -308,6 +308,16 @@ declare const processOperation: (args: {
308
308
  operation: OperationSpec;
309
309
  spec: OpenApiSpec;
310
310
  options: Required<OpenApiToToolsOptions>;
311
+ /**
312
+ * Parameters declared at the path-item level (shared by every operation on
313
+ * the path). Merged ahead of the operation's own parameters so operation-level
314
+ * entries win on a `name`+`in` clash.
315
+ */
316
+ pathItemParameters?: Array<{
317
+ name?: string;
318
+ in?: string;
319
+ [key: string]: unknown;
320
+ }>;
311
321
  }) => ToolDefinition | null;
312
322
  declare const processPath: (args: {
313
323
  pathTemplate: string;
package/dist/index.d.mts CHANGED
@@ -308,6 +308,16 @@ declare const processOperation: (args: {
308
308
  operation: OperationSpec;
309
309
  spec: OpenApiSpec;
310
310
  options: Required<OpenApiToToolsOptions>;
311
+ /**
312
+ * Parameters declared at the path-item level (shared by every operation on
313
+ * the path). Merged ahead of the operation's own parameters so operation-level
314
+ * entries win on a `name`+`in` clash.
315
+ */
316
+ pathItemParameters?: Array<{
317
+ name?: string;
318
+ in?: string;
319
+ [key: string]: unknown;
320
+ }>;
311
321
  }) => ToolDefinition | null;
312
322
  declare const processPath: (args: {
313
323
  pathTemplate: string;
package/dist/index.mjs CHANGED
@@ -224,8 +224,18 @@ var buildInputSchema = (pathParams, queryParams, bodyProps) => {
224
224
  required: requiredFields.length > 0 ? requiredFields : void 0
225
225
  };
226
226
  };
227
+ /**
228
+ * Deduplicates parameter entries by `name`, keeping the last occurrence. When
229
+ * path-item-level and operation-level parameters are concatenated (operation
230
+ * last), this makes the operation-level entry win — as the OpenAPI spec requires.
231
+ */
232
+ var dedupeByName = items => {
233
+ const byName = /* @__PURE__ */new Map();
234
+ for (const item of items) byName.set(item.name, item);
235
+ return [...byName.values()];
236
+ };
227
237
  var extractPathParams = args => {
228
- return (args.parameters || []).map(p => {
238
+ return dedupeByName((args.parameters || []).map(p => {
229
239
  return resolveParameter(p, args.spec);
230
240
  }).filter(p => {
231
241
  return p.in === "path";
@@ -234,10 +244,10 @@ var extractPathParams = args => {
234
244
  name: p.name || "",
235
245
  camelName: snakeToCamel(p.name || "")
236
246
  };
237
- });
247
+ }));
238
248
  };
239
249
  var extractQueryParams = args => {
240
- return (args.parameters || []).map(p => {
250
+ return dedupeByName((args.parameters || []).map(p => {
241
251
  return resolveParameter(p, args.spec);
242
252
  }).filter(p => {
243
253
  return p.in === "query";
@@ -249,7 +259,7 @@ var extractQueryParams = args => {
249
259
  required: p.required || false,
250
260
  type: p.schema?.type || "string"
251
261
  };
252
- });
262
+ }));
253
263
  };
254
264
  var resolveBodySchema = args => {
255
265
  const rawBodySchema = args.requestBody?.content?.["application/json"]?.schema;
@@ -292,12 +302,13 @@ var processOperation = args => {
292
302
  if (!args.operation.operationId) return null;
293
303
  if (args.operation[args.options.excludeExtension]) return null;
294
304
  const toolName = operationIdToToolName(args.operation.operationId);
305
+ const parameters = [...(args.pathItemParameters ?? []), ...(args.operation.parameters ?? [])];
295
306
  const pathParams = extractPathParams({
296
- parameters: args.operation.parameters || [],
307
+ parameters,
297
308
  spec: args.spec
298
309
  });
299
310
  const queryParams = extractQueryParams({
300
- parameters: args.operation.parameters || [],
311
+ parameters,
301
312
  spec: args.spec
302
313
  });
303
314
  const bodyProps = extractBodyProps({
@@ -325,14 +336,18 @@ var processOperation = args => {
325
336
  };
326
337
  };
327
338
  var processPath = args => {
339
+ const rawPathItemParameters = args.pathItem.parameters;
340
+ const pathItemParameters = Array.isArray(rawPathItemParameters) ? rawPathItemParameters : [];
328
341
  const tools = [];
329
342
  for (const [method, operation] of Object.entries(args.pathItem)) {
343
+ if (method === "parameters") continue;
330
344
  const tool = processOperation({
331
345
  pathTemplate: args.pathTemplate,
332
346
  method,
333
347
  operation,
334
348
  spec: args.spec,
335
- options: args.options
349
+ options: args.options,
350
+ pathItemParameters
336
351
  });
337
352
  if (tool) tools.push(tool);
338
353
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp-openapi",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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,7 +35,7 @@
35
35
  "dist"
36
36
  ],
37
37
  "dependencies": {
38
- "@ttoss/http-server-mcp": "^0.22.0"
38
+ "@ttoss/http-server-mcp": "^0.23.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "jest": "^30.4.2",