MCP Server Development: Build Tools for Claude and AI Assistants

Learn to build production-ready Model Context Protocol servers that extend Claude's capabilities with custom tools, resources, and prompts.

Introduction

The Model Context Protocol (MCP) represents a fundamental shift in how AI assistants like Claude interact with external tools and data sources. Rather than building one-off integrations for each AI platform, developers can now create standardized servers that any MCP-compatible client can discover and use. This guide walks through building production-ready MCP servers that extend Claude's capabilities with custom tools, resources, and prompts.

What Makes MCP Server Development Unique

MCP servers differ from traditional APIs in several important ways. First, they're designed for AI consumption--the LLM itself discovers available tools through a manifest, reasons about which to use, and constructs calls based on natural language requests. Second, MCP uses a JSON-RPC 2.0 message format over various transport layers, enabling both local (stdio) and remote (HTTP/SSE) communication. Third, tool definitions use JSON Schema for parameter validation, allowing the LLM to understand input requirements without explicit documentation parsing [CITE: Model Context Protocol - Tools].

When building MCP servers for Claude and similar assistants, you're essentially creating a bridge between natural language requests and actionable operations. The server exposes functions with clear schemas, handles the business logic, and returns structured results that the LLM can reason about. This abstraction means you can connect Claude to databases, APIs, file systems, or any external system without the AI needing to understand implementation details.

Related topics: Building Custom Tools for LLMs and Integrating MCP with Applications.

MCP Protocol Foundation

Understanding the protocol architecture is essential for building servers

JSON-RPC 2.0 Messaging

Standard message passing format with request-response pattern and notification support

Three Capability Categories

Tools (executable functions), Resources (data sources), and Prompts (templated interactions)

Capability Advertisement

Servers advertise capabilities during initialization for dynamic discovery

Version Negotiation

Semantic versioning with graceful degradation for incompatible versions

The MCP Protocol Foundation

Protocol Architecture Overview

The Model Context Protocol defines how AI applications (clients) communicate with servers that provide context, tools, and resources. At its core, MCP uses JSON-RPC 2.0 for message passing, with three primary capability categories: tools (executable functions), resources (data sources), and prompts (templated interactions). Servers advertise their capabilities during initialization, and clients can dynamically discover what operations are available.

The protocol specification mandates that servers follow a specific initialization sequence. Upon connection, the server sends a ServerCapabilities message describing its available tools, resources, and any server-specific features. Clients then use this information to present options to the LLM and construct appropriate requests. This capability advertisement system means servers can evolve independently of clients--new tools can be added without requiring client updates.

Message flow in MCP follows a request-response pattern with support for notifications. Tools are invoked through tool/call requests, which include the tool name and a JSON object of arguments matching the tool's input schema. The server responds with execution results, which may include text content, structured data, or error information. For long-running operations, servers can send progress notifications before completing the request.

[CITE: Model Context Protocol - Build a Server]

[CITE: Model Context Protocol - Transports]

Tool Schema Design

Understanding JSON Schema for Tools

Every MCP tool requires a schema that describes its name, description, and input parameters. The schema follows JSON Schema draft-07 notation, enabling sophisticated validation and documentation generation. A well-designed schema helps the LLM understand when and how to use your tool, what inputs it accepts, and what outputs to expect.

{
 "name": "get_weather",
 "description": "Get current weather conditions for a location",
 "inputSchema": {
 "type": "object",
 "properties": {
 "location": {
 "type": "string",
 "description": "City name or coordinates"
 },
 "units": {
 "type": "string",
 "enum": ["celsius", "fahrenheit"],
 "default": "celsius"
 }
 },
 "required": ["location"]
 }
}

The description field is particularly important because it directly influences the LLM's decision-making. Vague descriptions lead to incorrect tool selection or misuse. Best practices indicate that descriptions should explain what the tool does, when to use it, and what each parameter represents.

Advanced Schema Patterns

For complex tools, nested object schemas enable rich parameter structures. Consider a database query tool that accepts connection details, query parameters, and output formatting options. Rather than flattening everything into a single level, nested schemas reflect logical groupings and improve readability for both developers and the LLM.

Enum types help the LLM understand constrained choices, while default values reduce the number of parameters the LLM needs to specify. The maximum and minimum constraints on numeric types enable automatic validation.

See also: Building Custom Tools for LLMs for additional schema design patterns and tool implementation strategies.

[CITE: Model Context Protocol - Tools]

Transport Mechanisms

Standard Input/Output (STDIO)

STDIO transport is the simplest and most common choice for local MCP servers. In this mode, the server reads JSON-RPC messages from stdin and writes responses to stdout. This approach works well for subprocess-launched servers, such as those configured in Claude Desktop's settings.

The primary advantage of STDIO is simplicity--no network configuration or authentication concerns. However, it requires the server and client to run on the same machine, and communication is synchronous (one request at a time). For local tools like file system operations, database queries, or local API integrations, STDIO provides the most straightforward implementation path.

// TypeScript STDIO server example
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

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

server.setRequestHandler(ListToolsRequestSchema, async () => {
 return {
 tools: [
 {
 name: "analyze_file",
 description: "Analyze a file and extract key information",
 inputSchema: {
 type: "object",
 properties: {
 path: { type: "string", description: "File path to analyze" }
 },
 required: ["path"]
 }
 }
 ]
 };
});

const transport = new StdioServerTransport();
server.connect(transport);

Streamable HTTP and Server-Sent Events

For remote deployment scenarios, MCP supports HTTP-based transports using Server-Sent Events (SSE) for server-to-client streaming. This transport enables stateless server deployments that can scale horizontally, making it suitable for production environments where servers run on remote infrastructure.

The HTTP transport uses POST requests for client-to-server messages and SSE streams for server-to-client responses. This bidirectional communication pattern supports real-time updates and notifications, which is essential for long-running operations.

See also: MCP Transport Patterns for detailed transport configuration options and Integrating MCP with Applications for deployment strategies.

[CITE: Model Context Protocol - Transports]

TypeScript vs Python Implementation

Both official SDKs offer equivalent capabilities with different development patterns

TypeScript SDK

Reference implementation with full type safety, class-based structures, and comprehensive features

Python SDK

Concise implementation with FastMCP class, ideal for data science and automation workflows

Language Selection

Choose TypeScript for production type safety; Python for rapid prototyping and data processing

Performance

Negligible difference for most use cases--bottleneck is business logic, not protocol handling

TypeScript SDK Overview

The official TypeScript SDK (@modelcontextprotocol/sdk) provides the most feature-complete implementation. It's the reference implementation that other SDKs aim to match. TypeScript's type system catches schema errors at compile time, reducing runtime issues. The SDK includes built-in transport implementations, request handlers, and utilities for common patterns.

For teams already working with TypeScript in web development projects, the MCP SDK integrates naturally with existing codebases. The class-based structure aligns with component-oriented architectures, making it straightforward to organize MCP servers as modular, testable units.

Python SDK Overview

The Python SDK (mcp) offers a more concise implementation pattern, leveraging Python's dynamic typing for rapid development. It's particularly popular for data science and automation use cases where Python dominates the ecosystem. The SDK includes the FastMCP class for quick server creation.

from mcp.server.fastmcp import FastMCP

app = FastMCP("my-server")

@app.tool()
def analyze(data: str) -> str:
 """Analyze input data and return insights."""
 return f"Analysis of {data[:100]}..."

[CITE: Scrapfly Python MCP Guide]

Testing MCP Servers

Using the MCP Inspector

The MCP Inspector is the official debugging tool for testing servers independently of any specific client. It provides a CLI interface for invoking tools, inspecting server capabilities, and diagnosing connection issues. Running the Inspector helps validate that your server correctly implements the protocol before integrating with Claude or other clients.

# Install Inspector
npm install -g @modelcontextprotocol/inspector

# Connect to a local STDIO server
mcp-inspector --command "python server.py" --name "my-server"

Unit Testing Tool Implementations

Beyond Inspector-based testing, unit tests should cover tool logic independently of the MCP layer. This separation enables fast testing without starting server instances:

// TypeScript unit test example
import { analyze } from "./tools";

describe("analyze tool", () => {
 it("should process valid input correctly", async () => {
 const result = await analyze("test data");
 expect(result).toContain("test data");
 });
});

Integration Testing Patterns

Integration tests verify end-to-end functionality through actual MCP connections. These tests spawn the server process, connect a test client, and verify tool invocation results.

[CITE: Model Context Protocol - Build a Server]

Security Considerations

Input Validation and Sanitization

All tool inputs from MCP requests should be treated as untrusted user input. Even though the LLM generates arguments based on tool schemas, validation at the server layer prevents malformed data from causing issues:

async function analyzeTool(args: { path: string }) {
 // Validate path is within allowed directories
 const resolvedPath = path.resolve(args.path);
 if (!resolvedPath.startsWith(ALLOWED_BASE_PATH)) {
 throw new Error("Access denied: path outside allowed directory");
 }

 // Sanitize input to prevent command injection
 const sanitized = args.path.replace(/[^a-zA-Z0-9/_.-]/g, "_");

 return performAnalysis(sanitized);
}

Authentication for Remote Servers

HTTP-based MCP servers should implement authentication to prevent unauthorized access. Standard approaches include API keys for simple scenarios, OAuth 2.0 for enterprise integration, and Mutual TLS for high-security environments.

Rate Limiting and Resource Protection

MCP servers should implement rate limiting to prevent abuse and protect backend systems from excessive tool invocations.

Security Best Practices

Best Practices for Production Servers

Error Handling Patterns

Robust error handling ensures the LLM receives meaningful feedback when tools fail. Structured error responses help the LLM understand what went wrong and potentially retry or suggest alternatives:

async function handleToolCall(request: CallToolRequest) {
 try {
 const result = await executeTool(request.params.arguments);
 return {
 content: [{ type: "text", text: JSON.stringify(result) }]
 };
 } catch (error) {
 if (error instanceof ValidationError) {
 return {
 content: [{ type: "text", text: `Invalid input: ${error.message}` }],
 isError: true
 };
 }
 // Log unexpected errors for debugging
 console.error("Unexpected error:", error);
 return {
 content: [{ type: "text", text: "An unexpected error occurred. Please try again." }],
 isError: true
 };
 }
}

Performance Optimization

Long-running tool calls should support progress reporting to prevent timeouts and provide user feedback:

server.setRequestHandler(CallToolRequestSchema, async (request, sendProgress) => {
 const items = await fetchItems();
 const total = items.length;

 for (let i = 0; i < items.length; i++) {
 await processItem(items[i]);
 sendProgress({
 progress: i + 1,
 total,
 message: `Processed ${i + 1} of ${total} items`
 });
 }

 return { content: [{ type: "text", text: "Complete" }] };
});

Logging and Observability

Production servers should implement structured logging for debugging and monitoring. Track tool invocations, duration, success rates, and errors. Integrating with your AI automation services enables comprehensive monitoring of AI-driven workflows.

[CITE: Model Context Protocol - Build a Server]

Summary

MCP server development combines traditional API design principles with AI-specific considerations. The protocol's standardized approach means your servers can reach any MCP-compatible client, while the schema-driven tool definitions enable sophisticated LLM interactions. Whether implementing in TypeScript or Python, with STDIO or HTTP transport, the fundamental patterns remain consistent: define clear schemas, handle errors gracefully, and test thoroughly.

Building MCP servers opens new possibilities for extending AI assistants. By creating tools that connect Claude to your data and systems, you enable natural language interaction with previously technical workflows. The investment in understanding MCP pays dividends as the ecosystem continues to grow.

For organizations looking to leverage MCP for business automation, our AI automation services team can help design and implement custom server solutions. Additionally, our web development expertise ensures seamless integration of MCP capabilities into your existing applications.

Connect with our AI development team to discuss building custom MCP servers for your organization.


Sources

  1. Model Context Protocol - Build a Server
  2. freeCodeCamp - How to Build a Custom MCP Server with TypeScript
  3. Scrapfly - How to Build an MCP Server in Python
  4. Model Context Protocol - Transports
  5. Model Context Protocol - Tools