(input: EmitInput)
| 46 | } |
| 47 | |
| 48 | export async function emitDescriptors(input: EmitInput): Promise<string> { |
| 49 | const blocks: Array<string> = [ |
| 50 | '// AUTO-GENERATED by `npx @tanstack/ai-mcp generate`. Do not edit.', |
| 51 | "import type { ServerDescriptor } from '@tanstack/ai-mcp'", |
| 52 | '', |
| 53 | ] |
| 54 | // Track config-key -> interface-name so we can emit the combined pool map. |
| 55 | const mapEntries: Array<[string, string]> = [] |
| 56 | // Distinct server keys can pascal-case to the same identifier |
| 57 | // (`foo-bar` vs `foo_bar`) — fail loudly rather than emit duplicate |
| 58 | // interface declarations. |
| 59 | const seenIfaces = new Set<string>() |
| 60 | for (const [serverName, { prefix, surface }] of Object.entries(input)) { |
| 61 | const iface = `${pascal(serverName)}Server` |
| 62 | if (seenIfaces.has(iface)) { |
| 63 | throw new Error( |
| 64 | `Interface name collision for server key "${serverName}" -> ${iface}. ` + |
| 65 | `Rename one of the colliding servers in your codegen config.`, |
| 66 | ) |
| 67 | } |
| 68 | seenIfaces.add(iface) |
| 69 | mapEntries.push([serverName, iface]) |
| 70 | const toolEntries: Array<string> = [] |
| 71 | for (const tool of surface.tools) { |
| 72 | const key = prefix ? `${prefix}_${tool.name}` : tool.name |
| 73 | const inputType = await schemaToType( |
| 74 | tool.inputSchema, |
| 75 | `${pascal(key)}Input`, |
| 76 | ) |
| 77 | const outputType = tool.outputSchema |
| 78 | ? await schemaToType(tool.outputSchema, `${pascal(key)}Output`) |
| 79 | : 'unknown' |
| 80 | // Inline the compiled interface bodies as anonymous object types. |
| 81 | toolEntries.push( |
| 82 | ` ${tsString(key)}: { input: ${inlineBody(inputType)}; output: ${inlineBody(outputType)} }`, |
| 83 | ) |
| 84 | } |
| 85 | blocks.push( |
| 86 | `export interface ${iface} extends ServerDescriptor {`, |
| 87 | ` tools: {`, |
| 88 | toolEntries.join('\n'), |
| 89 | ` }`, |
| 90 | ` resources: ${emitResources(surface)}`, |
| 91 | ` prompts: ${emitPrompts(surface)}`, |
| 92 | ` capabilities: ${JSON.stringify(surface.capabilities)} & Record<string, unknown>`, |
| 93 | `}`, |
| 94 | '', |
| 95 | ) |
| 96 | } |
| 97 | // Combined map for createMCPClients<MCPServers>(...). Keys = config keys |
| 98 | // verbatim (NOT pascal-cased) so they match the runtime config object and |
| 99 | // pool.clients access. |
| 100 | blocks.push( |
| 101 | 'export interface MCPServers extends Record<string, ServerDescriptor> {', |
| 102 | ...mapEntries.map(([key, iface]) => ` ${tsString(key)}: ${iface}`), |
| 103 | '}', |
| 104 | '', |
| 105 | ) |
no test coverage detected