DEV Community

Sangmin Lee
Sangmin Lee

Posted on • Originally published at claudeguide.io

Build a Custom MCP Server for Claude Code: Complete Guide

Originally published at claudeguide.io/claude-mcp-custom-server-build

Build a Custom MCP Server for Claude Code: Complete Guide (2026)

A custom MCP (Model Context Protocol) server lets Claude Code call your own tools, APIs, and data sources as naturally as built-in commands — a minimal working server takes under 60 minutes to build. To build one: scaffold a Node.js/TypeScript project, implement the Server class from @modelcontextprotocol/sdk, define tools with JSON Schema, and register the server in Claude Code's settings. This guide walks through every step with production-ready patterns.

What Is MCP and Why Build a Custom Server?

MCP is an open standard that defines how AI models communicate with external tools. Claude Code ships with built-in MCP servers (filesystem, browser, memory), but custom servers let you:

  • Connect to internal APIs (JIRA, Confluence, Salesforce)
  • Query private databases
  • Wrap CLI tools as Claude-callable functions
  • Build domain-specific toolkits for your team

Benchmark: teams using custom MCP servers report 40–60% reduction in manual copy-paste steps per development session, based on internal surveys at early MCP adopters.

Prerequisites

  • Node.js 20+ and npm/bun
  • Claude Code installed and running
  • Basic TypeScript knowledge

Project Scaffold

mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
npx tsc --init
Enter fullscreen mode Exit fullscreen mode

Update tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "strict": true
  }
}
Enter fullscreen mode Exit fullscreen mode

Add to package.json:

{
  "scripts": {
    "dev": "tsx src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}
Enter fullscreen mode Exit fullscreen mode

Minimal MCP Server

Create src/index.ts:

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  ListToolsRequestSchema,
  CallToolRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";

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

// Define available tools
server.setRequestHandler(ListToolsRequestSchema, async () =

---

## Register the Server in Claude Code

Add to `~/.claude/settings.json` (or project `.claude/settings.json`):

Enter fullscreen mode Exit fullscreen mode


json
{
"mcpServers": {
"my-custom-server": {
"command": "node",
"args": ["/absolute/path/to/my-mcp-server/dist/index.js"],
"env": {
"MY_API_KEY": "your-key-here"
}
}
}
}


For development with hot reload:
Enter fullscreen mode Exit fullscreen mode


json
{
"mcpServers": {
"my-custom-server": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/my-mcp-server/src/index.ts"]
}
}
}


Restart Claude Code after updating settings. Verify the server is loaded with `/mcp` in Claude Code's command palette.

## Multi-Tool Server Pattern

Real servers expose multiple tools. Structure them cleanly:

Enter fullscreen mode Exit fullscreen mode


typescript
// tools/definitions.ts
export const TOOLS = [
{
name: "create_jira_ticket",
description: "\"Create a JIRA issue\","
inputSchema: {
type: "object",
properties: {
summary: { type: "string" },
description: "{ type: \"string\" },"
priority: { type: "string", enum: ["Low", "Medium", "High", "Critical"] },
},
required: ["summary"],
},
},
{
name: "search_confluence",
description: "\"Search Confluence wiki pages\","
inputSchema: {
type: "object",
properties: {
query: { type: "string" },
space: { type: "string", description: "\"Space key (optional)\" },"
},
required: ["query"],
},
},
];

// tools/handlers.ts
export async function handleTool(name: string, args: unknown) {
switch (name) {
case "create_jira_ticket":
return createJiraTicket(args);
case "search_confluence":
return searchConfluence(args);
default:
throw new Error(Unknown tool: ${name});
}
}


## Error Handling Best Practices

MCP tool errors should be returned as structured content, not thrown exceptions (which crash the server):

Enter fullscreen mode Exit fullscreen mode


typescript
server.setRequestHandler(CallToolRequestSchema, async (request) =


Frequently Asked Questions

What is MCP and how does it relate to Claude Code?

MCP (Model Context Protocol) is an open standard for connecting AI models to external tools and data. Claude Code has a built-in MCP client; by building a custom MCP server, you expose any function or API as a tool Claude can call during its agentic loop.

Do I need TypeScript to build an MCP server?

No. The MCP SDK is available for Python (mcp package) and TypeScript/JavaScript (@modelcontextprotocol/sdk). Python is popular for data and ML tooling; TypeScript is preferred for Node.js ecosystem integrations.

How do I pass environment variables to a custom MCP server?

In Claude Code's settings.json, add an "env" object inside the server config block. Claude Code will set those variables in the server process's environment before starting it.

Can multiple people use the same MCP server?

Yes. Deploy it as an HTTP SSE server (using SSEServerTransport) behind your internal network or VPN. Each Claude Code user points to the URL in their settings. Authentication is handled via bearer tokens in request headers.

How many tools can one MCP server expose?

There is no hard limit, but keep it practical. Claude includes all tool definitions in its context window, so 20–30 focused tools is a good upper bound. Group related tools into separate servers if the list grows large.

How do I debug a broken MCP server?

Run npx @modelcontextprotocol/inspector node dist/index.js to open the MCP inspector UI. It shows the exact JSON sent and received. Also check Claude Code's MCP logs: open the command palette → /mcp → select your server → view logs.

Is there a way to share MCP servers with my team?

Yes. Host the server as an HTTP service and share the URL, or commit the server repo and have teammates run it locally. For Claude Code, each user registers the server in their own settings.json. A shared project .claude/settings.json can automate this.

Related Guides

Top comments (0)