Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Bootstrap MCP (Model Context Protocol) servers with the official TypeScript SDK. Creates complete server implementations with transport layer, tools, resources, and proper error handling.
.claude/skills/a5c-ai-mcp-sdk-typescript-bootstrapper/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 99% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 48% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 75% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 102% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 12% | 0% |
Bootstrap production-ready MCP servers using the official TypeScript SDK with proper transport configuration, tool/resource handlers, and security best practices.
Invoke this skill when you need to:
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | serverName | string | Yes | Name of the MCP server (kebab-case) | | description | string | Yes | Server description for clients | | transport | string | No | stdio, sse, or websocket (default: stdio) | | tools | array | No | List of tools to scaffold | | resources | array | No | List of resources to provide | | capabilities | object | No | Server capability declarations |
json{ "tools": [ { "name": "read_file", "description": "Read contents of a file", "inputSchema": { "type": "object", "properties": { "path": { "type": "string", "description": "File path to read" } }, "required": ["path"] } } ] }
json{ "resources": [ { "uriTemplate": "file:///{path}", "name": "File Resource", "description": "Access file contents", "mimeType": "text/plain" } ] }
<serverName>/
├── package.json
├── tsconfig.json
├── .gitignore
├── README.md
├── src/
│ ├── index.ts # Server entry point
│ ├── server.ts # MCP server setup
│ ├── transport/
│ │ ├── stdio.ts # Stdio transport
│ │ ├── sse.ts # SSE transport (if selected)
│ │ └── websocket.ts # WebSocket transport (if selected)
│ ├── tools/
│ │ ├── index.ts # Tool registry
│ │ └── <tool>.ts # Individual tool handlers
│ ├── resources/
│ │ ├── index.ts # Resource registry
│ │ └── <resource>.ts # Resource providers
│ ├── prompts/
│ │ └── index.ts # Prompt templates (optional)
│ └── utils/
│ ├── validation.ts # Input validation helpers
│ ├── errors.ts # MCP error handling
│ └── logging.ts # Structured logging
├── tests/
│ ├── tools/
│ └── resources/
└── mcp.json # MCP server manifesttypescriptimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { registerTools } from './tools'; import { registerResources } from './resources'; export async function createServer() { const server = new McpServer({ name: '<serverName>', version: '1.0.0', }); // Register capabilities registerTools(server); registerResources(server); return server; } export async function startServer() { const server = await createServer(); const transport = new StdioServerTransport(); await server.connect(transport); console.error('[MCP] Server started on stdio'); }
typescriptimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { z } from 'zod'; import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; const inputSchema = z.object({ path: z.string().describe('File path to read'), }); export function registerReadFileTool(server: McpServer) { server.tool( 'read_file', 'Read contents of a file', inputSchema.shape, async (args) => { const { path } = inputSchema.parse(args); try { // Implementation const content = await readFile(path, 'utf-8'); return { content: [{ type: 'text', text: content }], }; } catch (error) { throw new McpError( ErrorCode.InternalError, `Failed to read file: ${error.message}` ); } } ); }
typescriptimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; export function registerFileResource(server: McpServer) { server.resource( 'file:///{path}', 'File Resource', 'Access file contents by path', async (uri) => { const path = uri.pathname; const content = await readFile(path, 'utf-8'); return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: content, }], }; } ); }
json{ "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "zod": "^3.22.0" }, "devDependencies": { "@types/node": "^20.0.0", "typescript": "^5.0.0", "vitest": "^1.0.0" } }
typescriptimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; const transport = new StdioServerTransport();
typescriptimport { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; import express from 'express'; const app = express(); app.get('/sse', (req, res) => { const transport = new SSEServerTransport('/message', res); server.connect(transport); });
typescriptimport { WebSocketServerTransport } from '@modelcontextprotocol/sdk/server/websocket.js'; import { WebSocketServer } from 'ws'; const wss = new WebSocketServer({ port: 3000 }); wss.on('connection', (ws) => { const transport = new WebSocketServerTransport(ws); server.connect(transport); });
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 14,438 | 19,658 | +36% | 1 | 1 | 0% | 3,340 | 6,648 | +99% | 0 | 0 | — |
case-02 | fail→pass | 19,428 | 19,865 | +2% | 1 | 1 | 0% | 4,695 | 6,927 | +48% | 0 | 0 | — |
case-03 | fail→pass | 17,753 | 21,361 | +20% | 1 | 1 | 0% | 4,180 | 7,311 | +75% | 0 | 0 | — |
case-04 | fail→fail | 11,621 | 24,198 | +108% | 1 | 1 | 0% | 2,622 | 6,269 | +139% | 0 | 0 | — |
case-05 | fail→fail | 17,316 | 16,354 | -6% | 1 | 1 | 0% | 3,316 | 5,403 | +63% | 0 | 0 | — |
case-06 | fail→fail | 14,822 | 13,024 | -12% | 1 | 1 | 0% | 3,147 | 4,631 | +47% | 0 | 0 | — |
case-07 | fail→pass | 8,660 | 7,841 | -9% | 1 | 1 | 0% | 1,777 | 3,589 | +102% | 0 | 0 | — |
case-08 | fail→pass | 12,839 | 4,235 | -67% | 1 | 1 | 0% | 2,394 | 2,676 | +12% | 0 | 0 | — |
case-09 | fail→pass | 11,577 | 8,299 | -28% | 1 | 1 | 0% | 1,975 | 3,676 | +86% | 0 | 0 | — |
case-10 | pass→pass | 8,241 | 9,135 | +11% | 1 | 1 | 0% | 1,865 | 3,674 | +97% | 0 | 0 | — |
case-11 | fail→pass | 10,486 | 12,413 | +18% | 1 | 1 | 0% | 2,169 | 4,446 | +105% | 0 | 0 | — |
case-12 | fail→fail | 9,923 | 6,825 | -31% | 1 | 1 | 0% | 2,009 | 3,253 | +62% | 0 | 0 | — |
case-13 | fail→pass | 10,624 | 7,096 | -33% | 1 | 1 | 0% | 2,021 | 3,264 | +62% | 0 | 0 | — |
case-14 | fail→pass | 9,052 | 1,591 | -82% | 1 | 1 | 0% | 1,565 | 2,160 | +38% | 0 | 0 | — |
case-15 | fail→pass | 15,971 | 14,505 | -9% | 1 | 1 | 0% | 3,088 | 5,063 | +64% | 0 | 0 | — |
case-16 | fail→pass | 11,095 | 6,869 | -38% | 1 | 1 | 0% | 2,361 | 3,424 | +45% | 0 | 0 | — |
case-17 | fail→pass | 10,220 | 7,132 | -30% | 1 | 1 | 0% | 2,257 | 3,426 | +52% | 0 | 0 | — |
case-18 | pass→pass | 9,496 | 4,926 | -48% | 1 | 1 | 0% | 1,960 | 2,990 | +53% | 0 | 0 | — |
case-19 | fail→fail | 2,853 | 2,896 | +2% | 1 | 1 | 0% | 548 | 2,312 | +322% | 0 | 0 | — |
case-20 | fail→fail | 7,882 | 6,186 | -22% | 1 | 1 | 0% | 1,538 | 2,754 | +79% | 0 | 0 | — |
case-21 | fail→fail | 11,695 | 4,216 | -64% | 1 | 1 | 0% | 2,178 | 2,851 | +31% | 0 | 0 | — |
case-22 | fail→fail | 10,437 | 4,060 | -61% | 1 | 1 | 0% | 2,098 | 2,804 | +34% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +55 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.