SDK Patterns — @modelcontextprotocol/sdk
| Field | Value |
|---|---|
| Type | Agent Reference |
| Source | ~/.copilot/agents/_refs/typescript-mcp-expert/sdk-patterns.md |
| Description | Not specified |
Source Content
SDK Patterns — @modelcontextprotocol/sdk
Reference for TypeScript MCP Server Expert. Canonical patterns for building servers
with the official TypeScript SDK.
Imports
Always import from specific SDK paths with the .js suffix (ES module resolution):
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';import { completable } from '@modelcontextprotocol/sdk/server/completable.js';Use ES modules (import/export) — never require.
Tool registration
Use registerTool() rather than the lower-level Server class unless you need
maximum control.
- Provide
title(human-readable) andname(machine identifier). - Define
inputSchemaas a plain object of zod validators:{ param: z.string() }. - Optionally define
outputSchemamirroringstructuredContentshape. - Implementations should return both:
content— array of text/image blocks for displaystructuredContent— typed payload for programmatic consumers
- Wrap the implementation in
try/catchand return{ isError: true, content: [...] }on failure with a meaningful message.
Resource registration
- Static:
registerResource(name, uri, metadata, reader). - Dynamic: pass a
ResourceTemplatesuch asnew ResourceTemplate('resource://{id}', { list: undefined }). - For very large payloads return a
ResourceLinkinstead of inlining bytes.
Prompt registration
- Always supply
titleand a description. - Use zod for
argsSchema. - Wrap argument values in
completable(z.string(), async (value, ctx) => [...])to provide context-aware completions.
Structured returns — required shape
return { content: [{ type: 'text', text: humanReadable }], structuredContent: typedPayload,};LLMs consume content; downstream tools consume structuredContent. Always emit both.
Error handling
try { // ...} catch (err) { return { isError: true, content: [{ type: 'text', text: `Failed: ${(err as Error).message}` }], };}Never let exceptions cross the transport boundary unhandled.
Naming and descriptions
- Titles and descriptions are read by the LLM — write them clearly, no jargon.
- Prefer verbs in tool names (
search_users, notusers). - Document each parameter via zod’s
.describe().