What Matters
- -Tool descriptions are the most critical element of MCP server development. Spending 2x more time on descriptions than handler code consistently produces better AI agent behavior.
- -Start with a single tool and test locally with Claude Desktop before expanding. This validates your description quality and response format before adding complexity.
- -Use the verb_noun naming convention (search_issues, get_customer) and JSON Schema enums for constrained values to reduce LLM input errors.
- -A server with 50 tools overwhelms LLM tool selection. Use 3-5 focused servers (one per domain) instead of one monolithic server.
- -Target under 2 seconds per tool call. AI agents call tools in loops, so 5-second tools create 50-second workflows. Cache aggressively for slow backends.
Model Context Protocol (MCP) servers are how AI applications connect to external tools and data. If you have an API, database, or service that AI models should be able to use, building an MCP server makes it accessible to Claude, Cursor, and every other MCP-compatible client.
MCP is becoming the standard for AI tool integration. Every major agentic AI framework now supports it. Building MCP servers today positions your services for the AI-first future. More practically, it turns your internal APIs into capabilities that any AI agent can use without custom integration code.
According to MCP adoption tracking, over 5,800 MCP servers are now publicly available, with monthly SDK downloads growing from roughly 100,000 in late 2024 to over 8 million by April 2025. That growth means more potential clients - any MCP-compatible AI application - can reach your tools the moment they are built.
This guide walks through MCP server development from first tool to production deployment, including the patterns and mistakes we have encountered building MCP servers for clients at 1Raft.
MCP Server Development Prerequisites
You need:
- Node.js 18+ (for TypeScript) or Python 3.10+ (for Python)
- Basic understanding of JSON Schema (for defining tool inputs)
- An API or service you want to expose to AI models
- Claude Desktop or Cursor for testing
No prior experience with AI protocols is required. The MCP SDK handles all protocol communication. You focus on tool definitions and business logic.
MCP Server Project Setup and Architecture
For a TypeScript server, your project structure looks like this:
my-mcp-server/
src/
index.ts # Server entry point
tools/ # Tool implementations
utils/ # Shared utilities
package.json
tsconfig.json
Install the MCP SDK (@modelcontextprotocol/sdk) and you have the foundation. The SDK provides the Server class, transport handlers, and type definitions.
The architecture of an MCP server follows a consistent pattern:
| Layer | Responsibility | Example |
|---|---|---|
| Tool registry | Declares available tools with names, descriptions, schemas | list_tools handler |
| Tool handlers | Business logic for each tool | API calls, DB queries, computations |
| Transport | Communication channel between client and server | Stdio (local), HTTP+SSE (remote) |
| Auth layer | Token validation and access control | OAuth, API keys |
| Middleware | Logging, rate limiting, caching | Per-tool or global |
How to Define MCP Tools That LLMs Actually Use Correctly
Each tool has three parts: a name, a description, and an input schema. The description is by far the most important.
Tool Naming Conventions
The name should be descriptive and action-oriented. Use the format verb_noun: search_issues, get_customer, create_ticket. The LLM reads tool names to understand what is available.
| Good Name | Why | Bad Name | Why Bad |
|---|---|---|---|
search_issues | Clear action + object | issues | Ambiguous |
get_customer_by_id | Specific lookup method | customer | Is this get, create, or update? |
create_support_ticket | Full action description | ticket | No verb |
calculate_shipping_cost | Domain-specific action | calc | Too vague |
Writing Tool Descriptions That Work
The description is the most critical element of MCP server development. Write it for the LLM. Explain what the tool does, when to use it, and what it returns. Include examples.
Good description: "Search for GitHub issues by label, status, and assignee. Use this when the user asks about bugs, feature requests, or issue status. Returns a list of matching issues with title, number, status, and assignee. Example: search for open bugs labeled 'critical' in the frontend repo."
Bad description: "Searches issues." The LLM will not know when to use this or what parameters to pass.
A great handler behind a bad description never gets called correctly. The description is the interface between the LLM's reasoning and your business logic.
At 1Raft, we have found that spending 2x more time on tool descriptions than on handler code consistently produces better agent behavior. The description is the interface between the LLM's reasoning and your business logic. A great handler behind a bad description never gets called correctly.
Input Schema Best Practices
The input schema uses JSON Schema to define parameters. Include type, description, required fields, and enums for constrained values.
Tips for schemas that reduce LLM errors:
- Mark only truly required fields as
required. Optional fields give the LLM flexibility. - Use
enumfor any parameter with a fixed set of valid values. This prevents hallucinated inputs. - Add
defaultvalues where sensible. The LLM can omit parameters that have good defaults. - Include
descriptionon every property, not just the tool itself.
Good vs bad tool descriptions
Spend 2x more time on descriptions than handler code. The description is the interface between the LLM's reasoning and your business logic.
Implementing MCP Server Tool Handlers
Each tool needs a handler function that receives validated input and returns a result. Handlers are where your business logic lives.
Handler Pattern Reference
| Pattern | When to Use | Example |
|---|---|---|
| API wrapper | Exposing an existing REST/GraphQL API | GitHub, Slack, Jira, CRM lookups |
| Database query | Direct data access | Customer search, analytics queries |
| Computation | Calculations or transformations | Pricing, formatting, aggregation |
| Composite | Multi-service orchestration | Customer 360, cross-system lookups |
Return Format Guidelines
Always return structured data as JSON objects. Do not return free text. The LLM will format the output for the user. Structured data gives the LLM more flexibility in how it presents results.
Include relevant metadata: timestamps, IDs, status codes. The LLM uses this metadata for follow-up actions and reasoning.
Strip unnecessary fields. A 5KB JSON response with 50 fields when the LLM only needs 5 wastes context window space and increases cost. Filter your response to the essential fields.
Error Handling in MCP Servers
Return error objects, do not throw exceptions. An error response should include:
- An error code (machine-readable)
- A message (human-readable, the LLM will use this to explain the error)
- Suggested remediation (if applicable)
Good error: "Error: Customer with ID 12345 not found. Verify the customer ID and try again." Bad error: "Error: 404"
Good error messages let the LLM recover gracefully and guide the user to a fix. This is the difference between an agent that handles failures and one that gives up.
MCP Transport Configuration: Stdio vs HTTP+SSE
MCP supports two transport modes:
Stdio (Standard Input/Output)
The server communicates via stdin/stdout. This is the default for local development. Claude Desktop and Cursor launch MCP servers as child processes and communicate over stdio.
When to use: Local development, single-user scenarios, testing.
HTTP + Server-Sent Events (SSE)
The server runs as an HTTP service. Clients connect over the network. This is for remote and multi-user deployments.
When to use: Production deployment, shared servers, remote access, multi-tenant environments.
Start with stdio for development. Switch to HTTP+SSE when you need remote access or multiple concurrent users. The code change is minimal because the MCP SDK abstracts transport from tool logic.
Testing MCP Servers: Local and Automated Approaches
Local Testing with Claude Desktop
Configure Claude Desktop to launch your MCP server. Add the server to the Claude Desktop config file, specifying the command to start it. Restart Claude Desktop, and your tools appear in the interface.
Test by asking Claude to use your tools: "Search for open issues labeled bug." Watch the server logs to verify correct tool calls and responses.
Automated Testing Strategy
Write unit tests for your tool handlers. Mock external API calls and verify:
- Correct parameter handling (especially edge cases like missing optional fields)
- Proper error responses for invalid inputs
- Output format matches the expected schema
Write integration tests that exercise the full MCP protocol flow: initialization, tool discovery, tool execution, error handling. This catches protocol-level bugs that unit tests miss.
Testing Checklist for MCP Server Development
| Test Category | What to Verify | Priority |
|---|---|---|
| Tool descriptions | LLM selects the right tool for 10 test prompts | Critical |
| Input validation | Handler rejects invalid inputs gracefully | Critical |
| Error recovery | LLM receives clear error messages it can act on | High |
| Response size | Responses stay under 2KB for common operations | High |
| Latency | Tool calls complete in under 2 seconds | Medium |
| Rate limiting | Server handles burst traffic without crashing | Medium |
MCP server testing workflow
Each stage catches different bug categories. Don't skip straight to production testing.
Mock external API calls. Verify correct parameter handling, edge cases, error responses, and output format.
Exercise the full MCP protocol flow: initialization, tool discovery, tool execution, and error handling.
Test with 10+ natural language prompts. Verify the LLM selects the right tool and passes correct parameters.
Production MCP Server Patterns
Authentication and Security
For servers that access sensitive data, implement authentication. The MCP protocol supports passing authentication tokens during initialization. Your server validates the token before processing any tool calls.
For multi-tenant environments, include tenant context in the auth payload. Each tool call should be scoped to the authenticated tenant's data.
Rate Limiting
LLMs can call tools rapidly, especially in AI agent loops that retry on failure. Protect your backend services with rate limits at the MCP server level. Return clear rate limit error messages so the LLM can wait and retry.
Logging and Observability
Log every tool call with: timestamp, tool name, input parameters (sanitized), response time, success/failure, token count of response. This data is essential for debugging, cost optimization, and understanding how AI agents interact with your tools.
Caching for Performance
For tools that query slow backends, implement caching. Cache at the MCP server level with appropriate TTLs. Return cached results instantly and refresh in the background. This is critical for tools used inside AI agent orchestration loops where the same data is queried multiple times per task.
Tool Versioning
As your tools evolve, maintain backward compatibility. Add new tools rather than changing existing ones. If you must change a tool, version it: search_issues_v2.
The 1Raft MCP Server Development Checklist
Based on patterns across MCP server projects delivered at 1Raft, here is the checklist we use for every production MCP server:
| Checkpoint | Pass Criteria |
|---|---|
| Tool descriptions | Each description is 40+ words with a usage example |
| Naming convention | All tools follow verb_noun pattern |
| Input schemas | All constrained values use enums, all properties have descriptions |
| Error messages | All errors include code, human message, and suggested fix |
| Response size | Average response under 2KB, max under 10KB |
| Auth | Token validation on every tool call for sensitive data |
| Rate limiting | Per-tool and global rate limits configured |
| Logging | Every tool call logged with timing and success/failure |
| Caching | Tools with 500ms+ backend latency have TTL caching |
| Tests | 80%+ handler coverage, 10+ integration test scenarios |
Common Mistakes in MCP Server Development
"We write tool descriptions before we write handler code. Every time we've skipped that step to ship faster, we've paid for it in debugging sessions where the LLM kept calling the wrong tool. The description is not documentation - it's the interface." - 1Raft Engineering Team
Vague tool descriptions. The LLM picks the wrong tool or passes wrong parameters because the description does not explain the tool clearly. Spend more time on descriptions than on code. At 1Raft, we write tool descriptions before writing handler code.
Returning raw API responses. A 5KB JSON response with 50 fields when the LLM only needs 5 wastes context window space and money. Filter and format responses for AI consumption.
No error context. "Error: 404" vs "Error: Customer with ID 12345 not found. Verify the customer ID and try again." Good error messages turn failures into self-correcting agent behavior.
Too many tools on one server. A server with 50 tools overwhelms the LLM's tool selection. Group related functionality into fewer, more powerful tools. Or split into multiple focused servers (one for CRM, one for billing, one for inventory). Most AI product engineering projects work better with 3-5 focused servers than one monolithic server.
Ignoring response latency. AI agents call tools in loops. A tool that takes 5 seconds means a 10-step workflow takes 50 seconds minimum. Target under 2 seconds per tool call. Cache aggressively for slow backends.
No rate limiting. An agent in a retry loop can generate hundreds of tool calls per minute. Without rate limiting, your backend APIs take the hit. Always implement rate limiting at the MCP server layer.
The Bottom Line
MCP server development involves three core decisions: tool definitions (names, descriptions, schemas), handler patterns (API wrapper, DB query, computation, composite), and transport (stdio for local, HTTP+SSE for production). Tool descriptions are the single most important factor in whether AI agents use your tools correctly. Start with one tool, test locally with Claude Desktop, then expand. Use the production checklist to verify auth, rate limiting, logging, caching, and testing are in place before deployment. MCP is becoming the standard for AI tool integration, and building servers today positions your services for every AI application that connects to them.
Frequently asked questions
1Raft has shipped 100+ AI products including MCP server implementations for enterprise internal APIs. We write tool descriptions before handler code because description quality determines agent behavior. Our production checklist covers auth, rate limiting, logging, caching, and testing. Typical delivery is 4-6 weeks for a production MCP server with 10-20 tools.
Related Articles
Model Context Protocol Explained
Read articleHow to Build an AI Agent
Read articleAI Orchestration Platform Guide
Read articleFurther Reading
Related posts

Model Context Protocol (MCP): The Complete Guide for 2026
Every AI app needs custom integrations for every tool. MCP solves that N x M problem with one universal standard. Here's how it works and how to use it.

How to Add AI to Your Existing Product: A Practical Guide
Your roadmap says "add AI" but your codebase says "not without a rewrite." Here's the incremental path to shipping AI features that move real metrics.

How to Reduce Software Development Costs Without Cutting Corners
Most development cost overruns come from three predictable sources: scope creep, wrong team structure, and rebuilding what should have been architected right the first time.
