The Model Context Protocol (MCP) is rapidly becoming the standard for connecting AI assistants to external tools and data sources. In this guide, we'll walk through building production-ready MCP servers that work seamlessly with Claude Desktop and Cursor.
What is MCP?
MCP (Model Context Protocol) is an open protocol that enables AI assistants to interact with external systems through a standardized interface. Instead of building custom integrations for each AI platform, you build one MCP server that works everywhere.
Why MCP Matters
Traditional AI integrations require:
- Custom API wrappers for each AI platform
- Complex authentication flows
- Manual tool definition maintenance
- Platform-specific error handling
MCP solves this by providing:
- A single protocol that works with Claude, ChatGPT, Cursor, and more
- Standardized tool definitions
- Built-in authentication patterns
- Consistent error handling
Getting Started
The fastest way to create an MCP server is using our open-source @emcy/openapi-to-mcp package:
npx @emcy/openapi-to-mcp generate --url https://api.example.com/openapi.json
This generates a complete TypeScript project with:
- Tool definitions from your OpenAPI spec
- Support for both Stdio and HTTP transports
- Authentication configuration
- Environment variable management
Project Structure
After generation, your project looks like this:
my-mcp-server/
├── src/
│ ├── index.ts # Main entry point
│ └── transport.ts # Transport configuration
├── package.json
├── tsconfig.json
├── .env.example
└── README.md
Transport Types
MCP supports two transport mechanisms:
Stdio Transport (Claude Desktop, Cursor)
Best for local development and desktop applications:
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const transport = new StdioServerTransport();
await server.connect(transport);
HTTP Transport (ChatGPT, Web Apps)
Best for production deployments and web-based clients:
import { StreamableHTTPServerTransport } from "./transport.js";
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => crypto.randomUUID(),
});
Authentication Best Practices
API Key Authentication
For simple use cases, pass API keys via environment variables:
const headers = {
"Authorization": `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
};
OAuth 2.0
For production systems, implement proper OAuth flows:
const getAccessToken = async () => {
const response = await fetch(tokenEndpoint, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
}),
});
return response.json();
};
Error Handling
Implement robust error handling to provide meaningful feedback to AI assistants:
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`API error: ${response.status} ${response.statusText}`);
}
return await response.json();
} catch (error) {
return {
error: true,
message: error instanceof Error ? error.message : "Unknown error",
};
}
Connecting to Claude Desktop
Add your server to Claude Desktop's configuration:
{
"mcpServers": {
"my-api": {
"command": "node",
"args": ["/path/to/my-mcp-server/dist/index.js"],
"env": {
"API_KEY": "your-api-key"
}
}
}
}
Adding Telemetry
Track tool invocations with the @emcy/sdk:
import { EmcyTelemetry } from "@emcy/sdk";
const telemetry = new EmcyTelemetry({
apiKey: process.env.EMCY_API_KEY,
serverName: "my-api",
});
// Wrap tool handlers
const result = await telemetry.trace("get_users", async () => {
return await fetchUsers();
});
Production Checklist
Before deploying to production, ensure you have:
- Proper error handling for all API calls
- Rate limiting to prevent abuse
- Input validation on all parameters
- Logging for debugging and monitoring
- Health check endpoint for HTTP transport
- Environment variable validation at startup
Conclusion
Building MCP servers doesn't have to be complex. With the right tools and patterns, you can expose your API to AI assistants in minutes. Start with @emcy/openapi-to-mcp for quick prototyping, then customize as needed.
Ready to get started? Try our wizard to generate your first MCP server in seconds.
