@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,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts parsed OpenAPI operations into MCP tool definitions and mappings.
|
|
3
|
+
*/
|
|
4
|
+
export function buildTools(operations) {
|
|
5
|
+
const tools = [];
|
|
6
|
+
const mappings = new Map();
|
|
7
|
+
const usedNames = new Set();
|
|
8
|
+
for (const operation of operations) {
|
|
9
|
+
const toolName = generateToolName(operation, usedNames);
|
|
10
|
+
usedNames.add(toolName);
|
|
11
|
+
const tool = buildToolDefinition(toolName, operation);
|
|
12
|
+
tools.push(tool);
|
|
13
|
+
mappings.set(toolName, { toolName, operation });
|
|
14
|
+
}
|
|
15
|
+
return { tools, mappings };
|
|
16
|
+
}
|
|
17
|
+
// ─── Tool Name Generation ───────────────────────────────────────────────────
|
|
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 function generateToolName(operation, usedNames) {
|
|
30
|
+
let name;
|
|
31
|
+
if (operation.operationId) {
|
|
32
|
+
// Priority 1: use operationId directly — preserve its casing
|
|
33
|
+
name = sanitizeName(operation.operationId, false);
|
|
34
|
+
}
|
|
35
|
+
else if (operation.tag) {
|
|
36
|
+
// Priority 2: tag + method + path — lowercase
|
|
37
|
+
name = sanitizeName(`${operation.tag}_${operation.method}_${operation.path}`, true);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// Priority 3: method + path — lowercase
|
|
41
|
+
name = sanitizeName(`${operation.method}_${operation.path}`, true);
|
|
42
|
+
}
|
|
43
|
+
// Guard against empty name after sanitization
|
|
44
|
+
if (!name) {
|
|
45
|
+
name = "unnamed_tool";
|
|
46
|
+
}
|
|
47
|
+
// Ensure uniqueness by appending a counter if needed
|
|
48
|
+
let uniqueName = name;
|
|
49
|
+
let counter = 2;
|
|
50
|
+
while (usedNames.has(uniqueName)) {
|
|
51
|
+
const suffix = `_${counter}`;
|
|
52
|
+
uniqueName = name.substring(0, 64 - suffix.length) + suffix;
|
|
53
|
+
counter++;
|
|
54
|
+
}
|
|
55
|
+
return uniqueName;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sanitizes a string into a valid MCP tool name.
|
|
59
|
+
* - Optionally lowercase
|
|
60
|
+
* - Replace special chars with _
|
|
61
|
+
* - Collapse multiple _ into one
|
|
62
|
+
* - Strip leading/trailing _
|
|
63
|
+
* - Max 64 characters
|
|
64
|
+
*/
|
|
65
|
+
function sanitizeName(raw, forceLowercase) {
|
|
66
|
+
let name = raw;
|
|
67
|
+
if (forceLowercase) {
|
|
68
|
+
name = name.toLowerCase();
|
|
69
|
+
}
|
|
70
|
+
return name
|
|
71
|
+
.replace(/[^a-zA-Z0-9_]/g, "_") // replace invalid chars with _
|
|
72
|
+
.replace(/_+/g, "_") // collapse multiple _
|
|
73
|
+
.replace(/^_|_$/g, "") // strip leading/trailing _
|
|
74
|
+
.substring(0, 64);
|
|
75
|
+
}
|
|
76
|
+
// ─── Tool Definition Building ───────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* Builds a full MCP tool definition from an operation.
|
|
79
|
+
*/
|
|
80
|
+
function buildToolDefinition(toolName, operation) {
|
|
81
|
+
// Build description: [METHOD /path] — summary — description
|
|
82
|
+
const descParts = [];
|
|
83
|
+
descParts.push(`[${operation.method.toUpperCase()} ${operation.path}]`);
|
|
84
|
+
if (operation.summary)
|
|
85
|
+
descParts.push(operation.summary);
|
|
86
|
+
if (operation.description && operation.description !== operation.summary) {
|
|
87
|
+
descParts.push(operation.description);
|
|
88
|
+
}
|
|
89
|
+
const description = descParts.join(" — ");
|
|
90
|
+
// Build input schema
|
|
91
|
+
const properties = {};
|
|
92
|
+
const requiredSet = new Set();
|
|
93
|
+
// Add parameters (path, query, header)
|
|
94
|
+
for (const param of operation.parameters) {
|
|
95
|
+
// Skip cookie params — rarely used with MCP
|
|
96
|
+
if (param.in === "cookie")
|
|
97
|
+
continue;
|
|
98
|
+
// Check for collision with the reserved "body" property name
|
|
99
|
+
const propName = param.name === "body" && operation.requestBody
|
|
100
|
+
? "body_param"
|
|
101
|
+
: param.name;
|
|
102
|
+
const propSchema = { ...param.schema };
|
|
103
|
+
// Enrich description with parameter location info
|
|
104
|
+
const descPieces = [];
|
|
105
|
+
if (param.description)
|
|
106
|
+
descPieces.push(param.description);
|
|
107
|
+
descPieces.push(`(${param.in} parameter)`);
|
|
108
|
+
propSchema.description = descPieces.join(" ");
|
|
109
|
+
properties[propName] = propSchema;
|
|
110
|
+
if (param.required) {
|
|
111
|
+
requiredSet.add(propName);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Add request body
|
|
115
|
+
if (operation.requestBody) {
|
|
116
|
+
const bodySchema = {
|
|
117
|
+
...operation.requestBody.schema,
|
|
118
|
+
};
|
|
119
|
+
if (operation.requestBody.description) {
|
|
120
|
+
bodySchema.description = operation.requestBody.description;
|
|
121
|
+
}
|
|
122
|
+
properties["body"] = bodySchema;
|
|
123
|
+
if (operation.requestBody.required) {
|
|
124
|
+
requiredSet.add("body");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const required = [...requiredSet];
|
|
128
|
+
return {
|
|
129
|
+
name: toolName,
|
|
130
|
+
description,
|
|
131
|
+
inputSchema: {
|
|
132
|
+
type: "object",
|
|
133
|
+
properties,
|
|
134
|
+
...(required.length > 0 ? { required } : {}),
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=tool-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-builder.js","sourceRoot":"","sources":["../../src/parser/tool-builder.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { ServerConfig } from "./core/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates and configures the MCP server.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. Fetch & parse the Swagger spec
|
|
8
|
+
* 2. Resolve the base URL (config → spec → spec URL origin)
|
|
9
|
+
* 3. Generate MCP tool definitions from operations
|
|
10
|
+
* 4. Register ListTools and CallTool handlers
|
|
11
|
+
*/
|
|
12
|
+
export declare function createServer(config: ServerConfig): Promise<Server>;
|
|
13
|
+
/**
|
|
14
|
+
* Resolves the base URL from 3 sources (priority order):
|
|
15
|
+
* 1. Explicit override from config
|
|
16
|
+
* 2. Base URL extracted from the spec
|
|
17
|
+
* 3. Origin of the spec URL itself
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveBaseUrl(specUrl: string, configBaseUrl?: string, specBaseUrl?: string): string;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { parseSwaggerSpec } from "./parser/swagger-parser.js";
|
|
4
|
+
import { buildTools } from "./parser/tool-builder.js";
|
|
5
|
+
import { executeToolRequest } from "./http/request-handler.js";
|
|
6
|
+
/**
|
|
7
|
+
* Creates and configures the MCP server.
|
|
8
|
+
*
|
|
9
|
+
* Flow:
|
|
10
|
+
* 1. Fetch & parse the Swagger spec
|
|
11
|
+
* 2. Resolve the base URL (config → spec → spec URL origin)
|
|
12
|
+
* 3. Generate MCP tool definitions from operations
|
|
13
|
+
* 4. Register ListTools and CallTool handlers
|
|
14
|
+
*/
|
|
15
|
+
export async function createServer(config) {
|
|
16
|
+
// ─── Parse the spec ─────────────────────────────────────────────────
|
|
17
|
+
let tools;
|
|
18
|
+
let mappings;
|
|
19
|
+
let baseUrl;
|
|
20
|
+
let apiTitle;
|
|
21
|
+
const result = await loadSpec(config);
|
|
22
|
+
tools = result.tools;
|
|
23
|
+
mappings = result.mappings;
|
|
24
|
+
baseUrl = result.baseUrl;
|
|
25
|
+
apiTitle = result.apiTitle;
|
|
26
|
+
// ─── Create MCP server ─────────────────────────────────────────────
|
|
27
|
+
const server = new Server({
|
|
28
|
+
name: `swagger-mcp: ${apiTitle}`,
|
|
29
|
+
version: "1.0.0",
|
|
30
|
+
}, {
|
|
31
|
+
capabilities: { tools: {} },
|
|
32
|
+
});
|
|
33
|
+
// ─── ListTools handler ─────────────────────────────────────────────
|
|
34
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
35
|
+
// Include the reload meta-tool
|
|
36
|
+
const allTools = [
|
|
37
|
+
...tools,
|
|
38
|
+
{
|
|
39
|
+
name: "_swagger_mcp_reload",
|
|
40
|
+
description: "Re-fetches and re-parses the Swagger/OpenAPI spec to update all tools. " +
|
|
41
|
+
"Use this if the API spec has changed and you want to pick up new endpoints.",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
return { tools: allTools };
|
|
49
|
+
});
|
|
50
|
+
// ─── CallTool handler ──────────────────────────────────────────────
|
|
51
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
52
|
+
const { name, arguments: args } = request.params;
|
|
53
|
+
// Handle the reload meta-tool
|
|
54
|
+
if (name === "_swagger_mcp_reload") {
|
|
55
|
+
console.error("[swagger-mcp] Reloading spec...");
|
|
56
|
+
try {
|
|
57
|
+
const reloaded = await loadSpec(config);
|
|
58
|
+
tools = reloaded.tools;
|
|
59
|
+
mappings = reloaded.mappings;
|
|
60
|
+
baseUrl = reloaded.baseUrl;
|
|
61
|
+
apiTitle = reloaded.apiTitle;
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: "text",
|
|
66
|
+
text: `Successfully reloaded spec. Found ${tools.length} tools from "${apiTitle}".`,
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
73
|
+
return {
|
|
74
|
+
content: [
|
|
75
|
+
{ type: "text", text: `Failed to reload spec: ${message}` },
|
|
76
|
+
],
|
|
77
|
+
isError: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Look up the tool mapping
|
|
82
|
+
const mapping = mappings.get(name);
|
|
83
|
+
if (!mapping) {
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: "text",
|
|
88
|
+
text: `Unknown tool: "${name}". Use ListTools to see available tools.`,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
isError: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// Execute the HTTP request with catch-all error handling
|
|
95
|
+
try {
|
|
96
|
+
const result = await executeToolRequest(mapping, (args || {}), config, baseUrl);
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: "text", text: result.content }],
|
|
99
|
+
isError: result.isError,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
104
|
+
return {
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
type: "text",
|
|
108
|
+
text: `Unexpected error executing tool "${name}": ${message}`,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
isError: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return server;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Loads the spec, builds tools, and resolves the base URL.
|
|
119
|
+
*/
|
|
120
|
+
async function loadSpec(config) {
|
|
121
|
+
const { operations, specBaseUrl, title } = await parseSwaggerSpec(config.specUrl);
|
|
122
|
+
const { tools, mappings } = buildTools(operations);
|
|
123
|
+
// Resolve base URL with 3-tier priority:
|
|
124
|
+
// 1. Config override (env var / CLI arg)
|
|
125
|
+
// 2. Spec's servers[0].url or host+basePath
|
|
126
|
+
// 3. Origin of the spec URL
|
|
127
|
+
const baseUrl = resolveBaseUrl(config.specUrl, config.baseUrl, specBaseUrl);
|
|
128
|
+
console.error(`[swagger-mcp] Base URL: ${baseUrl}`);
|
|
129
|
+
console.error(`[swagger-mcp] Registered ${tools.length} tools:`);
|
|
130
|
+
for (const tool of tools) {
|
|
131
|
+
console.error(` - ${tool.name}`);
|
|
132
|
+
}
|
|
133
|
+
return { tools, mappings, baseUrl, apiTitle: title };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Resolves the base URL from 3 sources (priority order):
|
|
137
|
+
* 1. Explicit override from config
|
|
138
|
+
* 2. Base URL extracted from the spec
|
|
139
|
+
* 3. Origin of the spec URL itself
|
|
140
|
+
*/
|
|
141
|
+
export function resolveBaseUrl(specUrl, configBaseUrl, specBaseUrl) {
|
|
142
|
+
// Priority 1: explicit config
|
|
143
|
+
if (configBaseUrl) {
|
|
144
|
+
return configBaseUrl.replace(/\/+$/, "");
|
|
145
|
+
}
|
|
146
|
+
// Priority 2: from spec
|
|
147
|
+
if (specBaseUrl) {
|
|
148
|
+
// specBaseUrl might be a relative path (OpenAPI 3.x allows this)
|
|
149
|
+
if (specBaseUrl.startsWith("http://") ||
|
|
150
|
+
specBaseUrl.startsWith("https://")) {
|
|
151
|
+
return specBaseUrl.replace(/\/+$/, "");
|
|
152
|
+
}
|
|
153
|
+
// Relative path — combine with spec URL origin
|
|
154
|
+
try {
|
|
155
|
+
const origin = new URL(specUrl).origin;
|
|
156
|
+
return `${origin}${specBaseUrl}`.replace(/\/+$/, "");
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// specUrl might be a file path — can't extract origin
|
|
160
|
+
return specBaseUrl.replace(/\/+$/, "");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Priority 3: origin of the spec URL
|
|
164
|
+
try {
|
|
165
|
+
const parsed = new URL(specUrl);
|
|
166
|
+
return parsed.origin;
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
console.error("[swagger-mcp] Warning: Could not derive base URL. " +
|
|
170
|
+
"Please provide SWAGGER_MCP_BASE_URL explicitly.");
|
|
171
|
+
// Return a clearly broken URL so errors are obvious
|
|
172
|
+
return "http://localhost";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@abhishekkumar00019/swagger-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Dynamic MCP server that converts Swagger/OpenAPI specs into callable MCP tools",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"swagger-mcp": "dist/index.js",
|
|
9
|
+
"@abhishekkumar00019/swagger-mcp": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/itachiuchihadev/swagger-mcp.git"
|
|
22
|
+
},
|
|
23
|
+
"author": "Abhishek Kumar",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"prepublishOnly": "npm run test && npm run build",
|
|
28
|
+
"dev": "tsx src/index.ts",
|
|
29
|
+
"start": "node dist/index.js",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"mcp",
|
|
35
|
+
"swagger",
|
|
36
|
+
"openapi",
|
|
37
|
+
"model-context-protocol",
|
|
38
|
+
"ai-tools",
|
|
39
|
+
"claude",
|
|
40
|
+
"copilot",
|
|
41
|
+
"cursor"
|
|
42
|
+
],
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@apidevtools/swagger-parser": "^10.1.1",
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
46
|
+
"openapi-types": "^12.1.3",
|
|
47
|
+
"zod": "^3.25.67"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^22.15.34",
|
|
51
|
+
"tsx": "^4.20.3",
|
|
52
|
+
"typescript": "^5.8.3",
|
|
53
|
+
"vitest": "^4.1.10"
|
|
54
|
+
}
|
|
55
|
+
}
|