2025-03-01 14:57:56 -05:00
# MCP TypeScript SDK  
## Table of Contents
2025-03-01 14:59:48 -05:00
2025-03-01 14:57:56 -05:00
- [Overview ](mdc:#overview )
- [Installation ](mdc:#installation )
- [Quickstart ](mdc:#quickstart )
- [What is MCP? ](mdc:#what-is-mcp )
- [Core Concepts ](mdc:#core-concepts )
- [Server ](mdc:#server )
- [Resources ](mdc:#resources )
- [Tools ](mdc:#tools )
- [Prompts ](mdc:#prompts )
- [Running Your Server ](mdc:#running-your-server )
- [stdio ](mdc:#stdio )
- [HTTP with SSE ](mdc:#http-with-sse )
- [Testing and Debugging ](mdc:#testing-and-debugging )
- [Examples ](mdc:#examples )
- [Echo Server ](mdc:#echo-server )
- [SQLite Explorer ](mdc:#sqlite-explorer )
- [Advanced Usage ](mdc:#advanced-usage )
- [Low-Level Server ](mdc:#low-level-server )
- [Writing MCP Clients ](mdc:#writing-mcp-clients )
- [Server Capabilities ](mdc:#server-capabilities )
## Overview
The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This TypeScript SDK implements the full MCP specification, making it easy to:
- Build MCP clients that can connect to any MCP server
- Create MCP servers that expose resources, prompts and tools
- Use standard transports like stdio and SSE
- Handle all MCP protocol messages and lifecycle events
## Installation
```bash
npm install @modelcontextprotocol/sdk
```
## Quick Start
Let's create a simple MCP server that exposes a calculator tool and some data:
```typescript
2025-03-01 14:59:48 -05:00
import {
McpServer,
ResourceTemplate,
} from "@modelcontextprotocol/sdk/server/mcp .js";
2025-03-01 14:57:56 -05:00
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio .js";
import { z } from "zod";
// Create an MCP server
const server = new McpServer({
name: "Demo",
2025-03-01 14:59:48 -05:00
version: "1.0.0",
2025-03-01 14:57:56 -05:00
});
// Add an addition tool
2025-03-01 14:59:48 -05:00
server.tool("add", { a: z.number(), b: z.number() }, async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
}));
2025-03-01 14:57:56 -05:00
// Add a dynamic greeting resource
server.resource(
"greeting",
new ResourceTemplate("greeting://{name}", { list: undefined }),
async (uri, { name }) => ({
2025-03-01 14:59:48 -05:00
contents: [
{
uri: uri.href,
text: `Hello, ${name}!` ,
},
],
2025-03-01 14:57:56 -05:00
})
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
```
## What is MCP?
The [Model Context Protocol (MCP) ](mdc:https:/modelcontextprotocol.io ) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
- Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
- And more!
## Core Concepts
### Server
The McpServer is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
```typescript
const server = new McpServer({
name: "My App",
2025-03-01 14:59:48 -05:00
version: "1.0.0",
2025-03-01 14:57:56 -05:00
});
```
### Resources
Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
```typescript
// Static resource
2025-03-01 14:59:48 -05:00
server.resource("config", "config://app", async (uri) => ({
contents: [
{
2025-03-01 14:57:56 -05:00
uri: uri.href,
2025-03-01 14:59:48 -05:00
text: "App configuration here",
},
],
}));
2025-03-01 14:57:56 -05:00
// Dynamic resource with parameters
server.resource(
"user-profile",
new ResourceTemplate("users://{userId}/profile", { list: undefined }),
async (uri, { userId }) => ({
2025-03-01 14:59:48 -05:00
contents: [
{
uri: uri.href,
text: `Profile data for user ${userId}` ,
},
],
2025-03-01 14:57:56 -05:00
})
);
```
### Tools
Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
```typescript
// Simple tool with parameters
server.tool(
"calculate-bmi",
{
weightKg: z.number(),
2025-03-01 14:59:48 -05:00
heightM: z.number(),
2025-03-01 14:57:56 -05:00
},
async ({ weightKg, heightM }) => ({
2025-03-01 14:59:48 -05:00
content: [
{
type: "text",
text: String(weightKg / (heightM * heightM)),
},
],
2025-03-01 14:57:56 -05:00
})
);
// Async tool with external API call
2025-03-01 14:59:48 -05:00
server.tool("fetch-weather", { city: z.string() }, async ({ city }) => {
const response = await fetch(`https://api.weather.com/${city}` );
const data = await response.text();
return {
content: [{ type: "text", text: data }],
};
});
2025-03-01 14:57:56 -05:00
```
### Prompts
Prompts are reusable templates that help LLMs interact with your server effectively:
```typescript
2025-03-01 14:59:48 -05:00
server.prompt("review-code", { code: z.string() }, ({ code }) => ({
messages: [
{
2025-03-01 14:57:56 -05:00
role: "user",
content: {
type: "text",
2025-03-01 14:59:48 -05:00
text: `Please review this code:\n\n${code}` ,
},
},
],
}));
2025-03-01 14:57:56 -05:00
```
## Running Your Server
MCP servers in TypeScript need to be connected to a transport to communicate with clients. How you start the server depends on the choice of transport:
### stdio
For command-line tools and direct integrations:
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp .js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio .js";
const server = new McpServer({
name: "example-server",
2025-03-01 14:59:48 -05:00
version: "1.0.0",
2025-03-01 14:57:56 -05:00
});
// ... set up server resources, tools, and prompts ...
const transport = new StdioServerTransport();
await server.connect(transport);
```
### HTTP with SSE
For remote servers, start a web server with a Server-Sent Events (SSE) endpoint, and a separate endpoint for the client to send its messages to:
```typescript
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp .js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse .js";
const server = new McpServer({
name: "example-server",
2025-03-01 14:59:48 -05:00
version: "1.0.0",
2025-03-01 14:57:56 -05:00
});
// ... set up server resources, tools, and prompts ...
const app = express();
app.get("/sse", async (req, res) => {
const transport = new SSEServerTransport("/messages", res);
await server.connect(transport);
});
app.post("/messages", async (req, res) => {
// Note: to support multiple simultaneous connections, these messages will
// need to be routed to a specific matching transport. (This logic isn't
// implemented here, for simplicity.)
await transport.handlePostMessage(req, res);
});
app.listen(3001);
```
### Testing and Debugging
To test your server, you can use the [MCP Inspector ](mdc:https:/github.com/modelcontextprotocol/inspector ). See its README for more information.
## Examples
### Echo Server
A simple server demonstrating resources, tools, and prompts:
```typescript
2025-03-01 14:59:48 -05:00
import {
McpServer,
ResourceTemplate,
} from "@modelcontextprotocol/sdk/server/mcp .js";
2025-03-01 14:57:56 -05:00
import { z } from "zod";
const server = new McpServer({
name: "Echo",
2025-03-01 14:59:48 -05:00
version: "1.0.0",
2025-03-01 14:57:56 -05:00
});
server.resource(
"echo",
new ResourceTemplate("echo://{message}", { list: undefined }),
async (uri, { message }) => ({
2025-03-01 14:59:48 -05:00
contents: [
{
uri: uri.href,
text: `Resource echo: ${message}` ,
},
],
2025-03-01 14:57:56 -05:00
})
);
2025-03-01 14:59:48 -05:00
server.tool("echo", { message: z.string() }, async ({ message }) => ({
content: [{ type: "text", text: `Tool echo: ${message}` }],
}));
2025-03-01 14:57:56 -05:00
2025-03-01 14:59:48 -05:00
server.prompt("echo", { message: z.string() }, ({ message }) => ({
messages: [
{
2025-03-01 14:57:56 -05:00
role: "user",
content: {
type: "text",
2025-03-01 14:59:48 -05:00
text: `Please process this message: ${message}` ,
},
},
],
}));
2025-03-01 14:57:56 -05:00
```
### SQLite Explorer
A more complex example showing database integration:
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp .js";
import sqlite3 from "sqlite3";
import { promisify } from "util";
import { z } from "zod";
const server = new McpServer({
name: "SQLite Explorer",
2025-03-01 14:59:48 -05:00
version: "1.0.0",
2025-03-01 14:57:56 -05:00
});
// Helper to create DB connection
const getDb = () => {
const db = new sqlite3.Database("database.db");
return {
all: promisify< string , any [ ] > (db.all.bind(db)),
2025-03-01 14:59:48 -05:00
close: promisify(db.close.bind(db)),
2025-03-01 14:57:56 -05:00
};
};
2025-03-01 14:59:48 -05:00
server.resource("schema", "schema://main", async (uri) => {
const db = getDb();
try {
const tables = await db.all(
"SELECT sql FROM sqlite_master WHERE type='table'"
);
return {
contents: [
{
2025-03-01 14:57:56 -05:00
uri: uri.href,
2025-03-01 14:59:48 -05:00
text: tables.map((t: { sql: string }) => t.sql).join("\n"),
},
],
};
} finally {
await db.close();
2025-03-01 14:57:56 -05:00
}
2025-03-01 14:59:48 -05:00
});
2025-03-01 14:57:56 -05:00
2025-03-01 14:59:48 -05:00
server.tool("query", { sql: z.string() }, async ({ sql }) => {
const db = getDb();
try {
const results = await db.all(sql);
return {
content: [
{
2025-03-01 14:57:56 -05:00
type: "text",
2025-03-01 14:59:48 -05:00
text: JSON.stringify(results, null, 2),
},
],
};
} catch (err: unknown) {
const error = err as Error;
return {
content: [
{
2025-03-01 14:57:56 -05:00
type: "text",
2025-03-01 14:59:48 -05:00
text: `Error: ${error.message}` ,
},
],
isError: true,
};
} finally {
await db.close();
2025-03-01 14:57:56 -05:00
}
2025-03-01 14:59:48 -05:00
});
2025-03-01 14:57:56 -05:00
```
## Advanced Usage
### Low-Level Server
For more control, you can use the low-level Server class directly:
```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index .js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio .js";
import {
ListPromptsRequestSchema,
2025-03-01 14:59:48 -05:00
GetPromptRequestSchema,
2025-03-01 14:57:56 -05:00
} from "@modelcontextprotocol/sdk/types .js";
const server = new Server(
{
name: "example-server",
2025-03-01 14:59:48 -05:00
version: "1.0.0",
2025-03-01 14:57:56 -05:00
},
{
capabilities: {
2025-03-01 14:59:48 -05:00
prompts: {},
},
2025-03-01 14:57:56 -05:00
}
);
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
2025-03-01 14:59:48 -05:00
prompts: [
{
name: "example-prompt",
description: "An example prompt template",
arguments: [
{
name: "arg1",
description: "Example argument",
required: true,
},
],
},
],
2025-03-01 14:57:56 -05:00
};
});
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
if (request.params.name !== "example-prompt") {
throw new Error("Unknown prompt");
}
return {
description: "Example prompt",
2025-03-01 14:59:48 -05:00
messages: [
{
role: "user",
content: {
type: "text",
text: "Example prompt text",
},
},
],
2025-03-01 14:57:56 -05:00
};
});
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Writing MCP Clients
The SDK provides a high-level client interface:
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index .js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio .js";
const transport = new StdioClientTransport({
command: "node",
2025-03-01 14:59:48 -05:00
args: ["server.js"],
2025-03-01 14:57:56 -05:00
});
const client = new Client(
{
name: "example-client",
2025-03-01 14:59:48 -05:00
version: "1.0.0",
2025-03-01 14:57:56 -05:00
},
{
capabilities: {
prompts: {},
resources: {},
2025-03-01 14:59:48 -05:00
tools: {},
},
2025-03-01 14:57:56 -05:00
}
);
await client.connect(transport);
// List prompts
const prompts = await client.listPrompts();
// Get a prompt
const prompt = await client.getPrompt("example-prompt", {
2025-03-01 14:59:48 -05:00
arg1: "value",
2025-03-01 14:57:56 -05:00
});
// List resources
const resources = await client.listResources();
// Read a resource
const resource = await client.readResource("file:///example.txt");
// Call a tool
const result = await client.callTool({
name: "example-tool",
arguments: {
2025-03-01 14:59:48 -05:00
arg1: "value",
},
2025-03-01 14:57:56 -05:00
});
```
## Documentation
- [Model Context Protocol documentation ](mdc:https:/modelcontextprotocol.io )
- [MCP Specification ](mdc:https:/spec.modelcontextprotocol.io )
- [Example Servers ](mdc:https:/github.com/modelcontextprotocol/servers )
## Contributing
Issues and pull requests are welcome on GitHub at https://github.com/modelcontextprotocol/typescript-sdk.
## License
2025-03-01 14:59:48 -05:00
This project is licensed under the MIT License—see the [LICENSE ](mdc:LICENSE ) file for details.