@emcy/openapi-to-mcp 0.2.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 +207 -0
- package/dist/__tests__/generator.test.d.ts +5 -0
- package/dist/__tests__/generator.test.d.ts.map +1 -0
- package/dist/__tests__/generator.test.js +236 -0
- package/dist/__tests__/generator.test.js.map +1 -0
- package/dist/__tests__/integration.test.d.ts +5 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.js +184 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/__tests__/mapper.test.d.ts +5 -0
- package/dist/__tests__/mapper.test.d.ts.map +1 -0
- package/dist/__tests__/mapper.test.js +250 -0
- package/dist/__tests__/mapper.test.js.map +1 -0
- package/dist/__tests__/parser.test.d.ts +5 -0
- package/dist/__tests__/parser.test.d.ts.map +1 -0
- package/dist/__tests__/parser.test.js +260 -0
- package/dist/__tests__/parser.test.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +235 -0
- package/dist/cli.js.map +1 -0
- package/dist/generator.d.ts +9 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +595 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mapper.d.ts +17 -0
- package/dist/mapper.d.ts.map +1 -0
- package/dist/mapper.js +79 -0
- package/dist/mapper.js.map +1 -0
- package/dist/parser.d.ts +31 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +183 -0
- package/dist/parser.js.map +1 -0
- package/dist/types.d.ts +97 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Generator - Generates MCP server code from tool definitions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Generate a complete MCP server from tool definitions
|
|
6
|
+
*/
|
|
7
|
+
export function generateMcpServer(tools, options, securitySchemes = {}) {
|
|
8
|
+
const files = {};
|
|
9
|
+
files["package.json"] = generatePackageJson(options);
|
|
10
|
+
files["tsconfig.json"] = generateTsConfig();
|
|
11
|
+
files["src/index.ts"] = generateServerEntry(tools, options, securitySchemes);
|
|
12
|
+
files["src/transport.ts"] = generateTransport();
|
|
13
|
+
files[".env.example"] = generateEnvExample(tools, securitySchemes);
|
|
14
|
+
files["README.md"] = generateReadme(options);
|
|
15
|
+
return files;
|
|
16
|
+
}
|
|
17
|
+
function generatePackageJson(options) {
|
|
18
|
+
const pkg = {
|
|
19
|
+
name: options.name,
|
|
20
|
+
version: options.version || "1.0.0",
|
|
21
|
+
description: `MCP Server generated from OpenAPI spec`,
|
|
22
|
+
type: "module",
|
|
23
|
+
main: "build/index.js",
|
|
24
|
+
scripts: {
|
|
25
|
+
build: "tsc",
|
|
26
|
+
start: "node build/index.js",
|
|
27
|
+
"start:http": "node build/index.js --transport=streamable-http",
|
|
28
|
+
dev: "tsc --watch",
|
|
29
|
+
},
|
|
30
|
+
dependencies: {
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.10.0",
|
|
32
|
+
axios: "^1.9.0",
|
|
33
|
+
dotenv: "^16.4.5",
|
|
34
|
+
hono: "^4.7.7",
|
|
35
|
+
"@hono/node-server": "^1.14.1",
|
|
36
|
+
...(options.emcyEnabled
|
|
37
|
+
? {
|
|
38
|
+
"@emcy/sdk": options.localSdkPath
|
|
39
|
+
? `file:${options.localSdkPath}`
|
|
40
|
+
: "^0.1.0",
|
|
41
|
+
}
|
|
42
|
+
: {}),
|
|
43
|
+
},
|
|
44
|
+
devDependencies: {
|
|
45
|
+
"@types/node": "^22.15.2",
|
|
46
|
+
typescript: "^5.8.3",
|
|
47
|
+
},
|
|
48
|
+
engines: {
|
|
49
|
+
node: ">=20.0.0",
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
return JSON.stringify(pkg, null, 2);
|
|
53
|
+
}
|
|
54
|
+
function generateTsConfig() {
|
|
55
|
+
const config = {
|
|
56
|
+
compilerOptions: {
|
|
57
|
+
target: "ES2022",
|
|
58
|
+
module: "NodeNext",
|
|
59
|
+
moduleResolution: "NodeNext",
|
|
60
|
+
lib: ["ES2022"],
|
|
61
|
+
outDir: "./build",
|
|
62
|
+
rootDir: "./src",
|
|
63
|
+
strict: true,
|
|
64
|
+
esModuleInterop: true,
|
|
65
|
+
skipLibCheck: true,
|
|
66
|
+
forceConsistentCasingInFileNames: true,
|
|
67
|
+
declaration: true,
|
|
68
|
+
sourceMap: true,
|
|
69
|
+
},
|
|
70
|
+
include: ["src/**/*"],
|
|
71
|
+
exclude: ["node_modules", "build"],
|
|
72
|
+
};
|
|
73
|
+
return JSON.stringify(config, null, 2);
|
|
74
|
+
}
|
|
75
|
+
function generateServerEntry(tools, options, securitySchemes) {
|
|
76
|
+
const toolDefinitions = tools
|
|
77
|
+
.map((tool) => {
|
|
78
|
+
return ` ["${tool.name}", {
|
|
79
|
+
name: "${tool.name}",
|
|
80
|
+
description: ${JSON.stringify(tool.description)},
|
|
81
|
+
inputSchema: ${JSON.stringify(tool.inputSchema)},
|
|
82
|
+
method: "${tool.httpMethod}",
|
|
83
|
+
pathTemplate: "${tool.pathTemplate}",
|
|
84
|
+
parameters: ${JSON.stringify(tool.parameters)},
|
|
85
|
+
requestBodyContentType: ${tool.requestBodyContentType
|
|
86
|
+
? `"${tool.requestBodyContentType}"`
|
|
87
|
+
: "undefined"},
|
|
88
|
+
securitySchemes: ${JSON.stringify(tool.securitySchemes)},
|
|
89
|
+
}]`;
|
|
90
|
+
})
|
|
91
|
+
.join(",\n");
|
|
92
|
+
const emcyImport = options.emcyEnabled
|
|
93
|
+
? `import { EmcyTelemetry } from '@emcy/sdk';\n`
|
|
94
|
+
: "";
|
|
95
|
+
const emcyInit = options.emcyEnabled
|
|
96
|
+
? `
|
|
97
|
+
// Initialize Emcy telemetry if API key is provided
|
|
98
|
+
const emcy = process.env.EMCY_API_KEY
|
|
99
|
+
? new EmcyTelemetry({
|
|
100
|
+
apiKey: process.env.EMCY_API_KEY,
|
|
101
|
+
endpoint: process.env.EMCY_TELEMETRY_URL,
|
|
102
|
+
mcpServerId: process.env.EMCY_MCP_SERVER_ID,
|
|
103
|
+
debug: process.env.EMCY_DEBUG === 'true',
|
|
104
|
+
})
|
|
105
|
+
: null;
|
|
106
|
+
|
|
107
|
+
// Set server info for telemetry metadata
|
|
108
|
+
if (emcy) {
|
|
109
|
+
emcy.setServerInfo(SERVER_NAME, SERVER_VERSION);
|
|
110
|
+
}
|
|
111
|
+
`
|
|
112
|
+
: "";
|
|
113
|
+
const emcyTrace = options.emcyEnabled
|
|
114
|
+
? `
|
|
115
|
+
// Wrap with Emcy telemetry if enabled
|
|
116
|
+
if (emcy) {
|
|
117
|
+
return emcy.trace(toolName, async () => executeRequest(toolDefinition, toolArgs ?? {}));
|
|
118
|
+
}
|
|
119
|
+
`
|
|
120
|
+
: "";
|
|
121
|
+
return `#!/usr/bin/env node
|
|
122
|
+
/**
|
|
123
|
+
* MCP Server: ${options.name}
|
|
124
|
+
* Generated by Emcy OpenAPI-to-MCP Generator
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
import dotenv from 'dotenv';
|
|
128
|
+
dotenv.config();
|
|
129
|
+
|
|
130
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
131
|
+
import {
|
|
132
|
+
CallToolRequestSchema,
|
|
133
|
+
ListToolsRequestSchema,
|
|
134
|
+
type Tool,
|
|
135
|
+
type CallToolResult,
|
|
136
|
+
type CallToolRequest
|
|
137
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
138
|
+
import axios, { type AxiosRequestConfig, type AxiosError } from 'axios';
|
|
139
|
+
import { setupStreamableHttpServer } from "./transport.js";
|
|
140
|
+
${emcyImport}
|
|
141
|
+
// Configuration
|
|
142
|
+
export const SERVER_NAME = "${options.name}";
|
|
143
|
+
export const SERVER_VERSION = "${options.version || "1.0.0"}";
|
|
144
|
+
export const API_BASE_URL = process.env.API_BASE_URL || "${options.baseUrl}";
|
|
145
|
+
|
|
146
|
+
// Tool definition interface
|
|
147
|
+
interface McpToolDefinition {
|
|
148
|
+
name: string;
|
|
149
|
+
description: string;
|
|
150
|
+
inputSchema: Record<string, unknown>;
|
|
151
|
+
method: string;
|
|
152
|
+
pathTemplate: string;
|
|
153
|
+
parameters: { name: string; in: string; required: boolean }[];
|
|
154
|
+
requestBodyContentType?: string;
|
|
155
|
+
securitySchemes: string[];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Security schemes
|
|
159
|
+
const securitySchemes: Record<string, unknown> = ${JSON.stringify(securitySchemes, null, 2)};
|
|
160
|
+
${emcyInit}
|
|
161
|
+
// Tool definitions
|
|
162
|
+
const toolDefinitionMap: Map<string, McpToolDefinition> = new Map([
|
|
163
|
+
${toolDefinitions}
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
// Create MCP server
|
|
167
|
+
const server = new Server(
|
|
168
|
+
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
169
|
+
{ capabilities: { tools: {} } }
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
// List tools handler
|
|
173
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
174
|
+
const toolsForClient: Tool[] = Array.from(toolDefinitionMap.values()).map(def => ({
|
|
175
|
+
name: def.name,
|
|
176
|
+
description: def.description,
|
|
177
|
+
inputSchema: def.inputSchema as Tool['inputSchema'],
|
|
178
|
+
}));
|
|
179
|
+
return { tools: toolsForClient };
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Call tool handler
|
|
183
|
+
server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest): Promise<CallToolResult> => {
|
|
184
|
+
const { name: toolName, arguments: toolArgs } = request.params;
|
|
185
|
+
const toolDefinition = toolDefinitionMap.get(toolName);
|
|
186
|
+
|
|
187
|
+
if (!toolDefinition) {
|
|
188
|
+
return { content: [{ type: "text", text: \`Error: Unknown tool: \${toolName}\` }] };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
${emcyTrace}
|
|
193
|
+
return await executeRequest(toolDefinition, toolArgs ?? {});
|
|
194
|
+
} catch (error) {
|
|
195
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
196
|
+
return { content: [{ type: "text", text: \`Error: \${message}\` }] };
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Execute API request
|
|
201
|
+
async function executeRequest(
|
|
202
|
+
def: McpToolDefinition,
|
|
203
|
+
args: Record<string, unknown>
|
|
204
|
+
): Promise<CallToolResult> {
|
|
205
|
+
let url = def.pathTemplate;
|
|
206
|
+
const queryParams: Record<string, unknown> = {};
|
|
207
|
+
const headers: Record<string, string> = { 'Accept': 'application/json' };
|
|
208
|
+
|
|
209
|
+
// Apply path and query parameters
|
|
210
|
+
for (const param of def.parameters) {
|
|
211
|
+
const value = args[param.name];
|
|
212
|
+
if (value !== undefined && value !== null) {
|
|
213
|
+
if (param.in === 'path') {
|
|
214
|
+
url = url.replace(\`{\${param.name}}\`, encodeURIComponent(String(value)));
|
|
215
|
+
} else if (param.in === 'query') {
|
|
216
|
+
queryParams[param.name] = value;
|
|
217
|
+
} else if (param.in === 'header') {
|
|
218
|
+
headers[param.name.toLowerCase()] = String(value);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Apply security (API key, Bearer token)
|
|
224
|
+
applySecurityHeaders(headers, def.securitySchemes);
|
|
225
|
+
|
|
226
|
+
// Build request config
|
|
227
|
+
const config: AxiosRequestConfig = {
|
|
228
|
+
method: def.method,
|
|
229
|
+
url: \`\${API_BASE_URL}\${url}\`,
|
|
230
|
+
params: queryParams,
|
|
231
|
+
headers,
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// Add request body if present
|
|
235
|
+
if (def.requestBodyContentType && args.requestBody !== undefined) {
|
|
236
|
+
config.data = args.requestBody;
|
|
237
|
+
headers['content-type'] = def.requestBodyContentType;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.error(\`Executing: \${def.method.toUpperCase()} \${config.url}\`);
|
|
241
|
+
|
|
242
|
+
const response = await axios(config);
|
|
243
|
+
|
|
244
|
+
let responseText: string;
|
|
245
|
+
if (typeof response.data === 'object') {
|
|
246
|
+
responseText = JSON.stringify(response.data, null, 2);
|
|
247
|
+
} else {
|
|
248
|
+
responseText = String(response.data ?? '');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
content: [{ type: "text", text: \`Status: \${response.status}\\n\\n\${responseText}\` }]
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Apply security headers based on environment variables
|
|
257
|
+
function applySecurityHeaders(headers: Record<string, string>, schemeNames: string[]) {
|
|
258
|
+
for (const schemeName of schemeNames) {
|
|
259
|
+
const scheme = securitySchemes[schemeName] as Record<string, unknown> | undefined;
|
|
260
|
+
if (!scheme) continue;
|
|
261
|
+
|
|
262
|
+
const envKey = schemeName.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase();
|
|
263
|
+
|
|
264
|
+
if (scheme.type === 'apiKey') {
|
|
265
|
+
const apiKey = process.env[\`API_KEY_\${envKey}\`];
|
|
266
|
+
if (apiKey && scheme.in === 'header' && typeof scheme.name === 'string') {
|
|
267
|
+
headers[scheme.name.toLowerCase()] = apiKey;
|
|
268
|
+
}
|
|
269
|
+
} else if (scheme.type === 'http' && scheme.scheme === 'bearer') {
|
|
270
|
+
const token = process.env[\`BEARER_TOKEN_\${envKey}\`];
|
|
271
|
+
if (token) {
|
|
272
|
+
headers['authorization'] = \`Bearer \${token}\`;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Main
|
|
279
|
+
async function main() {
|
|
280
|
+
const args = process.argv.slice(2);
|
|
281
|
+
const useHttp = args.includes('--transport=streamable-http');
|
|
282
|
+
|
|
283
|
+
if (useHttp) {
|
|
284
|
+
const port = parseInt(process.env.PORT || '3000', 10);
|
|
285
|
+
await setupStreamableHttpServer(server, port);
|
|
286
|
+
} else {
|
|
287
|
+
// Stdio transport for Claude Desktop, etc.
|
|
288
|
+
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
289
|
+
const transport = new StdioServerTransport();
|
|
290
|
+
await server.connect(transport);
|
|
291
|
+
console.error(\`\${SERVER_NAME} running on stdio\`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
main().catch(console.error);
|
|
296
|
+
`;
|
|
297
|
+
}
|
|
298
|
+
function generateTransport() {
|
|
299
|
+
return `/**
|
|
300
|
+
* HTTP Transport for MCP
|
|
301
|
+
* Uses Streamable HTTP transport (MCP specification 2025-03-26)
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
import { Hono } from 'hono';
|
|
305
|
+
import { cors } from 'hono/cors';
|
|
306
|
+
import { serve } from '@hono/node-server';
|
|
307
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
308
|
+
import { SERVER_NAME, SERVER_VERSION } from './index.js';
|
|
309
|
+
|
|
310
|
+
const { WebStandardStreamableHTTPServerTransport } = await import(
|
|
311
|
+
"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js"
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
const transports: Map<string, InstanceType<typeof WebStandardStreamableHTTPServerTransport>> = new Map();
|
|
315
|
+
|
|
316
|
+
export async function setupStreamableHttpServer(mcpServer: Server, port = 3000) {
|
|
317
|
+
const app = new Hono();
|
|
318
|
+
|
|
319
|
+
// CORS configuration for browser/client access
|
|
320
|
+
app.use('*', cors({
|
|
321
|
+
origin: '*',
|
|
322
|
+
allowMethods: ['GET', 'POST', 'DELETE', 'OPTIONS'],
|
|
323
|
+
allowHeaders: ['Content-Type', 'Accept', 'mcp-session-id', 'Last-Event-ID'],
|
|
324
|
+
exposeHeaders: ['mcp-session-id'],
|
|
325
|
+
}));
|
|
326
|
+
|
|
327
|
+
// Health check endpoint
|
|
328
|
+
app.get('/health', (c) => {
|
|
329
|
+
return c.json({
|
|
330
|
+
status: 'OK',
|
|
331
|
+
server: SERVER_NAME,
|
|
332
|
+
version: SERVER_VERSION,
|
|
333
|
+
mcp: {
|
|
334
|
+
transport: 'streamable-http',
|
|
335
|
+
endpoints: {
|
|
336
|
+
mcp: '/mcp',
|
|
337
|
+
health: '/health'
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Streamable HTTP Transport (MCP spec 2025-03-26)
|
|
344
|
+
// Supports ChatGPT, Cursor, and other modern MCP clients
|
|
345
|
+
app.all("/mcp", async (c) => {
|
|
346
|
+
const sessionId = c.req.header('mcp-session-id');
|
|
347
|
+
|
|
348
|
+
// Existing session
|
|
349
|
+
if (sessionId && transports.has(sessionId)) {
|
|
350
|
+
return transports.get(sessionId)!.handleRequest(c.req.raw);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// New session - create transport
|
|
354
|
+
if (!sessionId) {
|
|
355
|
+
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
356
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
357
|
+
onsessioninitialized: (newSessionId: string) => {
|
|
358
|
+
transports.set(newSessionId, transport);
|
|
359
|
+
console.error(\`New MCP session: \${newSessionId}\`);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
transport.onerror = (err: Error) => console.error('Transport error:', err);
|
|
364
|
+
transport.onclose = () => {
|
|
365
|
+
const sid = transport.sessionId;
|
|
366
|
+
if (sid) {
|
|
367
|
+
transports.delete(sid);
|
|
368
|
+
console.error(\`Session closed: \${sid}\`);
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
await mcpServer.connect(transport);
|
|
373
|
+
return transport.handleRequest(c.req.raw);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Session not found
|
|
377
|
+
return c.json({
|
|
378
|
+
error: 'Session not found',
|
|
379
|
+
message: 'The specified session ID does not exist. Start a new session by omitting the mcp-session-id header.'
|
|
380
|
+
}, 404);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// Legacy /sse endpoint - redirect to /mcp with guidance
|
|
384
|
+
app.get("/sse", (c) => {
|
|
385
|
+
return c.json({
|
|
386
|
+
error: 'SSE transport deprecated',
|
|
387
|
+
message: 'The SSE transport was deprecated in MCP specification 2025-03-26. Please use the Streamable HTTP transport at /mcp instead.',
|
|
388
|
+
redirect: '/mcp'
|
|
389
|
+
}, 410);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
serve({ fetch: app.fetch, port }, (info) => {
|
|
393
|
+
console.error('');
|
|
394
|
+
console.error(\`╔═══════════════════════════════════════════════════════════════╗\`);
|
|
395
|
+
console.error(\`║ MCP Server: \${SERVER_NAME.padEnd(46)} ║\`);
|
|
396
|
+
console.error(\`╠═══════════════════════════════════════════════════════════════╣\`);
|
|
397
|
+
console.error(\`║ Status: Running ║\`);
|
|
398
|
+
console.error(\`║ Port: \${String(info.port).padEnd(53)} ║\`);
|
|
399
|
+
console.error(\`╠═══════════════════════════════════════════════════════════════╣\`);
|
|
400
|
+
console.error(\`║ Endpoints: ║\`);
|
|
401
|
+
console.error(\`║ MCP: http://localhost:\${info.port}/mcp\`.padEnd(64) + \`║\`);
|
|
402
|
+
console.error(\`║ Health: http://localhost:\${info.port}/health\`.padEnd(64) + \`║\`);
|
|
403
|
+
console.error(\`╠═══════════════════════════════════════════════════════════════╣\`);
|
|
404
|
+
console.error(\`║ For AI Clients: ║\`);
|
|
405
|
+
console.error(\`║ ChatGPT/Cursor URL: http://localhost:\${info.port}/mcp\`.padEnd(64) + \`║\`);
|
|
406
|
+
console.error(\`║ Claude Desktop: Use stdio transport (npm start) ║\`);
|
|
407
|
+
console.error(\`╚═══════════════════════════════════════════════════════════════╝\`);
|
|
408
|
+
console.error('');
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
return app;
|
|
412
|
+
}
|
|
413
|
+
`;
|
|
414
|
+
}
|
|
415
|
+
function generateEnvExample(tools, securitySchemes) {
|
|
416
|
+
const lines = [
|
|
417
|
+
"# API Configuration",
|
|
418
|
+
"API_BASE_URL=http://localhost:5001",
|
|
419
|
+
"",
|
|
420
|
+
"# Emcy Telemetry (optional)",
|
|
421
|
+
"# Set these to enable telemetry to Emcy platform",
|
|
422
|
+
"# EMCY_API_KEY=your-api-key-from-emcy-dashboard",
|
|
423
|
+
"# EMCY_TELEMETRY_URL=http://localhost:5140/api/v1/telemetry",
|
|
424
|
+
"# EMCY_MCP_SERVER_ID=mcp_xxxxxxxxxxxx",
|
|
425
|
+
"# EMCY_DEBUG=false",
|
|
426
|
+
"",
|
|
427
|
+
"# Server Port (for HTTP transport)",
|
|
428
|
+
"PORT=3000",
|
|
429
|
+
];
|
|
430
|
+
// Collect unique security schemes used by tools
|
|
431
|
+
const usedSchemes = new Set();
|
|
432
|
+
for (const tool of tools) {
|
|
433
|
+
for (const scheme of tool.securitySchemes) {
|
|
434
|
+
usedSchemes.add(scheme);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (usedSchemes.size > 0) {
|
|
438
|
+
lines.push("", "# Security Credentials");
|
|
439
|
+
for (const schemeName of usedSchemes) {
|
|
440
|
+
const scheme = securitySchemes[schemeName];
|
|
441
|
+
const envKey = schemeName.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase();
|
|
442
|
+
if (scheme?.type === "apiKey") {
|
|
443
|
+
lines.push(`API_KEY_${envKey}=your-api-key`);
|
|
444
|
+
}
|
|
445
|
+
else if (scheme?.type === "http" && scheme.scheme === "bearer") {
|
|
446
|
+
lines.push(`BEARER_TOKEN_${envKey}=your-bearer-token`);
|
|
447
|
+
}
|
|
448
|
+
else if (scheme?.type === "oauth2") {
|
|
449
|
+
lines.push(`OAUTH_CLIENT_ID_${envKey}=your-client-id`);
|
|
450
|
+
lines.push(`OAUTH_CLIENT_SECRET_${envKey}=your-client-secret`);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return lines.join("\n");
|
|
455
|
+
}
|
|
456
|
+
function generateReadme(options) {
|
|
457
|
+
return `# ${options.name}
|
|
458
|
+
|
|
459
|
+
MCP Server generated from OpenAPI specification by [Emcy](https://emcy.dev).
|
|
460
|
+
|
|
461
|
+
## Quick Start
|
|
462
|
+
|
|
463
|
+
\`\`\`bash
|
|
464
|
+
# Install dependencies
|
|
465
|
+
npm install
|
|
466
|
+
|
|
467
|
+
# Build
|
|
468
|
+
npm run build
|
|
469
|
+
|
|
470
|
+
# Run with HTTP transport (for ChatGPT, Cursor, web clients)
|
|
471
|
+
npm run start:http
|
|
472
|
+
|
|
473
|
+
# Or run with stdio transport (for Claude Desktop)
|
|
474
|
+
npm start
|
|
475
|
+
\`\`\`
|
|
476
|
+
|
|
477
|
+
## Configuration
|
|
478
|
+
|
|
479
|
+
Copy \`.env.example\` to \`.env\` and configure:
|
|
480
|
+
|
|
481
|
+
- \`API_BASE_URL\`: Base URL of the API (default: ${options.baseUrl})
|
|
482
|
+
- \`PORT\`: Server port for HTTP transport (default: 3000)
|
|
483
|
+
- Security credentials as needed
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## 🤖 AI Client Configuration
|
|
488
|
+
|
|
489
|
+
### ChatGPT (OpenAI)
|
|
490
|
+
|
|
491
|
+
ChatGPT supports MCP servers via Developer Mode. Use the Streamable HTTP transport:
|
|
492
|
+
|
|
493
|
+
1. Start the server with HTTP transport:
|
|
494
|
+
\`\`\`bash
|
|
495
|
+
npm run start:http
|
|
496
|
+
\`\`\`
|
|
497
|
+
|
|
498
|
+
2. In ChatGPT Developer Mode, add your MCP server:
|
|
499
|
+
- **URL**: \`http://your-server-url:3000/mcp\`
|
|
500
|
+
- For local development, you'll need to expose via a tunnel (ngrok, cloudflare tunnel, etc.)
|
|
501
|
+
|
|
502
|
+
### Cursor IDE
|
|
503
|
+
|
|
504
|
+
Cursor supports both HTTP and stdio transports:
|
|
505
|
+
|
|
506
|
+
**Option A: HTTP Transport (Recommended)**
|
|
507
|
+
|
|
508
|
+
Add to your project's \`.cursor/mcp.json\`:
|
|
509
|
+
|
|
510
|
+
\`\`\`json
|
|
511
|
+
{
|
|
512
|
+
"mcpServers": {
|
|
513
|
+
"${options.name}": {
|
|
514
|
+
"url": "http://localhost:3000/mcp"
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
\`\`\`
|
|
519
|
+
|
|
520
|
+
Then start the server: \`npm run start:http\`
|
|
521
|
+
|
|
522
|
+
**Option B: Stdio Transport**
|
|
523
|
+
|
|
524
|
+
Add to your project's \`.cursor/mcp.json\`:
|
|
525
|
+
|
|
526
|
+
\`\`\`json
|
|
527
|
+
{
|
|
528
|
+
"mcpServers": {
|
|
529
|
+
"${options.name}": {
|
|
530
|
+
"command": "node",
|
|
531
|
+
"args": ["<absolute-path-to>/build/index.js"]
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
\`\`\`
|
|
536
|
+
|
|
537
|
+
Restart Cursor after adding the configuration.
|
|
538
|
+
|
|
539
|
+
### Claude Desktop
|
|
540
|
+
|
|
541
|
+
Claude Desktop uses stdio transport:
|
|
542
|
+
|
|
543
|
+
Add to your Claude Desktop config (\`~/Library/Application Support/Claude/claude_desktop_config.json\` on macOS):
|
|
544
|
+
|
|
545
|
+
\`\`\`json
|
|
546
|
+
{
|
|
547
|
+
"mcpServers": {
|
|
548
|
+
"${options.name}": {
|
|
549
|
+
"command": "node",
|
|
550
|
+
"args": ["<absolute-path-to>/build/index.js"]
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
\`\`\`
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## Transport Endpoints
|
|
559
|
+
|
|
560
|
+
When running with HTTP transport (\`npm run start:http\`):
|
|
561
|
+
|
|
562
|
+
| Endpoint | Transport | Description |
|
|
563
|
+
|----------|-----------|-------------|
|
|
564
|
+
| \`/mcp\` | Streamable HTTP | Modern transport (MCP spec 2025-03-26). **Recommended.** |
|
|
565
|
+
| \`/sse\` | Server-Sent Events | Legacy transport for older clients. |
|
|
566
|
+
| \`/health\` | - | Health check endpoint. |
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
## Troubleshooting
|
|
571
|
+
|
|
572
|
+
### "No Resources Found" in Cursor
|
|
573
|
+
|
|
574
|
+
1. Make sure the server is running: \`npm run start:http\`
|
|
575
|
+
2. Check the health endpoint: \`curl http://localhost:3000/health\`
|
|
576
|
+
3. Verify your \`mcp.json\` path is correct
|
|
577
|
+
4. Restart Cursor after configuration changes
|
|
578
|
+
5. Try using stdio transport instead of HTTP
|
|
579
|
+
|
|
580
|
+
### Connection Errors
|
|
581
|
+
|
|
582
|
+
1. Ensure the API base URL is correct in \`.env\`
|
|
583
|
+
2. Check that required API keys are set in \`.env\`
|
|
584
|
+
3. Verify the target API is accessible from your machine
|
|
585
|
+
|
|
586
|
+
### TypeScript Build Errors
|
|
587
|
+
|
|
588
|
+
\`\`\`bash
|
|
589
|
+
# Clean and rebuild
|
|
590
|
+
rm -rf build/
|
|
591
|
+
npm run build
|
|
592
|
+
\`\`\`
|
|
593
|
+
`;
|
|
594
|
+
}
|
|
595
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emcy OpenAPI to MCP Generator
|
|
3
|
+
*
|
|
4
|
+
* Converts OpenAPI specifications to MCP servers with optional Emcy telemetry.
|
|
5
|
+
*/
|
|
6
|
+
export { parseOpenAPI, validateOpenAPI, generateOperationId } from './parser.js';
|
|
7
|
+
export { mapToMcpTools, getEndpointKey, getAllEndpointKeys } from './mapper.js';
|
|
8
|
+
export { generateMcpServer } from './generator.js';
|
|
9
|
+
export type { OpenAPIEndpoint, ParsedOpenAPI, McpToolDefinition, GeneratorOptions, GeneratedFiles, EndpointParameter, SecurityScheme, } from './types.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,YAAY,EACV,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,cAAc,GACf,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emcy OpenAPI to MCP Generator
|
|
3
|
+
*
|
|
4
|
+
* Converts OpenAPI specifications to MCP servers with optional Emcy telemetry.
|
|
5
|
+
*/
|
|
6
|
+
export { parseOpenAPI, validateOpenAPI, generateOperationId } from './parser.js';
|
|
7
|
+
export { mapToMcpTools, getEndpointKey, getAllEndpointKeys } from './mapper.js';
|
|
8
|
+
export { generateMcpServer } from './generator.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/mapper.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Mapper - Maps OpenAPI endpoints to MCP tool definitions
|
|
3
|
+
*/
|
|
4
|
+
import type { OpenAPIEndpoint, McpToolDefinition } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Map OpenAPI endpoints to MCP tool definitions
|
|
7
|
+
*/
|
|
8
|
+
export declare function mapToMcpTools(endpoints: OpenAPIEndpoint[], enabledPaths?: Set<string>): McpToolDefinition[];
|
|
9
|
+
/**
|
|
10
|
+
* Generate a unique key for an endpoint
|
|
11
|
+
*/
|
|
12
|
+
export declare function getEndpointKey(endpoint: OpenAPIEndpoint): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get all endpoint keys from a list of endpoints
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAllEndpointKeys(endpoints: OpenAPIEndpoint[]): string[];
|
|
17
|
+
//# sourceMappingURL=mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAGlB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,eAAe,EAAE,EAC5B,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GACzB,iBAAiB,EAAE,CAQrB;AAgED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAEhE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,MAAM,EAAE,CAEzE"}
|