2025-03-19_23-48-building-an-mcp-server-guide.md•20.4 kB
<!-- Generated by SpecStory -->
# Building an MCP Server Guide (2025-03-19 23:48:45)
_**User**_
read this and tell me how to build an mcp server
---
_**Assistant**_
Based on the documentation provided, I'll help you understand how to build an MCP server. Let me break this down into clear steps:
1. First, let's understand what an MCP server is:
- It's part of the Model Context Protocol that provides standardized ways for LLMs to interact with data sources and tools
- It follows a client-server architecture where your server can provide three main capabilities:
- Resources: File-like data that can be read by clients
- Tools: Functions that can be called by the LLM
- Prompts: Pre-written templates for specific tasks
2. There are two main ways to create an MCP server:
**TypeScript/Node.js Approach:**
```bash
# Create a new directory and initialize
mkdir my-mcp-server
cd my-mcp-server
npm init -y
# Install MCP SDK
npm install @modelcontextprotocol/sdk
```
**Python Approach:**
```bash
# Create a new directory and virtual environment
mkdir my-mcp-server
cd my-mcp-server
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install MCP server package
pip install mcp-server-git
```
3. Basic Server Structure:
Here's a minimal example of what your server code might look like in TypeScript:
```typescript
import { createServer } from '@modelcontextprotocol/sdk';
// Create your tools/functions
const tools = {
'my-tool': {
description: 'Description of what this tool does',
parameters: {
// Define your parameters schema
type: 'object',
properties: {
param1: { type: 'string' },
// ... other parameters
},
required: ['param1']
},
handler: async (params) => {
// Implement your tool logic here
return { result: 'some result' };
}
}
};
// Create and start the server
const server = createServer({
tools,
// You can also define resources and prompts here
});
server.listen(3000);
```
4. Testing Your Server:
Once your server is running, you can test it using the MCP Inspector:
```bash
npx @modelcontextprotocol/inspector
```
5. Key Best Practices:
- Always provide clear descriptions for your tools
- Implement proper error handling
- Use proper parameter validation
- Follow security best practices, especially when handling sensitive data
- Document your server's capabilities
6. Integration:
Your MCP server can be integrated with Claude Desktop or other MCP clients by adding it to their configuration:
```json
{
"mcpServers": {
"your-server": {
"command": "node",
"args": ["your-server.js"]
}
}
}
```
Would you like me to help you get started with building a specific type of MCP server? I can provide more detailed guidance based on what functionality you'd like to implement.
I notice from the error output in your terminal that there might have been an issue with an SSE (Server-Sent Events) connection. If you're trying to run a server, we should make sure it's properly configured to handle SSE connections, which is the transport mechanism MCP uses for communication. Would you like me to help you debug that specific issue or would you prefer to start fresh with building a new server?
---
_**User**_
here is the readme from the typescript sdk @https://github.com/modelcontextprotocol/typescript-sdk/blob/main/README.md#mcp-typescript-sdk--
---
_**Assistant**_
Based on the documentation and the error output you've shared, I can help explain how to properly set up an MCP server using the TypeScript SDK. I notice you're getting a 404 error when trying to connect via SSE (Server-Sent Events), so let's fix that.
Here's how to build a basic MCP server with TypeScript:
1. First, let's set up a new project:
```bash
mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk express
```
2. Create a basic server with SSE support. Create a file called `server.ts`:
```typescript
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { z } from "zod";
// Create the MCP server
const server = new McpServer({
name: "example-server",
version: "1.0.0"
});
// Create Express app
const app = express();
// Add a simple tool as an example
server.tool(
"hello",
{ name: z.string() },
async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name}!` }]
})
);
// Set up SSE endpoint
app.get("/sse", async (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const transport = new SSEServerTransport("/messages", res);
await server.connect(transport);
});
// Set up message endpoint
app.post("/messages", express.json(), async (req, res) => {
try {
const transport = server.getTransport();
if (!transport) {
throw new Error("No transport connected");
}
await transport.handlePostMessage(req, res);
} catch (error) {
console.error("Error handling message:", error);
res.status(500).json({ error: "Internal server error" });
}
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
```
3. Add TypeScript configuration. Create `tsconfig.json`:
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"esModuleInterop": true,
"outDir": "dist",
"strict": true
},
"include": ["*.ts"],
"exclude": ["node_modules"]
}
```
4. Add build and start scripts to `package.json`:
```json
{
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/server.js"
}
}
```
5. Build and run the server:
```bash
npm run build
npm start
```
6. To test the server using the MCP Inspector:
```bash
npx @modelcontextprotocol/inspector --transport sse --url http://localhost:3000
```
The error you're seeing (`SseError: SSE error: Non-200 status code (404)`) indicates that the `/sse` endpoint isn't being found. This could be because:
1. The server isn't running
2. The endpoint isn't properly configured
3. The port number doesn't match
The code above should resolve these issues by:
- Properly setting up the SSE endpoint at `/sse`
- Setting the correct headers for SSE
- Handling message posting at `/messages`
- Using proper error handling
To integrate this with Claude Desktop, you would add this to your Claude configuration:
```json
{
"mcpServers": {
"example": {
"command": "node",
"args": ["dist/server.js"]
}
}
}
```
Would you like me to help you debug any specific issues or explain any part of the implementation in more detail?
---
_**User**_
MCP TypeScript SDK Guide
Build & Test Commands
npm run build # Build ESM and CJS versions
npm run lint # Run ESLint
npm test # Run all tests
npx jest path/to/file.test.ts # Run specific test file
npx jest -t "test name" # Run tests matching pattern
Code Style Guidelines
TypeScript: Strict type checking, ES modules, explicit return types
Naming: PascalCase for classes/types, camelCase for functions/variables
Files: Lowercase with hyphens, test files with .test.ts suffix
Imports: ES module style, include .js extension, group imports logically
Error Handling: Use TypeScript's strict mode, explicit error checking in tests
Formatting: 2-space indentation, semicolons required, single quotes preferred
Testing: Co-locate tests with source files, use descriptive test names
Comments: JSDoc for public APIs, inline comments for complex logic
Project Structure
/src: Source code with client, server, and shared modules
Tests alongside source files with .test.ts suffix
Node.js >= 18 required
---
_**Assistant**_
Based on the documentation and the error output you've shared, I'll help you set up a proper MCP TypeScript server following the SDK's guidelines. I notice you're getting a 404 error with SSE, so let's fix that by creating a properly structured project.
1. First, let's set up the project structure following the guidelines:
```bash
mkdir -p src/{client,server,shared}
cd src
touch server/index.ts
```
2. Create a proper `package.json`:
```bash
npm init -y
npm install @modelcontextprotocol/sdk express zod
npm install -D typescript @types/node @types/express
```
Update `package.json`:
```json
{
"name": "my-mcp-server",
"version": "1.0.0",
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/server/index.js",
"lint": "eslint src/**/*.ts",
"test": "jest"
}
}
```
3. Create a `tsconfig.json` following the style guidelines:
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
```
4. Create the server implementation in `src/server/index.ts`:
```typescript
import express from 'express';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import { z } from 'zod';
// Create MCP server instance
const server = new McpServer({
name: 'example-server',
version: '1.0.0',
});
// Add a simple tool for testing
server.tool(
'greet',
{ name: z.string() },
async ({ name }) => ({
content: [{ type: 'text', text: `Hello, ${name}!` }],
})
);
// Create Express app
const app = express();
// Handle SSE connections
app.get('/sse', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.setHeader('Access-Control-Allow-Origin', '*');
const transport = new SSEServerTransport('/messages', res);
server.connect(transport).catch(console.error);
});
// Handle incoming messages
app.post('/messages', express.json(), async (req, res) => {
try {
const transport = server.getTransport();
if (!transport) {
throw new Error('No transport connected');
}
await transport.handlePostMessage(req, res);
} catch (error) {
console.error('Error handling message:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Start server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
```
5. Build and run:
```bash
npm run build
npm start
```
6. Test with the MCP Inspector:
```bash
npx @modelcontextprotocol/inspector --transport sse --url http://localhost:3000
```
The key differences from your previous attempt that should fix the 404 error:
1. Proper CORS headers for SSE
2. Explicit route handlers for both `/sse` and `/messages`
3. Proper error handling and transport management
4. Following TypeScript SDK guidelines for project structure
To integrate with Claude Desktop, add this to your Claude configuration (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"example": {
"command": "node",
"args": ["dist/server/index.js"],
"cwd": "/absolute/path/to/your/project"
}
}
}
```
Would you like me to explain any part of this implementation in more detail or help you test it?
---
_**User**_
use the info just provided tp create a clear plan of how an mcp server works, use example code, best practices, architecture & flow charts. put it in an md file
---
_**Assistant**_
I'll create a comprehensive guide for building an MCP server. Let me create a markdown file that explains the architecture, best practices, and implementation details.
---
---
I apologize for the error in writing the file. Let me try a different approach to create the file.
---
---
I apologize for the technical difficulties with the file system operations. Let me try one more time with the standard file operations.
---
```diff
-
+ # Building an MCP Server: Complete Guide
+
+ ## Table of Contents
+ - [Overview](#overview)
+ - [Architecture](#architecture)
+ - [Implementation Guide](#implementation-guide)
+ - [Best Practices](#best-practices)
+ - [Testing and Debugging](#testing-and-debugging)
+ - [Integration with Claude Desktop](#integration-with-claude-desktop)
+
+ ## Overview
+
+ Model Context Protocol (MCP) is a standardized way for LLMs to interact with external tools and data sources. Think of it as a "USB-C port for AI" - it provides a consistent interface for AI models to connect with various data sources and tools.
+
+ ## Architecture
+
+ ### High-Level Architecture
+
+ ```mermaid
+ flowchart TB
+ subgraph "MCP Server"
+ Resources[Resources]
+ Tools[Tools]
+ Prompts[Prompts]
+ Transport[Transport Layer]
+
+ Resources --> Transport
+ Tools --> Transport
+ Prompts --> Transport
+ end
+
+ subgraph "Clients"
+ Claude[Claude Desktop]
+ IDE[IDEs]
+ Custom[Custom Clients]
+ end
+
+ Transport <--> Claude
+ Transport <--> IDE
+ Transport <--> Custom
+ ```
+
+ ### Core Components
+
+ 1. **Resources**: File-like data that can be read by clients
+ 2. **Tools**: Functions that can be called by the LLM
+ 3. **Prompts**: Reusable templates for interactions
+ 4. **Transport Layer**: Communication mechanism (stdio or SSE)
+
+ ## Implementation Guide
+
+ ### 1. Basic Server Setup
+
+ ```typescript
+ 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: "example-server",
+ version: "1.0.0"
+ });
+
+ // Connect transport
+ const transport = new StdioServerTransport();
+ await server.connect(transport);
+ ```
+
+ ### 2. Adding Resources
+
+ ```typescript
+ // Static resource
+ server.resource(
+ "config",
+ "config://app",
+ async (uri) => ({
+ contents: [{
+ uri: uri.href,
+ text: "Configuration data"
+ }]
+ })
+ );
+
+ // Dynamic resource with parameters
+ server.resource(
+ "user-data",
+ new ResourceTemplate("users://{userId}/data", { list: undefined }),
+ async (uri, { userId }) => ({
+ contents: [{
+ uri: uri.href,
+ text: `Data for user ${userId}`
+ }]
+ })
+ );
+ ```
+
+ ### 3. Implementing Tools
+
+ ```typescript
+ // Simple tool
+ server.tool(
+ "calculate",
+ {
+ x: z.number(),
+ y: z.number(),
+ operation: z.enum(["add", "subtract", "multiply", "divide"])
+ },
+ async ({ x, y, operation }) => {
+ let result;
+ switch (operation) {
+ case "add": result = x + y; break;
+ case "subtract": result = x - y; break;
+ case "multiply": result = x * y; break;
+ case "divide": result = x / y; break;
+ }
+ return {
+ content: [{ type: "text", text: String(result) }]
+ };
+ }
+ );
+ ```
+
+ ### 4. Adding Prompts
+
+ ```typescript
+ server.prompt(
+ "analyze-data",
+ { data: z.string() },
+ ({ data }) => ({
+ messages: [{
+ role: "user",
+ content: {
+ type: "text",
+ text: `Please analyze this data:\n\n${data}`
+ }
+ }]
+ })
+ );
+ ```
+
+ ## Best Practices
+
+ ### Project Structure
+ ```
+ /your-mcp-server
+ ├── src/
+ │ ├── server/
+ │ │ ├── index.ts # Main server file
+ │ │ ├── resources.ts # Resource definitions
+ │ │ ├── tools.ts # Tool implementations
+ │ │ └── prompts.ts # Prompt templates
+ │ ├── shared/
+ │ │ ├── types.ts # Shared type definitions
+ │ │ └── utils.ts # Utility functions
+ │ └── tests/
+ │ └── server.test.ts # Test files
+ ├── package.json
+ └── tsconfig.json
+ ```
+
+ ### Code Style Guidelines
+ - Use TypeScript with strict mode enabled
+ - Implement proper error handling
+ - Add comprehensive logging
+ - Write tests for all functionality
+ - Document public APIs with JSDoc
+ - Use meaningful variable and function names
+ - Follow single responsibility principle
+
+ ### Error Handling Example
+
+ ```typescript
+ server.tool(
+ "fetch-data",
+ { url: z.string().url() },
+ async ({ url }) => {
+ try {
+ const response = await fetch(url);
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const data = await response.text();
+ return {
+ content: [{ type: "text", text: data }]
+ };
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ return {
+ content: [{
+ type: "text",
+ text: `Error: ${error.message}`
+ }],
+ isError: true
+ };
+ }
+ }
+ );
+ ```
+
+ ## Testing and Debugging
+
+ ### Using MCP Inspector
+
+ ```bash
+ # Test with stdio transport
+ npx @modelcontextprotocol/inspector node dist/server/index.js
+
+ # Test with SSE transport
+ npx @modelcontextprotocol/inspector --transport sse --url http://localhost:3000
+ ```
+
+ ### Common Issues and Solutions
+
+ 1. **404 Error with SSE**
+ - Ensure server is running
+ - Verify endpoint paths (/sse and /messages)
+ - Check CORS headers
+ - Validate transport configuration
+
+ 2. **Connection Refused**
+ - Verify server is running on correct port
+ - Check firewall settings
+ - Ensure no port conflicts
+
+ ## Integration with Claude Desktop
+
+ ### Configuration
+
+ Create or modify `~/Library/Application Support/Claude/claude_desktop_config.json`:
+
+ ```json
+ {
+ "mcpServers": {
+ "your-server": {
+ "command": "node",
+ "args": ["dist/server/index.js"],
+ "cwd": "/absolute/path/to/your/project"
+ }
+ }
+ }
+ ```
+
+ ### Debugging Integration
+
+ 1. Check Claude's logs:
+ ```bash
+ tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
+ ```
+
+ 2. Verify server execution:
+ ```bash
+ node dist/server/index.js
+ ```
+
+ ## Security Considerations
+
+ 1. **Input Validation**
+ - Always validate input parameters using Zod schemas
+ - Sanitize any user-provided data
+ - Implement rate limiting for tools
+
+ 2. **Error Handling**
+ - Never expose sensitive information in error messages
+ - Implement proper logging
+ - Handle all edge cases
+
+ 3. **Access Control**
+ - Implement authentication if needed
+ - Restrict file system access
+ - Use environment variables for sensitive data
+
+ ## Performance Optimization
+
+ 1. **Caching**
+ - Cache resource results when appropriate
+ - Implement connection pooling for databases
+ - Use efficient data structures
+
+ 2. **Resource Management**
+ - Clean up resources properly
+ - Implement timeout mechanisms
+ - Handle concurrent requests efficiently
+
+ Remember to always follow the MCP protocol specifications and maintain backward compatibility when updating your server.
```
---
I've created a comprehensive markdown guide for building MCP servers. The guide includes:
1. A clear overview of MCP and its purpose
2. Detailed architecture diagrams and explanations
3. Step-by-step implementation instructions with code examples
4. Best practices for project structure and code style
5. Testing and debugging guidance
6. Integration instructions for Claude Desktop
7. Security considerations and performance optimization tips
The guide specifically addresses the 404 SSE error you encountered by including a troubleshooting section that covers common issues and their solutions.
Would you like me to explain any particular section in more detail or add any specific information that you feel is missing from the guide?
---
_**User**_
@mcp-server-guide.md read all of the other docs and update the mcp server guide
---
_**Assistant**_
I'll analyze the additional documentation and update the MCP server guide with more comprehensive information. Let me make the necessary changes.
---
Cancelled
---
---
---