Skip to content

AI Tooling

MCP Servers + Claude Tool Calling — Building a Custom Velocity X MCP

Extending Claude Code With Custom Tools

🔌 🛠️ ⚙️
Model Context Protocol (MCP) is the spec that lets Claude Code call external tools. Anthropic ships MCPs for Supabase, Netlify, and Playwright. But you can build your own. I built a custom Velocity X MCP that exposes read brand.json, list product deals, run marketing report, and push Git commits. This is how you do it.

What Is MCP and Why It Matters

MCP is a client-server protocol. Claude is the client. Your tool is the server. You define a list of tools (name, description, input schema), and Claude can request them during the conversation. The server responds with the result, Claude reads it, and continues reasoning. It's like function calling, but with full schema validation and async request handling. Why build a custom MCP? Because your business tools are unique. Shopify's pricing rules differ from Stripe's. Your brand asset library lives somewhere specific. Your reporting pipeline has custom SQL. A generic MCP won't know how to call your stuff. A custom MCP turns "hey Claude, what's the Q2 revenue trend" into a single tool invocation that hits your exact database query.

MCP Server Architecture

An MCP server is a Node process that listens on stdio. It speaks JSON-RPC. When Claude connects, it sends an initialize handshake, Claude responds with the server's manifest (list of tools), and they're paired. Then Claude sends tool requests, the server handles them and sends responses back. The skeleton: ```javascript import { StdioClientTransport, Server } from "@modelcontextprotocol/sdk/server/stdio.js"; import { Tool, TextContent } from "@modelcontextprotocol/sdk/types.js"; const server = new Server({ name: "velocity-x-mcp", version: "1.0.0", }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "read_brand_json", description: "Read the brand.json configuration file", inputSchema: { type: "object", properties: {}, required: [], }, }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name === "read_brand_json") { const data = fs.readFileSync("./brand.json", "utf-8"); return { content: [{ type: "text", text: data }], }; } }); const transport = new StdioClientTransport(); await server.connect(transport); ``` That's the bare minimum. You define tools in setRequestHandler(ListToolsRequestSchema), then handle each tool call in setRequestHandler(CallToolRequestSchema). Each tool gets a name, description, and JSON schema for its inputs.

Four Tools in the Velocity X MCP

1. read_brand_json — No input. Reads brand.json from disk, returns the JSON blob. Claude can now ask "what products do we sell" and get the exact list from the source of truth, not from training data. TTL is ~60 seconds — if brand.json changes, Claude gets the update on next tool call. 2. list_deals — Input: category (optional). Queries a Supabase table for active promotional deals. Returns deal name, discount percentage, start/end date. Claude can ask "what deals are running this quarter" and get live data, not a stale spreadsheet. 3. run_marketing_report — Input: start_date, end_date, report_type ("revenue" | "traffic" | "conversion"). Executes a custom SQL query against your analytics database and returns the results as a markdown table. The report is date-locked, so Claude can generate it on-demand without you running it manually. Example: "generate a Q2 marketing report" → Claude calls the tool with start_date=2026-04-01, end_date=2026-06-30, report_type="revenue" → the tool hits your database, formats the results, Claude reads the table and composes a summary. 4. push_git_commit — Input: branch, commit_message, changed_files (array of file paths). Stages the specified files, commits with the message, and pushes to the named branch. No interactive git CLI needed. Claude changes a config file, calls this tool, and the commit lands on main automatically. Useful for templated changes: "update the blog metadata for all 50 posts" → Claude loops over the posts, edits each one, collects the file paths, calls push_git_commit with all 50 files at once.

Integration With Claude Code

Claude Code finds MCPs via a config file: ~/.claude/config.json. You point to your MCP executable and any env vars it needs. ```json { "mcpServers": { "velocity-x": { "command": "node", "args": ["/path/to/velocity-x-mcp.js"], "env": { "SUPABASE_URL": "https://...", "SUPABASE_KEY": "eyJ...", "DATABASE_URL": "postgres://..." } } } } ``` On next session start, Claude loads the MCP, lists the four tools, and they're available in the conversation. No manual activation. If the MCP crashes, Claude logs the error and moves on — it doesn't block the session.

Real Example: Generating a Blog Post Index

Brief: "Create an index of all 50 blog posts with categories and links for the marketing homepage." Claude: reads the blog posts directory, calls read_brand_json to get the site metadata, loops over post files, extracts frontmatter, calls run_marketing_report to fetch post view counts, generates an index markdown file, and calls push_git_commit to land it on a feature branch. All in one session. No manual file reading, no manual database queries, no copy-paste of view counts. The index is always fresh because the MCP reads from the actual data sources.

Common Questions

Can I version control the MCP? Yes. Keep it in tools/mcp-server.js in your repo. Version the package.json, commit the code. The ~/.claude/config.json points to it. If the MCP crashes and you push a fix, next session automatically picks up the new version. What if my tool times out? MCPs have a 30-second default timeout. If your SQL query takes longer, break it into smaller queries or increase the timeout in the MCP handler. Can I connect multiple MCPs? Yes. Add multiple entries in ~/.claude/config.json. Claude will load all of them and expose all tools. Naming conflicts are resolved by prefixing tool names with the server name. Is this secure? MCPs run on your machine with your env vars. They're only exposed to Claude, not to the internet. If you need to expose them to other clients, you'd wrap them in HTTP, but that's out of scope for personal / team use.

The Bottom Line

Custom MCPs let Claude Code operate on your actual business logic, not on assumptions. Building one is 2–3 hours of work upfront: define your tools, scaffold the Node server, test each one. After that, every Claude Code session has direct access to your brand config, your deals, your analytics, your Git. The ROI is immediate. If you're shipping with Claude Code, a custom MCP is the difference between "Claude is helpful" and "Claude is indispensable". Start with one tool (read your main config file), test it, add more tools later.

See the full skills + MCP stack I use in production for context on where custom MCPs fit into the broader toolchain. Then visit pricing if you want to explore building one with Aidxn.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.