# Foundation Build Agent Prompt Build the foundation for the {{NAME}} MCP server at {{DIR}}. ## What to Build ### 1. `package.json` ```json { "name": "@mcpengine/{{NAME}}", "version": "1.0.0", "type": "module", "main": "dist/main.js", "scripts": { "build": "tsc", "start": "node dist/main.js", "dev": "tsx watch src/main.ts" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", "axios": "^1.7.0", "zod": "^3.23.0" }, "devDependencies": { "typescript": "^5.6.0", "tsx": "^4.19.0", "@types/node": "^22.0.0" } } ``` ### 2. `tsconfig.json` ```json { "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "outDir": "dist", "rootDir": "src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "declaration": true, "resolveJsonModule": true, "forceConsistentCasingInFileNames": true, "noUncheckedIndexedAccess": true, "jsx": "react-jsx" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] } ``` ### 3. `src/types/index.ts` - Define TypeScript interfaces for ALL API entities - Use branded types for IDs: `type CustomerId = string & { __brand: 'CustomerId' }` - Use discriminated unions for status fields - Export everything ### 4. `src/clients/{{NAME}}.ts` API client with: - Auth: {{AUTH_TYPE}} (Bearer token / API key / OAuth2) - Base URL: {{API_BASE}} - Retry with exponential backoff (3 retries, 1s/2s/4s) - Rate limit awareness (respect 429 + Retry-After header) - Automatic pagination (abstract cursor/offset) - Request interceptors for logging - Response interceptors for error normalization - Timeout: 30s default - OAuth token auto-refresh if applicable ```typescript import axios, { AxiosInstance, AxiosError } from 'axios'; export class {{PascalName}}Client { private client: AxiosInstance; private rateLimitRemaining = Infinity; private rateLimitReset = 0; constructor(config: { apiKey?: string; accessToken?: string; baseUrl?: string }) { this.client = axios.create({ baseURL: config.baseUrl || '{{API_BASE}}', timeout: 30000, headers: { /* auth headers */ } }); // Response interceptor for rate limiting this.client.interceptors.response.use( (res) => { this.rateLimitRemaining = parseInt(res.headers['x-ratelimit-remaining'] || 'Infinity'); this.rateLimitReset = parseInt(res.headers['x-ratelimit-reset'] || '0'); return res; }, async (error: AxiosError) => { if (error.response?.status === 429) { const retryAfter = parseInt(error.response.headers['retry-after'] || '5'); await this.sleep(retryAfter * 1000); return this.client.request(error.config!); } throw this.normalizeError(error); } ); } // Paginated fetch helper async paginate(endpoint: string, params?: Record): Promise { ... } // Retry with exponential backoff private async withRetry(fn: () => Promise, retries = 3): Promise { ... } } ``` ### 5. `src/server.ts` MCP server with: - Lazy-loaded tool modules (dynamic import) - Resource handlers for UI apps - Structured error responses - Request logging ```typescript import { Server } from '@modelcontextprotocol/sdk/server/index.js'; // Lazy load tool modules const toolModules = { 'customers': () => import('./tools/customers-tools.js'), 'orders': () => import('./tools/orders-tools.js'), // ... etc }; // Tools loaded on first call const loadedTools = new Map(); async function getToolHandler(category: string) { if (!loadedTools.has(category)) { const mod = await toolModules[category](); loadedTools.set(category, mod); } return loadedTools.get(category); } ``` ### 6. `src/main.ts` Entry point with: - Environment validation (fail fast) - Dual transport (stdio + HTTP/SSE) - Graceful shutdown handlers - Health check endpoint ### 7. `.env.example` + `.gitignore` + `README.md` ## Rules - DO NOT create tool files or app files — only foundation - TSC must compile clean with `strict: true` - Run `npm install` and `npx tsc --noEmit` to verify - Commit when done