diff --git a/README.md b/README.md index 7ba4323..a88360b 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ This CLI tool automates the generation of MCP-compatible servers that proxy requ - ๐Ÿ”Œ **Multiple Transports**: Communicate over stdio, SSE via Hono, or StreamableHTTP. - ๐Ÿงฐ **Project Scaffold**: Generates a complete Node.js project with `tsconfig.json`, `package.json`, and entry point. - ๐Ÿงช **Built-in HTML Test Clients**: Test API interactions visually in your browser (for web-based transports). +- ๐Ÿ“Š **Analytics & Telemetry**: Optional MCPcat analytics and OpenTelemetry support for monitoring and debugging. --- @@ -44,6 +45,15 @@ openapi-mcp-generator --input path/to/openapi.json --output path/to/output/dir - # Generate an MCP StreamableHTTP server openapi-mcp-generator --input path/to/openapi.json --output path/to/output/dir --transport=streamable-http --port=3000 + +# Generate with MCPcat analytics enabled +openapi-mcp-generator --input path/to/openapi.json --output path/to/output/dir --with-mcpcat + +# Generate with OpenTelemetry tracing enabled +openapi-mcp-generator --input path/to/openapi.json --output path/to/output/dir --with-otel + +# Generate with both MCPcat analytics and OpenTelemetry +openapi-mcp-generator --input path/to/openapi.json --output path/to/output/dir --with-mcpcat --with-otel ``` ### CLI Options @@ -58,6 +68,8 @@ openapi-mcp-generator --input path/to/openapi.json --output path/to/output/dir - | `--transport` | `-t` | Transport mode: `"stdio"` (default), `"web"`, or `"streamable-http"` | `"stdio"` | | `--port` | `-p` | Port for web-based transports | `3000` | | `--default-include` | | Default behavior for x-mcp filtering. Accepts `true` or `false` (case-insensitive). `true` = include by default, `false` = exclude by default. | `true` | +| `--with-mcpcat` | | Enable MCPcat product analytics for usage insights and debugging | `false` | +| `--with-otel` | | Enable OpenTelemetry (OTLP) exporters for distributed tracing and logging | `false` | | `--force` | | Overwrite existing files in the output directory without confirmation | `false` | ## ๐Ÿ“ฆ Programmatic API @@ -168,6 +180,43 @@ Configure auth credentials in your environment: --- +## ๐Ÿ“Š Analytics & Telemetry + +### MCPcat Analytics +[MCPcat](https://mcpcat.io) provides product analytics and live debugging tools specifically designed for MCP servers. When enabled with `--with-mcpcat`, your generated server will include: + +- Usage tracking and analytics +- Tool call monitoring +- Error detection and reporting +- Performance insights + +To use MCPcat: +1. Sign up for free at [mcpcat.io](https://mcpcat.io) +2. Get your project ID +3. Set the `MCPCAT_PROJECT_ID` environment variable + +### OpenTelemetry Support +Enable distributed tracing and logging with `--with-otel` to integrate with your existing observability stack: + +- OTLP trace exporters +- Distributed request tracing +- Performance metrics +- Integration with popular observability platforms (Datadog, New Relic, Grafana, etc.) + +Configure the OTLP endpoint with the `OTLP_ENDPOINT` environment variable. + +### Combined Usage +Use both flags together (`--with-mcpcat --with-otel`) to get the benefits of both MCPcat's MCP-specific analytics and OpenTelemetry's broader observability ecosystem. + +#### Environment Variables +Configure analytics and telemetry: + +| Variable | Description | Required When | +| -------------------- | -------------------------------------------------------- | ------------------ | +| `MCPCAT_PROJECT_ID` | Your MCPcat project ID from [mcpcat.io](https://mcpcat.io) | `--with-mcpcat` | +| `OTLP_ENDPOINT` | OpenTelemetry collector endpoint URL | `--with-otel` | + + ## ๐Ÿ”Ž Filtering Endpoints with OpenAPI Extensions You can control which operations are exposed as MCP tools using a vendor extension flag `x-mcp`. This extension is supported at the root, path, and operation levels. By default, endpoints are included unless explicitly excluded. diff --git a/src/generator/env-file.ts b/src/generator/env-file.ts index d1cc591..ca2f552 100644 --- a/src/generator/env-file.ts +++ b/src/generator/env-file.ts @@ -3,15 +3,18 @@ */ import { OpenAPIV3 } from 'openapi-types'; import { getEnvVarName } from '../utils/security.js'; +import { CliOptions } from '../types/index.js'; /** * Generates the content of .env.example file for the MCP server * * @param securitySchemes Security schemes from the OpenAPI spec + * @param options CLI options * @returns Content for .env.example file */ export function generateEnvExample( - securitySchemes?: OpenAPIV3.ComponentsObject['securitySchemes'] + securitySchemes?: OpenAPIV3.ComponentsObject['securitySchemes'], + options?: CliOptions ): string { let content = `# MCP Server Environment Variables # Copy this file to .env and fill in the values @@ -57,6 +60,19 @@ LOG_LEVEL=info content += `# No API authentication required\n`; } + // Add MCPcat environment variables if enabled + if (options?.withMcpcat) { + content += `\n# MCPcat -- MCP product analytics and live debugging tools`; + content += `\n# Sign up and get your project ID for free at https://mcpcat.io\n`; + content += `MCPCAT_PROJECT_ID=proj_0000000 # Replace with your MCPcat project ID\n`; + } + + // Add OpenTelemetry environment variables if enabled + if (options?.withOtel) { + content += `\n# OpenTelemetry Configuration for logging and traces\n`; + content += `OTLP_ENDPOINT=http://localhost:4318/v1/traces # OTLP collector endpoint\n`; + } + content += `\n# Add any other environment variables your API might need\n`; return content; diff --git a/src/generator/package-json.ts b/src/generator/package-json.ts index ef97985..91ae28c 100644 --- a/src/generator/package-json.ts +++ b/src/generator/package-json.ts @@ -1,17 +1,21 @@ +import { CliOptions } from '../types/index.js'; + /** * Generates the content of package.json for the MCP server * * @param serverName Server name * @param serverVersion Server version - * @param transportType Type of transport to use (stdio, web, or streamable-http) + * @param options CLI options * @returns JSON string for package.json */ export function generatePackageJson( serverName: string, serverVersion: string, - transportType: string = 'stdio' + options: CliOptions ): string { + const transportType = options.transport || 'stdio'; const includeWebDeps = transportType === 'web' || transportType === 'streamable-http'; + const includeMcpcat = options.withMcpcat || options.withOtel; const packageData: any = { name: serverName, @@ -36,6 +40,7 @@ export function generatePackageJson( dotenv: '^16.4.5', zod: '^3.24.3', 'json-schema-to-zod': '^2.6.1', + ...(includeMcpcat ? { mcpcat: '^0.1.5' } : {}), }, devDependencies: { '@types/node': '^22.15.2', diff --git a/src/generator/server-code.ts b/src/generator/server-code.ts index 6b6a447..18a0408 100644 --- a/src/generator/server-code.ts +++ b/src/generator/server-code.ts @@ -9,6 +9,46 @@ import { } from '../utils/code-gen.js'; import { generateExecuteApiToolFunction } from '../utils/security.js'; +/** + * Generates MCPcat tracking code based on options + */ +function generateMcpcatTracking(options: CliOptions): string { + if (!options.withMcpcat && !options.withOtel) { + return ''; + } + + let trackingCode = '\n// MCPcat Product analytics and OpenTelemetry exporters\n'; + + if (options.withMcpcat && options.withOtel) { + // Both flags enabled + trackingCode += `mcpcat.track(server, process.env.MCPCAT_PROJECT_ID || null, { + exporters: { + otlp: { + type: "otlp", + endpoint: process.env.OTLP_ENDPOINT || "http://localhost:4318/v1/traces" + } + } +});`; + } else if (options.withMcpcat) { + // Only MCPcat enabled + trackingCode += `mcpcat.track(server, process.env.MCPCAT_PROJECT_ID || null);`; + } else if (options.withOtel) { + // Only OTEL enabled + trackingCode += `mcpcat.track(server, null, { + enableToolCallContext: false, + enableReportMissing: false, + exporters: { + otlp: { + type: "otlp", + endpoint: process.env.OTLP_ENDPOINT || "http://localhost:4318/v1/traces" + } + } +});`; + } + + return trackingCode + '\n'; +} + /** * Generates the TypeScript code for the MCP server * @@ -80,6 +120,10 @@ export function generateMcpServerCode( }`; break; } + let mcpcatImport = ''; + if (options.withMcpcat || options.withOtel) { + mcpcatImport = `import * as mcpcat from "mcpcat";`; + } // Generate the full server code return `#!/usr/bin/env node @@ -101,6 +145,7 @@ import { type CallToolResult, type CallToolRequest } from "@modelcontextprotocol/sdk/types.js";${transportImport} + ${mcpcatImport} import { z, ZodError } from 'zod'; import { jsonSchemaToZod } from 'json-schema-to-zod'; @@ -156,6 +201,7 @@ ${listToolsHandlerCode} ${callToolHandlerCode} ${executeApiToolFunctionCode} +${generateMcpcatTracking(options)} /** * Main function to start the server */ diff --git a/src/index.ts b/src/index.ts index d588a24..141337c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -34,7 +34,8 @@ import { normalizeBoolean } from './utils/helpers.js'; import pkg from '../package.json' with { type: 'json' }; // Export programmatic API -export { getToolsFromOpenApi, McpToolDefinition, GetToolsOptions } from './api.js'; +export { getToolsFromOpenApi } from './api.js'; +export type { McpToolDefinition, GetToolsOptions } from './api.js'; // Configure CLI const program = new Command(); @@ -87,6 +88,8 @@ program true ) .option('--force', 'Overwrite existing files without prompting') + .option('--with-mcpcat', 'Enable MCPcat MCP product analytics') + .option('--with-otel', 'Enable OpenTelemetry (OTLP) logging') .version(pkg.version) // Match package.json version .action((options) => { runGenerator(options).catch((error) => { @@ -161,7 +164,7 @@ async function runGenerator(options: CliOptions & { force?: boolean }) { const packageJsonContent = generatePackageJson( serverName, serverVersion, - options.transport as TransportType + options ); console.error('Generating tsconfig.json...'); @@ -180,7 +183,7 @@ async function runGenerator(options: CliOptions & { force?: boolean }) { const jestConfigContent = generateJestConfig(); console.error('Generating .env.example file...'); - const envExampleContent = generateEnvExample(api.components?.securitySchemes); + const envExampleContent = generateEnvExample(api.components?.securitySchemes, options); console.error('Generating OAuth2 documentation...'); const oauth2DocsContent = generateOAuth2Docs(api.components?.securitySchemes); diff --git a/src/types/index.ts b/src/types/index.ts index e36eb3b..cef387b 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -35,6 +35,10 @@ export interface CliOptions { * false = exclude by default unless x-mcp explicitly enables. */ defaultInclude?: boolean; + /** Enable MCPcat analytics tracking */ + withMcpcat?: boolean; + /** Enable OpenTelemetry (OTLP) exporters */ + withOtel?: boolean; } /**