Expert guidance for building production MCP servers using MXCP (Model Context Protocol eXtension Platform), an enterprise framework with SQL and Python endpoints, security, testing, and deployment. Use when: (1) Creating or initializing MXCP projects or MCP servers, (2) Building MCP tools, resources, or prompts, (3) Configuring endpoints, authentication, or policies, (4) Testing, validating, or debugging MXCP applications, or any task involving MXCP or MCP server development.
This skill inherits all available tools. When active, it can use any tool Claude has access to.
MXCP (Model Context Protocol eXtension Platform) is an enterprise-grade framework for building production-ready AI tools with SQL and Python.
New to MXCP?
Building Endpoints:
YAML Schema Reference:
Quality & Testing:
Security:
Operations:
Reference:
Integrations:
Examples:
This skill prioritizes:
uv venv and activate before running mxcpmxcp validate after every change, fix errors immediatelymxcp test before proceedingmxcp lint to improve LLM understanding of toolsEnvironment setup (required before any mxcp command):
uv venv && source .venv/bin/activate
uv pip install mxcp
Follow this workflow for every MXCP project:
mxcp validate → Fix any errorsmxcp validate → Fix any errorsmxcp test → All tests must passmxcp lint → Address warningsmxcp run tool NAME → Confirm expected outputWhen using dbt, also run:
mxcp dbt test → Verify data quality (not_null, unique, relationships)models/schema.yml for all modelsDefinition of Done: A project is complete ONLY when:
mxcp validate passes with no errorsmxcp test passes with all tests greenmxcp dbt test passes (if using dbt)mxcp lint shows no critical issuesNever skip validation or testing steps.
MXCP endpoint tests must verify:
dbt data tests must verify:
not_nulluniquerelationshipsaccepted_values)Example dbt schema tests:
# models/schema.yml
models:
- name: customers
columns:
- name: id
tests: [not_null, unique]
- name: email
tests: [not_null, unique]
- name: status
tests:
- accepted_values:
values: ['active', 'inactive', 'pending']
Example MXCP endpoint tests with edge cases:
tests:
- name: valid_user
arguments: [{key: user_id, value: 1}]
result_contains: {id: 1}
- name: user_not_found
arguments: [{key: user_id, value: 99999}]
result: null
- name: handles_zero
arguments: [{key: user_id, value: 0}]
result: null
MXCP automatically creates and manages a DuckDB database. Do not configure a custom database path unless the user explicitly asks for it.
When you run mxcp init, MXCP creates:
data/db-default.duckdb (or data/db-{profile}.duckdb)Use the default (no database configuration needed):
# mxcp-site.yml - Minimal config
mxcp: 1
project: my-project
profile: default
# Database is automatically created at data/db-default.duckdb
Only configure duckdb.path if the user explicitly requests it (e.g., shared database, specific location, read-only mode). Do not proactively add database configuration.
For Excel files and external data, use dbt Python models instead of converting to CSV seeds.
WRONG approach:
# Don't do this workflow:
python convert_excel_to_csv.py # Convert Excel to CSV
# Then seed via dbt
mxcp dbt seed
CORRECT approach - Use dbt Python model:
# models/load_excel.py
import pandas as pd
def model(dbt, session):
df = pd.read_excel('data/sales.xlsx')
df = df.dropna(how='all')
df.columns = df.columns.str.lower().str.replace(' ', '_')
return df
Then run: mxcp dbt run --select load_excel
Why Python models are better:
When CSV seeds ARE appropriate:
Read this before creating any tools. These mistakes cause validation errors:
tool: Wrapper# WRONG
mxcp: 1
name: get_calendar
description: ...
# CORRECT
mxcp: 1
tool:
name: get_calendar
description: ...
# WRONG - causes validation error
parameters:
- name: user_id
type: string
# CORRECT
parameters:
- name: user_id
type: string
description: The unique user identifier
Valid types: string, number, integer, boolean, array, object
# WRONG
type: map # Use 'object'
type: strng # Typo
type: int # Use 'integer'
# CORRECT
type: object
type: string
type: integer
Parameter names must match ^[a-zA-Z_][a-zA-Z0-9_]*$
# WRONG
name: user-name # Hyphens not allowed
name: 1st_param # Can't start with number
# CORRECT
name: user_name
name: first_param
Valid formats: email, uri, date, time, date-time, duration, timestamp
# WRONG
format: datetime # Missing hyphen
# CORRECT
format: date-time
code and file in SourceSource must have exactly one of code or file:
# WRONG
source:
code: "SELECT 1"
file: "query.sql" # Can't have both
# CORRECT
source:
code: "SELECT 1"
# OR
source:
file: ../sql/query.sql
mkdir my-mxcp-project && cd my-mxcp-project
uv venv && source .venv/bin/activate
uv pip install mxcp
mxcp init --bootstrap
tools/my_tool.yml:mxcp: 1
tool:
name: my_tool
description: What this tool does
parameters:
- name: param_name
type: string
description: Parameter description
return:
type: object
properties:
result:
type: string
source:
file: ../sql/my_tool.sql
sql/my_tool.sql:SELECT $param_name as result
mxcp validate
Always validate after each change:
# 1. Create tool YAML
mxcp validate # Fix errors now
# 2. Create implementation
mxcp validate # Validate again
# 3. Add tests
mxcp test # Run tests
# 4. Check metadata quality
mxcp lint
# Run a tool manually
mxcp run tool my_tool --param param_name=value
# Run all tests
mxcp test
# Start the server
mxcp serve
mxcp-project/
├── mxcp-site.yml # Project configuration (required)
├── tools/ # Tool definitions (.yml)
├── resources/ # Resource definitions (.yml)
├── prompts/ # Prompt definitions (.yml)
├── sql/ # SQL implementations
├── python/ # Python implementations
├── evals/ # LLM evaluation tests
└── data/ # Database files (db-default.duckdb)
Directory rules:
tools/*.ymlresources/*.ymlprompts/*.ymlsql/, referenced via relative pathspython/, referenced via relative pathsUse SQL for:
Use Python for:
mxcp: 1
tool:
name: get_user
description: Get user by ID
parameters:
- name: user_id
type: integer
description: User ID
return:
type: object
source:
code: |
SELECT id, name, email
FROM users
WHERE id = $user_id
mxcp: 1
tool:
name: analyze_data
description: Analyze data with Python
language: python
parameters:
- name: dataset
type: string
description: Dataset name
return:
type: object
source:
file: ../python/analysis.py
# python/analysis.py
from mxcp.runtime import db
def analyze_data(dataset: str) -> dict:
# Use validated table names or query specific tables
allowed_tables = {"users", "orders", "products"}
if dataset not in allowed_tables:
return {"error": f"Unknown dataset: {dataset}"}
# Table names can't be parameterized - use validated string
results = db.execute(f"SELECT * FROM {dataset}")
return {"count": len(results), "data": results}
CRITICAL: Use MXCP built-in security features. NEVER write custom Python authentication code.
MXCP has built-in OAuth 2.0 support. Configure in ~/.mxcp/config.yml, NOT in Python:
# ~/.mxcp/config.yml - CORRECT way to add authentication
mxcp: 1
projects:
my-project:
profiles:
default:
auth:
provider: github # or: google, atlassian, salesforce, keycloak
github:
client_id: "${GITHUB_CLIENT_ID}"
client_secret: "${GITHUB_CLIENT_SECRET}"
callback_path: /callback
auth_url: https://github.com/login/oauth/authorize
token_url: https://github.com/login/oauth/access_token
scope: "read:user user:email"
Supported providers: GitHub, Google, Atlassian (Jira/Confluence), Salesforce, Keycloak
Use CEL policies in YAML, NOT Python if/else checks:
# In tool definition - CORRECT way to control access
policies:
input:
- condition: "!user.email.endsWith('@company.com')"
action: deny
reason: "Company email required"
- condition: "user.role != 'admin'"
action: deny
reason: "Admin role required"
Access user info in SQL, NOT by passing tokens manually:
-- Built-in functions for user context
SELECT get_username() as username;
SELECT get_user_email() as email;
SELECT get_user_provider() as provider;
SELECT get_user_external_token() as oauth_token;
Call external APIs using the user's OAuth token in SQL:
-- CORRECT: Use built-in token function for authenticated API calls
SELECT * FROM read_json_auto(
'https://api.github.com/user/repos',
headers = MAP {
'Authorization': 'Bearer ' || get_user_external_token(),
'User-Agent': 'MXCP'
}
);
# Project
mxcp init --bootstrap # Create new project
mxcp list # List all endpoints
# Quality
mxcp validate # Check structure
mxcp test # Run tests
mxcp lint # Check metadata
mxcp evals # AI behavior tests
# Running
mxcp serve # Start MCP server
mxcp run tool NAME --param k=v # Run tool manually
# Database
mxcp query "SELECT 1" # Execute SQL
# Operations
mxcp drift-snapshot # Create baseline
mxcp drift-check # Detect changes
mxcp log --since 1h # Query audit logs
mxcp validate --debug # Detailed validation errors
mxcp run tool NAME --debug # Debug tool execution
mxcp list # See available endpoints
Common issues: YAML syntax, missing required fields, invalid types, file paths.
Complete runnable examples in assets/project-templates/. Start with:
python-demo - Python endpoint patternscovid_owid - Data workflow with dbtcp -r assets/project-templates/python-demo my-project
cd my-project
mxcp validate && mxcp test
See Configuration for mxcp-site.yml and config.yml options.