Model Context Protocol (MCP) is a standardized way to connect Claude (and other AI models) to your tools, databases, APIs, and services. Think of it as a universal adapter that lets Claude safely access what it needs without hardcoding credentials or capabilities.
What Is MCP?
MCP is a specification that lets you expose capabilities to Claude in a structured way:
- Databases — Safely query your PostgreSQL, MongoDB, or SurrealDB
- APIs — Call internal services, third-party APIs, webhooks
- Local tools — Run scripts, CLI commands, analyze local files
- File systems — Read/write files with permission boundaries
- Custom logic — Anything you can code into a server
Instead of Claude needing to know your exact database schema or API secrets, MCP provides a clean interface that:
- Exposes only what you want exposed
- Hides credentials from Claude
- Validates all requests
- Logs all interactions
- Limits what Claude can do
How MCP Works
Simple Flow
Claude MCP Server Your Tool/Service
│ │ │
├──── request ────────→ │ │
│ ├──── query ─────────────→ │
│ │ │
│ │ ← response ──────────────┤
│ ← formatted result ──┤
│ │
Example: Querying a Database
Claude's request (natural language):
"What are the top 5 customers by revenue this month?"
MCP translates to (actual query):
SELECT customer_id, customer_name, SUM(amount) as revenue
FROM orders
WHERE created_at >= '2026-03-01'
GROUP BY customer_id, customer_name
ORDER BY revenue DESC
LIMIT 5
Claude gets back (formatted result):
1. Acme Corp: $50,000
2. TechStart Inc: $35,000
3. Global Solutions: $28,000
4. Local Business Co: $15,000
5. Startup Labs: $12,000
Claude never sees the raw SQL or database connection details.
MCP Servers — Common Types
Database Servers
Connect Claude to your database:
# Expose PostgreSQL database
type: database
engine: postgresql
host: internal-db.company
database: analytics
schema: public
tables:
- customers
- orders
- products
operations: [read] # Read-only, no writes
Claude can query but not modify.
API Servers
Expose internal APIs:
# Expose internal microservice
type: api
endpoint: http://internal-api.company/
base_path: /api/v1
operations:
- GET /customers
- GET /orders/{id}
- GET /products
- POST /support-tickets # Create new tickets
auth: api-key
rate_limit: 10/minute
Command Servers
Run local scripts and tools:
# Expose local CLI tools
type: command
commands:
- name: analyze-log
script: ./scripts/analyze-log.sh
args: [logfile]
- name: backup-db
script: ./scripts/backup.sh
- name: deploy
script: ./scripts/deploy.sh
args: [environment]
File Servers
Expose file system access:
# Expose specific directories
type: filesystem
paths:
- path: /data/reports/
access: read
- path: /documents/
access: read-write
- path: /tmp/uploads/
access: write # Claude can write but not read
max_file_size: 10MB
Setting Up an MCP Server
Simple Python MCP Server Example
from mcp.server import Server
from mcp.types import Tool, TextContent
import anthropic
# Create MCP server
mcp = Server("my-database-server")
# Define what Claude can do
@mcp.tool()
def query_customers(limit: int = 10) -> str:
"""Get top customers by revenue"""
# Your database logic here
results = db.query(
"SELECT id, name, revenue FROM customers ORDER BY revenue DESC LIMIT ?",
[limit]
)
return format_results(results)
@mcp.tool()
def get_customer_details(customer_id: int) -> str:
"""Get detailed info about a specific customer"""
result = db.query(
"SELECT * FROM customers WHERE id = ?",
[customer_id]
)
return format_result(result)
# Run the server
if __name__ == "__main__":
mcp.run()
Configuration in Claude Code
# .claude/mcp-config.yaml
servers:
- name: database
type: stdio
command: python
args: ["./mcp-servers/database-server.py"]
env:
DB_HOST: internal-db.company
DB_NAME: analytics
DB_USER: claude_user
- name: internal-api
type: http
url: http://internal-api.company:8080
auth: bearer
token_env: INTERNAL_API_TOKEN
- name: local-tools
type: stdio
command: python
args: ["./mcp-servers/tools-server.py"]
Claude Code automatically discovers and loads these MCP servers.
Security & Permissions
Principle of Least Privilege
Only expose what Claude needs:
# Good: Limited read access
database:
operations: [read]
tables: [customers, orders]
columns:
orders: [id, customer_id, amount, created_at]
customers: [id, name, email]
# Bad: Full database access
database:
operations: [read, write, delete]
tables: [*] # Access to everything
Rate Limiting
Prevent runaway requests:
rate_limits:
queries_per_minute: 60
max_result_size: 1000 rows
max_execution_time: 30 seconds
Audit Logging
Log all MCP operations:
logging:
enabled: true
log_file: /var/log/mcp-audit.log
log_level: INFO
include_results: false # Don't log sensitive data
Review logs regularly:
tail -f /var/log/mcp-audit.log
# Output:
# 2026-03-21 10:15:22 | QUERY | query_customers(limit=10) | SUCCESS
# 2026-03-21 10:15:45 | CALL | create_ticket(title=...) | SUCCESS
# 2026-03-21 10:16:00 | QUERY | get_customer_details(id=5) | SUCCESS
Real-World Examples
Example 1: Sales Analytics
servers:
- name: sales-db
type: database
operations: [read]
exposed:
- SELECT * FROM orders WHERE created_at >= DATE_SUB(NOW(), INTERVAL 90 DAY)
- SELECT customer_id, SUM(amount) as total FROM orders GROUP BY customer_id
- SELECT * FROM products WHERE active = 1
Claude can:
"Analyze orders from the last quarter. Which products have the highest margins?"
Claude queries:
- SELECT * FROM orders (90 days)
- SELECT * FROM products
- Calculates margins
- Provides analysis
Example 2: Support Ticket Management
servers:
- name: support-api
type: api
operations:
- GET /tickets?status=open
- GET /tickets/{id}
- POST /tickets # Create
- PATCH /tickets/{id} # Update
- POST /tickets/{id}/reply # Add message
Claude can:
"Show me all open support tickets that mention database errors"
Claude:
1. Lists all open tickets
2. Filters for "database error" mentions
3. Shows summary of each
"Reply to ticket #123 with technical troubleshooting steps"
Claude:
1. Gets ticket details
2. Generates response
3. Posts reply
Example 3: Infrastructure Management
servers:
- name: devops-tools
type: command
commands:
- name: deploy
script: ./deploy.sh
args: [service, environment]
- name: check-status
script: ./health-check.sh
- name: logs
script: ./get-logs.sh
args: [service, hours]
Claude can:
"What's the status of the API service?"
→ Runs health-check script
"Show me the last 2 hours of errors in the database service"
→ Runs get-logs.sh database 2
"Deploy version 2.4.1 to staging"
→ Runs deploy.sh api staging
Troubleshooting
MCP Server Not Connecting
Error: "MCP server not found"
Fix:
- Check server is running:
ps aux | grep mcp - Verify connection details in config
- Check firewall rules for network MCP servers
- Review server logs for errors
Claude Queries Are Slow
Issue: Database queries take too long
Fix:
- Add indexes to frequently queried columns
- Reduce query result limits
- Cache frequently requested data
- Use read replicas for heavy queries
Permission Denied Errors
Issue: Claude tries to access data it shouldn't
Fix:
- Check MCP server has correct permissions
- Verify database user has only needed grants
- Review allowed operations in MCP config
- Add explicit deny rules for sensitive tables
Best Practices
1. Start with Read-Only
Let Claude read and analyze before giving write access:
# Phase 1: Read
operations: [read]
# Phase 2: Write (after testing)
operations: [read, write]
2. Set Realistic Limits
Prevent accidental data spills:
limits:
max_rows: 100
max_execution_time: 5 seconds
max_result_size: 1MB
3. Mask Sensitive Data
Hide PII in results:
def format_result(row):
# Mask email addresses
row['email'] = '***@***.com'
# Mask credit card
row['card'] = 'XXXX-XXXX-XXXX-' + row['card'][-4:]
return row
4. Version Your MCP Servers
Track changes like code:
servers:
- name: database
version: 1.2.0
# v1.2.0: Added product_margin column
# v1.1.0: Added time filters
# v1.0.0: Initial release
5. Monitor Usage
Watch for abuse or errors:
# Count queries per minute
grep "QUERY" /var/log/mcp-audit.log | wc -l
# Find slow queries
grep "execution_time.*[5-9][0-9]\|[1-9][0-9]{2}" /var/log/mcp-audit.log
# Find errors
grep "ERROR\|FAILED" /var/log/mcp-audit.log
Checklist
- Understand MCP architecture and flow
- Choose which services to expose (databases, APIs, tools)
- Start with read-only access
- Set up audit logging
- Configure rate limits and timeouts
- Test MCP server connection to Claude
- Grant Claude access incrementally
- Monitor logs for suspicious activity
- Document exposed capabilities
- Review quarterly and remove unused access
Sources:
- Extend Claude with skills - Claude Code Docs
- Model Context Protocol Documentation
- GitHub - anthropics/anthropic-sdk
