cd /news/developer-tools/building-a-custom-mcp-server-for-cla… · home topics developer-tools article
[ARTICLE · art-74274] src=promptcube3.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Building a custom MCP server for Claude

Building a custom Model Context Protocol (MCP) server lets Claude execute real-world actions like querying databases or triggering GitHub Actions, moving beyond simple prompting. Anthropic's Claude Desktop uses MCP to connect to a Node.js or Python server via stdio, with tools defined in JSON-RPC. A sample server provides system stats, and developers must register it in the claude_desktop_config.json file with absolute paths to avoid silent failures.

read5 min views2 publishedJul 26, 2026
Building a custom MCP server for Claude
Image: Promptcube3 (auto-discovered)

ClaudeSkills" means just writing a better prompt. They're wrong. The real power isn't in the chat box; it's in the Model Context Protocol (MCP). If you want Claude to actually

dothings—like query your actual Postgres database, read your Jira tickets, or trigger a GitHub Action—you need to stop prompting and start building a server.

I spent three hours last Thursday fighting with a JSON-RPC error because I forgot a single comma in my tool definition. It's a pain, but once it clicks, you stop treating Claude like a chatbot and start treating it like an operator.

The architecture of a "Skill" #

To be clear, when we talk about extending Claude's capabilities, we are talking about creating a bridge. Claude (the client) sends a request to an MCP Server (your code), which executes a function and sends the result back.

| Component | Role | Example |

| :--- | :--- | :--- |

| Host | The UI/IDE | Claude Desktop / Cursor |

| Server | The "Skill" logic | A Node.js or Python script |

| Transport | The pipe | Standard Input/Output (stdio) |

Setting up your first MCP server in Node.js #

Don't overcomplicate this. You don't need a massive framework. You just need the @modelcontextprotocol/sdk

.

First, initialize your project:

mkdir claude-skills-test && cd claude-skills-test
npm init -y
npm install @modelcontextprotocol/sdk

Now, here is a raw implementation of a "skill" that lets Claude fetch the current system load and memory usage of your machine. This is something Claude can't do natively.

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

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

// 1. Tell Claude what this "skill" can do
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: "get_system_stats",
    description: "Returns current CPU load and free memory",
    inputSchema: {
      type: "object",
      properties: {}, 
    },
  }],
}));

// 2. Define the actual logic
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "get_system_stats") {
    const freeMem = (os.freemem() / 1024 / 1024 / 1024).toFixed(2);
    const load = os.loadavg()[0];
    
    return {
      content: [{ 
        type: "text", 
        text: `System Status: Load ${load}, Free RAM ${freeMem}GB` 
      }],
    };
  }
  throw new Error("Tool not found");
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch(console.error);

Wiring it into Claude Desktop #

This is where most devs trip up. You can't just run node index.js

and expect Claude to see it. You have to register the server in your config file.

Open your claude_desktop_config.json

.

  • MacOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Add this block:

{
  "mcpServers": {
    "my-system-skill": {
      "command": "node",
      "args": ["/absolute/path/to/your/claude-skills-test/index.js"]
    }
  }
}

Pro tip: Use absolute paths. Relative paths will fail silently, and you'll spend twenty minutes wondering why the hammer icon isn't appearing in your chat interface.

Restart Claude Desktop completely. If you see a small plug icon or hammer, you've successfully given Claude a new skill. Now you can ask, "How is my RAM doing?" and it will actually execute your JS code to find out.

Moving beyond basic scripts #

Once you have the basics, you start realizing that the bottleneck isn't the code—it's the context. If you feed a tool too much raw data, you waste tokens and confuse the model.

I've found that the most effective "skills" are those that act as filters. Instead of a tool that "Reads a whole File," build one that "Searches for a Regex pattern in a File."

When comparing AI Models, you'll notice some handle tool-calling (function calling) with much higher precision than others. Claude 3.5 Sonnet is currently the gold standard for MCP because it doesn't "hallucinate" arguments as often as GPT-4o does.

Common failure points #

If it's not working, it's usually one of these three things:

  1. Node Path: Claude can't find node

. Use the full path to the binary (find it with which node

).

  1. Async Hangs: If your tool takes more than 30 seconds to respond, Claude will often timeout. Use streaming or optimize your queries.

  2. JSON Schema errors: If your inputSchema

is wrong, Claude will try to pass arguments that your code isn't prepared to handle, leading to a crash.

The value of a shared ecosystem #

Building these in a vacuum is slow. This is why I spend so much time in the PromptCube community. Instead of guessing if a specific tool definition will trigger a hallucination, you can see how others structured their MCP servers for similar tasks.

Whether you're trying to automate your PR reviews or connect Claude to a niche API, joining PromptCube gives you access to a peer group of devs who are actually shipping AI-integrated workflows, not just chatting with a bot. You can share your server configs, troubleshoot weird edge cases, and stay updated on the latest protocol changes.

Optimizing for speed #

To make your skills feel snappy, avoid heavy imports inside the request handler.

Bad:

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const heavyLib = await import('some-massive-library'); // Slows down every call
  // ... logic
});

Good:

import heavyLib from 'some-massive-library'; // Import once at startup

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  // ... logic
});

The difference is usually around 200-500ms. It doesn't sound like much, but when you're in a flow, it's the difference between a tool that feels native and one that feels like a clunky plugin.

Next Claude Code and Codex have a nasty habit of treating your →

All Replies (0) #

No replies yet — be the first!

── more in #developer-tools 4 stories · sorted by recency
── more on @claude 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/building-a-custom-mc…] indexed:0 read:5min 2026-07-26 ·