@abhishekkumar00019/swagger-mcp 1.0.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 +20 -0
- package/README.md +314 -0
- package/dist/core/config.d.ts +21 -0
- package/dist/core/config.js +91 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/types.d.ts +58 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/http/auth.d.ts +8 -0
- package/dist/http/auth.js +31 -0
- package/dist/http/auth.js.map +1 -0
- package/dist/http/request-handler.d.ts +12 -0
- package/dist/http/request-handler.js +167 -0
- package/dist/http/request-handler.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/swagger-parser.d.ts +20 -0
- package/dist/parser/swagger-parser.js +262 -0
- package/dist/parser/swagger-parser.js.map +1 -0
- package/dist/parser/tool-builder.d.ts +29 -0
- package/dist/parser/tool-builder.js +138 -0
- package/dist/parser/tool-builder.js.map +1 -0
- package/dist/server.d.ts +19 -0
- package/dist/server.js +175 -0
- package/dist/server.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { getAuthHeaders } from "./auth.js";
|
|
2
|
+
/**
|
|
3
|
+
* Executes an HTTP request for a tool invocation.
|
|
4
|
+
*
|
|
5
|
+
* Takes the tool mapping (which knows the operation details) and the
|
|
6
|
+
* arguments provided by the LLM, builds the full HTTP request, executes it,
|
|
7
|
+
* and returns the response as a string.
|
|
8
|
+
*/
|
|
9
|
+
export async function executeToolRequest(mapping, args, config, baseUrl) {
|
|
10
|
+
const { operation } = mapping;
|
|
11
|
+
try {
|
|
12
|
+
// 1. Validate required path parameters are present
|
|
13
|
+
const missingPathParams = operation.parameters
|
|
14
|
+
.filter((p) => p.in === "path" && p.required && args[p.name] === undefined)
|
|
15
|
+
.map((p) => p.name);
|
|
16
|
+
if (missingPathParams.length > 0) {
|
|
17
|
+
return {
|
|
18
|
+
content: `Missing required path parameter(s): ${missingPathParams.join(", ")}`,
|
|
19
|
+
isError: true,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// 2. Build the URL with path parameters substituted
|
|
23
|
+
let url = buildUrl(baseUrl, operation.path, args, operation.parameters);
|
|
24
|
+
// 3. Append query parameters
|
|
25
|
+
url = appendQueryParams(url, args, operation.parameters);
|
|
26
|
+
// 4. Build headers
|
|
27
|
+
const headers = {
|
|
28
|
+
Accept: "application/json",
|
|
29
|
+
...config.defaultHeaders,
|
|
30
|
+
...getAuthHeaders(config.auth),
|
|
31
|
+
};
|
|
32
|
+
// Add header parameters from args
|
|
33
|
+
for (const param of operation.parameters) {
|
|
34
|
+
if (param.in === "header" && args[param.name] !== undefined) {
|
|
35
|
+
headers[param.name] = String(args[param.name]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// 5. Build request body (for methods that support it)
|
|
39
|
+
let body;
|
|
40
|
+
if (args.body !== undefined && ["post", "put", "patch", "delete"].includes(operation.method)) {
|
|
41
|
+
headers["Content-Type"] =
|
|
42
|
+
operation.requestBody?.contentType || "application/json";
|
|
43
|
+
body =
|
|
44
|
+
typeof args.body === "string"
|
|
45
|
+
? args.body
|
|
46
|
+
: JSON.stringify(args.body);
|
|
47
|
+
}
|
|
48
|
+
// 6. Execute the request
|
|
49
|
+
console.error(`[swagger-mcp] ${operation.method.toUpperCase()} ${url}`);
|
|
50
|
+
const controller = new AbortController();
|
|
51
|
+
const timeoutId = setTimeout(() => controller.abort(), config.timeout);
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetch(url, {
|
|
54
|
+
method: operation.method.toUpperCase(),
|
|
55
|
+
headers,
|
|
56
|
+
body,
|
|
57
|
+
signal: controller.signal,
|
|
58
|
+
});
|
|
59
|
+
clearTimeout(timeoutId);
|
|
60
|
+
// 7. Process response
|
|
61
|
+
const responseText = await response.text();
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
return {
|
|
64
|
+
content: formatErrorResponse(response.status, response.statusText, responseText),
|
|
65
|
+
isError: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
content: formatSuccessResponse(response.status, responseText),
|
|
70
|
+
isError: false,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
clearTimeout(timeoutId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
// Use standard AbortError detection instead of string matching
|
|
79
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
80
|
+
return {
|
|
81
|
+
content: `Request timed out after ${config.timeout}ms`,
|
|
82
|
+
isError: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
86
|
+
return {
|
|
87
|
+
content: `Request failed: ${message}`,
|
|
88
|
+
isError: true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Builds the full URL by substituting path parameters into the template.
|
|
94
|
+
* Uses replaceAll to handle duplicate path params (e.g. /users/{id}/friends/{id}).
|
|
95
|
+
*/
|
|
96
|
+
function buildUrl(baseUrl, pathTemplate, args, parameters) {
|
|
97
|
+
let resolvedPath = pathTemplate;
|
|
98
|
+
// Substitute path parameters: /users/{id} → /users/123
|
|
99
|
+
for (const param of parameters) {
|
|
100
|
+
if (param.in === "path" && args[param.name] !== undefined) {
|
|
101
|
+
resolvedPath = resolvedPath.replaceAll(`{${param.name}}`, encodeURIComponent(String(args[param.name])));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Ensure no double slashes between baseUrl and path
|
|
105
|
+
const cleanBase = baseUrl.replace(/\/+$/, "");
|
|
106
|
+
const cleanPath = resolvedPath.startsWith("/")
|
|
107
|
+
? resolvedPath
|
|
108
|
+
: `/${resolvedPath}`;
|
|
109
|
+
return `${cleanBase}${cleanPath}`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Appends query parameters to the URL.
|
|
113
|
+
* Skips null/undefined values to prevent sending "null" as a string.
|
|
114
|
+
*/
|
|
115
|
+
function appendQueryParams(url, args, parameters) {
|
|
116
|
+
const queryParams = new URLSearchParams();
|
|
117
|
+
for (const param of parameters) {
|
|
118
|
+
if (param.in === "query" && args[param.name] != null) {
|
|
119
|
+
const value = args[param.name];
|
|
120
|
+
if (Array.isArray(value)) {
|
|
121
|
+
// Handle array query params
|
|
122
|
+
for (const item of value) {
|
|
123
|
+
if (item != null) {
|
|
124
|
+
queryParams.append(param.name, String(item));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
queryParams.set(param.name, String(value));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const queryString = queryParams.toString();
|
|
134
|
+
if (!queryString)
|
|
135
|
+
return url;
|
|
136
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
137
|
+
return `${url}${separator}${queryString}`;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Formats a successful response for the MCP tool result.
|
|
141
|
+
*/
|
|
142
|
+
function formatSuccessResponse(status, body) {
|
|
143
|
+
let formattedBody;
|
|
144
|
+
try {
|
|
145
|
+
const parsed = JSON.parse(body);
|
|
146
|
+
formattedBody = JSON.stringify(parsed, null, 2);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
formattedBody = body;
|
|
150
|
+
}
|
|
151
|
+
return `HTTP ${status}\n\n${formattedBody}`;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Formats an error response for the MCP tool result.
|
|
155
|
+
*/
|
|
156
|
+
function formatErrorResponse(status, statusText, body) {
|
|
157
|
+
let formattedBody;
|
|
158
|
+
try {
|
|
159
|
+
const parsed = JSON.parse(body);
|
|
160
|
+
formattedBody = JSON.stringify(parsed, null, 2);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
formattedBody = body;
|
|
164
|
+
}
|
|
165
|
+
return `HTTP ${status} ${statusText}\n\n${formattedBody}`;
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=request-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-handler.js","sourceRoot":"","sources":["../../src/http/request-handler.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { loadConfig } from "./core/config.js";
|
|
4
|
+
import { createServer } from "./server.js";
|
|
5
|
+
/**
|
|
6
|
+
* Entry point for the swagger-mcp server.
|
|
7
|
+
*
|
|
8
|
+
* Loads configuration, creates the MCP server, and connects it
|
|
9
|
+
* to stdio transport for communication with MCP clients.
|
|
10
|
+
*/
|
|
11
|
+
async function main() {
|
|
12
|
+
console.error("[swagger-mcp] Starting...");
|
|
13
|
+
// Load configuration from env vars and CLI args
|
|
14
|
+
const config = loadConfig();
|
|
15
|
+
console.error(`[swagger-mcp] Spec URL: ${config.specUrl}`);
|
|
16
|
+
try {
|
|
17
|
+
// Create the MCP server (fetches spec, builds tools)
|
|
18
|
+
const server = await createServer(config);
|
|
19
|
+
// Connect via stdio transport
|
|
20
|
+
const transport = new StdioServerTransport();
|
|
21
|
+
await server.connect(transport);
|
|
22
|
+
console.error("[swagger-mcp] Server is running. Waiting for requests...");
|
|
23
|
+
// Handle graceful shutdown
|
|
24
|
+
const shutdown = async () => {
|
|
25
|
+
console.error("[swagger-mcp] Shutting down...");
|
|
26
|
+
await server.close();
|
|
27
|
+
process.exit(0);
|
|
28
|
+
};
|
|
29
|
+
process.on("SIGINT", shutdown);
|
|
30
|
+
process.on("SIGTERM", shutdown);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
34
|
+
console.error(`[swagger-mcp] Fatal error: ${message}`);
|
|
35
|
+
if (error instanceof Error && error.stack) {
|
|
36
|
+
console.error(error.stack);
|
|
37
|
+
}
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Safety nets for unhandled errors in the stdio server process
|
|
42
|
+
process.on("unhandledRejection", (reason) => {
|
|
43
|
+
console.error("[swagger-mcp] Unhandled rejection:", reason);
|
|
44
|
+
});
|
|
45
|
+
process.on("uncaughtException", (error) => {
|
|
46
|
+
console.error("[swagger-mcp] Uncaught exception:", error);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
});
|
|
49
|
+
main();
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;GAKG;AACH,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAE3C,gDAAgD;IAChD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,CAAC,KAAK,CAAC,2BAA2B,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAE3D,IAAI,CAAC;QACH,qDAAqD;QACrD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QAE1C,8BAA8B;QAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhC,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAE1E,2BAA2B;QAC3B,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;YAC1B,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;YAChD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC;QAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,8BAA8B,OAAO,EAAE,CAAC,CAAC;QACvD,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC1C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;IAC1C,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,MAAM,CAAC,CAAC;AAC9D,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE;IACxC,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ParsedOperation } from "../core/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Fetches and parses a Swagger/OpenAPI spec from a URL or file path.
|
|
4
|
+
* Supports both Swagger 2.0 and OpenAPI 3.x.
|
|
5
|
+
* Returns parsed operations and the resolved base URL from the spec.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseSwaggerSpec(specUrl: string): Promise<{
|
|
8
|
+
operations: ParsedOperation[];
|
|
9
|
+
specBaseUrl: string | undefined;
|
|
10
|
+
title: string;
|
|
11
|
+
version: string;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Sanitizes a schema object for use as a JSON Schema in MCP tools.
|
|
15
|
+
* Removes OpenAPI-specific extensions and null/undefined values.
|
|
16
|
+
*
|
|
17
|
+
* Uses a WeakSet to track visited objects and prevent infinite loops
|
|
18
|
+
* on circular references (which SwaggerParser.dereference() can create).
|
|
19
|
+
*/
|
|
20
|
+
export declare function sanitizeSchema(schema: Record<string, unknown>, visited?: WeakSet<object>): Record<string, unknown>;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
2
|
+
import { HTTP_METHODS, } from "../core/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Fetches and parses a Swagger/OpenAPI spec from a URL or file path.
|
|
5
|
+
* Supports both Swagger 2.0 and OpenAPI 3.x.
|
|
6
|
+
* Returns parsed operations and the resolved base URL from the spec.
|
|
7
|
+
*/
|
|
8
|
+
export async function parseSwaggerSpec(specUrl) {
|
|
9
|
+
console.error(`[swagger-mcp] Fetching spec from: ${specUrl}`);
|
|
10
|
+
let api;
|
|
11
|
+
try {
|
|
12
|
+
// Dereference resolves all $ref pointers so we get a flat object
|
|
13
|
+
api = await SwaggerParser.dereference(specUrl);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
throw new Error(`Failed to fetch or parse OpenAPI spec from "${specUrl}": ${message}`);
|
|
18
|
+
}
|
|
19
|
+
const title = api.info?.title || "Unknown API";
|
|
20
|
+
const version = api.info?.version || "0.0.0";
|
|
21
|
+
console.error(`[swagger-mcp] Parsed: ${title} v${version}`);
|
|
22
|
+
const specBaseUrl = extractBaseUrl(api);
|
|
23
|
+
const operations = extractOperations(api);
|
|
24
|
+
console.error(`[swagger-mcp] Found ${operations.length} operations`);
|
|
25
|
+
return { operations, specBaseUrl, title, version };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extracts the base URL from the spec.
|
|
29
|
+
* - OpenAPI 3.x: uses servers[0].url
|
|
30
|
+
* - Swagger 2.0: uses host + basePath + schemes
|
|
31
|
+
*/
|
|
32
|
+
function extractBaseUrl(api) {
|
|
33
|
+
// OpenAPI 3.x
|
|
34
|
+
if ("openapi" in api && api.openapi?.startsWith("3")) {
|
|
35
|
+
const doc = api;
|
|
36
|
+
if (doc.servers && doc.servers.length > 0) {
|
|
37
|
+
return doc.servers[0].url;
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
// Swagger 2.0
|
|
42
|
+
if ("swagger" in api) {
|
|
43
|
+
const doc = api;
|
|
44
|
+
if (doc.host) {
|
|
45
|
+
const scheme = doc.schemes && doc.schemes.length > 0 ? doc.schemes[0] : "https";
|
|
46
|
+
const basePath = doc.basePath || "";
|
|
47
|
+
return `${scheme}://${doc.host}${basePath}`;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extracts all operations from the spec into ParsedOperation objects.
|
|
55
|
+
*/
|
|
56
|
+
function extractOperations(api) {
|
|
57
|
+
const operations = [];
|
|
58
|
+
if (!api.paths)
|
|
59
|
+
return operations;
|
|
60
|
+
const isV3 = "openapi" in api;
|
|
61
|
+
for (const [path, pathItem] of Object.entries(api.paths)) {
|
|
62
|
+
if (!pathItem)
|
|
63
|
+
continue;
|
|
64
|
+
// Path-level parameters (shared by all operations on this path)
|
|
65
|
+
const pathLevelParams = extractPathLevelParams(pathItem);
|
|
66
|
+
for (const method of HTTP_METHODS) {
|
|
67
|
+
const operation = pathItem[method];
|
|
68
|
+
if (!operation || typeof operation !== "object")
|
|
69
|
+
continue;
|
|
70
|
+
const op = operation;
|
|
71
|
+
// Parse operation-level parameters, filtering out body params for Swagger 2.0
|
|
72
|
+
// (body params are handled separately in parseRequestBody)
|
|
73
|
+
const rawOperationParams = parseParameters(op.parameters || []);
|
|
74
|
+
const operationParams = rawOperationParams.filter((p) => p.in !== "body");
|
|
75
|
+
// Merge path-level and operation-level parameters
|
|
76
|
+
const mergedParams = mergeParameters(pathLevelParams, operationParams);
|
|
77
|
+
// Parse request body
|
|
78
|
+
const requestBody = parseRequestBody(op, api);
|
|
79
|
+
// Extract tag
|
|
80
|
+
const tags = op.tags;
|
|
81
|
+
const tag = tags && tags.length > 0 ? tags[0] : undefined;
|
|
82
|
+
operations.push({
|
|
83
|
+
operationId: op.operationId,
|
|
84
|
+
method,
|
|
85
|
+
path,
|
|
86
|
+
tag,
|
|
87
|
+
summary: op.summary,
|
|
88
|
+
description: op.description,
|
|
89
|
+
parameters: mergedParams,
|
|
90
|
+
requestBody,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return operations;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Extracts path-level parameters from a path item.
|
|
98
|
+
* Filters out body and formData params (handled separately).
|
|
99
|
+
*/
|
|
100
|
+
function extractPathLevelParams(pathItem) {
|
|
101
|
+
const params = pathItem.parameters;
|
|
102
|
+
if (!Array.isArray(params))
|
|
103
|
+
return [];
|
|
104
|
+
return parseParameters(params).filter((p) => p.in !== "body");
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parses parameter objects into ParsedParameter[].
|
|
108
|
+
* Handles both Swagger 2.0 and OpenAPI 3.x parameter formats.
|
|
109
|
+
*/
|
|
110
|
+
function parseParameters(params) {
|
|
111
|
+
return params
|
|
112
|
+
.filter((p) => p !== null && typeof p === "object")
|
|
113
|
+
.filter((param) => {
|
|
114
|
+
// Skip formData params — they're used for file uploads and
|
|
115
|
+
// don't map cleanly to JSON-based MCP tool inputs
|
|
116
|
+
const paramIn = param.in;
|
|
117
|
+
return paramIn !== "formData";
|
|
118
|
+
})
|
|
119
|
+
.map((param) => {
|
|
120
|
+
// Swagger 2.0: type is directly on the param
|
|
121
|
+
// OpenAPI 3.x: type is in param.schema
|
|
122
|
+
let schema = {};
|
|
123
|
+
if (param.schema && typeof param.schema === "object") {
|
|
124
|
+
// OpenAPI 3.x
|
|
125
|
+
schema = sanitizeSchema(param.schema);
|
|
126
|
+
}
|
|
127
|
+
else if (param.type) {
|
|
128
|
+
// Swagger 2.0
|
|
129
|
+
const schemaObj = {
|
|
130
|
+
type: param.type,
|
|
131
|
+
};
|
|
132
|
+
if (param.format)
|
|
133
|
+
schemaObj.format = param.format;
|
|
134
|
+
if (param.enum)
|
|
135
|
+
schemaObj.enum = param.enum;
|
|
136
|
+
if (param.default !== undefined)
|
|
137
|
+
schemaObj.default = param.default;
|
|
138
|
+
if (param.items && typeof param.items === "object") {
|
|
139
|
+
schemaObj.items = sanitizeSchema(param.items);
|
|
140
|
+
}
|
|
141
|
+
schema = sanitizeSchema(schemaObj);
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
name: param.name,
|
|
145
|
+
in: param.in,
|
|
146
|
+
description: param.description,
|
|
147
|
+
required: param.required || false,
|
|
148
|
+
schema,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Parses request body from an operation.
|
|
154
|
+
* Handles both Swagger 2.0 (body parameter) and OpenAPI 3.x (requestBody).
|
|
155
|
+
*/
|
|
156
|
+
function parseRequestBody(operation, api) {
|
|
157
|
+
// OpenAPI 3.x: requestBody object
|
|
158
|
+
if ("openapi" in api && operation.requestBody) {
|
|
159
|
+
const rb = operation.requestBody;
|
|
160
|
+
const content = rb.content;
|
|
161
|
+
if (content) {
|
|
162
|
+
// Prefer application/json, fall back to first content type
|
|
163
|
+
const contentType = content["application/json"]
|
|
164
|
+
? "application/json"
|
|
165
|
+
: Object.keys(content)[0];
|
|
166
|
+
if (contentType) {
|
|
167
|
+
const mediaType = content[contentType];
|
|
168
|
+
const schema = mediaType?.schema;
|
|
169
|
+
return {
|
|
170
|
+
description: rb.description,
|
|
171
|
+
required: rb.required || false,
|
|
172
|
+
schema: schema ? sanitizeSchema(schema) : { type: "object" },
|
|
173
|
+
contentType,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
// Swagger 2.0: look for a parameter with in: "body"
|
|
180
|
+
const params = operation.parameters;
|
|
181
|
+
if (params) {
|
|
182
|
+
const bodyParam = params.find((p) => p !== null &&
|
|
183
|
+
typeof p === "object" &&
|
|
184
|
+
p.in === "body");
|
|
185
|
+
if (bodyParam) {
|
|
186
|
+
const schema = bodyParam.schema;
|
|
187
|
+
return {
|
|
188
|
+
description: bodyParam.description,
|
|
189
|
+
required: bodyParam.required || false,
|
|
190
|
+
schema: schema ? sanitizeSchema(schema) : { type: "object" },
|
|
191
|
+
contentType: "application/json",
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Merge path-level and operation-level parameters.
|
|
199
|
+
* Operation params override path-level params with the same name+in.
|
|
200
|
+
*/
|
|
201
|
+
function mergeParameters(pathParams, operationParams) {
|
|
202
|
+
const merged = new Map();
|
|
203
|
+
for (const p of pathParams) {
|
|
204
|
+
merged.set(`${p.in}:${p.name}`, p);
|
|
205
|
+
}
|
|
206
|
+
for (const p of operationParams) {
|
|
207
|
+
merged.set(`${p.in}:${p.name}`, p);
|
|
208
|
+
}
|
|
209
|
+
return Array.from(merged.values());
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Sanitizes a schema object for use as a JSON Schema in MCP tools.
|
|
213
|
+
* Removes OpenAPI-specific extensions and null/undefined values.
|
|
214
|
+
*
|
|
215
|
+
* Uses a WeakSet to track visited objects and prevent infinite loops
|
|
216
|
+
* on circular references (which SwaggerParser.dereference() can create).
|
|
217
|
+
*/
|
|
218
|
+
export function sanitizeSchema(schema, visited = new WeakSet()) {
|
|
219
|
+
// Circular reference guard
|
|
220
|
+
if (visited.has(schema)) {
|
|
221
|
+
return { type: "object", description: "(circular reference)" };
|
|
222
|
+
}
|
|
223
|
+
visited.add(schema);
|
|
224
|
+
const result = {};
|
|
225
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
226
|
+
// Skip OpenAPI-specific extensions and undefined/null values
|
|
227
|
+
if (key.startsWith("x-") || value === undefined || value === null)
|
|
228
|
+
continue;
|
|
229
|
+
// Skip XML definitions
|
|
230
|
+
if (key === "xml")
|
|
231
|
+
continue;
|
|
232
|
+
if (key === "properties" && typeof value === "object" && value !== null) {
|
|
233
|
+
// Recursively sanitize nested property schemas
|
|
234
|
+
const props = {};
|
|
235
|
+
for (const [propName, propSchema] of Object.entries(value)) {
|
|
236
|
+
if (propSchema && typeof propSchema === "object") {
|
|
237
|
+
props[propName] = sanitizeSchema(propSchema, visited);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
props[propName] = propSchema;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
result[key] = props;
|
|
244
|
+
}
|
|
245
|
+
else if (key === "items" &&
|
|
246
|
+
typeof value === "object" &&
|
|
247
|
+
value !== null) {
|
|
248
|
+
// Recursively sanitize array items schema
|
|
249
|
+
result[key] = sanitizeSchema(value, visited);
|
|
250
|
+
}
|
|
251
|
+
else if (key === "additionalProperties" &&
|
|
252
|
+
typeof value === "object" &&
|
|
253
|
+
value !== null) {
|
|
254
|
+
result[key] = sanitizeSchema(value, visited);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
result[key] = value;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=swagger-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swagger-parser.js","sourceRoot":"","sources":["../../src/parser/swagger-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ParsedOperation, ToolMapping } from "../core/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Converts parsed OpenAPI operations into MCP tool definitions and mappings.
|
|
4
|
+
*/
|
|
5
|
+
export declare function buildTools(operations: ParsedOperation[]): {
|
|
6
|
+
tools: McpToolDefinition[];
|
|
7
|
+
mappings: Map<string, ToolMapping>;
|
|
8
|
+
};
|
|
9
|
+
export interface McpToolDefinition {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: "object";
|
|
14
|
+
properties: Record<string, unknown>;
|
|
15
|
+
required?: string[];
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generates a unique MCP tool name for an operation.
|
|
20
|
+
*
|
|
21
|
+
* Priority:
|
|
22
|
+
* 1. operationId (if present in the spec) — preserves casing
|
|
23
|
+
* 2. tag + method + path (if tag exists) — lowercased
|
|
24
|
+
* 3. method + path (last resort) — lowercased
|
|
25
|
+
*
|
|
26
|
+
* Sanitization: replace special chars with _, collapse multiples,
|
|
27
|
+
* strip leading/trailing _, max 64 chars.
|
|
28
|
+
*/
|
|
29
|
+
export declare function generateToolName(operation: ParsedOperation, usedNames: Set<string>): string;
|