This is page 1 of 2. Use http://codebase.md/lorrylockie/lark-mcp?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .gitignore ├── build │ ├── config.js │ ├── lark-client.js │ └── server.js ├── index.ts ├── llm-full.txt ├── package-lock.json ├── package.json ├── README.md ├── src │ ├── config.ts │ ├── lark-client.ts │ └── server.ts ├── tsconfig.json └── typescript-sdk.txt ``` # Files -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # vitepress build output 108 | **/.vitepress/dist 109 | 110 | # vitepress cache directory 111 | **/.vitepress/cache 112 | 113 | # Docusaurus cache and generated files 114 | .docusaurus 115 | 116 | # Serverless directories 117 | .serverless/ 118 | 119 | # FuseBox cache 120 | .fusebox/ 121 | 122 | # DynamoDB Local files 123 | .dynamodb/ 124 | 125 | # TernJS port file 126 | .tern-port 127 | 128 | # Stores VSCode versions used for testing VSCode extensions 129 | .vscode-test 130 | 131 | # yarn v2 132 | .yarn/cache 133 | .yarn/unplugged 134 | .yarn/build-state.yml 135 | .yarn/install-state.gz 136 | .pnp.* ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown 1 | # Lark MCP Server 2 | 3 | A Model Context Protocol (MCP) server that integrates with Lark/Feishu APIs, allowing LLMs to interact with Lark services. 4 | 5 | ## Features 6 | 7 | - Query employee information using Lark's Contact API 8 | - More features coming soon... 9 | 10 | ## Prerequisites 11 | 12 | - Node.js 16 or higher 13 | - A Lark/Feishu application with App ID and App Secret 14 | - [Claude for Desktop](https://claude.ai/download) or another MCP client 15 | 16 | ## Installation 17 | 18 | ```bash 19 | npm install 20 | npm run build 21 | ``` 22 | 23 | ## Usage 24 | 25 | You can run the server in two ways: 26 | 27 | ### 1. Using Command Line Arguments (Recommended) 28 | 29 | ```bash 30 | npx lark-mcp <app_id> <app_secret> 31 | ``` 32 | 33 | Replace `<app_id>` and `<app_secret>` with your Lark application credentials. 34 | 35 | ### 2. Using Environment Variables 36 | 37 | ```bash 38 | export LARK_APP_ID=your_app_id 39 | export LARK_APP_SECRET=your_app_secret 40 | npx lark-mcp 41 | ``` 42 | 43 | ## Available Tools 44 | 45 | ### get-user-info 46 | 47 | Retrieves employee information using their ID. 48 | 49 | Example usage in Claude: 50 | ``` 51 | Please look up employee information for ID 12345 52 | ``` 53 | 54 | ## Development 55 | 56 | 1. Clone the repository 57 | 2. Install dependencies: 58 | ```bash 59 | npm install 60 | ``` 61 | 3. Build the project: 62 | ```bash 63 | npm run build 64 | ``` 65 | 4. Start the server in development mode: 66 | ```bash 67 | npm run dev 68 | ``` 69 | 70 | ## Configuration 71 | 72 | The server prioritizes credentials in the following order: 73 | 1. Command line arguments 74 | 2. Environment variables 75 | 3. Default values (if any) 76 | 77 | ## Error Handling 78 | 79 | - The server will validate credentials before starting 80 | - API errors are properly handled and returned to the client 81 | - Detailed error messages help with troubleshooting 82 | 83 | ## License 84 | 85 | MIT 86 | 87 | ## Contributing 88 | 89 | 1. Fork the repository 90 | 2. Create your feature branch 91 | 3. Commit your changes 92 | 4. Push to the branch 93 | 5. Create a new Pull Request ``` -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- ```typescript 1 | ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "module": "Node16", 5 | "moduleResolution": "Node16", 6 | "outDir": "./build", 7 | "rootDir": "./src", 8 | "strict": true, 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules"] 15 | } ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "lark-mcp", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "description": "Lark MCP Server", 6 | "main": "build/server.js", 7 | "scripts": { 8 | "build": "tsc", 9 | "start": "node build/server.js", 10 | "dev": "tsc && node build/server.js" 11 | }, 12 | "dependencies": { 13 | "@larksuiteoapi/node-sdk": "^1.43.0", 14 | "@modelcontextprotocol/sdk": "^1.6.1" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^20.0.0", 18 | "typescript": "^5.0.0" 19 | } 20 | } 21 | ``` -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- ```typescript 1 | export interface LarkConfig { 2 | appId: string; 3 | appSecret: string; 4 | } 5 | 6 | function parseArgs(): Partial<LarkConfig> { 7 | const args = process.argv.slice(2); 8 | const config: Partial<LarkConfig> = {}; 9 | 10 | // Use positional arguments - first is appId, second is appSecret 11 | if (args.length >= 1) config.appId = args[0]; 12 | if (args.length >= 2) config.appSecret = args[1]; 13 | 14 | return config; 15 | } 16 | 17 | // Get config from command line args first, then fall back to environment variables 18 | const argsConfig = parseArgs(); 19 | export const config: LarkConfig = { 20 | appId: argsConfig.appId || process.env.LARK_APP_ID || '', 21 | appSecret: argsConfig.appSecret || process.env.LARK_APP_SECRET || '' 22 | }; 23 | 24 | // Validate config 25 | if (!config.appId || !config.appSecret) { 26 | console.error(` 27 | Error: Missing required credentials 28 | Please provide credentials either through: 29 | 1. Command line arguments (recommended): 30 | npx command <app_id> <app_secret> 31 | 2. Environment variables: 32 | LARK_APP_ID=xxx LARK_APP_SECRET=xxx npx command 33 | `); 34 | process.exit(1); 35 | } ``` -------------------------------------------------------------------------------- /src/lark-client.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { Client } from "@larksuiteoapi/node-sdk"; 2 | import { config } from "./config.js"; 3 | 4 | export class LarkClient { 5 | private client: Client; 6 | 7 | constructor() { 8 | this.client = new Client({ 9 | appId: config.appId, 10 | appSecret: config.appSecret, 11 | disableTokenCache: false // Enable SDK's automatic token management 12 | }); 13 | } 14 | 15 | // Get user information by employee ID 16 | async getUserInfo(employeeId: string) { 17 | try { 18 | const response = await this.client.contact.v3.user.get({ 19 | path: { 20 | user_id: employeeId, 21 | }, 22 | params: { 23 | user_id_type: 'user_id', // Using open_id as the lookup type 24 | department_id_type: 'open_department_id', 25 | } 26 | }); 27 | 28 | return response.data; 29 | } catch (error) { 30 | console.error('Error fetching user info:', error); 31 | throw error; 32 | } 33 | } 34 | 35 | // This method will be used to get the client instance 36 | getClient(): Client { 37 | return this.client; 38 | } 39 | 40 | // Add helper methods for common Lark API operations 41 | // These will be implemented based on the specific tools we need 42 | } ``` -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 2 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 3 | import { z } from "zod"; 4 | import { LarkClient } from "./lark-client.js"; 5 | 6 | // Initialize Lark client 7 | const larkClient = new LarkClient(); 8 | 9 | // Create MCP server 10 | const server = new McpServer({ 11 | name: "lark-mcp", 12 | version: "1.0.0" 13 | }); 14 | 15 | // Tool for getting user information 16 | server.tool( 17 | "get-user-info", 18 | { 19 | employee_id: z.string().describe("Employee ID to look up") 20 | }, 21 | async ({ employee_id }) => { 22 | try { 23 | const userData = await larkClient.getUserInfo(employee_id); 24 | return { 25 | content: [{ 26 | type: "text", 27 | text: JSON.stringify(userData, null, 2) 28 | }] 29 | }; 30 | } catch (error) { 31 | return { 32 | content: [{ 33 | type: "text", 34 | text: `Error fetching user info: ${error instanceof Error ? error.message : 'Unknown error'}` 35 | }], 36 | isError: true 37 | }; 38 | } 39 | } 40 | ); 41 | 42 | // Example tool structure - will be replaced with actual implementations 43 | server.tool( 44 | "send-message", 45 | { 46 | receive_id: z.string().describe("Receiver's ID"), 47 | msg_type: z.string().describe("Message type (text, post, image, etc.)"), 48 | content: z.string().describe("Message content") 49 | }, 50 | async ({ receive_id, msg_type, content }) => { 51 | try { 52 | // Placeholder for actual implementation 53 | return { 54 | content: [{ 55 | type: "text", 56 | text: "Message sent successfully" 57 | }] 58 | }; 59 | } catch (error) { 60 | return { 61 | content: [{ 62 | type: "text", 63 | text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}` 64 | }], 65 | isError: true 66 | }; 67 | } 68 | } 69 | ); 70 | 71 | // Main function to start the server 72 | async function main() { 73 | try { 74 | const transport = new StdioServerTransport(); 75 | await server.connect(transport); 76 | console.error("Lark MCP Server running on stdio"); 77 | } catch (error) { 78 | console.error("Fatal error:", error); 79 | process.exit(1); 80 | } 81 | } 82 | 83 | // Start the server 84 | main().catch((error) => { 85 | console.error("Unhandled error:", error); 86 | process.exit(1); 87 | }); ``` -------------------------------------------------------------------------------- /typescript-sdk.txt: -------------------------------------------------------------------------------- ``` 1 | # MCP TypeScript SDK   2 | 3 | ## Table of Contents 4 | - [Overview](#overview) 5 | - [Installation](#installation) 6 | - [Quickstart](#quickstart) 7 | - [What is MCP?](#what-is-mcp) 8 | - [Core Concepts](#core-concepts) 9 | - [Server](#server) 10 | - [Resources](#resources) 11 | - [Tools](#tools) 12 | - [Prompts](#prompts) 13 | - [Running Your Server](#running-your-server) 14 | - [stdio](#stdio) 15 | - [HTTP with SSE](#http-with-sse) 16 | - [Testing and Debugging](#testing-and-debugging) 17 | - [Examples](#examples) 18 | - [Echo Server](#echo-server) 19 | - [SQLite Explorer](#sqlite-explorer) 20 | - [Advanced Usage](#advanced-usage) 21 | - [Low-Level Server](#low-level-server) 22 | - [Writing MCP Clients](#writing-mcp-clients) 23 | - [Server Capabilities](#server-capabilities) 24 | 25 | ## Overview 26 | 27 | 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: 28 | 29 | - Build MCP clients that can connect to any MCP server 30 | - Create MCP servers that expose resources, prompts and tools 31 | - Use standard transports like stdio and SSE 32 | - Handle all MCP protocol messages and lifecycle events 33 | 34 | ## Installation 35 | 36 | ```bash 37 | npm install @modelcontextprotocol/sdk 38 | ``` 39 | 40 | ## Quick Start 41 | 42 | Let's create a simple MCP server that exposes a calculator tool and some data: 43 | 44 | ```typescript 45 | import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; 46 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 47 | import { z } from "zod"; 48 | 49 | // Create an MCP server 50 | const server = new McpServer({ 51 | name: "Demo", 52 | version: "1.0.0" 53 | }); 54 | 55 | // Add an addition tool 56 | server.tool("add", 57 | { a: z.number(), b: z.number() }, 58 | async ({ a, b }) => ({ 59 | content: [{ type: "text", text: String(a + b) }] 60 | }) 61 | ); 62 | 63 | // Add a dynamic greeting resource 64 | server.resource( 65 | "greeting", 66 | new ResourceTemplate("greeting://{name}", { list: undefined }), 67 | async (uri, { name }) => ({ 68 | contents: [{ 69 | uri: uri.href, 70 | text: `Hello, ${name}!` 71 | }] 72 | }) 73 | ); 74 | 75 | // Start receiving messages on stdin and sending messages on stdout 76 | const transport = new StdioServerTransport(); 77 | await server.connect(transport); 78 | ``` 79 | 80 | ## What is MCP? 81 | 82 | The [Model Context Protocol (MCP)](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: 83 | 84 | - Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context) 85 | - Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect) 86 | - Define interaction patterns through **Prompts** (reusable templates for LLM interactions) 87 | - And more! 88 | 89 | ## Core Concepts 90 | 91 | ### Server 92 | 93 | The McpServer is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing: 94 | 95 | ```typescript 96 | const server = new McpServer({ 97 | name: "My App", 98 | version: "1.0.0" 99 | }); 100 | ``` 101 | 102 | ### Resources 103 | 104 | 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: 105 | 106 | ```typescript 107 | // Static resource 108 | server.resource( 109 | "config", 110 | "config://app", 111 | async (uri) => ({ 112 | contents: [{ 113 | uri: uri.href, 114 | text: "App configuration here" 115 | }] 116 | }) 117 | ); 118 | 119 | // Dynamic resource with parameters 120 | server.resource( 121 | "user-profile", 122 | new ResourceTemplate("users://{userId}/profile", { list: undefined }), 123 | async (uri, { userId }) => ({ 124 | contents: [{ 125 | uri: uri.href, 126 | text: `Profile data for user ${userId}` 127 | }] 128 | }) 129 | ); 130 | ``` 131 | 132 | ### Tools 133 | 134 | Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects: 135 | 136 | ```typescript 137 | // Simple tool with parameters 138 | server.tool( 139 | "calculate-bmi", 140 | { 141 | weightKg: z.number(), 142 | heightM: z.number() 143 | }, 144 | async ({ weightKg, heightM }) => ({ 145 | content: [{ 146 | type: "text", 147 | text: String(weightKg / (heightM * heightM)) 148 | }] 149 | }) 150 | ); 151 | 152 | // Async tool with external API call 153 | server.tool( 154 | "fetch-weather", 155 | { city: z.string() }, 156 | async ({ city }) => { 157 | const response = await fetch(`https://api.weather.com/${city}`); 158 | const data = await response.text(); 159 | return { 160 | content: [{ type: "text", text: data }] 161 | }; 162 | } 163 | ); 164 | ``` 165 | 166 | ### Prompts 167 | 168 | Prompts are reusable templates that help LLMs interact with your server effectively: 169 | 170 | ```typescript 171 | server.prompt( 172 | "review-code", 173 | { code: z.string() }, 174 | ({ code }) => ({ 175 | messages: [{ 176 | role: "user", 177 | content: { 178 | type: "text", 179 | text: `Please review this code:\n\n${code}` 180 | } 181 | }] 182 | }) 183 | ); 184 | ``` 185 | 186 | ## Running Your Server 187 | 188 | 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: 189 | 190 | ### stdio 191 | 192 | For command-line tools and direct integrations: 193 | 194 | ```typescript 195 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 196 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 197 | 198 | const server = new McpServer({ 199 | name: "example-server", 200 | version: "1.0.0" 201 | }); 202 | 203 | // ... set up server resources, tools, and prompts ... 204 | 205 | const transport = new StdioServerTransport(); 206 | await server.connect(transport); 207 | ``` 208 | 209 | ### HTTP with SSE 210 | 211 | 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: 212 | 213 | ```typescript 214 | import express from "express"; 215 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 216 | import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; 217 | 218 | const server = new McpServer({ 219 | name: "example-server", 220 | version: "1.0.0" 221 | }); 222 | 223 | // ... set up server resources, tools, and prompts ... 224 | 225 | const app = express(); 226 | 227 | app.get("/sse", async (req, res) => { 228 | const transport = new SSEServerTransport("/messages", res); 229 | await server.connect(transport); 230 | }); 231 | 232 | app.post("/messages", async (req, res) => { 233 | // Note: to support multiple simultaneous connections, these messages will 234 | // need to be routed to a specific matching transport. (This logic isn't 235 | // implemented here, for simplicity.) 236 | await transport.handlePostMessage(req, res); 237 | }); 238 | 239 | app.listen(3001); 240 | ``` 241 | 242 | ### Testing and Debugging 243 | 244 | To test your server, you can use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). See its README for more information. 245 | 246 | ## Examples 247 | 248 | ### Echo Server 249 | 250 | A simple server demonstrating resources, tools, and prompts: 251 | 252 | ```typescript 253 | import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; 254 | import { z } from "zod"; 255 | 256 | const server = new McpServer({ 257 | name: "Echo", 258 | version: "1.0.0" 259 | }); 260 | 261 | server.resource( 262 | "echo", 263 | new ResourceTemplate("echo://{message}", { list: undefined }), 264 | async (uri, { message }) => ({ 265 | contents: [{ 266 | uri: uri.href, 267 | text: `Resource echo: ${message}` 268 | }] 269 | }) 270 | ); 271 | 272 | server.tool( 273 | "echo", 274 | { message: z.string() }, 275 | async ({ message }) => ({ 276 | content: [{ type: "text", text: `Tool echo: ${message}` }] 277 | }) 278 | ); 279 | 280 | server.prompt( 281 | "echo", 282 | { message: z.string() }, 283 | ({ message }) => ({ 284 | messages: [{ 285 | role: "user", 286 | content: { 287 | type: "text", 288 | text: `Please process this message: ${message}` 289 | } 290 | }] 291 | }) 292 | ); 293 | ``` 294 | 295 | ### SQLite Explorer 296 | 297 | A more complex example showing database integration: 298 | 299 | ```typescript 300 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 301 | import sqlite3 from "sqlite3"; 302 | import { promisify } from "util"; 303 | import { z } from "zod"; 304 | 305 | const server = new McpServer({ 306 | name: "SQLite Explorer", 307 | version: "1.0.0" 308 | }); 309 | 310 | // Helper to create DB connection 311 | const getDb = () => { 312 | const db = new sqlite3.Database("database.db"); 313 | return { 314 | all: promisify<string, any[]>(db.all.bind(db)), 315 | close: promisify(db.close.bind(db)) 316 | }; 317 | }; 318 | 319 | server.resource( 320 | "schema", 321 | "schema://main", 322 | async (uri) => { 323 | const db = getDb(); 324 | try { 325 | const tables = await db.all( 326 | "SELECT sql FROM sqlite_master WHERE type='table'" 327 | ); 328 | return { 329 | contents: [{ 330 | uri: uri.href, 331 | text: tables.map((t: {sql: string}) => t.sql).join("\n") 332 | }] 333 | }; 334 | } finally { 335 | await db.close(); 336 | } 337 | } 338 | ); 339 | 340 | server.tool( 341 | "query", 342 | { sql: z.string() }, 343 | async ({ sql }) => { 344 | const db = getDb(); 345 | try { 346 | const results = await db.all(sql); 347 | return { 348 | content: [{ 349 | type: "text", 350 | text: JSON.stringify(results, null, 2) 351 | }] 352 | }; 353 | } catch (err: unknown) { 354 | const error = err as Error; 355 | return { 356 | content: [{ 357 | type: "text", 358 | text: `Error: ${error.message}` 359 | }], 360 | isError: true 361 | }; 362 | } finally { 363 | await db.close(); 364 | } 365 | } 366 | ); 367 | ``` 368 | 369 | ## Advanced Usage 370 | 371 | ### Low-Level Server 372 | 373 | For more control, you can use the low-level Server class directly: 374 | 375 | ```typescript 376 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; 377 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 378 | import { 379 | ListPromptsRequestSchema, 380 | GetPromptRequestSchema 381 | } from "@modelcontextprotocol/sdk/types.js"; 382 | 383 | const server = new Server( 384 | { 385 | name: "example-server", 386 | version: "1.0.0" 387 | }, 388 | { 389 | capabilities: { 390 | prompts: {} 391 | } 392 | } 393 | ); 394 | 395 | server.setRequestHandler(ListPromptsRequestSchema, async () => { 396 | return { 397 | prompts: [{ 398 | name: "example-prompt", 399 | description: "An example prompt template", 400 | arguments: [{ 401 | name: "arg1", 402 | description: "Example argument", 403 | required: true 404 | }] 405 | }] 406 | }; 407 | }); 408 | 409 | server.setRequestHandler(GetPromptRequestSchema, async (request) => { 410 | if (request.params.name !== "example-prompt") { 411 | throw new Error("Unknown prompt"); 412 | } 413 | return { 414 | description: "Example prompt", 415 | messages: [{ 416 | role: "user", 417 | content: { 418 | type: "text", 419 | text: "Example prompt text" 420 | } 421 | }] 422 | }; 423 | }); 424 | 425 | const transport = new StdioServerTransport(); 426 | await server.connect(transport); 427 | ``` 428 | 429 | ### Writing MCP Clients 430 | 431 | The SDK provides a high-level client interface: 432 | 433 | ```typescript 434 | import { Client } from "@modelcontextprotocol/sdk/client/index.js"; 435 | import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; 436 | 437 | const transport = new StdioClientTransport({ 438 | command: "node", 439 | args: ["server.js"] 440 | }); 441 | 442 | const client = new Client( 443 | { 444 | name: "example-client", 445 | version: "1.0.0" 446 | }, 447 | { 448 | capabilities: { 449 | prompts: {}, 450 | resources: {}, 451 | tools: {} 452 | } 453 | } 454 | ); 455 | 456 | await client.connect(transport); 457 | 458 | // List prompts 459 | const prompts = await client.listPrompts(); 460 | 461 | // Get a prompt 462 | const prompt = await client.getPrompt("example-prompt", { 463 | arg1: "value" 464 | }); 465 | 466 | // List resources 467 | const resources = await client.listResources(); 468 | 469 | // Read a resource 470 | const resource = await client.readResource("file:///example.txt"); 471 | 472 | // Call a tool 473 | const result = await client.callTool({ 474 | name: "example-tool", 475 | arguments: { 476 | arg1: "value" 477 | } 478 | }); 479 | ``` 480 | 481 | ## Documentation 482 | 483 | - [Model Context Protocol documentation](https://modelcontextprotocol.io) 484 | - [MCP Specification](https://spec.modelcontextprotocol.io) 485 | - [Example Servers](https://github.com/modelcontextprotocol/servers) 486 | 487 | ## Contributing 488 | 489 | Issues and pull requests are welcome on GitHub at https://github.com/modelcontextprotocol/typescript-sdk. 490 | 491 | ## License 492 | 493 | This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details. ```