Skip to main content
Glama

MCP API Server

by fikri2992
server-generator.ts14.2 kB
import { ParsedAPICollection } from '../parser/types.js'; import { GeneratedMCPTool } from './mcp-tool-generator.js'; import { TemplateContext } from './template-engine.js'; /** * Configuration for server generation */ export interface ServerGeneratorConfig { /** Server name */ serverName: string; /** Server version */ serverVersion?: string; /** Server description */ serverDescription?: string; /** Package name for generated server */ packageName?: string; /** Author information */ author?: string; /** License */ license?: string; /** Repository URL */ repository?: string; /** Enable debug logging */ debug?: boolean; /** Include test files */ includeTests?: boolean; /** Include documentation */ includeDocumentation?: boolean; /** TypeScript configuration */ typescript?: boolean; /** Server configuration options */ serverConfig?: { timeout?: number; maxResponseLength?: number; allowLocalhost?: boolean; allowPrivateIps?: boolean; userAgent?: string; }; } /** * Generated server structure */ export interface GeneratedServer { /** Server metadata */ name: string; version: string; description: string; packageName: string; /** Generated tools */ tools: GeneratedMCPTool[]; /** API specifications */ apis: ParsedAPICollection['apis']; /** Server configuration */ configuration: { timeout: number; maxResponseLength: number; allowLocalhost: boolean; allowPrivateIps: boolean; userAgent: string; }; /** Package dependencies */ dependencies: PackageDependency[]; /** Import statements */ imports: ImportStatement[]; /** Export statements */ exports: ExportStatement[]; /** Generated metadata */ metadata: { generatedAt: string; generatedBy: string; sourceFile?: string; version: string; toolCount: number; apiCount: number; }; } /** * Package dependency information */ export interface PackageDependency { name: string; version: string; type: 'dependency' | 'devDependency'; description?: string; } /** * Import statement information */ export interface ImportStatement { module: string; imports: string[]; isDefault?: boolean; isNamespace?: boolean; alias?: string; } /** * Export statement information */ export interface ExportStatement { name: string; type: 'function' | 'class' | 'interface' | 'type' | 'const'; isDefault?: boolean; } /** * Server generation result */ export interface ServerGenerationResult { /** Generated server structure */ server: GeneratedServer; /** Template context for code generation */ templateContext: TemplateContext; /** Generation statistics */ stats: { toolsGenerated: number; apisProcessed: number; dependenciesAdded: number; importsGenerated: number; exportsGenerated: number; }; /** Any warnings during generation */ warnings: string[]; } /** * Generator for MCP server structure and metadata */ export class ServerGenerator { private config: Required<ServerGeneratorConfig>; constructor(config: ServerGeneratorConfig) { this.config = { serverName: config.serverName, serverVersion: config.serverVersion ?? '1.0.0', serverDescription: config.serverDescription ?? `MCP server for ${config.serverName}`, packageName: config.packageName ?? this.generatePackageName(config.serverName), author: config.author ?? 'Generated by MCP Builder CLI', license: config.license ?? 'MIT', repository: config.repository ?? '', debug: config.debug ?? false, includeTests: config.includeTests ?? true, includeDocumentation: config.includeDocumentation ?? true, typescript: config.typescript ?? true, serverConfig: { timeout: config.serverConfig?.timeout ?? parseInt(process.env.API_TIMEOUT || '30000', 10), maxResponseLength: config.serverConfig?.maxResponseLength ?? parseInt(process.env.MAX_RESPONSE_LENGTH || '50000', 10), allowLocalhost: config.serverConfig?.allowLocalhost ?? (process.env.ALLOW_LOCALHOST === 'true'), allowPrivateIps: config.serverConfig?.allowPrivateIps ?? false, userAgent: config.serverConfig?.userAgent ?? `MCP-Server/${config.serverVersion ?? '1.0.0'}`, }, }; this.log('ServerGenerator initialized', { serverName: this.config.serverName, packageName: this.config.packageName, includeTests: this.config.includeTests, includeDocumentation: this.config.includeDocumentation, }); } /** * Generate server structure from API collection and tools */ generateServer( apiCollection: ParsedAPICollection, tools: GeneratedMCPTool[] ): ServerGenerationResult { this.log(`Generating server for ${apiCollection.name}`, { apiCount: apiCollection.apis.length, toolCount: tools.length, }); // Generate server structure const server = this.createServerStructure(apiCollection, tools); // Generate template context const templateContext = this.createTemplateContext(server); // Calculate statistics const stats = { toolsGenerated: tools.length, apisProcessed: apiCollection.apis.length, dependenciesAdded: server.dependencies.length, importsGenerated: server.imports.length, exportsGenerated: server.exports.length, }; // Generate warnings const warnings = this.generateWarnings(server, apiCollection, tools); this.log('Server generation completed', stats); return { server, templateContext, stats, warnings, }; } /** * Create server structure from API collection and tools */ private createServerStructure( apiCollection: ParsedAPICollection, tools: GeneratedMCPTool[] ): GeneratedServer { const timestamp = new Date().toISOString(); return { name: this.config.serverName, version: this.config.serverVersion, description: this.config.serverDescription, packageName: this.config.packageName, tools, apis: apiCollection.apis, configuration: { timeout: this.config.serverConfig.timeout ?? parseInt(process.env.API_TIMEOUT || '30000', 10), maxResponseLength: this.config.serverConfig.maxResponseLength ?? parseInt(process.env.MAX_RESPONSE_LENGTH || '50000', 10), allowLocalhost: this.config.serverConfig.allowLocalhost ?? (process.env.ALLOW_LOCALHOST === 'true'), allowPrivateIps: this.config.serverConfig.allowPrivateIps ?? false, userAgent: this.config.serverConfig.userAgent ?? `MCP-Server/${this.config.serverVersion}`, }, dependencies: this.generateDependencies(), imports: this.generateImports(tools), exports: this.generateExports(tools), metadata: { generatedAt: timestamp, generatedBy: 'MCP Builder CLI', sourceFile: apiCollection.metadata.fileName, version: '1.0.0', toolCount: tools.length, apiCount: apiCollection.apis.length, }, }; } /** * Generate package dependencies */ private generateDependencies(): PackageDependency[] { const dependencies: PackageDependency[] = [ { name: '@modelcontextprotocol/sdk', version: '^1.0.0', type: 'dependency', description: 'Model Context Protocol SDK', }, { name: 'zod', version: '^3.22.0', type: 'dependency', description: 'TypeScript-first schema validation', }, { name: 'node-fetch', version: '^3.3.0', type: 'dependency', description: 'HTTP client for Node.js', }, ]; if (this.config.typescript) { dependencies.push( { name: 'typescript', version: '^5.0.0', type: 'devDependency', description: 'TypeScript compiler', }, { name: '@types/node', version: '^20.0.0', type: 'devDependency', description: 'Node.js type definitions', } ); } if (this.config.includeTests) { dependencies.push( { name: 'vitest', version: '^1.0.0', type: 'devDependency', description: 'Testing framework', }, { name: '@types/jest', version: '^29.0.0', type: 'devDependency', description: 'Jest type definitions', } ); } return dependencies; } /** * Generate import statements */ private generateImports(tools: GeneratedMCPTool[]): ImportStatement[] { const imports: ImportStatement[] = [ { module: '@modelcontextprotocol/sdk/server/index.js', imports: ['Server'], }, { module: '@modelcontextprotocol/sdk/server/stdio.js', imports: ['StdioServerTransport'], }, { module: '@modelcontextprotocol/sdk/types.js', imports: ['CallToolRequestSchema', 'ListToolsRequestSchema'], }, { module: 'zod', imports: ['z'], }, { module: 'node-fetch', imports: ['fetch'], isDefault: true, }, ]; // Add tool-specific imports if needed const hasComplexValidation = tools.some(tool => tool.validation.bodySchema || tool.validation.headerSchema || tool.validation.querySchema ); if (hasComplexValidation) { imports.push({ module: './validation.js', imports: ['validateRequest', 'ValidationError'], }); } return imports; } /** * Generate export statements */ private generateExports(tools: GeneratedMCPTool[]): ExportStatement[] { const exports: ExportStatement[] = [ { name: 'MCPServer', type: 'class', isDefault: true, }, { name: 'ALL_TOOLS', type: 'const', }, { name: 'TOOL_MAP', type: 'const', }, ]; // Add tool handler exports for (const tool of tools) { exports.push({ name: tool.functionName, type: 'function', }); } return exports; } /** * Create template context for code generation */ private createTemplateContext(server: GeneratedServer): TemplateContext { return { server: { name: server.name, version: server.version, description: server.description, packageName: server.packageName, author: this.config.author, license: this.config.license, repository: this.config.repository, }, tools: server.tools.map(tool => ({ name: tool.name, description: tool.description, functionName: tool.functionName, httpMethod: tool.httpMethod, inputSchema: tool.inputSchema, hasBody: tool.hasBody, parameters: tool.parameters, })), apis: server.apis.map(api => ({ name: api.name, description: api.description, method: api.method, url: api.url, headers: api.headers, body: api.body, parameters: api.parameters, })), imports: server.imports.map(imp => imp.isDefault ? `import ${imp.imports[0]} from '${imp.module}';` : `import { ${imp.imports.join(', ')} } from '${imp.module}';` ), exports: server.exports.map(exp => exp.isDefault ? `export default ${exp.name};` : `export { ${exp.name} };` ), metadata: server.metadata, configuration: server.configuration, }; } /** * Generate warnings for potential issues */ private generateWarnings( server: GeneratedServer, apiCollection: ParsedAPICollection, tools: GeneratedMCPTool[] ): string[] { const warnings: string[] = []; // Check for missing descriptions const apisWithoutDescriptions = server.apis.filter(api => !api.description); if (apisWithoutDescriptions.length > 0) { warnings.push(`${apisWithoutDescriptions.length} APIs are missing descriptions`); } // Check for tools with many parameters const complexTools = tools.filter(tool => tool.parameters.length > 8); if (complexTools.length > 0) { warnings.push(`${complexTools.length} tools have more than 8 parameters, consider simplifying`); } // Check for duplicate API endpoints const endpoints = server.apis.map(api => `${api.method} ${api.url}`); const duplicateEndpoints = endpoints.filter((endpoint, index) => endpoints.indexOf(endpoint) !== index ); if (duplicateEndpoints.length > 0) { warnings.push(`Duplicate API endpoints detected: ${[...new Set(duplicateEndpoints)].join(', ')}`); } // Check for missing base URL if (!apiCollection.baseUrl && server.apis.some(api => !api.url.startsWith('http'))) { warnings.push('Some APIs have relative URLs but no base URL is specified'); } // Check for large number of tools if (tools.length > 20) { warnings.push(`Generated ${tools.length} tools, consider grouping related functionality`); } return warnings; } /** * Generate package name from server name */ private generatePackageName(serverName: string): string { return serverName .toLowerCase() .replace(/[^a-z0-9]/g, '-') .replace(/-+/g, '-') .replace(/^-|-$/g, ''); } /** * Update generator configuration */ updateConfig(config: Partial<ServerGeneratorConfig>): void { Object.assign(this.config, config); this.log('ServerGenerator configuration updated', this.config); } /** * Get current configuration */ getConfig(): Required<ServerGeneratorConfig> { return { ...this.config }; } /** * Log messages with optional debug filtering */ private log(message: string, data?: any): void { if (this.config.debug) { const timestamp = new Date().toISOString(); if (data !== undefined) { console.error(`[${timestamp}] ServerGenerator: ${message}`, data); } else { console.error(`[${timestamp}] ServerGenerator: ${message}`); } } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/fikri2992/mcp0'

If you have feedback or need assistance with the MCP directory API, please join our Discord server