@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 +21 -0
- package/README.md +143 -0
- package/dist/index.cjs +456 -0
- package/dist/index.d.cts +335 -0
- package/dist/index.d.mts +335 -0
- package/dist/index.mjs +434 -0
- package/package.json +55 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
+
import { registerToolFromSchema } from "@ttoss/http-server-mcp";
|
|
3
|
+
|
|
4
|
+
//#region src/schema.ts
|
|
5
|
+
var getAlternativeSchemas = schema => {
|
|
6
|
+
if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0) return schema.oneOf;
|
|
7
|
+
if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) return schema.anyOf;
|
|
8
|
+
};
|
|
9
|
+
var mergeResolvedSchemas = resolvedAlternatives => {
|
|
10
|
+
const mergedProperties = Object.assign({}, ...resolvedAlternatives.map(candidate => {
|
|
11
|
+
return candidate.properties ?? {};
|
|
12
|
+
}));
|
|
13
|
+
const requiredIntersection = resolvedAlternatives.reduce((current, candidate) => {
|
|
14
|
+
const required = candidate.required ?? [];
|
|
15
|
+
if (current === void 0) return [...required];
|
|
16
|
+
return current.filter(field => {
|
|
17
|
+
return required.includes(field);
|
|
18
|
+
});
|
|
19
|
+
}, void 0);
|
|
20
|
+
return {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: Object.keys(mergedProperties).length > 0 ? mergedProperties : void 0,
|
|
23
|
+
required: requiredIntersection && requiredIntersection.length > 0 ? requiredIntersection : void 0
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
var dereferenceValue = args => {
|
|
27
|
+
const {
|
|
28
|
+
value,
|
|
29
|
+
spec,
|
|
30
|
+
seenRefs
|
|
31
|
+
} = args;
|
|
32
|
+
if (Array.isArray(value)) return value.map(item => {
|
|
33
|
+
return dereferenceValue({
|
|
34
|
+
value: item,
|
|
35
|
+
spec,
|
|
36
|
+
seenRefs
|
|
37
|
+
});
|
|
38
|
+
});
|
|
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
|
+
return dereferenceValue({
|
|
46
|
+
value: resolved,
|
|
47
|
+
spec,
|
|
48
|
+
seenRefs: new Set(seenRefs).add(refName)
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const result = {};
|
|
52
|
+
for (const [key, entryValue] of Object.entries(obj)) result[key] = dereferenceValue({
|
|
53
|
+
value: entryValue,
|
|
54
|
+
spec,
|
|
55
|
+
seenRefs
|
|
56
|
+
});
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Recursively inlines every `$ref` in a schema (including refs nested inside
|
|
63
|
+
* `properties`, `items`, `oneOf`, `anyOf`, etc.), producing a self-contained
|
|
64
|
+
* schema safe to hand to an MCP client or LLM provider as a tool definition —
|
|
65
|
+
* provider tool schemas have no `components` section to resolve refs against.
|
|
66
|
+
*/
|
|
67
|
+
var dereferenceSchema = (schema, spec) => {
|
|
68
|
+
if (!schema) return schema;
|
|
69
|
+
return dereferenceValue({
|
|
70
|
+
value: schema,
|
|
71
|
+
spec,
|
|
72
|
+
seenRefs: /* @__PURE__ */new Set()
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Resolves a schema down to a single object shape: follows a top-level `$ref`
|
|
77
|
+
* and merges `oneOf` / `anyOf` alternatives (union of properties, intersection
|
|
78
|
+
* of `required`) so the caller sees one flat property set.
|
|
79
|
+
*/
|
|
80
|
+
var resolveSchema = (schema, spec) => {
|
|
81
|
+
if (!schema) return {};
|
|
82
|
+
if (typeof schema.$ref === "string") {
|
|
83
|
+
const refName = schema.$ref.replace("#/components/schemas/", "");
|
|
84
|
+
const resolved = spec.components?.schemas?.[refName];
|
|
85
|
+
return resolveSchema(resolved, spec);
|
|
86
|
+
}
|
|
87
|
+
const alternatives = getAlternativeSchemas(schema);
|
|
88
|
+
if (alternatives) return mergeResolvedSchemas(alternatives.map(candidate => {
|
|
89
|
+
return resolveSchema(candidate, spec);
|
|
90
|
+
}));
|
|
91
|
+
return schema;
|
|
92
|
+
};
|
|
93
|
+
/** Follows a parameter `$ref` into `components.parameters`, if present. */
|
|
94
|
+
var resolveParameter = (param, spec) => {
|
|
95
|
+
if (!param) return {};
|
|
96
|
+
if (typeof param.$ref === "string") {
|
|
97
|
+
const refName = param.$ref.replace("#/components/parameters/", "");
|
|
98
|
+
return spec.components?.parameters?.[refName] || {};
|
|
99
|
+
}
|
|
100
|
+
return param;
|
|
101
|
+
};
|
|
102
|
+
/** Builds a function that substitutes path params into the path template. */
|
|
103
|
+
var buildPathFn = (pathTemplate, pathParams) => {
|
|
104
|
+
return args => {
|
|
105
|
+
let result = pathTemplate;
|
|
106
|
+
for (const {
|
|
107
|
+
name,
|
|
108
|
+
camelName
|
|
109
|
+
} of pathParams) {
|
|
110
|
+
const value = args[camelName];
|
|
111
|
+
if (value !== void 0) result = result.replace(`{${name}}`, encodeURIComponent(String(value)));
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Builds a function that serialises query params into a query string
|
|
118
|
+
* (including the leading `?`). Returns `undefined` when the op has no query
|
|
119
|
+
* params. Array values are appended once per element.
|
|
120
|
+
*/
|
|
121
|
+
var buildQueryFn = queryParams => {
|
|
122
|
+
if (queryParams.length === 0) return void 0;
|
|
123
|
+
return args => {
|
|
124
|
+
const search = new URLSearchParams();
|
|
125
|
+
for (const {
|
|
126
|
+
name,
|
|
127
|
+
camelName
|
|
128
|
+
} of queryParams) {
|
|
129
|
+
const value = args[camelName];
|
|
130
|
+
if (value === void 0 || value === null) continue;
|
|
131
|
+
if (Array.isArray(value)) for (const item of value) search.append(name, String(item));else search.append(name, String(value));
|
|
132
|
+
}
|
|
133
|
+
const qs = search.toString();
|
|
134
|
+
return qs ? `?${qs}` : "";
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Builds a function that maps camelCase args back to a snake_case request
|
|
139
|
+
* body, skipping `undefined` args. Returns `undefined` when the op has no body.
|
|
140
|
+
*/
|
|
141
|
+
var buildBodyFn = bodyProps => {
|
|
142
|
+
if (bodyProps.length === 0) return void 0;
|
|
143
|
+
return args => {
|
|
144
|
+
const body = {};
|
|
145
|
+
for (const {
|
|
146
|
+
snakeName,
|
|
147
|
+
camelName
|
|
148
|
+
} of bodyProps) if (args[camelName] !== void 0) body[snakeName] = args[camelName];
|
|
149
|
+
return body;
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/types.ts
|
|
155
|
+
var DEFAULT_EXCLUDE_EXTENSION = "x-mcp-exclude";
|
|
156
|
+
var DEFAULT_SERVER_MANAGED_EXTENSION = "x-mcp-server-managed";
|
|
157
|
+
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/toolDefinitions.ts
|
|
160
|
+
/**
|
|
161
|
+
* Folds `_` and `-` separators into camelCase. OpenAPI operation and parameter
|
|
162
|
+
* names may be snake_case (`agent_id`) or kebab-case (`list-tools`), and MCP
|
|
163
|
+
* tool inputs are camelCase by convention, so both are folded here.
|
|
164
|
+
*/
|
|
165
|
+
var snakeToCamel = str => {
|
|
166
|
+
return str.replace(/[_-]([a-z])/g, (_, letter) => {
|
|
167
|
+
return letter.toUpperCase();
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
/** Converts a camelCase `operationId` to a kebab-case tool name. */
|
|
171
|
+
var operationIdToToolName = operationId => {
|
|
172
|
+
return operationId.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
173
|
+
};
|
|
174
|
+
var getJsonSchemaType = schemaType => {
|
|
175
|
+
if (schemaType === "integer" || schemaType === "number") return "number";
|
|
176
|
+
if (schemaType === "boolean") return "boolean";
|
|
177
|
+
if (schemaType === "array") return "array";
|
|
178
|
+
if (schemaType === "object") return "object";
|
|
179
|
+
return "string";
|
|
180
|
+
};
|
|
181
|
+
var sanitizeDescription = description => {
|
|
182
|
+
return (description || "").replace(/'/g, "\\'").replace(/\n/g, " ").trim();
|
|
183
|
+
};
|
|
184
|
+
var buildInputSchema = (pathParams, queryParams, bodyProps) => {
|
|
185
|
+
const allParams = [...pathParams, ...queryParams, ...bodyProps];
|
|
186
|
+
if (allParams.length === 0) return {
|
|
187
|
+
type: "object"
|
|
188
|
+
};
|
|
189
|
+
const requiredFields = [...pathParams.map(p => {
|
|
190
|
+
return p.camelName;
|
|
191
|
+
}), ...queryParams.filter(p => {
|
|
192
|
+
return p.required;
|
|
193
|
+
}).map(p => {
|
|
194
|
+
return p.camelName;
|
|
195
|
+
}), ...bodyProps.filter(p => {
|
|
196
|
+
return p.required;
|
|
197
|
+
}).map(p => {
|
|
198
|
+
return p.camelName;
|
|
199
|
+
})];
|
|
200
|
+
const properties = {};
|
|
201
|
+
for (const param of allParams) if ("type" in param) {
|
|
202
|
+
const jsonType = getJsonSchemaType(param.type);
|
|
203
|
+
const description = sanitizeDescription(param.description);
|
|
204
|
+
if (param.type === "array") {
|
|
205
|
+
const itemsSchema = "items" in param && param.items ? param.items : {
|
|
206
|
+
type: "string"
|
|
207
|
+
};
|
|
208
|
+
properties[param.camelName] = {
|
|
209
|
+
type: "array",
|
|
210
|
+
items: itemsSchema,
|
|
211
|
+
description
|
|
212
|
+
};
|
|
213
|
+
} else properties[param.camelName] = {
|
|
214
|
+
type: jsonType,
|
|
215
|
+
description
|
|
216
|
+
};
|
|
217
|
+
} else properties[param.camelName] = {
|
|
218
|
+
type: "string",
|
|
219
|
+
description: ""
|
|
220
|
+
};
|
|
221
|
+
return {
|
|
222
|
+
type: "object",
|
|
223
|
+
properties,
|
|
224
|
+
required: requiredFields.length > 0 ? requiredFields : void 0
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
var extractPathParams = args => {
|
|
228
|
+
return (args.parameters || []).map(p => {
|
|
229
|
+
return resolveParameter(p, args.spec);
|
|
230
|
+
}).filter(p => {
|
|
231
|
+
return p.in === "path";
|
|
232
|
+
}).map(p => {
|
|
233
|
+
return {
|
|
234
|
+
name: p.name || "",
|
|
235
|
+
camelName: snakeToCamel(p.name || "")
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
var extractQueryParams = args => {
|
|
240
|
+
return (args.parameters || []).map(p => {
|
|
241
|
+
return resolveParameter(p, args.spec);
|
|
242
|
+
}).filter(p => {
|
|
243
|
+
return p.in === "query";
|
|
244
|
+
}).map(p => {
|
|
245
|
+
return {
|
|
246
|
+
name: p.name || "",
|
|
247
|
+
camelName: snakeToCamel(p.name || ""),
|
|
248
|
+
description: p.description || "",
|
|
249
|
+
required: p.required || false,
|
|
250
|
+
type: p.schema?.type || "string"
|
|
251
|
+
};
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
var resolveBodySchema = args => {
|
|
255
|
+
const rawBodySchema = args.requestBody?.content?.["application/json"]?.schema;
|
|
256
|
+
return resolveSchema(dereferenceSchema(rawBodySchema, args.spec), args.spec);
|
|
257
|
+
};
|
|
258
|
+
/**
|
|
259
|
+
* snake_case names of every top-level property an operation's request schema
|
|
260
|
+
* declares, including server-managed ones.
|
|
261
|
+
*/
|
|
262
|
+
var extractAcceptedBodyFields = args => {
|
|
263
|
+
const bodySchema = resolveBodySchema(args);
|
|
264
|
+
return Object.keys(bodySchema?.properties ?? {});
|
|
265
|
+
};
|
|
266
|
+
var extractBodyProps = args => {
|
|
267
|
+
const bodySchema = resolveBodySchema(args);
|
|
268
|
+
if (!bodySchema?.properties) return [];
|
|
269
|
+
return Object.entries(bodySchema.properties).filter(([, value]) => {
|
|
270
|
+
return !value[args.serverManagedExtension];
|
|
271
|
+
}).map(([key, value]) => {
|
|
272
|
+
const val = value;
|
|
273
|
+
return {
|
|
274
|
+
snakeName: key,
|
|
275
|
+
camelName: snakeToCamel(key),
|
|
276
|
+
description: typeof val.description === "string" ? val.description : "",
|
|
277
|
+
required: (bodySchema.required || []).includes(key),
|
|
278
|
+
type: typeof val.type === "string" ? val.type : "string",
|
|
279
|
+
items: val.items
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
/** Collects every `x-` prefixed extension declared on the operation. */
|
|
284
|
+
var extractExtensions = operation => {
|
|
285
|
+
const extensions = {};
|
|
286
|
+
for (const [key, value] of Object.entries(operation)) if (key.startsWith("x-")) extensions[key] = value;
|
|
287
|
+
return extensions;
|
|
288
|
+
};
|
|
289
|
+
var processOperation = args => {
|
|
290
|
+
const httpMethod = args.method.toUpperCase();
|
|
291
|
+
if (!["GET", "POST", "PUT", "PATCH", "DELETE"].includes(httpMethod)) return null;
|
|
292
|
+
if (!args.operation.operationId) return null;
|
|
293
|
+
if (args.operation[args.options.excludeExtension]) return null;
|
|
294
|
+
const toolName = operationIdToToolName(args.operation.operationId);
|
|
295
|
+
const pathParams = extractPathParams({
|
|
296
|
+
parameters: args.operation.parameters || [],
|
|
297
|
+
spec: args.spec
|
|
298
|
+
});
|
|
299
|
+
const queryParams = extractQueryParams({
|
|
300
|
+
parameters: args.operation.parameters || [],
|
|
301
|
+
spec: args.spec
|
|
302
|
+
});
|
|
303
|
+
const bodyProps = extractBodyProps({
|
|
304
|
+
requestBody: args.operation.requestBody,
|
|
305
|
+
spec: args.spec,
|
|
306
|
+
serverManagedExtension: args.options.serverManagedExtension
|
|
307
|
+
});
|
|
308
|
+
const inputSchema = buildInputSchema(pathParams, queryParams, bodyProps);
|
|
309
|
+
const acceptedBodyFields = extractAcceptedBodyFields({
|
|
310
|
+
requestBody: args.operation.requestBody,
|
|
311
|
+
spec: args.spec
|
|
312
|
+
});
|
|
313
|
+
return {
|
|
314
|
+
name: toolName,
|
|
315
|
+
description: sanitizeDescription(args.operation.description),
|
|
316
|
+
inputSchema,
|
|
317
|
+
method: httpMethod,
|
|
318
|
+
pathTemplate: args.pathTemplate,
|
|
319
|
+
operationId: args.operation.operationId,
|
|
320
|
+
path: buildPathFn(args.pathTemplate, pathParams),
|
|
321
|
+
query: buildQueryFn(queryParams),
|
|
322
|
+
body: buildBodyFn(bodyProps),
|
|
323
|
+
acceptedBodyFields,
|
|
324
|
+
extensions: extractExtensions(args.operation)
|
|
325
|
+
};
|
|
326
|
+
};
|
|
327
|
+
var processPath = args => {
|
|
328
|
+
const tools = [];
|
|
329
|
+
for (const [method, operation] of Object.entries(args.pathItem)) {
|
|
330
|
+
const tool = processOperation({
|
|
331
|
+
pathTemplate: args.pathTemplate,
|
|
332
|
+
method,
|
|
333
|
+
operation,
|
|
334
|
+
spec: args.spec,
|
|
335
|
+
options: args.options
|
|
336
|
+
});
|
|
337
|
+
if (tool) tools.push(tool);
|
|
338
|
+
}
|
|
339
|
+
return tools;
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
342
|
+
* Translates one or more OpenAPI documents into REST-backed MCP tool
|
|
343
|
+
* definitions. Each translatable operation (has an `operationId`, a supported
|
|
344
|
+
* HTTP method, and is not excluded) becomes one {@link ToolDefinition}.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```typescript
|
|
348
|
+
* import { openApiToToolDefinitions } from '@ttoss/http-server-mcp-openapi';
|
|
349
|
+
*
|
|
350
|
+
* const tools = openApiToToolDefinitions({ spec: myOpenApiDocument });
|
|
351
|
+
* ```
|
|
352
|
+
*/
|
|
353
|
+
var openApiToToolDefinitions = args => {
|
|
354
|
+
const options = {
|
|
355
|
+
excludeExtension: args.options?.excludeExtension ?? "x-mcp-exclude",
|
|
356
|
+
serverManagedExtension: args.options?.serverManagedExtension ?? "x-mcp-server-managed"
|
|
357
|
+
};
|
|
358
|
+
const specs = Array.isArray(args.spec) ? args.spec : [args.spec];
|
|
359
|
+
const tools = [];
|
|
360
|
+
for (const spec of specs) {
|
|
361
|
+
const paths = spec.paths || {};
|
|
362
|
+
for (const [pathTemplate, pathItem] of Object.entries(paths)) tools.push(...processPath({
|
|
363
|
+
pathTemplate,
|
|
364
|
+
pathItem,
|
|
365
|
+
spec,
|
|
366
|
+
options
|
|
367
|
+
}));
|
|
368
|
+
}
|
|
369
|
+
return tools;
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/registerOpenApiTools.ts
|
|
374
|
+
var defaultToText = data => {
|
|
375
|
+
return typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* Derives MCP tools from OpenAPI document(s) and registers each on the given
|
|
379
|
+
* MCP server. Every tool's handler resolves the incoming camelCase args into a
|
|
380
|
+
* concrete HTTP request and delegates execution to `callApi`.
|
|
381
|
+
*
|
|
382
|
+
* @returns The list of {@link ToolDefinition} that were registered.
|
|
383
|
+
*
|
|
384
|
+
* @example
|
|
385
|
+
* ```typescript
|
|
386
|
+
* import { McpServer } from '@ttoss/http-server-mcp';
|
|
387
|
+
* import { registerOpenApiTools } from '@ttoss/http-server-mcp-openapi';
|
|
388
|
+
*
|
|
389
|
+
* const server = new McpServer({ name: 'my-api', version: '1.0.0' });
|
|
390
|
+
*
|
|
391
|
+
* registerOpenApiTools({
|
|
392
|
+
* server,
|
|
393
|
+
* spec: myOpenApiDocument,
|
|
394
|
+
* callApi: async ({ method, url, body }) => {
|
|
395
|
+
* const res = await fetch(`https://api.example.com${url}`, {
|
|
396
|
+
* method,
|
|
397
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
398
|
+
* body: body ? JSON.stringify(body) : undefined,
|
|
399
|
+
* });
|
|
400
|
+
* return res.json();
|
|
401
|
+
* },
|
|
402
|
+
* });
|
|
403
|
+
* ```
|
|
404
|
+
*/
|
|
405
|
+
var registerOpenApiTools = args => {
|
|
406
|
+
const toText = args.toText ?? defaultToText;
|
|
407
|
+
const tools = openApiToToolDefinitions({
|
|
408
|
+
spec: args.spec,
|
|
409
|
+
options: args.options
|
|
410
|
+
});
|
|
411
|
+
for (const tool of tools) registerToolFromSchema(args.server, {
|
|
412
|
+
name: tool.name,
|
|
413
|
+
description: tool.description,
|
|
414
|
+
inputSchema: tool.inputSchema,
|
|
415
|
+
handler: async handlerArgs => {
|
|
416
|
+
const url = tool.path(handlerArgs) + (tool.query ? tool.query(handlerArgs) : "");
|
|
417
|
+
return {
|
|
418
|
+
content: [{
|
|
419
|
+
type: "text",
|
|
420
|
+
text: toText(await args.callApi({
|
|
421
|
+
method: tool.method,
|
|
422
|
+
url,
|
|
423
|
+
body: tool.body ? tool.body(handlerArgs) : void 0,
|
|
424
|
+
tool
|
|
425
|
+
}))
|
|
426
|
+
}]
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
return tools;
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
//#endregion
|
|
434
|
+
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 };
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ttoss/http-server-mcp-openapi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Generate Model Context Protocol (MCP) tools from an OpenAPI specification for @ttoss/http-server-mcp",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"koa",
|
|
8
|
+
"llm",
|
|
9
|
+
"mcp",
|
|
10
|
+
"model-context-protocol",
|
|
11
|
+
"openapi",
|
|
12
|
+
"rest",
|
|
13
|
+
"server"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/ttoss/ttoss.git",
|
|
18
|
+
"directory": "packages/http-server-mcp-openapi"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "ttoss",
|
|
22
|
+
"contributors": [
|
|
23
|
+
"Pedro Arantes <pedro@arantespp.com> (https://arantespp.com)"
|
|
24
|
+
],
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"import": "./dist/index.mjs",
|
|
30
|
+
"require": "./dist/index.cjs",
|
|
31
|
+
"types": "./dist/index.d.mts"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist"
|
|
36
|
+
],
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@ttoss/http-server-mcp": "^0.22.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"jest": "^30.4.2",
|
|
42
|
+
"supertest": "^7.2.2",
|
|
43
|
+
"tsdown": "^0.22.2",
|
|
44
|
+
"@ttoss/config": "^1.37.17",
|
|
45
|
+
"@ttoss/http-server": "^0.7.1"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"provenance": true
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsdown",
|
|
53
|
+
"test": "jest --projects tests/unit"
|
|
54
|
+
}
|
|
55
|
+
}
|