feat: Add MCPcat analytics and OpenTelemetry support

- Add --with-mcpcat and --with-otel CLI options for optional analytics and telemetry
    - Generate MCPcat tracking code in server when enabled
    - Include MCPcat environment variables in .env.example when configured
    - Add MCPcat dependency to generated package.json when enabled
    - Support both MCPcat-only, OTEL-only, and combined configurations
    - Update generator functions to accept full CliOptions object
    - Convert module exports to type-only exports where appropriate
This commit is contained in:
Naseem AlNaji 2025-10-01 20:03:43 -04:00
parent 8ee9fc383d
commit 518b885f33
5 changed files with 80 additions and 6 deletions

View File

@ -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;

View File

@ -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',

View File

@ -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
*/

View File

@ -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);

View File

@ -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;
}
/**