# MCP Templates - Scaffolding TypeScript > Templates de código prontos a usar. Substituir `` pelo nome real do MCP. --- ## package.json ```json { "name": "mcp-", "version": "1.0.0", "type": "module", "main": "dist/index.js", "scripts": { "build": "tsc", "start": "node dist/index.js", "start:http": "node dist/index-http.js", "dev": "tsx src/index.ts", "dev:http": "tsx src/index-http.ts", "eval": "tsx eval/run-evals.ts", "eval:ci": "npm run build && npm run eval", "reload:http": "npm run build && systemctl --user restart mcp- && sleep 2 && curl -s http://127.0.0.1:32XX/health" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "zod": "^3.22.0" }, "devDependencies": { "@types/node": "^20.0.0", "typescript": "^5.0.0", "tsx": "^4.0.0" } } ``` --- ## tsconfig.json ```json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "declaration": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "eval"] } ``` --- ## src/index.ts (stdio — padrão local) ```typescript #!/usr/bin/env node /** * MCP * @author Descomplicar® | @link descomplicar.pt | @copyright 2026 */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; // --- Schemas de validação --- const ExampleSchema = z.object({ param: z.string().min(1, 'param é obrigatório'), }); // --- Definição de tools --- const allTools = [ { name: 'example_get_item', // {serviço}_{acção}_{recurso} description: 'Obtém um item pelo ID', annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, inputSchema: { type: 'object' as const, properties: { param: { type: 'string', description: 'ID do item' }, }, required: ['param'], }, handler: async (args: unknown) => { const { param } = ExampleSchema.parse(args); // ... lógica aqui return { content: [{ type: 'text' as const, text: `Item: ${param}` }], structuredContent: { id: param, status: 'found' }, }; }, }, ]; // --- Servidor --- const server = new Server( { name: 'mcp-', version: '1.0.0' }, { capabilities: { tools: {}, resources: {}, prompts: {} } } ); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: allTools.map(t => ({ name: t.name, description: t.description, annotations: t.annotations, inputSchema: t.inputSchema, })), })); server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [] })); server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: [] })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const tool = allTools.find(t => t.name === name); if (!tool) { return { content: [{ type: 'text', text: `Tool desconhecida: ${name}` }], isError: true, }; } try { return await tool.handler(args); } catch (error) { if (error instanceof z.ZodError) { return { content: [{ type: 'text', text: `Parâmetros inválidos:\n${error.errors.map(e => ` - ${e.path.join('.')}: ${e.message}`).join('\n')}`, }], isError: true, }; } return { content: [{ type: 'text', text: `Erro em ${name}: ${error instanceof Error ? error.message : String(error)}`, }], isError: true, }; } }); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('MCP running on stdio'); } main().catch(console.error); ``` --- ## src/index-http.ts (StreamableHTTP — padrão remoto) ```typescript #!/usr/bin/env node /** * MCP - HTTP Server Mode * @author Descomplicar® | @link descomplicar.pt | @copyright 2026 */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ListPromptsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import * as http from 'http'; import { URL } from 'url'; import { randomUUID } from 'crypto'; const PORT = parseInt(process.env.MCP_HTTP_PORT || '3200', 10); const HOST = process.env.MCP_HTTP_HOST || '127.0.0.1'; const STATEFUL = process.env.MCP_STATEFUL !== 'false'; const sessions = new Map(); // Importar allTools do mesmo local que stdio import { allTools } from './tools/index.js'; function createMcpServer(): Server { const server = new Server( { name: 'mcp-', version: '1.0.0' }, { capabilities: { tools: {}, resources: {}, prompts: {} } } ); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: allTools.map(t => ({ name: t.name, description: t.description, annotations: t.annotations, inputSchema: t.inputSchema, })), })); server.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: [] })); server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: [] })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; const tool = allTools.find(t => t.name === name); if (!tool) { return { content: [{ type: 'text', text: `Tool desconhecida: ${name}` }], isError: true }; } try { return await tool.handler(args); } catch (error) { return { content: [{ type: 'text', text: `Erro: ${error instanceof Error ? error.message : String(error)}` }], isError: true, }; } }); return server; } async function main() { const httpServer = http.createServer(async (req, res) => { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Mcp-Session-Id'); if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; } const url = new URL(req.url || '/', `http://${HOST}:${PORT}`); if (url.pathname === '/health') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'ok', version: '1.0.0', sessions: sessions.size, tools: allTools.length })); return; } if (url.pathname === '/mcp') { try { const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: STATEFUL ? () => randomUUID() : undefined, }); const srv = createMcpServer(); if (STATEFUL && transport.sessionId) { sessions.set(transport.sessionId, { transport }); transport.onclose = () => { if (transport.sessionId) sessions.delete(transport.sessionId); }; } await srv.connect(transport); await transport.handleRequest(req, res); } catch (error) { if (!res.headersSent) { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Internal server error' })); } } return; } res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Not found' })); }); httpServer.listen(PORT, HOST, () => { console.log(`MCP HTTP v1.0.0`); console.log(` Endpoint: http://${HOST}:${PORT}/mcp`); console.log(` Health: http://${HOST}:${PORT}/health`); console.log(` Mode: ${STATEFUL ? 'Stateful' : 'Stateless'}`); }); const shutdown = () => httpServer.close(() => process.exit(0)); process.on('SIGINT', shutdown); process.on('SIGTERM', shutdown); } main().catch(console.error); ``` --- ## ~/.config/systemd/user/mcp-.service ```ini [Unit] Description=MCP HTTP Server After=network.target [Service] Type=simple WorkingDirectory=/home/ealmeida/mcp-servers/mcp- ExecStart=/home/ealmeida/.nvm/versions/node/v22.18.0/bin/node dist/index-http.js Restart=on-failure RestartSec=5 Environment=NODE_ENV=production Environment=MCP_HTTP_PORT=32XX Environment=LOG_LEVEL=error StandardOutput=journal StandardError=journal [Install] WantedBy=default.target ``` --- ## Configuração ~/.claude.json ```json { "mcpServers": { "": { "type": "http", "url": "http://127.0.0.1:32XX/mcp" } } } ``` --- *templates.md v1.0 | 2026-03-10*