Skip to content

MCP (Model Context Protocol)

The Model Context Protocol (MCP) provides a standardized way for AI agents and LLM-powered applications to interact with EvidentSource. MCP tools return responses in TOON (Token-Oriented Object Notation) format, optimized for LLM consumption.

EvidentSource implements MCP using a proxy pattern: MCP tools proxy requests to the REST API and return TOON-formatted responses that are efficient for LLM token consumption.

AI Agent → MCP Server (port 3001) → REST API (Accept: text/plain) → TOON Response
  • Token-efficient responses: TOON format uses natural language summaries with CSV-like tabular data
  • Full API access: All event store operations available through MCP tools
  • Direct REST fallback: Sophisticated agents can bypass MCP using HTTP hints in tool descriptions
  • Authentication forwarding: Auth headers are forwarded to the REST API

The MCP server runs standalone on port 3001 (separate from the REST API on port 3000):

POST http://localhost:3001/

The MCP server uses Streamable HTTP transport with Server-Sent Events (SSE) for responses.

HeaderValueDescription
Content-Typeapplication/jsonRequest body format
Acceptapplication/json, text/event-streamBoth required for SSE
mcp-session-id<session-id>Required after initialization
AuthorizationBearer <token>Optional, forwarded to REST API

MCP requires a specific initialization sequence:

Terminal window
# Step 1: Initialize session
INIT=$(curl -s -i -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {"name": "my-agent", "version": "1.0.0"}
},
"id": 1
}')
# Extract session ID from response headers
SESSION=$(echo "$INIT" | grep -i mcp-session-id | awk '{print $2}' | tr -d '\r')
echo "Session: $SESSION"
# Step 2: Send initialized notification (REQUIRED)
curl -s -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SESSION" \
-d '{"jsonrpc": "2.0", "method": "notifications/initialized"}'
# Step 3: Now you can use tools
timeout 2s curl -s -N -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SESSION" \
-d '{"jsonrpc": "2.0", "method": "tools/list", "params": {}, "id": 2}'

Responses are SSE (Server-Sent Events) format:

data: {"jsonrpc":"2.0","id":2,"result":{...}}
id: 0/0

Use timeout with curl since SSE streams stay open.

List all databases accessible to the authenticated user.

Parameters: None

HTTP Equivalent: GET / with Accept: text/plain

Terminal window
curl -s -N -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SESSION" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {"name": "list_databases", "arguments": {}},
"id": 3
}'

Example Response (TOON format):

You have access to 2 databases.
databases[2]{name,revision,created_at,updated_at}:
orders,1247,2024-01-15T10:30:00Z,2024-01-20T14:22:00Z
inventory,892,2024-01-10T08:00:00Z,2024-01-19T16:45:00Z
To get details for a database: GET /db/{name}/latest
To query events: GET /db/{name}/latest/events?q=...
To create a database: POST /api/v1/db

Get metadata for a specific database including current revision.

Parameters:

NameTypeRequiredDescription
databasestringYesDatabase name

HTTP Equivalent: GET /db/{database}/latest with Accept: text/plain

Terminal window
curl -s -N -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SESSION" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {"name": "get_database", "arguments": {"database": "orders"}},
"id": 3
}'

Example Response (TOON format):

Database "orders" is at revision 1247.
database:
name: orders
revision: 1247
created_at: 2024-01-15T10:30:00Z
updated_at: 2024-01-20T14:22:00Z
To query events: GET /db/orders/latest/events?q=...
To commit events: POST /api/v1/db/orders
To list state views: GET /db/orders/latest/state-views

Query events from a database using bi-temporal selectors.

Parameters:

NameTypeRequiredDescription
databasestringYesDatabase name
revisionintegerNoDatabase revision (default: latest)
selectorobjectNoEvent filter criteria
selector.stream_equalsstringNoFilter by event stream (source)
selector.subject_equalsstringNoFilter by event subject
selector.event_type_equalsstringNoFilter by event type
limitintegerNoMaximum events to return

HTTP Equivalent: GET /db/{database}/{revision}/events?q={base64_query} with Accept: text/plain

Terminal window
curl -s -N -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SESSION" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "query_events",
"arguments": {
"database": "orders",
"selector": {"event_type_equals": "OrderCreated"},
"limit": 10
}
},
"id": 3
}'

Example Response (TOON format):

Found 3 events in database "orders" (revisions 42-44).
events[3]{revision,id,type,source,subject,time}:
42,evt-001,OrderCreated,order-service,order-123,2024-01-15T10:30:00Z
43,evt-002,OrderCreated,order-service,order-124,2024-01-15T11:15:00Z
44,evt-003,OrderCreated,order-service,order-125,2024-01-15T12:00:00Z
event_data[3]{revision,data}:
42,{"orderId":"order-123","total":99.99}
43,{"orderId":"order-124","total":149.99}
44,{"orderId":"order-125","total":79.99}
Database "orders" is currently at revision 1247.
To query events after this: GET /db/orders/latest/events?q=... (with revision_from=45)

Submit a batch of CloudEvents with optional consistency constraints.

Parameters:

NameTypeRequiredDescription
databasestringYesDatabase name
eventsarrayYesCloudEvents to commit
conditionsarrayNoAppend conditions (DCB spec)
transaction_idstringNoUUID for idempotent retries

HTTP Equivalent: POST /api/v1/db/{database} with Accept: text/plain

Terminal window
curl -s -N -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SESSION" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "transact_batch",
"arguments": {
"database": "orders",
"events": [{
"specversion": "1.0",
"type": "OrderCreated",
"source": "order-service",
"id": "evt-new-001",
"subject": "order-999",
"data": {"orderId": "order-999", "total": 199.99}
}]
}
},
"id": 3
}'

Example Response (TOON format):

Batch abc-123-def committed successfully to database "orders".
batch:
id: abc-123-def
database: orders
revision_before: 1247
revision_after: 1248
transaction_time: 2024-01-20T15:30:00Z
event_count: 1
committed_events[1]{index,assigned_id}:
0,evt-new-001
All 1 events committed atomically.
To query these events: GET /db/orders/1248/events
To verify the batch: GET /api/v1/db/orders/batch/abc-123-def

Execute a registered State View query at a specific revision.

Parameters:

NameTypeRequiredDescription
databasestringYesDatabase name
state_viewstringYesState view name
versionintegerYesState view version
revisionintegerNoDatabase revision (default: latest)
effective_time_end_atstringNoISO 8601 timestamp for bi-temporal queries

HTTP Equivalent: GET /db/{database}/{revision}/state-views/{state_view}/v{version} with Accept: text/plain

Terminal window
curl -s -N -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SESSION" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get_state_view",
"arguments": {
"database": "orders",
"state_view": "order-summary",
"version": 1
}
},
"id": 3
}'

TOON (Token-Oriented Object Notation) is a text format designed for LLM consumption:

[Natural language summary]
[TOON-formatted data - key-value pairs or CSV-like tables]
[Contextual guidance for next actions]

Arrays of uniform objects use CSV-like format:

events[3]{revision,id,type,source}:
42,evt-001,OrderCreated,order-service
43,evt-002,ItemAdded,order-service
44,evt-003,OrderSubmitted,order-service

You can request TOON format directly from the REST API:

Terminal window
# List databases in TOON format
curl -H "Accept: text/plain" http://localhost:3000/
# Get database details in TOON format
curl -H "Accept: text/plain" http://localhost:3000/db/orders/latest
# Query events in TOON format
curl -H "Accept: text/plain" http://localhost:3000/db/orders/latest/events

When authentication is enabled, pass the auth header during initialization:

Terminal window
# Initialize with auth header
INIT=$(curl -s -i -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {"name": "my-agent", "version": "1.0.0"}
},
"id": 1
}')

The MCP server extracts the Authorization header and forwards it to the REST API for each tool call.

Each tool includes MCP standard annotations:

ToolreadOnlyHintidempotentHintDescription
list_databasestrue-Read-only operation
get_databasetrue-Read-only operation
query_eventstrue-Read-only operation
transact_batchfalsetrueWrite operation, idempotent with transaction_id
get_state_viewtrue-Read-only operation

Sophisticated agents can bypass MCP and call the REST API directly. Each tool description includes HTTP hints:

HTTP: GET /db/{database}/latest with Accept: text/plain

Use Accept: text/plain for TOON format or Accept: application/json for JSON format.

Errors are returned as MCP error responses:

{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32603,
"message": "Request failed with status 404: Database not found"
}
}

”Failed to create service: expect initialized notification”

Section titled “”Failed to create service: expect initialized notification””

You must send notifications/initialized after the initialize request:

Terminal window
curl -s -X POST http://localhost:3001/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: $SESSION" \
-d '{"jsonrpc": "2.0", "method": "notifications/initialized"}'

MCP uses SSE (Server-Sent Events) which keeps connections open. Use timeout with curl:

Terminal window
timeout 2s curl -s -N -X POST http://localhost:3001/ ...

Both application/json and text/event-stream are required:

Terminal window
-H "Accept: application/json, text/event-stream"