Building Custom MCP Connectors for Claude: A Practical Guide

by Sandlabs Team, Founder, Sandlabs

The Model Context Protocol (MCP) is the open standard that lets Claude connect to external tools and data sources. With 12,000+ MCP servers in the wild and adoption from Claude, ChatGPT, Gemini, and VS Code, MCP has become the universal interface between AI and business tools.

But the real power isn't in the pre-built connectors — it's in building custom ones for your proprietary systems. This guide covers everything you need to build, deploy, and maintain custom MCP connectors.

What Is MCP?

MCP defines how AI applications communicate with external tools using a client-server architecture built on JSON-RPC 2.0.

Three participants:

  • MCP Host: The AI application (Claude Desktop, Claude Code, ChatGPT)
  • MCP Client: Maintains a 1:1 connection to each MCP server
  • MCP Server: Your custom connector that exposes tools, resources, and prompts

Three core primitives:

  • Tools: Executable functions (e.g., query a database, call an API, send a message)
  • Resources: Data sources (e.g., file contents, database records, API responses)
  • Prompts: Reusable interaction templates

Two transport mechanisms:

  • stdio: For local servers running on your machine (simplest)
  • Streamable HTTP: For remote servers accessible over the network (production)

When a user asks Claude to "check the latest sales figures," Claude discovers available tools via MCP, calls the appropriate one, and incorporates the results into its response — all without the user needing to know which API or database was queried.

When to Build a Custom Connector

The built-in connector directory covers 75+ tools (Slack, Google Drive, Salesforce, etc.). Build a custom connector when:

  • Your tool isn't in the directory (internal CRM, custom database, proprietary API)
  • You need specific operations the built-in connector doesn't support
  • You want fine-grained access control over what Claude can do
  • You're connecting to internal systems behind a firewall
  • You need to combine data from multiple sources into a single tool

Building Your First MCP Server (Python)

The fastest way to build an MCP server is with Python's FastMCP framework.

Installation

pip install "mcp[cli]"

Requires Python 3.10+.

Basic structure

from mcp.server.fastmcp import FastMCP

# Create server
mcp = FastMCP("my-business-tools")

@mcp.tool()
async def get_customer(customer_id: str) -> str:
    """Look up a customer by their ID and return their profile.

    Args:
        customer_id: The unique identifier for the customer
    """
    # Your database/API logic here
    customer = await db.customers.find_one({"id": customer_id})
    return f"Name: {customer['name']}, Email: {customer['email']}, Plan: {customer['plan']}"

@mcp.tool()
async def list_recent_orders(customer_id: str, limit: int = 10) -> str:
    """List recent orders for a customer.

    Args:
        customer_id: The customer to look up orders for
        limit: Maximum number of orders to return (default 10)
    """
    orders = await db.orders.find({"customer_id": customer_id}).limit(limit)
    return "\n".join([f"#{o['id']}: {o['product']} - ${o['amount']}" for o in orders])

@mcp.resource("customers://stats")
async def customer_stats() -> str:
    """Current customer statistics."""
    total = await db.customers.count_documents({})
    active = await db.customers.count_documents({"status": "active"})
    return f"Total: {total}, Active: {active}, Churn rate: {((total-active)/total)*100:.1f}%"

def main():
    mcp.run(transport="stdio")

if __name__ == "__main__":
    main()

FastMCP automatically generates tool definitions from your Python type hints and docstrings. Clear, descriptive docstrings are critical — they help Claude understand when and how to use each tool.

TypeScript alternative

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

const server = new McpServer({
  name: "my-business-tools",
  version: "1.0.0",
});

server.tool(
  "get_customer",
  "Look up a customer by their ID",
  { customer_id: z.string().describe("The unique customer identifier") },
  async ({ customer_id }) => {
    const customer = await db.findCustomer(customer_id);
    return {
      content: [{ type: "text", text: JSON.stringify(customer) }],
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

Connecting to Claude Desktop

Add your server to Claude Desktop's configuration (claude_desktop_config.json):

{
  "mcpServers": {
    "my-business-tools": {
      "command": "python",
      "args": ["/path/to/server.py"],
      "env": {
        "DATABASE_URL": "postgresql://..."
      }
    }
  }
}

For Claude Code, use:

claude mcp add my-business-tools python /path/to/server.py

Architecture Decisions

Local vs. Remote

Local (stdio):

  • Server runs on the same machine as Claude Desktop
  • Simplest setup — no networking, no auth
  • Good for: personal tools, development, internal databases accessible via VPN
  • Limitation: only works for one user

Remote (Streamable HTTP):

  • Server runs on your infrastructure, accessible via HTTPS
  • Required for: team deployments, Claude Cowork connectors, multi-user setups
  • Needs: OAuth 2.1 authentication, HTTPS, proper security
  • Good for: production deployments, shared tools

Tool granularity

Too broad: query_database(sql: str) — gives Claude raw SQL access. Dangerous.

Too narrow: get_customer_email(id: str) — Claude needs to call 10 tools for basic tasks.

Just right: get_customer_profile(id: str) — returns a complete, useful response. search_customers(query: str, filters: dict) — flexible but bounded.

Design tools at the level of business operations, not database queries.

Error handling

Return clear, actionable error messages. Claude uses error messages to decide what to do next:

@mcp.tool()
async def update_customer(customer_id: str, email: str) -> str:
    """Update a customer's email address."""
    if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
        return "Error: Invalid email format. Please provide a valid email address."

    customer = await db.customers.find_one({"id": customer_id})
    if not customer:
        return f"Error: Customer {customer_id} not found. Use search_customers to find the correct ID."

    await db.customers.update_one({"id": customer_id}, {"$set": {"email": email}})
    return f"Updated email for {customer['name']} to {email}."

Security Best Practices

MCP servers can access sensitive business data. Security is not optional.

Authentication

  • Use OAuth 2.1 for remote servers (Authorization Code Flow with PKCE)
  • Never hardcode credentials — use environment variables or secret managers
  • Short-lived tokens with rotating refresh tokens
  • Per-client consent before forwarding to third-party auth

Authorisation

  • Implement per-tool scopes (e.g., customers:read, customers:write, orders:read)
  • Progressive least-privilege — start with read-only, add write access only when needed
  • Never give Claude unrestricted database access

Data handling

  • Never log access tokens, API keys, or sensitive data
  • Validate all inputs before executing
  • Sanitise outputs to prevent data leakage
  • Use HTTPS for all remote connections
  • Block private IP ranges to prevent SSRF attacks

Common vulnerabilities to avoid

  1. Confused deputy problem — Attackers exploiting proxy servers to steal authorization codes. Mitigation: per-client consent flows.
  2. SSRF — Malicious servers pointing to internal IPs. Mitigation: enforce HTTPS, block private ranges.
  3. Scope inflation — Over-broad token scopes increasing blast radius. Mitigation: per-tool scopes.

OWASP has published a dedicated guide for secure MCP server development.

Deploying to Production

For Claude Cowork (Team/Enterprise)

  1. Deploy your MCP server to your infrastructure (Docker recommended)
  2. Expose via HTTPS with OAuth 2.1 authentication
  3. In Claude: Organisation settings > Connectors > "Add custom connector"
  4. Enter your MCP server URL and configure OAuth credentials
  5. Team members connect via Settings > Connectors

For Claude Code

# Add with environment variables
claude mcp add \
  -e API_KEY=your-key \
  -e DATABASE_URL=your-db-url \
  my-tools -- python server.py

Monitoring

  • Log all tool invocations (without sensitive data) for debugging
  • Track error rates, latency, and usage patterns
  • Set up alerts for failures and anomalies
  • Monitor token consumption — MCP tools contribute to Claude's context window

Real-World Examples

Commission processing (financial services)

We built custom MCP connectors for a mortgage broker platform that process lender remittance files from 24+ aggregators. Claude reads the raw files, extracts commission data, reconciles against expected payments, and generates RCTI invoices — reducing processing time from hours to minutes.

Document management (legal)

A law firm needed Claude to access their internal document management system. We built an MCP connector that lets Claude search case files, extract relevant clauses, and cross-reference with regulatory databases — all through natural language queries.

Inventory and supply chain

An e-commerce business needed Claude to check stock levels, trigger reorders, and generate supplier communications. Custom MCP connectors bridged Claude with their inventory API, Shopify store, and email system.

What It Costs

EngagementWhat You GetCostTimeline
Single MCP connectorOne connector for one system$5K-$15K1-2 weeks
Cowork Setup SprintCowork config + 2-3 custom connectors + training$3K-$5K1 week
Multi-system integration3-5 connectors with orchestration$15K-$40K3-6 weeks
Enterprise MCP platformCustom connector framework + security + monitoring$40K-$80K6-10 weeks

Getting Started

If you need custom MCP connectors for your business:

  1. Identify your tools — What systems does your team access daily that aren't in Claude's connector directory?
  2. Map the operations — What specific actions do you need Claude to perform? (read data, create records, trigger workflows)
  3. Assess security requirements — What data will Claude access? Are there compliance requirements?
  4. Start with one connector — Build and validate a single connector before expanding.

We build custom MCP connectors for businesses across Australia and the US. Tell us about your workflow to discuss your integration needs.

Explore our AI & Claude consulting services →

More articles

Claude Certification 2026: All Four Anthropic Exams, What They Cost, and Whether Your Team Needs One

Anthropic now runs four proctored Claude certifications through Pearson VUE. What CCAO-F, CCDV-F, CCAR-F and CCAR-P actually test, what they cost in AUD, how to study for free, and the honest answer on whether a certificate changes anything for your business.

Read more

Does Anthropic Charge GST in Australia? Claude Invoices, ABNs and Your BAS

Anthropic adds 10% GST to Australian Claude subscriptions by default - and if you do not add your ABN, you probably cannot claim it back. How the imported-services rules work, the two-minute fix, and what to do about invoices you have already paid.

Read more

Let's build something great together.

Melbourne, Australia — serving founders worldwide. [email protected]