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
npx @tessl/cli install tessl/npm-modelcontextprotocol--sdk@1.20.0TypeScript 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' });