Skip to main content
Glama

MCP TypeScript SDK

MIT License
3,786,513

MCP TypeScript SDK NPM Version MIT licensed

Table of Contents

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 Streamable HTTP
  • Handle all MCP protocol messages and lifecycle events

Installation

npm install @modelcontextprotocol/sdk

Quick Start

Let's create a simple MCP server that exposes a calculator tool and some data:

import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; // Create an MCP server const server = new McpServer({ name: "demo-server", version: "1.0.0" }); // Add an addition tool server.registerTool("add", { title: "Addition Tool", description: "Add two numbers", inputSchema: { a: z.number(), b: z.number() } }, async ({ a, b }) => ({ content: [{ type: "text", text: String(a + b) }] }) ); // Add a dynamic greeting resource server.registerResource( "greeting", new ResourceTemplate("greeting://{name}", { list: undefined }), { title: "Greeting Resource", // Display name for UI description: "Dynamic greeting generator" }, async (uri, { name }) => ({ contents: [{ uri: uri.href, text: `Hello, ${name}!` }] }) ); // 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) 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:

const server = new McpServer({ name: "my-app", version: "1.0.0" });

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:

// Static resource server.registerResource( "config", "config://app", { title: "Application Config", description: "Application configuration data", mimeType: "text/plain" }, async (uri) => ({ contents: [{ uri: uri.href, text: "App configuration here" }] }) ); // Dynamic resource with parameters server.registerResource( "user-profile", new ResourceTemplate("users://{userId}/profile", { list: undefined }), { title: "User Profile", description: "User profile information" }, async (uri, { userId }) => ({ contents: [{ uri: uri.href, text: `Profile data for user ${userId}` }] }) ); // Resource with context-aware completion server.registerResource( "repository", new ResourceTemplate("github://repos/{owner}/{repo}", { list: undefined, complete: { // Provide intelligent completions based on previously resolved parameters repo: (value, context) => { if (context?.arguments?.["owner"] === "org1") { return ["project1", "project2", "project3"].filter(r => r.startsWith(value)); } return ["default-repo"].filter(r => r.startsWith(value)); } } }), { title: "GitHub Repository", description: "Repository information" }, async (uri, { owner, repo }) => ({ contents: [{ uri: uri.href, text: `Repository: ${owner}/${repo}` }] }) );

Tools

Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:

// Simple tool with parameters server.registerTool( "calculate-bmi", { title: "BMI Calculator", description: "Calculate Body Mass Index", inputSchema: { weightKg: z.number(), heightM: z.number() } }, async ({ weightKg, heightM }) => ({ content: [{ type: "text", text: String(weightKg / (heightM * heightM)) }] }) ); // Async tool with external API call server.registerTool( "fetch-weather", { title: "Weather Fetcher", description: "Get weather data for a city", inputSchema: { 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 }] }; } ); // Tool that returns ResourceLinks server.registerTool( "list-files", { title: "List Files", description: "List project files", inputSchema: { pattern: z.string() } }, async ({ pattern }) => ({ content: [ { type: "text", text: `Found files matching "${pattern}":` }, // ResourceLinks let tools return references without file content { type: "resource_link", uri: "file:///project/README.md", name: "README.md", mimeType: "text/markdown", description: 'A README file' }, { type: "resource_link", uri: "file:///project/src/index.ts", name: "index.ts", mimeType: "text/typescript", description: 'An index file' } ] }) );

Tools can return ResourceLink objects to reference resources without embedding their full content. This is essential for performance when dealing with large files or many resources - clients can then selectively read only the resources they need using the provided URIs.

Prompts

Prompts are reusable templates that help LLMs interact with your server effectively:

import { completable } from "@modelcontextprotocol/sdk/server/completable.js"; server.registerPrompt( "review-code", { title: "Code Review", description: "Review code for best practices and potential issues", argsSchema: { code: z.string() } }, ({ code }) => ({ messages: [{ role: "user", content: { type: "text", text: `Please review this code:\n\n${code}` } }] }) ); // Prompt with context-aware completion server.registerPrompt( "team-greeting", { title: "Team Greeting", description: "Generate a greeting for team members", argsSchema: { department: completable(z.string(), (value) => { // Department suggestions return ["engineering", "sales", "marketing", "support"].filter(d => d.startsWith(value)); }), name: completable(z.string(), (value, context) => { // Name suggestions based on selected department const department = context?.arguments?.["department"]; if (department === "engineering") { return ["Alice", "Bob", "Charlie"].filter(n => n.startsWith(value)); } else if (department === "sales") { return ["David", "Eve", "Frank"].filter(n => n.startsWith(value)); } else if (department === "marketing") { return ["Grace", "Henry", "Iris"].filter(n => n.startsWith(value)); } return ["Guest"].filter(n => n.startsWith(value)); }) } }, ({ department, name }) => ({ messages: [{ role: "assistant", content: { type: "text", text: `Hello ${name}, welcome to the ${department} team!` } }] }) );

Completions

MCP supports argument completions to help users fill in prompt arguments and resource template parameters. See the examples above for resource completions and prompt completions.

Client Usage
// Request completions for any argument const result = await client.complete({ ref: { type: "ref/prompt", // or "ref/resource" name: "example" // or uri: "template://..." }, argument: { name: "argumentName", value: "partial" // What the user has typed so far }, context: { // Optional: Include previously resolved arguments arguments: { previousArg: "value" } } });

Display Names and Metadata

All resources, tools, and prompts support an optional title field for better UI presentation. The title is used as a display name, while name remains the unique identifier.

Note: The register* methods (registerTool, registerPrompt, registerResource) are the recommended approach for new code. The older methods (tool, prompt, resource) remain available for backwards compatibility.

Title Precedence for Tools

For tools specifically, there are two ways to specify a title:

  • title field in the tool configuration
  • annotations.title field (when using the older tool() method with annotations)

The precedence order is: titleannotations.titlename

// Using registerTool (recommended) server.registerTool("my_tool", { title: "My Tool", // This title takes precedence annotations: { title: "Annotation Title" // This is ignored if title is set } }, handler); // Using tool with annotations (older API) server.tool("my_tool", "description", { title: "Annotation Title" // This is used as title }, handler);

When building clients, use the provided utility to get the appropriate display name:

import { getDisplayName } from "@modelcontextprotocol/sdk/shared/metadataUtils.js"; // Automatically handles the precedence: title → annotations.title → name const displayName = getDisplayName(tool);

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:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; const server = new McpServer({ name: "example-server", version: "1.0.0" }); // ... set up server resources, tools, and prompts ... const transport = new StdioServerTransport(); await server.connect(transport);

Streamable HTTP

For remote servers, set up a Streamable HTTP transport that handles both client requests and server-to-client notifications.

With Session Management

In some cases, servers need to be stateful. This is achieved by session management.

import express from "express"; import { randomUUID } from "node:crypto"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js" const app = express(); app.use(express.json()); // Map to store transports by session ID const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {}; // Handle POST requests for client-to-server communication app.post('/mcp', async (req, res) => { // Check for existing session ID const sessionId = req.headers['mcp-session-id'] as string | undefined; let transport: StreamableHTTPServerTransport; if (sessionId && transports[sessionId]) { // Reuse existing transport transport = transports[sessionId]; } else if (!sessionId && isInitializeRequest(req.body)) { // New initialization request transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (sessionId) => { // Store the transport by session ID transports[sessionId] = transport; } }); // Clean up transport when closed transport.onclose = () => { if (transport.sessionId) { delete transports[transport.sessionId]; } }; const server = new McpServer({ name: "example-server", version: "1.0.0" }); // ... set up server resources, tools, and prompts ... // Connect to the MCP server await server.connect(transport); } else { // Invalid request res.status(400).json({ jsonrpc: '2.0', error: { code: -32000, message: 'Bad Request: No valid session ID provided', }, id: null, }); return; } // Handle the request await transport.handleRequest(req, res, req.body); }); // Reusable handler for GET and DELETE requests const handleSessionRequest = async (req: express.Request, res: express.Response) => { const sessionId = req.headers['mcp-session-id'] as string | undefined; if (!sessionId || !transports[sessionId]) { res.status(400).send('Invalid or missing session ID'); return; } const transport = transports[sessionId]; await transport.handleRequest(req, res); }; // Handle GET requests for server-to-client notifications via SSE app.get('/mcp', handleSessionRequest); // Handle DELETE requests for session termination app.delete('/mcp', handleSessionRequest); app.listen(3000);
Without Session Management (Stateless)

For simpler use cases where session management isn't needed:

const app = express(); app.use(express.json()); app.post('/mcp', async (req: Request, res: Response) => { // In stateless mode, create a new instance of transport and server for each request // to ensure complete isolation. A single instance would cause request ID collisions // when multiple clients connect concurrently. try { const server = getServer(); const transport: StreamableHTTPServerTransport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, }); res.on('close', () => { console.log('Request closed'); transport.close(); server.close(); }); await server.connect(transport); await transport.handleRequest(req, res, req.body); } catch (error) { console.error('Error handling MCP request:', error); if (!res.headersSent) { res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: 'Internal server error', }, id: null, }); } } }); app.get('/mcp', async (req: Request, res: Response) => { console.log('Received GET MCP request'); res.writeHead(405).end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32000, message: "Method not allowed." }, id: null })); }); app.delete('/mcp', async (req: Request, res: Response) => { console.log('Received DELETE MCP request'); res.writeHead(405).end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32000, message: "Method not allowed." }, id: null })); }); // Start the server const PORT = 3000; app.listen(PORT, () => { console.log(`MCP Stateless Streamable HTTP Server listening on port ${PORT}`); });

This stateless approach is useful for:

  • Simple API wrappers
  • RESTful scenarios where each request is independent
  • Horizontally scaled deployments without shared session state

Testing and Debugging

To test your server, you can use the MCP Inspector. See its README for more information.

Examples

Echo Server

A simple server demonstrating resources, tools, and prompts:

import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; const server = new McpServer({ name: "echo-server", version: "1.0.0" }); server.registerResource( "echo", new ResourceTemplate("echo://{message}", { list: undefined }), { title: "Echo Resource", description: "Echoes back messages as resources" }, async (uri, { message }) => ({ contents: [{ uri: uri.href, text: `Resource echo: ${message}` }] }) ); server.registerTool( "echo", { title: "Echo Tool", description: "Echoes back the provided message", inputSchema: { message: z.string() } }, async ({ message }) => ({ content: [{ type: "text", text: `Tool echo: ${message}` }] }) ); server.registerPrompt( "echo", { title: "Echo Prompt", description: "Creates a prompt to process a message", argsSchema: { message: z.string() } }, ({ message }) => ({ messages: [{ role: "user", content: { type: "text", text: `Please process this message: ${message}` } }] }) );

SQLite Explorer

A more complex example showing database integration:

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", version: "1.0.0" }); // Helper to create DB connection const getDb = () => { const db = new sqlite3.Database("database.db"); return { all: promisify<string, any[]>(db.all.bind(db)), close: promisify(db.close.bind(db)) }; }; server.registerResource( "schema", "schema://main", { title: "Database Schema", description: "SQLite database schema", mimeType: "text/plain" }, async (uri) => { const db = getDb(); try { const tables = await db.all( "SELECT sql FROM sqlite_master WHERE type='table'" ); return { contents: [{ uri: uri.href, text: tables.map((t: {sql: string}) => t.sql).join("\n") }] }; } finally { await db.close(); } } ); server.registerTool( "query", { title: "SQL Query", description: "Execute SQL queries on the database", inputSchema: { sql: z.string() } }, async ({ sql }) => { const db = getDb(); try { const results = await db.all(sql); return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] }; } catch (err: unknown) { const error = err as Error; return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true }; } finally { await db.close(); } } );

Advanced Usage

Dynamic Servers

If you want to offer an initial set of tools/prompts/resources, but later add additional ones based on user action or external state change, you can add/update/remove them after the Server is connected. This will automatically emit the corresponding listChanged notifications:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; const server = new McpServer({ name: "Dynamic Example", version: "1.0.0" }); const listMessageTool = server.tool( "listMessages", { channel: z.string() }, async ({ channel }) => ({ content: [{ type: "text", text: await listMessages(channel) }] }) ); const putMessageTool = server.tool( "putMessage", { channel: z.string(), message: z.string() }, async ({ channel, message }) => ({ content: [{ type: "text", text: await putMessage(channel, string) }] }) ); // Until we upgrade auth, `putMessage` is disabled (won't show up in listTools) putMessageTool.disable() const upgradeAuthTool = server.tool( "upgradeAuth", { permission: z.enum(["write', admin"])}, // Any mutations here will automatically emit `listChanged` notifications async ({ permission }) => { const { ok, err, previous } = await upgradeAuthAndStoreToken(permission) if (!ok) return {content: [{ type: "text", text: `Error: ${err}` }]} // If we previously had read-only access, 'putMessage' is now available if (previous === "read") { putMessageTool.enable() } if (permission === 'write') { // If we've just upgraded to 'write' permissions, we can still call 'upgradeAuth' // but can only upgrade to 'admin'. upgradeAuthTool.update({ paramSchema: { permission: z.enum(["admin"]) }, // change validation rules }) } else { // If we're now an admin, we no longer have anywhere to upgrade to, so fully remove that tool upgradeAuthTool.remove() } } ) // Connect as normal const transport = new StdioServerTransport(); await server.connect(transport);

Low-Level Server

For more control, you can use the low-level Server class directly:

import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { ListPromptsRequestSchema, GetPromptRequestSchema } from "@modelcontextprotocol/sdk/types.js"; const server = new Server( { name: "example-server", version: "1.0.0" }, { capabilities: { prompts: {} } } ); server.setRequestHandler(ListPromptsRequestSchema, async () => { return { prompts: [{ name: "example-prompt", description: "An example prompt template", arguments: [{ name: "arg1", description: "Example argument", required: true }] }] }; }); server.setRequestHandler(GetPromptRequestSchema, async (request) => { if (request.params.name !== "example-prompt") { throw new Error("Unknown prompt"); } return { description: "Example prompt", messages: [{ role: "user", content: { type: "text", text: "Example prompt text" } }] }; }); const transport = new StdioServerTransport(); await server.connect(transport);

Eliciting User Input

MCP servers can request additional information from users through the elicitation feature. This is useful for interactive workflows where the server needs user input or confirmation:

// Server-side: Restaurant booking tool that asks for alternatives server.tool( "book-restaurant", { restaurant: z.string(), date: z.string(), partySize: z.number() }, async ({ restaurant, date, partySize }) => { // Check availability const available = await checkAvailability(restaurant, date, partySize); if (!available) { // Ask user if they want to try alternative dates const result = await server.server.elicitInput({ message: `No tables available at ${restaurant} on ${date}. Would you like to check alternative dates?`, requestedSchema: { type: "object", properties: { checkAlternatives: { type: "boolean", title: "Check alternative dates", description: "Would you like me to check other dates?" }, flexibleDates: { type: "string", title: "Date flexibility", description: "How flexible are your dates?", enum: ["next_day", "same_week", "next_week"], enumNames: ["Next day", "Same week", "Next week"] } }, required: ["checkAlternatives"] } }); if (result.action === "accept" && result.content?.checkAlternatives) { const alternatives = await findAlternatives( restaurant, date, partySize, result.content.flexibleDates as string ); return { content: [{ type: "text", text: `Found these alternatives: ${alternatives.join(", ")}` }] }; } return { content: [{ type: "text", text: "No booking made. Original date not available." }] }; } // Book the table await makeBooking(restaurant, date, partySize); return { content: [{ type: "text", text: `Booked table for ${partySize} at ${restaurant} on ${date}` }] }; } );

Client-side: Handle elicitation requests

// This is a placeholder - implement based on your UI framework async function getInputFromUser(message: string, schema: any): Promise<{ action: "accept" | "reject" | "cancel"; data?: Record<string, any>; }> { // This should be implemented depending on the app throw new Error("getInputFromUser must be implemented for your platform"); } client.setRequestHandler(ElicitRequestSchema, async (request) => { const userResponse = await getInputFromUser( request.params.message, request.params.requestedSchema ); return { action: userResponse.action, content: userResponse.action === "accept" ? userResponse.data : undefined }; });

Note: Elicitation requires client support. Clients must declare the elicitation capability during initialization.

Writing MCP Clients

The SDK provides a high-level client interface:

import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; const transport = new StdioClientTransport({ command: "node", args: ["server.js"] }); const client = new Client( { name: "example-client", version: "1.0.0" } ); await client.connect(transport); // List prompts const prompts = await client.listPrompts(); // Get a prompt const prompt = await client.getPrompt({ name: "example-prompt", arguments: { arg1: "value" } }); // List resources const resources = await client.listResources(); // Read a resource const resource = await client.readResource({ uri: "file:///example.txt" }); // Call a tool const result = await client.callTool({ name: "example-tool", arguments: { arg1: "value" } });

Proxy Authorization Requests Upstream

You can proxy OAuth requests to an external authorization provider:

import express from 'express'; import { ProxyOAuthServerProvider } from '@modelcontextprotocol/sdk/server/auth/providers/proxyProvider.js'; import { mcpAuthRouter } from '@modelcontextprotocol/sdk/server/auth/router.js'; const app = express(); const proxyProvider = new ProxyOAuthServerProvider({ endpoints: { authorizationUrl: "https://auth.external.com/oauth2/v1/authorize", tokenUrl: "https://auth.external.com/oauth2/v1/token", revocationUrl: "https://auth.external.com/oauth2/v1/revoke", }, verifyAccessToken: async (token) => { return { token, clientId: "123", scopes: ["openid", "email", "profile"], } }, getClient: async (client_id) => { return { client_id, redirect_uris: ["http://localhost:3000/callback"], } } }) app.use(mcpAuthRouter({ provider: proxyProvider, issuerUrl: new URL("http://auth.external.com"), baseUrl: new URL("http://mcp.example.com"), serviceDocumentationUrl: new URL("https://docs.example.com/"), }))

This setup allows you to:

  • Forward OAuth requests to an external provider
  • Add custom token validation logic
  • Manage client registrations
  • Provide custom documentation URLs
  • Maintain control over the OAuth flow while delegating to an external provider

Backwards Compatibility

Clients and servers with StreamableHttp tranport can maintain backwards compatibility with the deprecated HTTP+SSE transport (from protocol version 2024-11-05) as follows

Client-Side Compatibility

For clients that need to work with both Streamable HTTP and older SSE servers:

import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; let client: Client|undefined = undefined const baseUrl = new URL(url); try { client = new Client({ name: 'streamable-http-client', version: '1.0.0' }); const transport = new StreamableHTTPClientTransport( new URL(baseUrl) ); await client.connect(transport); console.log("Connected using Streamable HTTP transport"); } catch (error) { // If that fails with a 4xx error, try the older SSE transport console.log("Streamable HTTP connection failed, falling back to SSE transport"); client = new Client({ name: 'sse-client', version: '1.0.0' }); const sseTransport = new SSEClientTransport(baseUrl); await client.connect(sseTransport); console.log("Connected using SSE transport"); }
Server-Side Compatibility

For servers that need to support both Streamable HTTP and older clients:

import express from "express"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; const server = new McpServer({ name: "backwards-compatible-server", version: "1.0.0" }); // ... set up server resources, tools, and prompts ... const app = express(); app.use(express.json()); // Store transports for each session type const transports = { streamable: {} as Record<string, StreamableHTTPServerTransport>, sse: {} as Record<string, SSEServerTransport> }; // Modern Streamable HTTP endpoint app.all('/mcp', async (req, res) => { // Handle Streamable HTTP transport for modern clients // Implementation as shown in the "With Session Management" example // ... }); // Legacy SSE endpoint for older clients app.get('/sse', async (req, res) => { // Create SSE transport for legacy clients const transport = new SSEServerTransport('/messages', res); transports.sse[transport.sessionId] = transport; res.on("close", () => { delete transports.sse[transport.sessionId]; }); await server.connect(transport); }); // Legacy message endpoint for older clients app.post('/messages', async (req, res) => { const sessionId = req.query.sessionId as string; const transport = transports.sse[sessionId]; if (transport) { await transport.handlePostMessage(req, res, req.body); } else { res.status(400).send('No transport found for sessionId'); } }); app.listen(3000);

Note: The SSE transport is now deprecated in favor of Streamable HTTP. New implementations should use Streamable HTTP, and existing SSE implementations should plan to migrate.

Documentation

Contributing

Issues and pull requests are welcome on GitHub at https://github.com/modelcontextprotocol/typescript-sdk.

License

This project is licensed under the MIT License—see the LICENSE file for details.

-
security - not tested
A
license - permissive license
-
quality - not tested

A toolkit for building Model Context Protocol servers and clients that provide standardized context for LLMs, allowing applications to expose resources, tools, and prompts through stdio or Streamable HTTP transports.

  1. Table of Contents
    1. Overview
      1. Installation
        1. Quick Start
          1. What is MCP?
            1. Core Concepts
              1. Server
              2. Resources
              3. Tools
              4. Prompts
              5. Completions
              6. Display Names and Metadata
            2. Running Your Server
              1. stdio
              2. Streamable HTTP
              3. Testing and Debugging
            3. Examples
              1. Echo Server
              2. SQLite Explorer
            4. Advanced Usage
              1. Dynamic Servers
              2. Low-Level Server
              3. Eliciting User Input
              4. Writing MCP Clients
              5. Proxy Authorization Requests Upstream
              6. Backwards Compatibility
            5. Documentation
              1. Contributing
                1. License

                  Related MCP Servers

                  • -
                    security
                    A
                    license
                    -
                    quality
                    A comprehensive toolkit that enhances LLM capabilities through the Model Context Protocol, allowing LLMs to interact with external services including command-line operations, file management, Figma integration, and audio processing.
                    Last updated -
                    17
                    Python
                    Apache 2.0
                    • Linux
                    • Apple
                  • A
                    security
                    A
                    license
                    A
                    quality
                    A Model Context Protocol server that fetches up-to-date, version-specific documentation and code examples from libraries directly into LLM prompts, helping developers get accurate answers without outdated or hallucinated information.
                    Last updated -
                    2
                    90,385
                    13,947
                    JavaScript
                    MIT License
                    • Linux
                    • Apple
                  • -
                    security
                    F
                    license
                    -
                    quality
                    A ready-to-use starter implementation of the Model Context Protocol (MCP) server that enables applications to provide standardized context for LLMs with sample resources, tools, and prompts.
                    Last updated -
                    TypeScript
                  • -
                    security
                    F
                    license
                    -
                    quality
                    A comprehensive utilities library for building Model Context Protocol servers, providing standardized tools for response formatting, caching, rate limiting, logging, and WebSocket management.
                    Last updated -
                    TypeScript

                  View all related MCP servers

                  MCP directory API

                  We provide all the information about MCP servers via our MCP API.

                  curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jeffwalters9597/MCP'

                  If you have feedback or need assistance with the MCP directory API, please join our Discord server