Mcp
Implements the Model Context Protocol over JSON-RPC 2.0. All operations go through a single POST /mcp endpoint, differentiated by the request body.
- Spec: modelcontextprotocol.io
- MIME:
application/json - Serializer:
McpSerializer - Routing: Body-matched (single endpoint)
import crate.protocols.mcp.policy;
auto crateRouter = router.crateSetup!Mcp;crateRouter.add(userCrate);Generated Tools
Section titled “Generated Tools”All operations use POST /mcp with a JSON-RPC body. The params.name field determines the operation:
| Tool Name | Operation |
|---|---|
list_users | List all |
get_user | Get one |
create_user | Create |
replace_user | Replace |
update_user | Update fields |
delete_user | Delete |
Request Format
Section titled “Request Format”{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "get_user", "arguments": { "id": "abc123" } }, "id": 1}Base Operations
Section titled “Base Operations”MCP registers additional protocol-level operations via onRouterInit:
| Endpoint | Body Match | Purpose |
|---|---|---|
POST /mcp | method: "initialize" | Protocol handshake |
POST /mcp | method: "tools/list" | List available tools |
POST /mcp | method: "notifications/initialized" | Client notification (202 response) |
POST /mcp | method: "ping" | Ping/pong health check |
POST /mcp | name: "get_upload_instructions" | File upload endpoint discovery |
POST /mcp | name: "get_list_query_options" | Query parameter discovery |
GET /mcp/sse | — | Server-Sent Events stream |
GET /.well-known/oauth-protected-resource | — | OAuth 2.1 metadata |
GET /.well-known/oauth-protected-resource/mcp | — | 301 redirect to MCP endpoint |
The tools list is populated lazily via onRouterReady after all models are registered.
Discovery Tools
Section titled “Discovery Tools”MCP provides two discovery tools that help AI clients understand what operations are available and how to use them.
get_upload_instructions
Section titled “get_upload_instructions”Returns REST API upload instructions for a resource field, so AI clients can upload files directly via HTTP instead of passing base64 through tool arguments.
Request:
{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "get_upload_instructions", "arguments": { "model": "picture", "id": "abc123", "field": "picture" } }, "id": 1}Parameters:
| Name | Required | Description |
|---|---|---|
model | yes | Model name (singular, lowercase) |
id | yes | Resource ID to upload to |
field | yes | Field name (e.g. "picture", "image/value") |
Response (upload available):
{ "jsonrpc": "2.0", "id": 1, "result": { "content": [{ "type": "text", "text": "{\"url\":\"http://localhost/pictures/abc123/picture\",\"method\":\"POST\",\"contentType\":\"multipart/form-data\",\"example\":\"curl -X POST 'http://localhost/pictures/abc123/picture' -H 'Authorization: Bearer {token}' -F 'file=@/path/to/file'\"}" }] }}Response (no upload endpoint):
If no REST upload endpoint exists for the given model/field, the response suggests using the base64 tool instead:
{ "jsonrpc": "2.0", "id": 1, "result": { "content": [{ "type": "text", "text": "No REST upload endpoint available for picture/avatar. Use the `set_picture_avatar_value` tool with base64-encoded data instead." }] }}get_list_query_options
Section titled “get_list_query_options”Returns the available query/filter parameters for a model’s list endpoint, so AI clients can discover filtering, pagination, and search options.
Request:
{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "get_list_query_options", "arguments": { "model": "team" } }, "id": 2}Parameters:
| Name | Required | Description |
|---|---|---|
model | yes | Model name (singular, lowercase) |
Response:
Returns a JSON Schema object describing the available query parameters:
{ "jsonrpc": "2.0", "id": 2, "result": { "content": [{ "type": "text", "text": "{\"type\":\"object\",\"properties\":{\"limit\":{\"type\":\"string\",\"description\":\"Max items to return\",\"in\":\"query\"},\"skip\":{\"type\":\"string\",\"description\":\"Items to skip\",\"in\":\"query\"}}}" }] }}The tool description in tools/list is automatically updated with the list of available models.
Notifications
Section titled “Notifications”MCP supports client-initiated notifications and ping requests.
notifications/initialized
Section titled “notifications/initialized”Sent by the client after the initialize handshake completes. This is a fire-and-forget message that returns 202 Accepted with no body.
{ "jsonrpc": "2.0", "method": "notifications/initialized"}Response: 202 Accepted (empty body)
Standard MCP ping request. Returns a JSON-RPC pong response.
{ "jsonrpc": "2.0", "method": "ping", "id": 3}Response:
{ "jsonrpc": "2.0", "id": 3, "result": {}}Request Processing
Section titled “Request Processing”MCP uses two internal middleware layers to bridge JSON-RPC requests into the same format that REST operations expect. This makes all downstream middleware and operations protocol-agnostic.
Context Marker
Section titled “Context Marker”The McpContextMarker middleware runs on every request (@any). It detects MCP requests by checking for the jsonrpc field in the request body and sets two context flags:
_isMcpRequest—truefor all MCP requests_mcpMethod— the JSON-RPC method string (e.g."tools/call","tools/list")
Other middleware can check req.context["_isMcpRequest"] to branch on protocol.
Request Normalization
Section titled “Request Normalization”The McpRequestNormalizer middleware transforms JSON-RPC tool calls into REST-compatible format:
- Extracts the RPC ID and stores it in
req.params["_rpcId"] - Extracts tool arguments from
params.arguments - Unwraps the
datafield for_recordtools (e.g.create_record) - Moves the item
idfrom arguments toreq.params["id"] - Forwards non-reserved arguments to
req.queryas filter/pagination params - Stores base64 data in
req.params["_base64Data"]if present - Rewrites the request body to model-specific format (e.g.
{ "icon": {...} })
Reserved keys (not forwarded to query): id, model, data, fullJsonExport
Response Formatting
Section titled “Response Formatting”MCP responses are wrapped in the JSON-RPC tool result envelope. The serializer supports two output modes controlled by summary fields and the fullJsonExport argument.
Summary Mode (default)
Section titled “Summary Mode (default)”When a model has fields marked @isId or @isSummary, read responses return a compact key-value text format:
_id: 000000000000000000000001name: My Team---_id: 000000000000000000000002name: Other TeamThis reduces token usage for AI clients that only need an overview.
Full JSON Mode
Section titled “Full JSON Mode”Pass fullJsonExport: true in the tool arguments to get the complete JSON representation:
{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "get_user", "arguments": { "id": "abc123", "fullJsonExport": true } }, "id": 1}If no summary fields are defined on the model, full JSON is always returned regardless of this flag.
Mutating Operations
Section titled “Mutating Operations”Create, update, replace, and delete operations return a success confirmation instead of the full item:
{ "jsonrpc": "2.0", "id": 1, "result": { "content": [{ "type": "text", "text": "create_user succeeded. id: 000000000000000000000001" }] }}Response Mappers
Section titled “Response Mappers”Context mappers registered on operations are applied to response data before serialization. This works for both toResponseItem and toResponseList, allowing field transformation, enrichment, or filtering at the protocol level.
Not Yet Supported
Section titled “Not Yet Supported”- Resources: Only tools are exposed; no MCP resource endpoints
- Prompts: No prompt support
- Sampling: No sampling / LLM model endpoints
- Progress tracking: No progress reporting mechanism
- Logging: No structured logging API
- Cancellation: No request cancellation
Custom Base URL
Section titled “Custom Base URL”auto crateRouter = router.crateSetup!(McpPolicy!(PolicyConfig("/tools")));// Endpoint at POST /tools/mcpOAuth Protected Resource Discovery
Section titled “OAuth Protected Resource Discovery”The standard /.well-known/oauth-protected-resource endpoint returns OAuth 2.1 metadata. Additionally, /.well-known/oauth-protected-resource/mcp issues a 301 redirect to the MCP endpoint (respecting any configured base URL prefix).