Build This Now
Build This Now
Keyboard ShortcutsStatus Line Guide
CLAUDE.md, Skills, Subagents, Hooks: When to Use WhichClaude Code Subagents: The 3 to 5 Agent Sweet SpotCLAUDE.md Best Practices: The File That Makes Claude Code ReliableHow to Fix Claude Code Running Out of Context
speedy_devvkoen_salo
Blog/Toolkit/MCP/Build Your Own MCP Server for Claude Code

Build Your Own MCP Server for Claude Code

Build a custom Claude Code MCP server in Node.js. Tool definitions, request handlers, REST and Postgres patterns, plus the config Claude Code needs to load it.

Stop configuring. Start building.

SaaS builder templates with AI orchestration.

See what we build for companies →
speedy_devvWritten by speedy_devvPublished Mar 8, 2026Toolkit hubMCP index

Problem: The public MCP servers don't talk to the systems you actually use. Your internal API, the company Postgres, a custom workflow nobody else touches. For Claude Code to reach those, you have to write the server yourself.

Quick Win: Five minutes of Node.js gets Claude talking to any REST API:

// my-api-server.js - Connect Claude to your API
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
 
const server = new Server({ name: "my-api-server", version: "1.0.0" });
 
server.setRequestHandler("tools/list", async () => ({
  tools: [
    {
      name: "fetch_user_data",
      description: "Get user information from our internal API",
      inputSchema: {
        type: "object",
        properties: {
          userId: { type: "string", description: "User ID to fetch" },
        },
        required: ["userId"],
      },
    },
  ],
}));
 
server.setRequestHandler("tools/call", async (request) => {
  const { name, arguments: args } = request.params;
 
  if (name === "fetch_user_data") {
    const response = await fetch(
      `https://api.yourcompany.com/users/${args.userId}`,
      {
        headers: { Authorization: `Bearer ${process.env.API_TOKEN}` },
      },
    );
    return {
      content: [{ type: "text", text: JSON.stringify(await response.json()) }],
    };
  }
});
 
server.connect(process.stdio);

Save the file as my-api-server.js. Run node my-api-server.js to test it. That's a working integration.

What an MCP Server Actually Is

An MCP server is a Node.js process that hands Claude Code a list of callable tools. It runs on its own, separate from the editor, and gives Claude a wire into anything you can reach from Node: APIs, databases, internal services.

Every server ships four things:

  • Tool definitions: the functions Claude is allowed to call
  • Tool handlers: the code that runs when Claude calls one
  • Error handling: useful messages when the call fails
  • Authentication: a safe way to reach the systems behind it

Patterns That Cover Most Cases

Talking to a REST API

Point Claude at any HTTP endpoint with a small connector:

// Generic API connector pattern
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
 
const server = new Server({ name: "api-connector", version: "1.0.0" });
 
server.setRequestHandler("tools/list", async () => ({
  tools: [
    {
      name: "api_get",
      description: "GET request to any endpoint",
      inputSchema: {
        type: "object",
        properties: {
          endpoint: { type: "string", description: "API endpoint path" },
          params: { type: "object", description: "Query parameters" },
        },
        required: ["endpoint"],
      },
    },
  ],
}));
 
server.setRequestHandler("tools/call", async (request) => {
  const { name, arguments: args } = request.params;
 
  if (name === "api_get") {
    const url = new URL(`${process.env.API_BASE_URL}${args.endpoint}`);
    if (args.params) {
      Object.entries(args.params).forEach(([key, value]) =>
        url.searchParams.append(key, value),
      );
    }
 
    const response = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.API_TOKEN}` },
    });
 
    return {
      content: [
        { type: "text", text: JSON.stringify(await response.json(), null, 2) },
      ],
    };
  }
});
 
server.connect(process.stdio);

The same shape handles Stripe, Shopify, your internal dashboard, anything that speaks HTTP.

Talking to a Database

Swap the fetch call for a database client:

// Database connector for PostgreSQL, MySQL, SQLite
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
const { Client } = require("pg");
 
const server = new Server({ name: "database-connector", version: "1.0.0" });
const client = new Client({ connectionString: process.env.DATABASE_URL });
 
server.setRequestHandler("tools/call", async (request) => {
  if (request.params.name === "query_database") {
    const result = await client.query(request.params.arguments.query);
    return {
      content: [{ type: "text", text: JSON.stringify(result.rows, null, 2) }],
    };
  }
});

Claude can now run SQL and help out with database work.

Setup and Testing

Start the project:

mkdir my-mcp-server && cd my-mcp-server
npm init -y && npm install @modelcontextprotocol/sdk

Then point Claude Code at the server from its MCP config file. Where that file sits depends on how you run Claude:

  • Claude Code CLI: ~/.claude.json (user-level) or .mcp.json (project-level)
  • Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
  "mcpServers": {
    "my-custom-server": {
      "command": "node",
      "args": ["/path/to/your/server.js"],
      "env": { "API_TOKEN": "your-token" }
    }
  }
}

Restart Claude Code after you save. The new server loads on startup.

When Things Break

Server not found: the config path or JSON is wrong. Double-check the file location. Use an absolute path for command.

Tool timeout: long-running calls hang the tool. Wrap them in your own timeout so they fail cleanly.

Authentication failed: the environment variables in the config aren't reaching the server. Verify they're spelled right and present.

Things Worth Doing Up Front

  • Every external call goes in a try-catch so errors surface as text, not crashes
  • Tokens live in environment variables, never in the source
  • Rate-limited APIs need their own throttle so Claude can't burn through your quota
  • console.log output shows up in Claude's logs, so use it freely for debugging

Next Steps

Pick one thing to wire up and build from there:

  1. Start with one API: the one you touch every day
  2. Copy the REST pattern: the connector above is the template
  3. Confirm it loaded: ask Claude "What MCP tools are available?" and your new tool should appear
  4. Write good tool descriptions: MCP Tool Search uses them to decide when to load your server
  5. Read further: the MCP basics guide and the popular MCP servers list cover what to build next

A custom MCP server turns Claude Code into a client for your own stack. One server a week and the list of things Claude can reach quietly gets longer.

Continue in MCP

  • 50+ MCP Servers for Claude Code
    50+ Claude Code MCP servers, editor integrations, usage monitors, orchestrators, database connectors, browser drivers, and starter kits worth wiring in today.
  • Browser Automation MCP for Claude Code
    Wire Playwright or Puppeteer into Claude Code over MCP and drive real browsers with plain-language prompts for scraping, QA, regression clicks, zero selectors.
  • How to Build an MCP Server for Claude Code
    A step-by-step tutorial: build a minimal MCP server in Node and TypeScript, expose one tool over stdio, and register it with Claude Code via claude mcp add and a project .mcp.json.
  • Claude for Creative Work Connectors
    Nine official Anthropic integrations now wire Claude into Blender, Adobe Creative Cloud, Autodesk Fusion, Ableton, Splice, Affinity, SketchUp, and Resolume.
  • Context7 MCP
    Add Context7 MCP to Claude Code so prompts fetch current library docs at query time, killing stale training-data guesses, invented APIs, and renamed functions.
  • Cursor MCP Servers
    Configure MCP servers in Cursor IDE. Where .cursor/mcp.json lives, the JSON format Cursor expects, and the first servers to add for search, git, and browser.

More from Toolkit

  • CLAUDE.md, Skills, Subagents, Hooks: When to Use Which
    Claude Code skills vs subagents vs hooks vs CLAUDE.md: a plain mental model for picking the right primitive, with token costs and examples.
  • Claude Code Subagents: The 3 to 5 Agent Sweet Spot
    Claude code subagents work best at 3-5 concurrent agents. Here is why that ceiling exists, how to set them up, and what to use past it.
  • CLAUDE.md Best Practices: The File That Makes Claude Code Reliable
    CLAUDE.md best practices: keep it under 200 lines, write it by hand, and use hooks when you need real enforcement, not advice.
  • How to Fix Claude Code Running Out of Context
    Claude Code running out of context is a session design problem. Fix it with /compact, lean CLAUDE.md, skills, and subagents, not a bigger window.

Stop configuring. Start building.

SaaS builder templates with AI orchestration.

See what we build for companies →

On this page

What an MCP Server Actually Is
Patterns That Cover Most Cases
Talking to a REST API
Talking to a Database
Setup and Testing
When Things Break
Things Worth Doing Up Front
Next Steps

Stop configuring. Start building.

SaaS builder templates with AI orchestration.

See what we build for companies →