TypeScript SDK for implementing the Model Context Protocol, enabling developers to build MCP servers and clients with support for multiple transports, tools, resources, prompts, and authentication
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
TypeScript implementation for building MCP servers and clients. Enables exposing context (resources, tools, prompts) to LLMs with transports, OAuth, sampling, and elicitation.
Package: @modelcontextprotocol/sdk@1.20.2 | npm install @modelcontextprotocol/sdk | Protocol: 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07
Server:
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
server.registerTool('add', {
title: 'Addition Tool',
description: 'Add two numbers',
inputSchema: { a: z.number(), b: z.number() },
outputSchema: { result: z.number() }
}, async ({ a, b }) => ({
content: [{ type: 'text', text: String(a + b) }],
structuredContent: { result: a + b }
}));
await server.connect(new StdioServerTransport());Client:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
const client = new Client({ name: 'my-client', version: '1.0.0' });
await client.connect(new StdioClientTransport({ command: 'node', args: ['server.js'] }));
const { tools } = await client.listTools();
const result = await client.callTool({ name: 'add', arguments: { a: 5, b: 3 } });
console.log(result.structuredContent); // { result: 8 }Server Primitives:
| Primitive | Purpose | Control | Use Case |
|---|---|---|---|
| Tools | Model actions | Model | Computations, APIs, side effects |
| Resources | App data | App | Config, files, data |
| Prompts | Templates | User | Slash commands, starters |
Transports:
| Transport | Use Case | Characteristics |
|---|---|---|
| Stdio | Local/CLI | Simple, fast |
| StreamableHTTP | Remote/web | Stateless, scalable |
| WebSocket | Real-time | Low latency |
| InMemory | Testing | Isolated |
import fs from 'fs/promises';
server.registerResource('readme', 'file:///project/README.md', {
title: 'Project README', mimeType: 'text/markdown'
}, async (uri) => ({
contents: [{ uri: uri.href, mimeType: 'text/markdown', text: await fs.readFile('/project/README.md', 'utf-8') }]
}));
server.registerTool('list-files', {
description: 'List files in a directory',
inputSchema: { path: z.string() }
}, async ({ path }) => ({
content: [{ type: 'text', text: (await fs.readdir(path)).join('\n') }]
}));server.registerTool('fetch-api', {
description: 'Fetch from external API',
inputSchema: { url: z.string().url(), method: z.enum(['GET', 'POST']).optional() }
}, async ({ url, method = 'GET' }) => {
const response = await fetch(url, { method });
const data = await response.json();
return { content: [{ type: 'text', text: JSON.stringify(data) }], structuredContent: data };
});import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
server.registerResource('user', new ResourceTemplate('db://users/{userId}', {}), {
title: 'User Profile'
}, async (uri, { userId }) => {
const user = await db.getUser(userId);
return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(user) }] };
});
server.registerTool('query-users', {
description: 'Query users by criteria',
inputSchema: { role: z.string().optional(), active: z.boolean().optional() }
}, async (args) => {
const users = await db.queryUsers(args);
return {
content: users.map(u => ({ type: 'text', text: `${u.name} (${u.email})` })),
structuredContent: { users }
};
});server.registerTool('safe-add', {
inputSchema: { a: z.number().min(0).max(1000), b: z.number().min(0).max(1000) },
outputSchema: { result: z.number() }
}, async ({ a, b }) => ({
content: [{ type: 'text', text: String(a + b) }],
structuredContent: { result: a + b }
}));return {
content: [{ type: 'text', text: JSON.stringify(output) }],
structuredContent: output // Must match outputSchema
};try {
const result = await performOperation(id);
return { content: [{ type: 'text', text: `Success: ${result}` }], structuredContent: { success: true, result } };
} catch (error) {
return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
}Tools not appearing: Call server.connect() after registration; verify client capabilities.
Transport errors: Verify server is listening; check URLs/credentials.
Validation errors: Ensure Zod schemas match; structuredContent must match outputSchema.
// Server
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport, StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
// Client
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport, StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
// Types
import type { Tool, Resource, Prompt, CallToolResult, ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';
// Error handling
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
throw new McpError(ErrorCode.InvalidParams, 'Message', { field: 'value' });