name: mcp-enterprise-patterns
description: Patterns for building and consuming enterprise MCP (Model Context Protocol) servers. Use when wrapping enterprise APIs (Salesforce, ServiceNow, SAP, Oracle) as MCP servers, or consuming MCP servers from Claude, OpenAI, or Gemini agents.
tags: [mcp, enterprise, integration, agents]
MCP Enterprise Integration Patterns
Patterns for building MCP servers that wrap enterprise APIs, and for consuming MCP servers across different AI agent frameworks (Claude, OpenAI Agents SDK, Google ADK).
When to Use
- Wrapping an enterprise REST API (Salesforce, ServiceNow, SAP OData) as an MCP server
- Connecting MCP servers to Claude Desktop, Claude Code, OpenAI Agents SDK, or Google ADK
- Building multi-tenant MCP servers with authentication and audit logging
- Designing MCP tool schemas for complex enterprise workflows
MCP Ecosystem Adoption
| Platform |
MCP Support |
Implementation |
| Claude Desktop / Code |
Native (creator) |
MCP client in stdio + SSE + Streamable HTTP |
| OpenAI Agents SDK |
Native |
MCPServerStdio, MCPServerSse, HostedMCPTool |
| Google ADK |
Native |
MCPToolset with StdioServerParameters |
| AWS (awslabs/mcp) |
15+ servers |
S3, Lambda, DynamoDB, Bedrock, CloudWatch |
| Snowflake |
Official server |
Schema, SQL, Cortex integration |
| Salesforce |
Official server |
SOQL, CRUD, Metadata, Agentforce |
Patterns
1. Build an Enterprise MCP Server (Python/FastMCP)
from mcp.server.fastmcp import FastMCP
import httpx
mcp = FastMCP("Enterprise CRM Server")
# Configuration via environment
import os
CRM_BASE_URL = os.environ["CRM_BASE_URL"]
CRM_API_KEY = os.environ["CRM_API_KEY"]
@mcp.tool()
async def search_customers(query: str, limit: int = 10) -> list[dict]:
"""Search customers by name or email.
Args:
query: Search term (name, email, or phone)
limit: Maximum results to return (default: 10)
"""
async with httpx.AsyncClient() as client:
response = await client.get(
f"{CRM_BASE_URL}/api/customers/search",
params={"q": query, "limit": limit},
headers={"Authorization": f"Bearer {CRM_API_KEY}"},
)
response.raise_for_status()
return response.json()["results"]
@mcp.tool()
async def create_ticket(
customer_id: str,
subject: str,
description: str,
priority: str = "medium",
) -> dict:
"""Create a support ticket for a customer.
Args:
customer_id: The customer's unique ID
subject: Brief ticket subject (max 200 chars)
description: Detailed description of the issue
priority: Ticket priority: low, medium, high, critical
"""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{CRM_BASE_URL}/api/tickets",
json={
"customer_id": customer_id,
"subject": subject,
"description": description,
"priority": priority,
},
headers={"Authorization": f"Bearer {CRM_API_KEY}"},
)
response.raise_for_status()
return response.json()
@mcp.resource("crm://schema")
async def get_schema() -> str:
"""Return the CRM data model schema for agent context."""
return """
Customer: id, name, email, phone, company, created_at
Ticket: id, customer_id, subject, description, priority, status, created_at
Order: id, customer_id, items[], total, status, created_at
"""
2. Consume MCP from Claude Code
// .mcp.json (project-level MCP config)
{
"mcpServers": {
"enterprise-crm": {
"command": "python",
"args": ["-m", "crm_mcp_server"],
"env": {
"CRM_BASE_URL": "https://crm.example.com",
"CRM_API_KEY": "${CRM_API_KEY}"
}
},
"servicenow": {
"command": "npx",
"args": ["-y", "@community/mcp-server-servicenow"],
"env": {
"SERVICENOW_INSTANCE": "mycompany",
"SERVICENOW_USER": "${SN_USER}",
"SERVICENOW_PASSWORD": "${SN_PASSWORD}"
}
}
}
}
3. Consume MCP from OpenAI Agents SDK
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
# Connect to enterprise MCP server
crm_server = MCPServerStdio(
command="python",
args=["-m", "crm_mcp_server"],
env={"CRM_BASE_URL": "https://crm.example.com", "CRM_API_KEY": "..."},
)
agent = Agent(
name="Customer Service Agent",
instructions="Help customers by looking up their info and creating tickets when needed.",
mcp_servers=[crm_server],
)
async def main():
async with crm_server:
result = await Runner.run(agent, "Find customer John Smith and check his open tickets")
print(result.final_output)
4. Consume MCP from Google ADK
from google.adk.agents import Agent
from google.adk.tools.mcp_tool import MCPToolset, StdioServerParameters
crm_mcp = MCPToolset(
connection_params=StdioServerParameters(
command="python",
args=["-m", "crm_mcp_server"],
env={"CRM_BASE_URL": "https://crm.example.com"},
)
)
agent = Agent(
model="gemini-2.0-flash",
name="customer_service",
instruction="Help customers using CRM tools.",
tools=[crm_mcp],
)
5. Multi-Tenant MCP Server Pattern
from mcp.server.fastmcp import FastMCP
from contextvars import ContextVar
mcp = FastMCP("Multi-Tenant Enterprise Server")
# Tenant context (set per-session)
current_tenant = ContextVar("current_tenant", default=None)
@mcp.tool()
async def query_data(table: str, filters: dict | None = None) -> list[dict]:
"""Query data scoped to the current tenant.
Args:
table: Table name (customers, orders, tickets)
filters: Optional key-value filters
"""
tenant_id = current_tenant.get()
if not tenant_id:
return {"error": "No tenant context. Authenticate first."}
# All queries automatically scoped to tenant
query = f"SELECT * FROM {table} WHERE tenant_id = :tenant_id"
# ... execute with tenant isolation
6. Enterprise MCP Server Checklist
## Production Readiness Checklist
### Security
- [ ] Authentication required (API key, OAuth, mTLS)
- [ ] Multi-tenant data isolation (tenant_id in all queries)
- [ ] PII handling documented (what data flows through)
- [ ] Secrets via environment variables (never hardcoded)
- [ ] Rate limiting implemented
### Observability
- [ ] Structured logging (JSON, with correlation IDs)
- [ ] Metrics exposed (tool call count, latency, errors)
- [ ] Audit trail for all write operations
- [ ] Error messages are actionable (guide agent to fix)
### Reliability
- [ ] Timeout handling for upstream API calls
- [ ] Retry logic with exponential backoff
- [ ] Circuit breaker for upstream failures
- [ ] Graceful degradation (read-only mode if writes fail)
### Documentation
- [ ] Tool descriptions are clear and specific
- [ ] Parameter descriptions include constraints and examples
- [ ] Resource URIs follow consistent naming scheme
- [ ] README with setup and authentication instructions
Anti-Patterns
- Building one mega MCP server for all enterprise systems -- split by domain (CRM, ITSM, ERP)
- Exposing raw database queries as tools -- always add business logic and validation
- Skipping authentication -- enterprise MCP servers MUST authenticate
- Returning raw API responses -- transform to agent-friendly format (relevant fields only)
- Missing error handling -- agents need structured error messages to recover
Key MCP Server Registries
| Registry |
URL |
Description |
| Official |
github.com/modelcontextprotocol/servers |
Anthropic reference + community index |
| AWS |
github.com/awslabs/mcp |
15+ AWS service servers |
| Smithery |
smithery.ai |
2,000+ community servers, searchable |
| mcp.so |
mcp.so |
Another curated directory |
References
1---2name: mcp-enterprise-patterns3description: <!-- AUTO-GENERATED by export-skills.py — DO NOT EDIT -->4---5<!-- AUTO-GENERATED by export-skills.py — DO NOT EDIT -->6---7name: mcp-enterprise-patterns8description: Patterns for building and consuming enterprise MCP (Model Context Protocol) servers. Use when wrapping enterprise APIs (Salesforce, ServiceNow, SAP, Oracle) as MCP servers, or consuming MCP servers from Claude, OpenAI, or Gemini agents.9tags: [mcp, enterprise, integration, agents]10---1112# MCP Enterprise Integration Patterns1314Patterns for building MCP servers that wrap enterprise APIs, and for consuming MCP servers across different AI agent frameworks (Claude, OpenAI Agents SDK, Google ADK).1516## When to Use1718- Wrapping an enterprise REST API (Salesforce, ServiceNow, SAP OData) as an MCP server19- Connecting MCP servers to Claude Desktop, Claude Code, OpenAI Agents SDK, or Google ADK20- Building multi-tenant MCP servers with authentication and audit logging21- Designing MCP tool schemas for complex enterprise workflows2223## MCP Ecosystem Adoption2425| Platform | MCP Support | Implementation |26|---|---|---|27| Claude Desktop / Code | Native (creator) | MCP client in stdio + SSE + Streamable HTTP |28| OpenAI Agents SDK | Native | MCPServerStdio, MCPServerSse, HostedMCPTool |29| Google ADK | Native | MCPToolset with StdioServerParameters |30| AWS (awslabs/mcp) | 15+ servers | S3, Lambda, DynamoDB, Bedrock, CloudWatch |31| Snowflake | Official server | Schema, SQL, Cortex integration |32| Salesforce | Official server | SOQL, CRUD, Metadata, Agentforce |3334## Patterns3536### 1. Build an Enterprise MCP Server (Python/FastMCP)3738```python39from mcp.server.fastmcp import FastMCP40import httpx4142mcp = FastMCP("Enterprise CRM Server")4344# Configuration via environment45import os46CRM_BASE_URL = os.environ["CRM_BASE_URL"]47CRM_API_KEY = os.environ["CRM_API_KEY"]4849@mcp.tool()50async def search_customers(query: str, limit: int = 10) -> list[dict]:51 """Search customers by name or email.5253 Args:54 query: Search term (name, email, or phone)55 limit: Maximum results to return (default: 10)56 """57 async with httpx.AsyncClient() as client:58 response = await client.get(59 f"{CRM_BASE_URL}/api/customers/search",60 params={"q": query, "limit": limit},61 headers={"Authorization": f"Bearer {CRM_API_KEY}"},62 )63 response.raise_for_status()64 return response.json()["results"]656667@mcp.tool()68async def create_ticket(69 customer_id: str,70 subject: str,71 description: str,72 priority: str = "medium",73) -> dict:74 """Create a support ticket for a customer.7576 Args:77 customer_id: The customer's unique ID78 subject: Brief ticket subject (max 200 chars)79 description: Detailed description of the issue80 priority: Ticket priority: low, medium, high, critical81 """82 async with httpx.AsyncClient() as client:83 response = await client.post(84 f"{CRM_BASE_URL}/api/tickets",85 json={86 "customer_id": customer_id,87 "subject": subject,88 "description": description,89 "priority": priority,90 },91 headers={"Authorization": f"Bearer {CRM_API_KEY}"},92 )93 response.raise_for_status()94 return response.json()959697@mcp.resource("crm://schema")98async def get_schema() -> str:99 """Return the CRM data model schema for agent context."""100 return """101 Customer: id, name, email, phone, company, created_at102 Ticket: id, customer_id, subject, description, priority, status, created_at103 Order: id, customer_id, items[], total, status, created_at104 """105```106107### 2. Consume MCP from Claude Code108109```json110// .mcp.json (project-level MCP config)111{112 "mcpServers": {113 "enterprise-crm": {114 "command": "python",115 "args": ["-m", "crm_mcp_server"],116 "env": {117 "CRM_BASE_URL": "https://crm.example.com",118 "CRM_API_KEY": "${CRM_API_KEY}"119 }120 },121 "servicenow": {122 "command": "npx",123 "args": ["-y", "@community/mcp-server-servicenow"],124 "env": {125 "SERVICENOW_INSTANCE": "mycompany",126 "SERVICENOW_USER": "${SN_USER}",127 "SERVICENOW_PASSWORD": "${SN_PASSWORD}"128 }129 }130 }131}132```133134### 3. Consume MCP from OpenAI Agents SDK135136```python137from agents import Agent, Runner138from agents.mcp import MCPServerStdio139140# Connect to enterprise MCP server141crm_server = MCPServerStdio(142 command="python",143 args=["-m", "crm_mcp_server"],144 env={"CRM_BASE_URL": "https://crm.example.com", "CRM_API_KEY": "..."},145)146147agent = Agent(148 name="Customer Service Agent",149 instructions="Help customers by looking up their info and creating tickets when needed.",150 mcp_servers=[crm_server],151)152153async def main():154 async with crm_server:155 result = await Runner.run(agent, "Find customer John Smith and check his open tickets")156 print(result.final_output)157```158159### 4. Consume MCP from Google ADK160161```python162from google.adk.agents import Agent163from google.adk.tools.mcp_tool import MCPToolset, StdioServerParameters164165crm_mcp = MCPToolset(166 connection_params=StdioServerParameters(167 command="python",168 args=["-m", "crm_mcp_server"],169 env={"CRM_BASE_URL": "https://crm.example.com"},170 )171)172173agent = Agent(174 model="gemini-2.0-flash",175 name="customer_service",176 instruction="Help customers using CRM tools.",177 tools=[crm_mcp],178)179```180181### 5. Multi-Tenant MCP Server Pattern182183```python184from mcp.server.fastmcp import FastMCP185from contextvars import ContextVar186187mcp = FastMCP("Multi-Tenant Enterprise Server")188189# Tenant context (set per-session)190current_tenant = ContextVar("current_tenant", default=None)191192@mcp.tool()193async def query_data(table: str, filters: dict | None = None) -> list[dict]:194 """Query data scoped to the current tenant.195196 Args:197 table: Table name (customers, orders, tickets)198 filters: Optional key-value filters199 """200 tenant_id = current_tenant.get()201 if not tenant_id:202 return {"error": "No tenant context. Authenticate first."}203204 # All queries automatically scoped to tenant205 query = f"SELECT * FROM {table} WHERE tenant_id = :tenant_id"206 # ... execute with tenant isolation207```208209### 6. Enterprise MCP Server Checklist210211```markdown212## Production Readiness Checklist213214### Security215- [ ] Authentication required (API key, OAuth, mTLS)216- [ ] Multi-tenant data isolation (tenant_id in all queries)217- [ ] PII handling documented (what data flows through)218- [ ] Secrets via environment variables (never hardcoded)219- [ ] Rate limiting implemented220221### Observability222- [ ] Structured logging (JSON, with correlation IDs)223- [ ] Metrics exposed (tool call count, latency, errors)224- [ ] Audit trail for all write operations225- [ ] Error messages are actionable (guide agent to fix)226227### Reliability228- [ ] Timeout handling for upstream API calls229- [ ] Retry logic with exponential backoff230- [ ] Circuit breaker for upstream failures231- [ ] Graceful degradation (read-only mode if writes fail)232233### Documentation234- [ ] Tool descriptions are clear and specific235- [ ] Parameter descriptions include constraints and examples236- [ ] Resource URIs follow consistent naming scheme237- [ ] README with setup and authentication instructions238```239240## Anti-Patterns241242- Building one mega MCP server for all enterprise systems -- split by domain (CRM, ITSM, ERP)243- Exposing raw database queries as tools -- always add business logic and validation244- Skipping authentication -- enterprise MCP servers MUST authenticate245- Returning raw API responses -- transform to agent-friendly format (relevant fields only)246- Missing error handling -- agents need structured error messages to recover247248## Key MCP Server Registries249250| Registry | URL | Description |251|---|---|---|252| Official | github.com/modelcontextprotocol/servers | Anthropic reference + community index |253| AWS | github.com/awslabs/mcp | 15+ AWS service servers |254| Smithery | smithery.ai | 2,000+ community servers, searchable |255| mcp.so | mcp.so | Another curated directory |256257## References258259- [MCP Specification](https://spec.modelcontextprotocol.io)260- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)261- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)262- [Official MCP Servers](https://github.com/modelcontextprotocol/servers)263- [AWS MCP Servers](https://github.com/awslabs/mcp)264- [OpenAI Agents SDK MCP](https://github.com/openai/openai-agents-python)265- [Google ADK MCP](https://google.github.io/adk-docs/)266267<!-- Source: .faos/custom/skills/tools/mcp-enterprise-patterns/SKILL.md -->