@ttoss/http-server-mcp-openapi 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024, Terezinha Tech Operations (ttoss)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # @ttoss/http-server-mcp-openapi
2
+
3
+ Generate [Model Context Protocol (MCP)](https://modelcontextprotocol.io) tools
4
+ from an [OpenAPI](https://www.openapis.org/) specification and register them on
5
+ a [@ttoss/http-server-mcp](https://ttoss.dev/docs/modules/packages/http-server-mcp)
6
+ server.
7
+
8
+ Point it at your existing OpenAPI document and every operation becomes an MCP
9
+ tool whose handler resolves the incoming arguments into an HTTP request against
10
+ your REST API. The OpenAPI spec stays the single source of truth for both your
11
+ REST surface and your MCP tool surface.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pnpm add @ttoss/http-server-mcp-openapi @ttoss/http-server-mcp
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```typescript
22
+ import { App, bodyParser } from '@ttoss/http-server';
23
+ import { createMcpRouter, McpServer } from '@ttoss/http-server-mcp';
24
+ import { registerOpenApiTools } from '@ttoss/http-server-mcp-openapi';
25
+
26
+ import openApiDocument from './openapi.json' with { type: 'json' };
27
+
28
+ const server = new McpServer({ name: 'my-api', version: '1.0.0' });
29
+
30
+ registerOpenApiTools({
31
+ server,
32
+ spec: openApiDocument,
33
+ // You own how the request is executed — base URL, auth, fetch impl.
34
+ callApi: async ({ method, url, body }) => {
35
+ const res = await fetch(`https://api.example.com${url}`, {
36
+ method,
37
+ headers: { 'Content-Type': 'application/json' },
38
+ body: body ? JSON.stringify(body) : undefined,
39
+ });
40
+ return res.json();
41
+ },
42
+ });
43
+
44
+ const app = new App();
45
+ app.use(bodyParser());
46
+ app.use(createMcpRouter(server).routes());
47
+ app.listen(3000);
48
+ ```
49
+
50
+ ## How Operations Map to Tools
51
+
52
+ Each OpenAPI operation with an `operationId` and a supported HTTP method
53
+ (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) becomes one tool:
54
+
55
+ | OpenAPI | MCP tool |
56
+ | ------------------------- | -------------------------------------------- |
57
+ | `operationId: listAgents` | tool name `list-agents` (kebab-case) |
58
+ | path/query/body params | a single camelCase `inputSchema` object |
59
+ | `$ref`, `oneOf`, `anyOf` | dereferenced and merged into a flat schema |
60
+ | snake_case body fields | camelCase tool inputs, mapped back on call |
61
+ | operation `description` | tool description (quotes/newlines sanitised) |
62
+
63
+ Path params are always required strings. Query and body params carry their
64
+ declared type and `required` flag. Array params keep their `items` schema.
65
+
66
+ Tool arguments are **camelCase** (`agentId`, `projectId`); the generated
67
+ request path, query string, and body use the original **snake_case** names.
68
+
69
+ ## `registerOpenApiTools`
70
+
71
+ | Field | Description |
72
+ | ---------- | ------------------------------------------------------------------------------------------------------------- |
73
+ | `server` | The `McpServer` to register tools on. |
74
+ | `spec` | One OpenAPI document, or an array of them (tools are flattened). |
75
+ | `callApi` | Runs the resolved `{ method, url, body, tool }` request and returns the raw data. |
76
+ | `toText?` | Serialises the raw data into the tool's text payload. Defaults to pretty JSON; strings pass through verbatim. |
77
+ | `options?` | See [Options](#options). |
78
+
79
+ Returns the list of `ToolDefinition`s that were registered.
80
+
81
+ ## `openApiToToolDefinitions`
82
+
83
+ Use the lower-level function when you want the tool definitions without
84
+ registering them — to inspect, filter, or wire handlers yourself:
85
+
86
+ ```typescript
87
+ import { openApiToToolDefinitions } from '@ttoss/http-server-mcp-openapi';
88
+
89
+ const tools = openApiToToolDefinitions({ spec: openApiDocument });
90
+
91
+ for (const tool of tools) {
92
+ // tool.name, tool.method, tool.inputSchema, tool.extensions, ...
93
+ const url = tool.path(args) + (tool.query ? tool.query(args) : '');
94
+ const body = tool.body?.(args);
95
+ }
96
+ ```
97
+
98
+ Each `ToolDefinition` exposes `name`, `description`, `inputSchema`, `method`,
99
+ `pathTemplate`, `operationId`, the `path`/`query`/`body` builders,
100
+ `acceptedBodyFields`, and `extensions`.
101
+
102
+ ## Options
103
+
104
+ ```typescript
105
+ registerOpenApiTools({
106
+ server,
107
+ spec,
108
+ callApi,
109
+ options: {
110
+ excludeExtension: 'x-mcp-exclude', // operations flagged truthy are skipped
111
+ serverManagedExtension: 'x-mcp-server-managed', // body fields hidden from the input schema
112
+ },
113
+ });
114
+ ```
115
+
116
+ - **`excludeExtension`** (default `x-mcp-exclude`) — an operation with this
117
+ extension set truthy is omitted from the tool surface.
118
+ - **`serverManagedExtension`** (default `x-mcp-server-managed`) — a request-body
119
+ property with this extension set truthy is hidden from the tool's
120
+ `inputSchema` (the caller can't set it) but still appears in
121
+ `acceptedBodyFields`.
122
+
123
+ ### Reading custom extensions
124
+
125
+ Every `x-` prefixed extension on an operation is forwarded verbatim on
126
+ `tool.extensions`, so you can attach and read your own metadata without this
127
+ package needing to know about it:
128
+
129
+ ```typescript
130
+ const tools = openApiToToolDefinitions({ spec: openApiDocument });
131
+ const iamAction = tools[0].extensions['x-iam-action'];
132
+ ```
133
+
134
+ ## Related Packages
135
+
136
+ - [@ttoss/http-server-mcp](https://ttoss.dev/docs/modules/packages/http-server-mcp) - MCP server integration for @ttoss/http-server
137
+ - [@ttoss/http-server](https://ttoss.dev/docs/modules/packages/http-server) - HTTP server foundation
138
+ - [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/sdk) - MCP SDK
139
+
140
+ ## Resources
141
+
142
+ - [MCP Documentation](https://modelcontextprotocol.io)
143
+ - [OpenAPI Specification](https://spec.openapis.org/oas/latest.html)
package/dist/index.cjs ADDED
@@ -0,0 +1,456 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ Object.defineProperty(exports, Symbol.toStringTag, {
3
+ value: 'Module'
4
+ });
5
+ let _ttoss_http_server_mcp = require("@ttoss/http-server-mcp");
6
+
7
+ //#region src/schema.ts
8
+ var getAlternativeSchemas = schema => {
9
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) return schema.oneOf;
10
+ if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) return schema.anyOf;
11
+ };
12
+ var mergeResolvedSchemas = resolvedAlternatives => {
13
+ const mergedProperties = Object.assign({}, ...resolvedAlternatives.map(candidate => {
14
+ return candidate.properties ?? {};
15
+ }));
16
+ const requiredIntersection = resolvedAlternatives.reduce((current, candidate) => {
17
+ const required = candidate.required ?? [];
18
+ if (current === void 0) return [...required];
19
+ return current.filter(field => {
20
+ return required.includes(field);
21
+ });
22
+ }, void 0);
23
+ return {
24
+ type: "object",
25
+ properties: Object.keys(mergedProperties).length > 0 ? mergedProperties : void 0,
26
+ required: requiredIntersection && requiredIntersection.length > 0 ? requiredIntersection : void 0
27
+ };
28
+ };
29
+ var dereferenceValue = args => {
30
+ const {
31
+ value,
32
+ spec,
33
+ seenRefs
34
+ } = args;
35
+ if (Array.isArray(value)) return value.map(item => {
36
+ return dereferenceValue({
37
+ value: item,
38
+ spec,
39
+ seenRefs
40
+ });
41
+ });
42
+ if (value && typeof value === "object") {
43
+ const obj = value;
44
+ if (typeof obj.$ref === "string") {
45
+ const refName = obj.$ref.replace("#/components/schemas/", "");
46
+ if (seenRefs.has(refName)) return {};
47
+ const resolved = spec.components?.schemas?.[refName];
48
+ return dereferenceValue({
49
+ value: resolved,
50
+ spec,
51
+ seenRefs: new Set(seenRefs).add(refName)
52
+ });
53
+ }
54
+ const result = {};
55
+ for (const [key, entryValue] of Object.entries(obj)) result[key] = dereferenceValue({
56
+ value: entryValue,
57
+ spec,
58
+ seenRefs
59
+ });
60
+ return result;
61
+ }
62
+ return value;
63
+ };
64
+ /**
65
+ * Recursively inlines every `$ref` in a schema (including refs nested inside
66
+ * `properties`, `items`, `oneOf`, `anyOf`, etc.), producing a self-contained
67
+ * schema safe to hand to an MCP client or LLM provider as a tool definition —
68
+ * provider tool schemas have no `components` section to resolve refs against.
69
+ */
70
+ var dereferenceSchema = (schema, spec) => {
71
+ if (!schema) return schema;
72
+ return dereferenceValue({
73
+ value: schema,
74
+ spec,
75
+ seenRefs: /* @__PURE__ */new Set()
76
+ });
77
+ };
78
+ /**
79
+ * Resolves a schema down to a single object shape: follows a top-level `$ref`
80
+ * and merges `oneOf` / `anyOf` alternatives (union of properties, intersection
81
+ * of `required`) so the caller sees one flat property set.
82
+ */
83
+ var resolveSchema = (schema, spec) => {
84
+ if (!schema) return {};
85
+ if (typeof schema.$ref === "string") {
86
+ const refName = schema.$ref.replace("#/components/schemas/", "");
87
+ const resolved = spec.components?.schemas?.[refName];
88
+ return resolveSchema(resolved, spec);
89
+ }
90
+ const alternatives = getAlternativeSchemas(schema);
91
+ if (alternatives) return mergeResolvedSchemas(alternatives.map(candidate => {
92
+ return resolveSchema(candidate, spec);
93
+ }));
94
+ return schema;
95
+ };
96
+ /** Follows a parameter `$ref` into `components.parameters`, if present. */
97
+ var resolveParameter = (param, spec) => {
98
+ if (!param) return {};
99
+ if (typeof param.$ref === "string") {
100
+ const refName = param.$ref.replace("#/components/parameters/", "");
101
+ return spec.components?.parameters?.[refName] || {};
102
+ }
103
+ return param;
104
+ };
105
+ /** Builds a function that substitutes path params into the path template. */
106
+ var buildPathFn = (pathTemplate, pathParams) => {
107
+ return args => {
108
+ let result = pathTemplate;
109
+ for (const {
110
+ name,
111
+ camelName
112
+ } of pathParams) {
113
+ const value = args[camelName];
114
+ if (value !== void 0) result = result.replace(`{${name}}`, encodeURIComponent(String(value)));
115
+ }
116
+ return result;
117
+ };
118
+ };
119
+ /**
120
+ * Builds a function that serialises query params into a query string
121
+ * (including the leading `?`). Returns `undefined` when the op has no query
122
+ * params. Array values are appended once per element.
123
+ */
124
+ var buildQueryFn = queryParams => {
125
+ if (queryParams.length === 0) return void 0;
126
+ return args => {
127
+ const search = new URLSearchParams();
128
+ for (const {
129
+ name,
130
+ camelName
131
+ } of queryParams) {
132
+ const value = args[camelName];
133
+ if (value === void 0 || value === null) continue;
134
+ if (Array.isArray(value)) for (const item of value) search.append(name, String(item));else search.append(name, String(value));
135
+ }
136
+ const qs = search.toString();
137
+ return qs ? `?${qs}` : "";
138
+ };
139
+ };
140
+ /**
141
+ * Builds a function that maps camelCase args back to a snake_case request
142
+ * body, skipping `undefined` args. Returns `undefined` when the op has no body.
143
+ */
144
+ var buildBodyFn = bodyProps => {
145
+ if (bodyProps.length === 0) return void 0;
146
+ return args => {
147
+ const body = {};
148
+ for (const {
149
+ snakeName,
150
+ camelName
151
+ } of bodyProps) if (args[camelName] !== void 0) body[snakeName] = args[camelName];
152
+ return body;
153
+ };
154
+ };
155
+
156
+ //#endregion
157
+ //#region src/types.ts
158
+ var DEFAULT_EXCLUDE_EXTENSION = "x-mcp-exclude";
159
+ var DEFAULT_SERVER_MANAGED_EXTENSION = "x-mcp-server-managed";
160
+
161
+ //#endregion
162
+ //#region src/toolDefinitions.ts
163
+ /**
164
+ * Folds `_` and `-` separators into camelCase. OpenAPI operation and parameter
165
+ * names may be snake_case (`agent_id`) or kebab-case (`list-tools`), and MCP
166
+ * tool inputs are camelCase by convention, so both are folded here.
167
+ */
168
+ var snakeToCamel = str => {
169
+ return str.replace(/[_-]([a-z])/g, (_, letter) => {
170
+ return letter.toUpperCase();
171
+ });
172
+ };
173
+ /** Converts a camelCase `operationId` to a kebab-case tool name. */
174
+ var operationIdToToolName = operationId => {
175
+ return operationId.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
176
+ };
177
+ var getJsonSchemaType = schemaType => {
178
+ if (schemaType === "integer" || schemaType === "number") return "number";
179
+ if (schemaType === "boolean") return "boolean";
180
+ if (schemaType === "array") return "array";
181
+ if (schemaType === "object") return "object";
182
+ return "string";
183
+ };
184
+ var sanitizeDescription = description => {
185
+ return (description || "").replace(/'/g, "\\'").replace(/\n/g, " ").trim();
186
+ };
187
+ var buildInputSchema = (pathParams, queryParams, bodyProps) => {
188
+ const allParams = [...pathParams, ...queryParams, ...bodyProps];
189
+ if (allParams.length === 0) return {
190
+ type: "object"
191
+ };
192
+ const requiredFields = [...pathParams.map(p => {
193
+ return p.camelName;
194
+ }), ...queryParams.filter(p => {
195
+ return p.required;
196
+ }).map(p => {
197
+ return p.camelName;
198
+ }), ...bodyProps.filter(p => {
199
+ return p.required;
200
+ }).map(p => {
201
+ return p.camelName;
202
+ })];
203
+ const properties = {};
204
+ for (const param of allParams) if ("type" in param) {
205
+ const jsonType = getJsonSchemaType(param.type);
206
+ const description = sanitizeDescription(param.description);
207
+ if (param.type === "array") {
208
+ const itemsSchema = "items" in param && param.items ? param.items : {
209
+ type: "string"
210
+ };
211
+ properties[param.camelName] = {
212
+ type: "array",
213
+ items: itemsSchema,
214
+ description
215
+ };
216
+ } else properties[param.camelName] = {
217
+ type: jsonType,
218
+ description
219
+ };
220
+ } else properties[param.camelName] = {
221
+ type: "string",
222
+ description: ""
223
+ };
224
+ return {
225
+ type: "object",
226
+ properties,
227
+ required: requiredFields.length > 0 ? requiredFields : void 0
228
+ };
229
+ };
230
+ var extractPathParams = args => {
231
+ return (args.parameters || []).map(p => {
232
+ return resolveParameter(p, args.spec);
233
+ }).filter(p => {
234
+ return p.in === "path";
235
+ }).map(p => {
236
+ return {
237
+ name: p.name || "",
238
+ camelName: snakeToCamel(p.name || "")
239
+ };
240
+ });
241
+ };
242
+ var extractQueryParams = args => {
243
+ return (args.parameters || []).map(p => {
244
+ return resolveParameter(p, args.spec);
245
+ }).filter(p => {
246
+ return p.in === "query";
247
+ }).map(p => {
248
+ return {
249
+ name: p.name || "",
250
+ camelName: snakeToCamel(p.name || ""),
251
+ description: p.description || "",
252
+ required: p.required || false,
253
+ type: p.schema?.type || "string"
254
+ };
255
+ });
256
+ };
257
+ var resolveBodySchema = args => {
258
+ const rawBodySchema = args.requestBody?.content?.["application/json"]?.schema;
259
+ return resolveSchema(dereferenceSchema(rawBodySchema, args.spec), args.spec);
260
+ };
261
+ /**
262
+ * snake_case names of every top-level property an operation's request schema
263
+ * declares, including server-managed ones.
264
+ */
265
+ var extractAcceptedBodyFields = args => {
266
+ const bodySchema = resolveBodySchema(args);
267
+ return Object.keys(bodySchema?.properties ?? {});
268
+ };
269
+ var extractBodyProps = args => {
270
+ const bodySchema = resolveBodySchema(args);
271
+ if (!bodySchema?.properties) return [];
272
+ return Object.entries(bodySchema.properties).filter(([, value]) => {
273
+ return !value[args.serverManagedExtension];
274
+ }).map(([key, value]) => {
275
+ const val = value;
276
+ return {
277
+ snakeName: key,
278
+ camelName: snakeToCamel(key),
279
+ description: typeof val.description === "string" ? val.description : "",
280
+ required: (bodySchema.required || []).includes(key),
281
+ type: typeof val.type === "string" ? val.type : "string",
282
+ items: val.items
283
+ };
284
+ });
285
+ };
286
+ /** Collects every `x-` prefixed extension declared on the operation. */
287
+ var extractExtensions = operation => {
288
+ const extensions = {};
289
+ for (const [key, value] of Object.entries(operation)) if (key.startsWith("x-")) extensions[key] = value;
290
+ return extensions;
291
+ };
292
+ var processOperation = args => {
293
+ const httpMethod = args.method.toUpperCase();
294
+ if (!["GET", "POST", "PUT", "PATCH", "DELETE"].includes(httpMethod)) return null;
295
+ if (!args.operation.operationId) return null;
296
+ if (args.operation[args.options.excludeExtension]) return null;
297
+ const toolName = operationIdToToolName(args.operation.operationId);
298
+ const pathParams = extractPathParams({
299
+ parameters: args.operation.parameters || [],
300
+ spec: args.spec
301
+ });
302
+ const queryParams = extractQueryParams({
303
+ parameters: args.operation.parameters || [],
304
+ spec: args.spec
305
+ });
306
+ const bodyProps = extractBodyProps({
307
+ requestBody: args.operation.requestBody,
308
+ spec: args.spec,
309
+ serverManagedExtension: args.options.serverManagedExtension
310
+ });
311
+ const inputSchema = buildInputSchema(pathParams, queryParams, bodyProps);
312
+ const acceptedBodyFields = extractAcceptedBodyFields({
313
+ requestBody: args.operation.requestBody,
314
+ spec: args.spec
315
+ });
316
+ return {
317
+ name: toolName,
318
+ description: sanitizeDescription(args.operation.description),
319
+ inputSchema,
320
+ method: httpMethod,
321
+ pathTemplate: args.pathTemplate,
322
+ operationId: args.operation.operationId,
323
+ path: buildPathFn(args.pathTemplate, pathParams),
324
+ query: buildQueryFn(queryParams),
325
+ body: buildBodyFn(bodyProps),
326
+ acceptedBodyFields,
327
+ extensions: extractExtensions(args.operation)
328
+ };
329
+ };
330
+ var processPath = args => {
331
+ const tools = [];
332
+ for (const [method, operation] of Object.entries(args.pathItem)) {
333
+ const tool = processOperation({
334
+ pathTemplate: args.pathTemplate,
335
+ method,
336
+ operation,
337
+ spec: args.spec,
338
+ options: args.options
339
+ });
340
+ if (tool) tools.push(tool);
341
+ }
342
+ return tools;
343
+ };
344
+ /**
345
+ * Translates one or more OpenAPI documents into REST-backed MCP tool
346
+ * definitions. Each translatable operation (has an `operationId`, a supported
347
+ * HTTP method, and is not excluded) becomes one {@link ToolDefinition}.
348
+ *
349
+ * @example
350
+ * ```typescript
351
+ * import { openApiToToolDefinitions } from '@ttoss/http-server-mcp-openapi';
352
+ *
353
+ * const tools = openApiToToolDefinitions({ spec: myOpenApiDocument });
354
+ * ```
355
+ */
356
+ var openApiToToolDefinitions = args => {
357
+ const options = {
358
+ excludeExtension: args.options?.excludeExtension ?? "x-mcp-exclude",
359
+ serverManagedExtension: args.options?.serverManagedExtension ?? "x-mcp-server-managed"
360
+ };
361
+ const specs = Array.isArray(args.spec) ? args.spec : [args.spec];
362
+ const tools = [];
363
+ for (const spec of specs) {
364
+ const paths = spec.paths || {};
365
+ for (const [pathTemplate, pathItem] of Object.entries(paths)) tools.push(...processPath({
366
+ pathTemplate,
367
+ pathItem,
368
+ spec,
369
+ options
370
+ }));
371
+ }
372
+ return tools;
373
+ };
374
+
375
+ //#endregion
376
+ //#region src/registerOpenApiTools.ts
377
+ var defaultToText = data => {
378
+ return typeof data === "string" ? data : JSON.stringify(data, null, 2);
379
+ };
380
+ /**
381
+ * Derives MCP tools from OpenAPI document(s) and registers each on the given
382
+ * MCP server. Every tool's handler resolves the incoming camelCase args into a
383
+ * concrete HTTP request and delegates execution to `callApi`.
384
+ *
385
+ * @returns The list of {@link ToolDefinition} that were registered.
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * import { McpServer } from '@ttoss/http-server-mcp';
390
+ * import { registerOpenApiTools } from '@ttoss/http-server-mcp-openapi';
391
+ *
392
+ * const server = new McpServer({ name: 'my-api', version: '1.0.0' });
393
+ *
394
+ * registerOpenApiTools({
395
+ * server,
396
+ * spec: myOpenApiDocument,
397
+ * callApi: async ({ method, url, body }) => {
398
+ * const res = await fetch(`https://api.example.com${url}`, {
399
+ * method,
400
+ * headers: { 'Content-Type': 'application/json' },
401
+ * body: body ? JSON.stringify(body) : undefined,
402
+ * });
403
+ * return res.json();
404
+ * },
405
+ * });
406
+ * ```
407
+ */
408
+ var registerOpenApiTools = args => {
409
+ const toText = args.toText ?? defaultToText;
410
+ const tools = openApiToToolDefinitions({
411
+ spec: args.spec,
412
+ options: args.options
413
+ });
414
+ for (const tool of tools) (0, _ttoss_http_server_mcp.registerToolFromSchema)(args.server, {
415
+ name: tool.name,
416
+ description: tool.description,
417
+ inputSchema: tool.inputSchema,
418
+ handler: async handlerArgs => {
419
+ const url = tool.path(handlerArgs) + (tool.query ? tool.query(handlerArgs) : "");
420
+ return {
421
+ content: [{
422
+ type: "text",
423
+ text: toText(await args.callApi({
424
+ method: tool.method,
425
+ url,
426
+ body: tool.body ? tool.body(handlerArgs) : void 0,
427
+ tool
428
+ }))
429
+ }]
430
+ };
431
+ }
432
+ });
433
+ return tools;
434
+ };
435
+
436
+ //#endregion
437
+ exports.DEFAULT_EXCLUDE_EXTENSION = DEFAULT_EXCLUDE_EXTENSION;
438
+ exports.DEFAULT_SERVER_MANAGED_EXTENSION = DEFAULT_SERVER_MANAGED_EXTENSION;
439
+ exports.buildBodyFn = buildBodyFn;
440
+ exports.buildInputSchema = buildInputSchema;
441
+ exports.buildPathFn = buildPathFn;
442
+ exports.buildQueryFn = buildQueryFn;
443
+ exports.dereferenceSchema = dereferenceSchema;
444
+ exports.extractAcceptedBodyFields = extractAcceptedBodyFields;
445
+ exports.extractBodyProps = extractBodyProps;
446
+ exports.extractPathParams = extractPathParams;
447
+ exports.extractQueryParams = extractQueryParams;
448
+ exports.getJsonSchemaType = getJsonSchemaType;
449
+ exports.openApiToToolDefinitions = openApiToToolDefinitions;
450
+ exports.operationIdToToolName = operationIdToToolName;
451
+ exports.processOperation = processOperation;
452
+ exports.processPath = processPath;
453
+ exports.registerOpenApiTools = registerOpenApiTools;
454
+ exports.resolveParameter = resolveParameter;
455
+ exports.resolveSchema = resolveSchema;
456
+ exports.snakeToCamel = snakeToCamel;