The Model Context Protocol (MCP) represents a significant advancement in how AI assistants interact with external tools and data sources. Developed by Anthropic, MCP enables Claude to seamlessly communicate with custom servers, allowing it to access real-time information, execute complex workflows, and interact with APIs without leaving the conversation context. This capability transforms Claude from a standalone LLM into a versatile assistant that can leverage external functionality while maintaining conversation coherence.
In this comprehensive guide, we'll walk through the process of building a TypeScript MCP server from scratch and connecting it to Claude Desktop. By implementing this integration, you'll enable Claude to perform tasks like retrieving real-time data, executing computations, or interacting with your custom business logic directly within conversations.
Before diving into our MCP server implementation, it's worth mentioning that your choice of API development tool can significantly impact your workflow efficiency.

- While Postman has long been the industry standard, Apidog has emerged as a superior alternative that perfectly complements modern development workflows like the one we're building.
- Unlike Postman's limitations with APIs under development, Apidog offers real-time synchronization between your API specifications and requests, ensuring your documentation and tests automatically stay current as your APIs evolve.
- With visual API specification creation, unlimited collection runs (compared to Postman's 25/month limit), and powerful features like auto-generated requests and mock responses, Apidog streamlines the entire API lifecycle. Its comprehensive testing capabilities, including visual test creation and self-hosted runners, make it ideal for teams implementing complex integrations like our MCP server.
As we build our TypeScript MCP server, consider how Apidog's collaborative features and development-focused approach can enhance your team's productivity and ensure your APIs remain consistent, well-tested, and thoroughly documented throughout the process.
Understanding the Model Context Protocol
The Model Context Protocol defines a standardized way for Claude to communicate with external services. When Claude identifies that it needs information from an external source, it can invoke an MCP server through a specially formatted JSON request. The server processes this request and returns the requested data, which Claude can then incorporate into its response.
MCP offers several advantages over traditional AI integration approaches:
- Contextual awareness: Claude maintains the full conversation history when making requests
- Bidirectional communication: The protocol supports complex interactions between Claude and your server
- Security and control: You determine what functionality to expose and how requests are processed
- Seamless experience: Users interact with Claude naturally without needing to know about the underlying integrations
Prerequisites
Before we begin building our MCP server, ensure you have the following:
- Node.js (v18 or later) installed
- A code editor like Visual Studio Code
- Basic knowledge of TypeScript
- Claude Desktop application installed
- Familiarity with Express.js (for building the server endpoints)
Setting Up Your TypeScript Project
Let's start by creating a new TypeScript project for our MCP server:
mkdir claude-mcp-server
cd claude-mcp-server
npm init -y
npm install typescript @types/node ts-node express @types/express cors @types/cors
npx tsc --init
Next, update your tsconfig.json
to include these settings:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
Implementing the MCP Server
Create a new file called server.ts
in your project root directory. This will be the entry point for our MCP server:
import express from 'express';
import cors from 'cors';
import { Request, Response } from 'express';
// Define types for the MCP protocol
interface MCPRequest {
query: string;
conversation_id: string;
request_id: string;
parameters?: Record<string, any>;
}
interface MCPResponse {
response: string;
status: 'success' | 'error';
error?: string;
}
const app = express();
app.use(cors());
app.use(express.json());
// Health check endpoint
app.get('/health', (req: Request, res: Response) => {
res.status(200).json({ status: 'healthy' });
});
// MCP endpoint
app.post('/mcp', (req: Request, res: Response) => {
try {
const mcpRequest = req.body as MCPRequest;
console.log('Received MCP request:', JSON.stringify(mcpRequest, null, 2));
// Process the request based on the query
const response = processQuery(mcpRequest);
res.status(200).json({
status: 'success',
response
} as MCPResponse);
} catch (error) {
console.error('Error processing MCP request:', error);
res.status(500).json({
status: 'error',
error: error instanceof Error ? error.message : 'Unknown error',
response: 'Sorry, there was an error processing your request.'
} as MCPResponse);
}
});
// Function to process different query types
function processQuery(request: MCPRequest): string {
const { query, parameters } = request;
// Example query handling - customize this for your use case
switch (query) {
case 'getCurrentTime':
return `The current time is ${new Date().toLocaleTimeString()}`;
case 'getWeather':
const location = parameters?.location || 'Unknown';
// In a real app, you would call a weather API here
return `The weather in ${location} is currently sunny and 72°F`;
case 'calculateSum':
if (parameters?.numbers && Array.isArray(parameters.numbers)) {
const sum = parameters.numbers.reduce((a: number, b: number) => a + b, 0);
return `The sum of the numbers is ${sum}`;
}
return 'Invalid parameters for sum calculation';
default:
return `Unrecognized query: ${query}`;
}
}
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`MCP server running on port ${PORT}`);
});
Running Your MCP Server
To run your server, execute:
npx ts-node server.ts
Your MCP server should now be running on port 3000 (or your specified port).
Connecting to Claude Desktop
Now that your MCP server is running, you need to configure Claude Desktop to connect to it. Here's how:
- Open Claude Desktop application
- Go to Settings (usually in the top-right corner)
- Navigate to the "Experimental Features" section
- Enable the "Model Context Protocol" toggle
- Add a new MCP endpoint with the URL
http://localhost:3000/mcp
- Save your settings
Claude Desktop will now be able to communicate with your custom MCP server.
Testing the Integration
To test your MCP server with Claude, try asking Claude questions that would trigger the specific queries you've implemented. For example:
- "What time is it right now?" (should trigger the
getCurrentTime
query) - "What's the weather like in San Francisco?" (should trigger the
getWeather
query with "San Francisco" as the location parameter) - "Can you calculate the sum of 5, 10, 15, and 20?" (should trigger the
calculateSum
query)
When Claude recognizes that it needs external information to answer these questions, it will automatically send an MCP request to your server and incorporate the response into its answer.
Extending Your MCP Server
The basic server we've built is just a starting point. Here are some ideas for extending its functionality:
Add Authentication
To secure your MCP server, add authentication:
// Middleware for basic auth
const authenticateMCP = (req: Request, res: Response, next: Function) => {
const apiKey = req.headers['x-api-key'];
if (!apiKey || apiKey !== process.env.MCP_API_KEY) {
return res.status(401).json({
status: 'error',
error: 'Unauthorized',
response: 'Authentication failed'
});
}
next();
};
// Apply middleware to MCP endpoint
app.post('/mcp', authenticateMCP, (req: Request, res: Response) => {
// Existing handler code
});
Implement Database Integration
Connect your MCP server to a database to retrieve or store information:
import { MongoClient } from 'mongodb';
// Initialize database connection
const dbClient = new MongoClient('mongodb://localhost:27017');
let db: any;
async function connectToDb() {
await dbClient.connect();
db = dbClient.db('mcpDatabase');
console.log('Connected to database');
}
connectToDb().catch(console.error);
// Add a query handler for database interactions
case 'getUserData':
if (parameters?.userId) {
const user = await db.collection('users').findOne({ id: parameters.userId });
return user ? JSON.stringify(user) : 'User not found';
}
return 'Invalid user ID';
Add Webhook Support
Implement webhook functionality to notify external services:
case 'sendNotification':
if (parameters?.message && parameters?.destination) {
// Call external notification service
await fetch('https://your-webhook-url.com', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: parameters.message })
});
return `Notification sent to ${parameters.destination}`;
}
return 'Invalid notification parameters';
Best Practices for MCP Server Development
- Handle errors gracefully: Always catch exceptions and return informative error messages
- Implement logging: Log all requests and responses for debugging and auditing
- Use TypeScript interfaces: Define clear interfaces for all data structures
- Set timeouts: Implement request timeouts to prevent hanging operations
- Validate inputs: Carefully validate all input parameters before processing
- Add unit tests: Test your query handlers thoroughly to ensure reliability
Conclusion
Building a TypeScript MCP server opens up exciting possibilities for extending Claude's capabilities. By following this guide, you've created a foundation for integrating Claude with your own services and data. The Model Context Protocol enables a seamless user experience where Claude can access external information without breaking the conversation flow.
As MCP continues to evolve, we can expect even more sophisticated integrations between large language models and external systems. Whether you're building productivity tools, knowledge management systems, or custom business applications, MCP provides a powerful way to combine Claude's intelligence with your specialized functionality.
Start exploring the possibilities by extending your server with additional query handlers specific to your use cases, and share your experiences with the growing community of MCP developers.