Pro12 min

Build Your Own MCP Tool

When the agent keeps needing a capability nothing provides, build it. A custom MCP server exposes your internal systems (a deployment API, a feature-flag service, a proprietary search) as tools the agent can call. This is the highest-leverage pro skill: you are extending the agent's hands to fit your exact stack.

Step 1: Define one clear tool

Start with a single tool that does one thing well, with a precise description and typed inputs. The description is what the model reads to decide when to call it, so make it specific.

server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const server = new McpServer({ name: "deploys", version: "1.0.0" });

server.tool(
  "deploy_status",
  "Get the current deploy status for a service by name.",
  { service: z.string().describe("service name, e.g. 'payments'") },
  async ({ service }) => {
    const res = await fetch(`https://ops.internal/status/${service}`);
    const data = await res.json();
    return { content: [{ type: "text", text: JSON.stringify(data) }] };
  },
);

Step 2: Connect and test it

Register the local server with your agent, then ask a question that should trigger the tool. Confirm the model picks it correctly and that the output is useful, not raw noise.

claude - ops
$claude mcp add deploys -- node server.ts
Added MCP server 'deploys'. 1 tool available.
$> is payments deployed?
Called deploy_status(payments): live, v412, healthy.
$

Step 3: Make it safe by design

Scope credentials to the minimum, validate every input with a schema, and prefer read-only tools unless a write is genuinely needed. A tool that can deploy to production must require an explicit, confirmable argument, never a loose default.

The description is the API the model sees
Models choose tools from their descriptions. A vague description causes wrong or missed calls; a sharp one with clear inputs and examples makes tool use reliable. Treat tool docs as production interfaces.
Agent - custom tool call
You
did the last deploy of payments succeed?
Agent
Calling deploy_status(payments) ...
Agent
Yes. payments is live on v412 and reporting healthy.
Your internal system, now a first-class capability the agent can call.

Hands-on tasks