specrun 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.
@@ -0,0 +1,398 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseOpenApiSpec = parseOpenApiSpec;
7
+ exports.updateSpecServerUrls = updateSpecServerUrls;
8
+ exports.resolveServerUrl = resolveServerUrl;
9
+ exports.isOpenAPIFile = isOpenAPIFile;
10
+ const swagger_parser_1 = __importDefault(require("@apidevtools/swagger-parser"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const yaml_1 = __importDefault(require("yaml"));
14
+ const auth_1 = require("./auth");
15
+ const DEFAULT_SERVER_URL = "https://api-server.placeholder";
16
+ async function parseOpenApiSpec(filePath) {
17
+ try {
18
+ const spec = (await swagger_parser_1.default.validate(filePath)); // OpenAPIV3.Document;
19
+ const apiName = (0, auth_1.getApiNameFromFile)(filePath);
20
+ const tools = generateToolsFromSpec(spec, apiName);
21
+ return {
22
+ apiName,
23
+ filePath,
24
+ spec,
25
+ tools,
26
+ };
27
+ }
28
+ catch (error) {
29
+ // Only log errors for files that look like they should be OpenAPI specs
30
+ const filename = path_1.default.basename(filePath);
31
+ if (filename.toLowerCase().includes("openapi") ||
32
+ filename.toLowerCase().includes("swagger") ||
33
+ filename.toLowerCase().includes("api")) {
34
+ console.error(`Failed to parse OpenAPI spec at ${filePath}:`, error);
35
+ }
36
+ else {
37
+ // For other files, just log a brief message
38
+ console.log(`Skipping ${filename} - not a valid OpenAPI specification`);
39
+ }
40
+ return null;
41
+ }
42
+ }
43
+ function generateToolsFromSpec(spec, apiName) {
44
+ const tools = [];
45
+ const baseUrl = getBaseUrl(spec);
46
+ if (!spec.paths)
47
+ return tools;
48
+ for (const [pathTemplate, pathItem] of Object.entries(spec.paths)) {
49
+ if (!pathItem || typeof pathItem !== "object")
50
+ continue;
51
+ const methods = [
52
+ "get",
53
+ "post",
54
+ "put",
55
+ "patch",
56
+ "delete",
57
+ "head",
58
+ "options",
59
+ ];
60
+ for (const method of methods) {
61
+ const operation = pathItem[method];
62
+ if (!operation)
63
+ continue;
64
+ const tool = createToolFromOperation(apiName, pathTemplate, method, operation, baseUrl, pathItem.parameters, spec);
65
+ if (tool) {
66
+ tools.push(tool);
67
+ }
68
+ }
69
+ }
70
+ return tools;
71
+ }
72
+ function createToolFromOperation(apiName, pathTemplate, method, operation, baseUrl, pathLevelParams, spec) {
73
+ try {
74
+ const toolName = generateToolName(apiName, operation, pathTemplate, method);
75
+ const description = operation.summary ||
76
+ operation.description ||
77
+ `${method.toUpperCase()} ${pathTemplate}`;
78
+ // Combine path-level and operation-level parameters
79
+ const allParams = [
80
+ ...(pathLevelParams || []),
81
+ ...(operation.parameters || []),
82
+ ];
83
+ const parameters = extractParameters(allParams, spec);
84
+ return {
85
+ name: toolName,
86
+ description,
87
+ operationId: operation.operationId,
88
+ method: method.toUpperCase(),
89
+ path: pathTemplate,
90
+ parameters,
91
+ requestBody: operation.requestBody,
92
+ responses: operation.responses,
93
+ security: operation.security || [],
94
+ baseUrl,
95
+ };
96
+ }
97
+ catch (error) {
98
+ console.error(`Failed to create tool for ${method} ${pathTemplate}:`, error);
99
+ return null;
100
+ }
101
+ }
102
+ function generateToolName(apiName, operation, pathTemplate, method) {
103
+ if (operation.operationId) {
104
+ return `${apiName}_${operation.operationId}`;
105
+ }
106
+ // Generate from path and method
107
+ const pathParts = pathTemplate
108
+ .split("/")
109
+ .filter((part) => part && !part.startsWith("{"))
110
+ .map((part) => part.replace(/[^a-zA-Z0-9]/g, ""));
111
+ const pathName = pathParts.join("_") || "root";
112
+ return `${apiName}_${method}_${pathName}`;
113
+ }
114
+ function extractParameters(paramRefs, spec) {
115
+ const parameters = [];
116
+ for (const paramRef of paramRefs) {
117
+ const param = resolveParameterRef(paramRef, spec);
118
+ if (!param) {
119
+ continue;
120
+ }
121
+ const schema = getParameterSchema(param);
122
+ if (param.in && param.name && schema) {
123
+ parameters.push({
124
+ name: param.name,
125
+ in: param.in,
126
+ required: param.required || param.in === "path",
127
+ schema: schema,
128
+ description: param.description,
129
+ });
130
+ }
131
+ }
132
+ return parameters;
133
+ }
134
+ function getBaseUrl(spec) {
135
+ if (isOpenApi3Spec(spec) && typeof spec["x-base-url"] === "string") {
136
+ const baseUrl = spec["x-base-url"].trim();
137
+ if (baseUrl) {
138
+ return appendBasePathIfNeeded(baseUrl, spec);
139
+ }
140
+ }
141
+ if (isOpenApi3Spec(spec) && spec.servers && spec.servers.length > 0) {
142
+ const baseUrl = resolveOpenApi3ServerUrl(spec.servers[0]);
143
+ return appendBasePathIfNeeded(baseUrl, spec);
144
+ }
145
+ if (isSwagger2Spec(spec)) {
146
+ const schemes = Array.isArray(spec.schemes) ? spec.schemes : [];
147
+ const scheme = schemes[0] || "https";
148
+ const host = typeof spec.host === "string" ? spec.host : "";
149
+ const basePath = typeof spec.basePath === "string" ? spec.basePath : "";
150
+ if (host) {
151
+ return `${scheme}://${host}${basePath}`;
152
+ }
153
+ }
154
+ // Fallback for older specs or specs without servers
155
+ return DEFAULT_SERVER_URL;
156
+ }
157
+ function resolveParameterRef(paramRef, spec) {
158
+ if (!paramRef || typeof paramRef !== "object") {
159
+ return null;
160
+ }
161
+ if (!("$ref" in paramRef)) {
162
+ return paramRef;
163
+ }
164
+ const ref = String(paramRef.$ref || "");
165
+ if (!ref || !spec) {
166
+ return null;
167
+ }
168
+ return resolveJsonPointer(spec, ref);
169
+ }
170
+ function resolveJsonPointer(root, ref) {
171
+ if (!ref.startsWith("#/")) {
172
+ return null;
173
+ }
174
+ const parts = ref
175
+ .slice(2)
176
+ .split("/")
177
+ .map((part) => part.replace(/~1/g, "/").replace(/~0/g, "~"));
178
+ let current = root;
179
+ for (const part of parts) {
180
+ if (!current || typeof current !== "object" || !(part in current)) {
181
+ return null;
182
+ }
183
+ current = current[part];
184
+ }
185
+ return current;
186
+ }
187
+ function getParameterSchema(param) {
188
+ if (param.schema && typeof param.schema === "object") {
189
+ return param.schema;
190
+ }
191
+ if (param.content && typeof param.content === "object") {
192
+ const content = param.content;
193
+ const preferred = content["application/json"] ||
194
+ Object.values(content).find((entry) => entry && entry.schema);
195
+ if (preferred && preferred.schema) {
196
+ return preferred.schema;
197
+ }
198
+ }
199
+ if (param.type) {
200
+ const schema = { type: param.type };
201
+ if (param.format) {
202
+ schema.format = param.format;
203
+ }
204
+ if (param.items) {
205
+ schema.items = param.items;
206
+ }
207
+ if (param.enum) {
208
+ schema.enum = param.enum;
209
+ }
210
+ if (param.default !== undefined) {
211
+ schema.default = param.default;
212
+ }
213
+ return schema;
214
+ }
215
+ return null;
216
+ }
217
+ function resolveOpenApi3ServerUrl(server) {
218
+ if (!server || typeof server !== "object") {
219
+ return DEFAULT_SERVER_URL;
220
+ }
221
+ const rawUrl = typeof server.url === "string" ? server.url : "";
222
+ if (!rawUrl) {
223
+ return DEFAULT_SERVER_URL;
224
+ }
225
+ if (!server.variables || typeof server.variables !== "object") {
226
+ return rawUrl;
227
+ }
228
+ return rawUrl.replace(/\{([^}]+)\}/g, (_match, varName) => {
229
+ const variable = server.variables[varName];
230
+ if (variable && typeof variable.default === "string") {
231
+ return variable.default;
232
+ }
233
+ return _match;
234
+ });
235
+ }
236
+ function appendBasePathIfNeeded(baseUrl, spec) {
237
+ const basePath = getOpenApiBasePath(spec);
238
+ if (!basePath) {
239
+ return baseUrl;
240
+ }
241
+ try {
242
+ const parsed = new URL(baseUrl);
243
+ const hasPath = parsed.pathname && parsed.pathname !== "/";
244
+ if (hasPath) {
245
+ return baseUrl;
246
+ }
247
+ parsed.pathname = basePath;
248
+ return parsed.toString().replace(/\/$/, "");
249
+ }
250
+ catch {
251
+ return baseUrl;
252
+ }
253
+ }
254
+ function getOpenApiBasePath(spec) {
255
+ const raw = (typeof spec?.basePath === "string" && spec.basePath) || "";
256
+ const trimmed = String(raw).trim();
257
+ if (!trimmed) {
258
+ return null;
259
+ }
260
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
261
+ }
262
+ function readSpecFile(filePath) {
263
+ try {
264
+ const content = fs_1.default.readFileSync(filePath, "utf8");
265
+ const ext = path_1.default.extname(filePath).toLowerCase();
266
+ if (ext === ".json") {
267
+ return { spec: JSON.parse(content), format: "json" };
268
+ }
269
+ return { spec: yaml_1.default.parse(content), format: "yaml" };
270
+ }
271
+ catch {
272
+ return null;
273
+ }
274
+ }
275
+ function writeSpecFile(filePath, spec, format) {
276
+ if (format === "json") {
277
+ fs_1.default.writeFileSync(filePath, `${JSON.stringify(spec, null, 2)}\n`, "utf8");
278
+ return;
279
+ }
280
+ fs_1.default.writeFileSync(filePath, yaml_1.default.stringify(spec), "utf8");
281
+ }
282
+ function updateSpecServerUrls(specFiles, env) {
283
+ for (const filePath of specFiles) {
284
+ const apiName = (0, auth_1.getApiNameFromFile)(filePath);
285
+ if (!apiName) {
286
+ continue;
287
+ }
288
+ const newUrl = resolveServerUrl(apiName, env);
289
+ if (!newUrl) {
290
+ continue;
291
+ }
292
+ const parsed = readSpecFile(filePath);
293
+ if (!parsed || !parsed.spec || typeof parsed.spec !== "object") {
294
+ continue;
295
+ }
296
+ const spec = parsed.spec;
297
+ const updated = applyServerUrlToSpec(spec, newUrl);
298
+ if (updated) {
299
+ writeSpecFile(filePath, spec, parsed.format);
300
+ }
301
+ }
302
+ }
303
+ function resolveServerUrl(apiName, env) {
304
+ const envKey = `${apiName.toUpperCase()}_SERVER_URL`;
305
+ const envValue = env[envKey];
306
+ if (typeof envValue === "string" && envValue.trim()) {
307
+ return envValue.trim();
308
+ }
309
+ return null;
310
+ }
311
+ function isSwagger2Spec(spec) {
312
+ return Boolean(spec && typeof spec === "object" && spec.swagger === "2.0");
313
+ }
314
+ function isOpenApi3Spec(spec) {
315
+ return Boolean(spec && typeof spec === "object" && spec.openapi);
316
+ }
317
+ function applyServerUrlToSpec(spec, newUrl) {
318
+ let updated = false;
319
+ if (isSwagger2Spec(spec)) {
320
+ updated = applySwagger2ServerUrl(spec, newUrl) || updated;
321
+ }
322
+ else if (isOpenApi3Spec(spec)) {
323
+ updated = applyOpenApi3ServerUrl(spec, newUrl) || updated;
324
+ }
325
+ return updated;
326
+ }
327
+ function applyOpenApi3ServerUrl(spec, newUrl) {
328
+ let updated = false;
329
+ if (Array.isArray(spec.servers) && spec.servers.length > 0) {
330
+ const first = spec.servers[0];
331
+ if (!first || typeof first !== "object" || first.url !== newUrl) {
332
+ spec.servers[0] = { ...(first || {}), url: newUrl };
333
+ updated = true;
334
+ }
335
+ }
336
+ else {
337
+ spec.servers = [{ url: newUrl }];
338
+ updated = true;
339
+ }
340
+ return updated;
341
+ }
342
+ function applySwagger2ServerUrl(spec, newUrl) {
343
+ let updated = false;
344
+ const parsedUrl = safeParseUrl(newUrl);
345
+ if (parsedUrl) {
346
+ const scheme = parsedUrl.protocol.replace(":", "");
347
+ const host = parsedUrl.host;
348
+ const hasPath = parsedUrl.pathname && parsedUrl.pathname !== "/";
349
+ const basePath = hasPath ? parsedUrl.pathname : spec.basePath;
350
+ if (scheme &&
351
+ (!Array.isArray(spec.schemes) || spec.schemes[0] !== scheme)) {
352
+ spec.schemes = [scheme];
353
+ updated = true;
354
+ }
355
+ if (host && spec.host !== host) {
356
+ spec.host = host;
357
+ updated = true;
358
+ }
359
+ if (hasPath && spec.basePath !== basePath) {
360
+ spec.basePath = basePath;
361
+ updated = true;
362
+ }
363
+ }
364
+ if (spec.servers) {
365
+ delete spec.servers;
366
+ updated = true;
367
+ }
368
+ return updated;
369
+ }
370
+ function safeParseUrl(rawUrl) {
371
+ try {
372
+ return new URL(rawUrl);
373
+ }
374
+ catch {
375
+ return null;
376
+ }
377
+ }
378
+ function isOpenAPIFile(filePath) {
379
+ const ext = path_1.default.extname(filePath).toLowerCase();
380
+ const filename = path_1.default.basename(filePath).toLowerCase();
381
+ // Only accept certain extensions
382
+ if (![".json", ".yaml", ".yml"].includes(ext)) {
383
+ return false;
384
+ }
385
+ // Skip common non-OpenAPI files
386
+ const skipFiles = [
387
+ "package.json",
388
+ "package-lock.json",
389
+ "tsconfig.json",
390
+ ".eslintrc.json",
391
+ "jest.config.json",
392
+ ];
393
+ if (skipFiles.includes(filename)) {
394
+ return false;
395
+ }
396
+ return true;
397
+ }
398
+ //# sourceMappingURL=openapi-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi-parser.js","sourceRoot":"","sources":["../../src/utils/openapi-parser.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "specrun",
3
+ "version": "1.0.0",
4
+ "description": "An MCP server that converts OpenAPI specifications to MCP tools - scan a folder for spec files and automatically generate corresponding tools",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "specrun": "dist/cli.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "watch": "tsc --watch",
12
+ "dev": "tsx src/cli.ts",
13
+ "dev:watch": "tsx watch src/cli.ts",
14
+ "start": "node dist/cli.js",
15
+ "test": "npm run build && node dist/cli.js --help",
16
+ "prepare": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "mcp",
20
+ "openapi",
21
+ "swagger",
22
+ "api",
23
+ "tools",
24
+ "spec",
25
+ "fastmcp",
26
+ "runner",
27
+ "generator"
28
+ ],
29
+ "author": "Pavel Piha",
30
+ "types": "dist/index.d.ts",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git@github.com:Pavel-Piha/specrun.git"
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "specs",
39
+ "README.md",
40
+ "LICENSE.md"
41
+ ],
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "dependencies": {
46
+ "@apidevtools/swagger-parser": "^12.1.0",
47
+ "axios": "^1.13.5",
48
+ "commander": "^14.0.3",
49
+ "dotenv": "^17.3.1",
50
+ "fastmcp": "^3.32.0",
51
+ "yaml": "^2.8.2",
52
+ "zod": "^4.3.6"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^25.2.3",
56
+ "tsx": "^4.21.0",
57
+ "typescript": "^5.9.3"
58
+ },
59
+ "engines": {
60
+ "node": ">=22.0.0"
61
+ }
62
+ }
package/specs/.env ADDED
@@ -0,0 +1,20 @@
1
+ # Example authentication configuration
2
+
3
+ # API Key authentication (X-API-Key header)
4
+ CARS_API_KEY=your_cars_api_key_here
5
+
6
+ # Bearer token authentication
7
+ GITHUB_TOKEN=ghp_your_github_personal_access_token
8
+ OPENAI_API_KEY=sk-your_openai_api_key
9
+
10
+ # Basic authentication (username + password)
11
+ MYAPI_USERNAME=your_username
12
+ MYAPI_PASSWORD=your_password
13
+
14
+ # SpecRun placeholders
15
+ CARS_SERVER_URL=
16
+ CARS_BEARER_TOKEN=
17
+ GITHUB_SERVER_URL=
18
+ GITHUB_BEARER_TOKEN=
19
+ OBJECTS_SERVER_URL=
20
+ OBJECTS_BEARER_TOKEN=
@@ -0,0 +1,105 @@
1
+ {
2
+ "openapi": "3.0.0",
3
+ "info": {
4
+ "title": "Cars API",
5
+ "version": "1.0.0",
6
+ "description": "A simple API for managing cars"
7
+ },
8
+ "servers": [
9
+ {
10
+ "url": "https://api-server.placeholder"
11
+ }
12
+ ],
13
+ "paths": {
14
+ "/cars/{carId}": {
15
+ "get": {
16
+ "operationId": "getCarById",
17
+ "summary": "Find car by ID",
18
+ "description": "Returns a single car",
19
+ "parameters": [
20
+ {
21
+ "name": "carId",
22
+ "in": "path",
23
+ "required": true,
24
+ "schema": {
25
+ "type": "integer",
26
+ "format": "int64"
27
+ },
28
+ "description": "ID of car to return"
29
+ }
30
+ ],
31
+ "responses": {
32
+ "200": {
33
+ "description": "successful operation"
34
+ },
35
+ "400": {
36
+ "description": "Invalid ID supplied"
37
+ },
38
+ "404": {
39
+ "description": "Car not found"
40
+ }
41
+ }
42
+ }
43
+ },
44
+ "/cars": {
45
+ "post": {
46
+ "operationId": "addCar",
47
+ "summary": "Add a new car",
48
+ "description": "Add a new car to the catalog",
49
+ "requestBody": {
50
+ "description": "Create a new car in the catalog",
51
+ "content": {
52
+ "application/json": {
53
+ "schema": {
54
+ "type": "object",
55
+ "required": ["make", "model", "year"],
56
+ "properties": {
57
+ "make": {
58
+ "type": "string",
59
+ "example": "Toyota"
60
+ },
61
+ "model": {
62
+ "type": "string",
63
+ "example": "Corolla"
64
+ },
65
+ "year": {
66
+ "type": "integer",
67
+ "format": "int32",
68
+ "example": 2022
69
+ },
70
+ "status": {
71
+ "type": "string",
72
+ "description": "car status in the catalog",
73
+ "enum": ["available", "reserved", "sold"]
74
+ }
75
+ }
76
+ }
77
+ }
78
+ },
79
+ "required": true
80
+ },
81
+ "responses": {
82
+ "200": {
83
+ "description": "Successful operation"
84
+ },
85
+ "405": {
86
+ "description": "Invalid input"
87
+ }
88
+ }
89
+ }
90
+ },
91
+ "/inventory": {
92
+ "get": {
93
+ "operationId": "getInventory",
94
+ "summary": "Returns car inventory by status",
95
+ "description": "Returns a map of status codes to quantities",
96
+ "responses": {
97
+ "200": {
98
+ "description": "successful operation"
99
+ }
100
+ }
101
+ }
102
+ }
103
+ },
104
+ "x-base-url": "https://api-server.placeholder"
105
+ }