From APIs to Agent Tools: Wrapping Enterprise Services with MCP
A clean, practical guide to converting your existing REST, GraphQL, gRPC, and data systems into MCP tools & resources that AI agents can discover, invoke, and govern—without rewriting your backend.
1) Why Wrap APIs as MCP Tools?
Enterprises already have hundreds of APIs. MCP (Model/Modal Context Protocol) lets you expose those capabilities to AI agents through a uniform, schema-driven interface. Instead of brittle prompt-based HTTP calls, agents invoke clearly defined tools (actions) and resources (read-only data) with JSON schemas, while your platform applies the same governance you use for APIs.
- Consistency: One interface for many backends (REST/GraphQL/gRPC/DB).
- Safety: Schema validation, RBAC/ABAC, audit trails.
- Velocity: Runtime discovery; no per-agent glue code.
- Reuse: Generate tools from OpenAPI specs to avoid rework.
2) Architecture: Mapping Providers to Agent-Ready Capabilities
MCP follows a client–server model. Your agent or host app is the MCP client; your wrapper service is the MCP server exposing a catalog of tools/resources.
Agent (MCP Client)
└─> Handshake (discover catalog)
├─ tools: actions (createOrder, refund, schedulePickup)
├─ resources: read contexts (customerProfile, inventoryAt)
└─ prompts: reusable instruction templates (optional)
MCP Server
└─> Calls existing systems: REST / GraphQL / gRPC / DB / SaaS
(auth, retries, mapping, error normalization happen here) Rule of thumb: expose “verbs” as tools (mutations, commands) and “nouns/queries” as resources (read-only, cacheable).
3) Wrapping REST, GraphQL, gRPC, and Datastores
3.1 REST → Tools/Resources
// REST endpoints
GET /v1/customers/{id} → resource: customerProfile(id)
POST /v1/orders → tool: createOrder(customerId, items[])
POST /v1/orders/{id}/refund → tool: refundOrder(orderId, reason)
```
3.2 GraphQL → Tools/Resources
// GraphQL
```
query getCustomer(\$id: ID!) → resource: customerProfile(id)
mutation createOrder(...) → tool: createOrder(...)
```
3.3 gRPC → Tools/Resources
// gRPC
```
rpc CreateShipment(CreateShipmentRequest) returns (Shipment)
→ tool: createShipment(orderId, address, method)
```
3.4 DB/Analytics → Resources
// SQL/warehouse
```
SELECT \* FROM inventory WHERE sku=? AND location=?
→ resource: inventoryAt(sku, location)
4) Designing Tools: Names, Schemas, Idempotency, Errors
Keep tools stable, descriptive, and documented via JSON Schema. Treat them like public functions.
- Naming: lowerCamelCase verbs (e.g.,
createOrder,refundOrder). - Input/Output: precise JSON Schemas; enums for states; types for money/dates.
- Idempotency: support
idempotencyKeyfor safe retries on tools with side effects. - Error envelope: consistent shape for validation/business/system errors.
Tool Definition (Conceptual)
{
"name": "createOrder",
"description": "Create a new order for a customer",
"inputSchema": {
"type": "object",
"properties": {
"customerId": {"type":"string"},
"items": {
"type":"array",
"items":{"type":"object","properties":{"sku":{"type":"string"},"qty":{"type":"integer","minimum":1}},"required":["sku","qty"]}
},
"idempotencyKey": {"type":"string"}
},
"required": ["customerId","items"]
},
"outputSchema": {
"type":"object",
"properties": {
"orderId":{"type":"string"},
"status":{"type":"string","enum":["pending","paid","shipped","canceled"]}
},
"required":["orderId","status"]
}
}
```
Standard Error Model
{
```
"error": {
"code": "TOOL\_VALIDATION\_FAILED",
"message": "Missing item.sku at index 0",
"correlationId": "7e1a-...",
"details": {"field":"items\[0].sku"}
}
}
5) Designing Resources: Read-Only Contexts Done Right
- Stable names: nouns (e.g.,
customerProfile,inventoryAt). - Parameters: minimal, explicit (
id,sku,location). - Pagination & filtering: standard params; include
nextCursor. - Caching: allow server-side caching; include
asOftimestamps.
Resource Definition (Conceptual)
{
"name":"customerProfile",
"params":{"id":"string"},
"schema":{
"type":"object",
"properties":{
"id":{"type":"string"},
"name":{"type":"string"},
"email":{"type":"string"},
"tier":{"type":"string","enum":["gold","silver","bronze"]},
"asOf":{"type":"string","format":"date-time"}
},
"required":["id","name","asOf"]
}
}
6) OpenAPI → MCP: Auto-Generate to Move Fast
Where possible, generate MCP tools/resources from your existing OpenAPI specs. A simple mapping works well:
// Mapping rules (example)
GET /v1/customers/{id} → resource: customerProfile(id)
POST /v1/orders → tool: createOrder(...)
POST /v1/orders/{id}/refund → tool: refundOrder(orderId, reason)
Tips: honor request/response schemas; convert validation rules to JSON Schema; carry over enums & examples; document auth scopes.
7) Security, Privacy & Governance
- AuthN: OAuth2/OIDC for user-initiated flows; mTLS or workload identity for services.
- AuthZ: RBAC for simplicity; ABAC for tenant/context-aware access; scope tools by purpose.
- PII/Secrets: never echo sensitive outputs by default; allow redaction masks in schemas.
- Audit: log caller, tool/resource, input keys (redacted), output type, latency, correlationId.
OPA/Rego Policy (Allow only orders:write)
package mcp.authz
default allow = false
allow {
input.user.scopes[_] == "orders:write"
input.tool.name == "createOrder"
}
8) Versioning & Deprecation: Side-by-Side, No Surprises
- Expose
createOrder_v1andcreateOrder_v2concurrently; document differences. - Mark deprecated tools/resources in the catalog; provide end-of-life dates.
- Offer migration guides; instrument usage to identify lagging consumers.
// Catalog (excerpt)
"tools": [
{"name":"createOrder_v1", "inputSchema":{...}, "outputSchema":{...}, "deprecated":true, "sunset":"2026-06-30"},
{"name":"createOrder_v2", "inputSchema":{...}, "outputSchema":{...}}
]
9) CI/CD for MCP Servers
- Lint: naming, error envelope, enum constraints, pagination standards.
- Contract tests: schema-based validation for inputs/outputs.
- Security scans: dep scanning, secret scanning, IaC checks for deploy configs.
Pipeline (Sketch)
name: mcp-ci
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint MCP catalog
run: npx spectral lint mcp/catalog.json
- name: Contract tests
run: npm run test:contract
- name: Security scan
run: npx trivy fs --exit-code 1 .
10) Gateways, Mesh & Deployment
Run MCP servers behind your existing API gateway or mesh to reuse policies and observability.
# Pseudo gateway policy
route: /mcp/orders
upstream: mcp-orders.svc.cluster.local:8443
policies:
- oauth2-jwt-verify
- rate-limit: 600/min
- schema-validate: ./mcp/orders-tools.json
- waf: owasp-top-10
Mesh tips: enable mTLS, locality-aware routing, retries with budgets, and circuit breaking for downstream APIs.
11) Observability: Logs, Metrics, Traces
- Logs: tool/resource name, version, caller, tenant, status, latency, correlationId.
- Metrics: P50/P95 per tool, error rate, validation failure count, auth failures.
- Tracing: propagate request IDs from agent → MCP server → provider APIs.
INFO mcp.call tool=createOrder_v2 status=200 latencyMs=183 user=svc-web tenant=retail corr=4f2a-...
12) Migration Playbook: Legacy → MCP
- Inventory: list top APIs by usage and business impact.
- Generate: create initial tools/resources from OpenAPI; normalize errors.
- Pilot: wrap one domain (e.g., Orders) and run an internal agent against it.
- Harden: add gateway policies, RBAC, audits; fix gaps found in pilot.
- Scale: roll out to adjacent domains; publish templates and CLI scaffolding.
13) Example Scenarios
13.1 Fulfillment Agent
Agent orchestrates reserveInventory → createShipment → notifyCustomer; errors trigger compensations (releaseInventory, cancelShipment).
13.2 Finance Close Assistant
Resources aggregate ledger snapshots; tools kick off reconciliation tasks; audit logs feed compliance.
13.3 Support Copilot
Resources fetch profile, orders, tickets; tools create cases, issue refunds, schedule callbacks—policy-gated.
14) Final Checklist & 30–60–90 Roadmap
Checklist
- ✅ Clear tool/resource naming, stable schemas, idempotency for writes
- ✅ Error envelope, correlation IDs, and standardized validation
- ✅ Gateway policies (auth, rate limits, schema, WAF) and mesh mTLS
- ✅ OpenAPI → MCP generation; CI lint + contract tests
- ✅ Logs/metrics/traces; team scorecards and SLOs per tool
- ✅ Versioning + deprecation policy with usage telemetry
30–60–90
Days 0–30:
• Pick one domain; generate initial tools/resources from OpenAPI
• Stand up MCP server behind gateway; add logs/metrics/traces
• Run a pilot agent; fix schema/latency/permission gaps
Days 31–60:
• Expand to 3–5 high-value APIs; publish to portal with docs/samples
• Enforce RBAC/ABAC, quotas; add contract tests and error budgets
• Launch CLI scaffolding + templates
Days 61–90:
• Make schema validation and CI checks mandatory for prod
• Introduce version/deprecation policy; start monthly scorecards
• Roll out to two more domains; plan multi-region if needed
15) FAQ
Q: Do I need to rewrite my APIs?
A: No. Wrap them. Start with OpenAPI→MCP generation and normalize errors/schemas.
Q: How do I prevent risky actions?
A: Scope tools, require approvals for sensitive ones, enforce RBAC/ABAC, and log every call.
Q: Is MCP only for agents?
A: It’s ideal for agents, but any app can act as an MCP client to gain the same standardized interface.
Takeaway: You don’t need to rebuild your backend for AI. Wrap what you already have with MCP, enforce standards and policies at the edge, and give agents a clean, universal way to act—safely and at scale.
