Back to Blog
Enterprise

Self-Hosted MCP Servers for Claude: Building Custom Tool Extensions On-Prem

Claude Directory January 10, 2026
1 views

Tired of cloud dependencies for Claude's tool calling? Discover how self-hosted MCP servers keep your enterprise data secure on-prem with Docker Compose and Rust examples.

Why Self-Host MCP Servers for Claude?

Hey there, Claude enthusiasts! If you're knee-deep in enterprise AI deployments, you've probably hit the wall with cloud-hosted tools exposing sensitive data. Enter self-hosted MCP (Model Context Protocol) servers – your ticket to private, lightning-fast tool extensions for Claude. In this guide, we'll dive into building and deploying these bad boys on-prem, complete with Docker Compose setups and real-world examples for database queries and API calls.

We'll compare cloud vs. on-prem setups, walk through Rust-based servers (because why not go fast and safe?), and share actionable code. By the end, you'll have a secure toolchain that Claude loves. Let's roll!

MCP Servers 101: Claude's Extension Superpower

MCP servers are lightweight HTTP endpoints that supercharge Claude's tool-calling abilities. Claude (Opus, Sonnet, Haiku) can dynamically invoke these for tasks like data retrieval or computations, keeping your prompts context-rich without bloating token limits.

Key perks for Claude users:

  • Structured outputs: JSON schemas enforced server-side.
  • Stateful sessions: Protocol handles multi-turn context.
  • Claude-native: Integrates seamlessly via Anthropic's Messages API.

But here's the rub: Public MCP hubs (like those in the Anthropic ecosystem) route through the cloud. For enterprises? That's a no-go for compliance (GDPR, HIPAA) or latency-sensitive ops.

Cloud-Hosted vs. Self-Hosted MCP: Head-to-Head

Let's break it down conversationally – imagine you're at a coffee shop debating with your dev lead:

FeatureCloud-Hosted (e.g., Anthropic Marketplace)Self-Hosted On-Prem
SecurityShared infra, potential data exfilAir-gapped, full control
Latency100-500ms roundtrips<50ms local network
CostPer-call pricingOne-time setup, zero marginal
CustomizationLimited to templatesFull Rust/any-lang freedom
ScalabilityAuto-scalesKubernetes/Docker Swarm
ComplianceVendor audits onlySOC2 in your datacenter

Self-hosted wins for enterprises handling proprietary data. Claude Enterprise users: This pairs perfectly with VPC deployments.

Prerequisites: Gear Up Your Setup

Before we code:

  • Docker & Docker Compose (v2+).
  • Rust toolchain (for custom servers): curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh.
  • Claude API key (Opus recommended for complex tools).
  • Basic YAML/JSON knowledge.

Test your Claude integration first:

pip install anthropic
anthropic --api-key $ANTHROPIC_API_KEY messages --model claude-3-opus-20240229

Quickstart: Docker Compose for a Basic MCP Server

Spin up a minimal MCP echo server in 5 minutes. MCP protocol basics:

  • POST /mcp/call with JSON { "tool": "echo", "params": {...}, "session_id": "uuid" }.
  • Respond with { "result": ..., "next_tools": [...] }.

docker-compose.yml:

version: '3.8'
services:
  mcp-server:
    image: rust:1.75-slim  # Or your custom image
    ports:
      - "8080:8080"
    volumes:
      - ./mcp-server:/app
    working_dir: /app
    command: bash -c "cargo run --release"
    environment:
      - RUST_LOG=info

  # Add Postgres later

Build a Rust server skeleton (Cargo.toml):

[package]
name = "claude-mcp"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "1.0", features = ["v4", "serde"] }

src/main.rs (basic echo):

use axum::{routing::post, Json, Router};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Deserialize)]
struct MCPRequest {
    tool: String,
    params: serde_json::Value,
    session_id: Option<Uuid>,
}

#[derive(Serialize)]
struct MCPResponse {
    result: serde_json::Value,
    next_tools: Vec<String>,
}

async fn handle_call(Json(req): Json<MCPRequest>) -> Json<MCPResponse> {
    let result = match req.tool.as_str() {
        "echo" => req.params.clone(),
        _ => serde_json::json!({ "error": "Unknown tool" }),
    };
    Json(MCPResponse {
        result,
        next_tools: vec![],
    })
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/mcp/call", post(handle_call));
    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

Run: docker compose up --build. Test with curl:

curl -X POST http://localhost:8080/mcp/call \
  -H 'Content-Type: application/json' \
  -d '{"tool":"echo","params":{"msg":"Hello Claude!"},"session_id":"123"}'

Boom – your first MCP server! Now, Claude prompt: "Use tool echo with msg 'Test' via MCP at localhost:8080" (adapt for API).

Real-World Example 1: Database Integration (Postgres)

Secure internal DB queries without exposing creds to Claude. Add Postgres to Compose:

  postgres:
    image: postgres:16
    environment:
      POSTGRES_DB: claude_db
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"
volumes:
  pgdata:

Extend Rust server (Cargo.toml + sqlx = { version = "0.7", features = ["runtime-tokio", "postgres", "chrono"] }):

use sqlx::{PgPool, postgres::PgPoolOptions};
use once_cell::sync::Lazy;

static POOL: Lazy<PgPool> = Lazy::new(|| {
    PgPoolOptions::new().connect("postgres://user:pass@localhost/claude_db").unwrap()
});

async fn query_db(params: serde_json::Value) -> Result<serde_json::Value, String> {
    let sql = params["query"].as_str().ok_or("No query")?;
    let rows = sqlx::query(sql).fetch_all(&*POOL).await.map_err(|e| e.to_string())?;
    Ok(serde_json::to_value(rows).unwrap())
}

// In handle_call:
"db_query" => query_db(req.params).await.map_err(|e| serde_json::json!({ "error": e }))?.into(),

Claude usage: Prompt Claude to call db_query tool for sales data. Zero data leaves your prem!

Real-World Example 2: Internal API Integrations

Proxy calls to your CRM/ERP APIs. Add auth middleware in Rust:

use axum::http::HeaderMap;

async fn api_call(params: serde_json::Value, headers: HeaderMap) -> Result<serde_json::Value, String> {
    let client = reqwest::Client::new();
    let url = params["url"].as_str().ok_or("No URL")?;
    let api_key = std::env::var("INTERNAL_API_KEY").unwrap();
    let res = client.get(url)
        .header("Authorization", format!("Bearer {api_key}"))
        .json(&params["body"])
        .send().await
        .map_err(|e| e.to_string())?;
    res.json().await.map_err(|e| e.to_string())
}

Secure with env vars in Docker. Compare to Zapier: No vendor lock-in, sub-10ms latency.

Scaling & Security Best Practices

  • Auth: JWT or mTLS for MCP endpoints.
  • Scaling: docker compose scale mcp-server=3 or Kubernetes.
  • Monitoring: Prometheus + Grafana sidecar.
  • Claude Tips: Use tool_choice: auto in API calls; pin schemas.

Edge case: High-volume? Rust's async shines over Node.js (2x throughput in benchmarks).

Wrapping Up: Your On-Prem Claude Arsenal

Self-hosted MCP servers transform Claude from a chatty sidekick to an enterprise powerhouse. We've covered Docker basics, Rust builds, DB/API examples – all deployable today. Dip into Claude Directory for more: API SDKs, agents, and playbooks.

Questions? Drop a comment. Stay secure, code fast! 🚀

(Word count: ~1450)

Comments

More Blog

View all
Claude for Developers

Building Voice Agents with Claude API and ElevenLabs: Conversational AI Guide

Build natural voice agents combining Claude API's superior reasoning with ElevenLabs' lifelike TTS. This end-to-end guide creates a conversational web app with STT, AI chat, and speech synthesis.

C
Claude Directory
2
Model Comparisons

Claude vs Mistral Large 2: 2025 Data Analysis Benchmarks and Use Cases

As data volumes explode in 2025, choosing between Claude's reasoning depth and Mistral Large 2's efficiency is critical. We benchmark SQL generation, visualizations, and large datasets to reveal the w

C
Claude Directory
1
Enterprise

Claude Enterprise for Cybersecurity: Threat Modeling and Incident Response

In the high-stakes world of cybersecurity, rapid threat modeling and incident response can mean the difference between containment and catastrophe. Discover how Claude Enterprise empowers security tea

C
Claude Directory
1
Claude Code

Claude Code in VS Code: Custom Commands for Refactoring Large Codebases

Refactoring sprawling codebases manually? Harness Claude Code's power in VS Code with custom commands to automate AI-driven refactors across TypeScript and Python projects—saving hours of drudgery.

C
Claude Directory
1
Claude for Developers

Claude SDK Rust for Blockchain: Smart Contract Auditing Agents

Build blazing-fast smart contract auditing agents in Rust using the Claude SDK. Harness Claude's reasoning to scan Solidity code for vulnerabilities like reentrancy and overflows.

C
Claude Directory
1
Claude Best Practices

Advanced Claude Artifacts: Collaborative Editing in Multi-User Sessions

Elevate team productivity with Claude Artifacts in multi-user projects—enable real-time iterative editing for code reviews and docs without leaving the interface.

C
Claude Directory
1