@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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +207 -0
  3. package/dist/__tests__/generator.test.d.ts +5 -0
  4. package/dist/__tests__/generator.test.d.ts.map +1 -0
  5. package/dist/__tests__/generator.test.js +236 -0
  6. package/dist/__tests__/generator.test.js.map +1 -0
  7. package/dist/__tests__/integration.test.d.ts +5 -0
  8. package/dist/__tests__/integration.test.d.ts.map +1 -0
  9. package/dist/__tests__/integration.test.js +184 -0
  10. package/dist/__tests__/integration.test.js.map +1 -0
  11. package/dist/__tests__/mapper.test.d.ts +5 -0
  12. package/dist/__tests__/mapper.test.d.ts.map +1 -0
  13. package/dist/__tests__/mapper.test.js +250 -0
  14. package/dist/__tests__/mapper.test.js.map +1 -0
  15. package/dist/__tests__/parser.test.d.ts +5 -0
  16. package/dist/__tests__/parser.test.d.ts.map +1 -0
  17. package/dist/__tests__/parser.test.js +260 -0
  18. package/dist/__tests__/parser.test.js.map +1 -0
  19. package/dist/cli.d.ts +12 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +235 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/generator.d.ts +9 -0
  24. package/dist/generator.d.ts.map +1 -0
  25. package/dist/generator.js +595 -0
  26. package/dist/generator.js.map +1 -0
  27. package/dist/index.d.ts +10 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +9 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/mapper.d.ts +17 -0
  32. package/dist/mapper.d.ts.map +1 -0
  33. package/dist/mapper.js +79 -0
  34. package/dist/mapper.js.map +1 -0
  35. package/dist/parser.d.ts +31 -0
  36. package/dist/parser.d.ts.map +1 -0
  37. package/dist/parser.js +183 -0
  38. package/dist/parser.js.map +1 -0
  39. package/dist/types.d.ts +97 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +5 -0
  42. package/dist/types.js.map +1 -0
  43. 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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"}
@@ -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"}
@@ -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"}