MCP Protocol Reference
This page documents the wire-level protocol that flAPI's MCP server speaks. If you are wiring a client by hand—or debugging an existing one—this is the canonical reference.
For higher-level concepts (why MCP, how YAML maps to tools) see the MCP Overview.
Transport
flAPI exposes MCP as JSON-RPC 2.0 over HTTP on a single route:
| Method | Path | Purpose |
|---|---|---|
POST | /mcp/jsonrpc | Send any MCP request (initialize, tools, resources, prompts...) |
DELETE | /mcp/jsonrpc | Close an MCP session (requires Mcp-Session-Id header) |
GET | /mcp/health | Plain HTTP liveness probe (not part of MCP) |
The transport is shared with the REST API on the same port — there is no separate MCP port.
JSON-RPC 2.0 Envelope
Every request and response uses the standard JSON-RPC 2.0 envelope:
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
| Field | Type | Required | Notes |
|---|---|---|---|
jsonrpc | string | yes | Must be "2.0" |
id | string or number | yes | Echoed back in the response. Use null only for notifications. |
method | string | yes | One of the methods in the table below |
params | object | no | Method-specific parameters; defaults to {} |
Success response:
{
"jsonrpc": "2.0",
"id": 1,
"result": { "...": "..." }
}
Error response:
{
"jsonrpc": "2.0",
"id": 1,
"error": { "code": -32601, "message": "Method not found" }
}
Session Header
flAPI tracks state per MCP session. Sessions are created on the first initialize request and identified by the Mcp-Session-Id HTTP header.
| Direction | Header | Behaviour |
|---|---|---|
| Response → Client | Mcp-Session-Id | Server returns the new (or existing) session id on every response |
| Client → Server | Mcp-Session-Id | Echo the value back on subsequent requests to stay in the same session |
Sending no header on the first initialize is normal; the server creates a fresh session. To close a session explicitly, send DELETE /mcp/jsonrpc with the header set.
Methods
flAPI implements the following MCP methods. Method names are case-sensitive.
| Method | Purpose | Auth-able |
|---|---|---|
initialize | Handshake, protocol negotiation, capability exchange | yes |
ping | Liveness check inside an MCP session | yes |
tools/list | Discover available tools | yes |
tools/call | Invoke a tool by name with arguments | yes |
resources/list | Discover available resources | yes |
resources/read | Read a resource by URI (flapi://<name>) | yes |
prompts/list | Discover available prompt templates | yes |
prompts/get | Render a prompt template with arguments | yes |
logging/setLevel | Set server log level for the session | yes |
completion/complete | Auto-complete tool/prompt arguments | yes |
All ten methods are dispatched in MCPRouteHandlers::handleMessage. Anything else is rejected with -32601 Method not found.
initialize
Establishes a session and negotiates the protocol version.
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"clientInfo": { "name": "my-client", "version": "1.0.0" },
"capabilities": { "sampling": {}, "roots": {} }
}
}
Supported protocol versions (selected via highest mutual match):
2025-11-25(server default)2025-06-182025-03-262024-11-05
If the client requests an unknown version, the server uses its default and logs a warning.
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": false, "listChanged": true },
"prompts": { "listChanged": true },
"logging": {}
},
"serverInfo": { "name": "flapi-mcp-server", "version": "0.3.0" },
"instructions": "..."
}
}
If the mcp.instructions / instructions-file setting is configured in flapi.yaml, the contents are returned in result.instructions for the LLM to read.
tools/list
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }
Returns an array of tool definitions:
{
"tools": [
{
"name": "customer_lookup",
"description": "Retrieve customer information by ID",
"inputSchema": {
"type": "object",
"properties": {
"id": { "type": "string", "description": "Customer ID" }
},
"required": ["id"]
}
}
]
}
The schema is generated from the endpoint's request fields. All properties currently emit "type": "string"; richer JSON Schema typing is a roadmap item.
tools/call
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "customer_lookup",
"arguments": { "id": "12345" }
}
}
Note the parameter shape: the tool inputs go under
arguments, notparameters. This trips up many hand-written clients.
The response wraps the tool result in MCP content blocks:
{
"content": [
{
"type": "text",
"text": "[{\"id\":12345,\"name\":\"John Doe\"}]"
}
]
}
For SQL-backed tools, the text field contains a JSON-serialised array of result rows. For write operations (INSERT/UPDATE/DELETE), it contains { "rows_affected": N, "data": ... }.
resources/list and resources/read
{ "jsonrpc": "2.0", "id": 4, "method": "resources/list", "params": {} }
Returns resources discovered from mcp-resource: YAML blocks. Each resource has a name, description, mimeType, and a URI of the form flapi://<name>.
To fetch a resource:
{
"jsonrpc": "2.0",
"id": 5,
"method": "resources/read",
"params": { "uri": "flapi://customer_schema" }
}
Response:
{
"contents": [
{
"uri": "flapi://customer_schema",
"mimeType": "application/json",
"text": "{\"fields\":[{\"name\":\"id\",\"type\":\"INTEGER\"}]}"
}
]
}
prompts/list and prompts/get
prompts/list returns prompts declared via mcp-prompt:. prompts/get substitutes Mustache-style {{argument_name}} placeholders and returns a fully rendered chat message:
{
"jsonrpc": "2.0",
"id": 6,
"method": "prompts/get",
"params": {
"name": "analyze_customer",
"arguments": { "customer_id": "12345" }
}
}
Response:
{
"description": "Generate customer analysis prompt",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Analyze customer 12345 and provide insights."
}
}
]
}
ping
{ "jsonrpc": "2.0", "id": 7, "method": "ping", "params": {} }
Returns an empty object {} on success — useful for keepalives.
logging/setLevel
Sets the server's log verbosity for diagnostics:
{
"jsonrpc": "2.0",
"id": 8,
"method": "logging/setLevel",
"params": { "level": "debug" }
}
Valid levels: debug, info, notice, warning, error, critical, alert, emergency (with notice→info and critical/alert/emergency→error internally).
completion/complete
Suggests values for a tool or prompt argument. Populated from enum validators declared on request fields:
{
"jsonrpc": "2.0",
"id": 9,
"method": "completion/complete",
"params": { "ref": "customer_lookup", "argument": "status", "value": "act" }
}
Response:
{ "values": ["active"], "total": 1, "hasMore": false }
Notifications
flAPI advertises listChanged capability for tools, resources, and prompts in the initialize response. When --config-service mutates an endpoint at runtime, the server can emit notifications/tools/list_changed, notifications/resources/list_changed, and notifications/prompts/list_changed so clients re-fetch the affected list. Clients themselves typically send notifications/initialized after the handshake (it is accepted but currently a no-op on the server side).
Session Lifecycle
Client flAPI
│ │
│ POST /mcp/jsonrpc │
│ { method: "initialize", ... } │
│ ──────────────────────────────────────► │
│ │ create session
│ ◄────────────────────────────────────── │
│ Mcp-Session-Id: <sid> │
│ { result: { protocolVersion, ... } } │
│ │
│ POST /mcp/jsonrpc │
│ Mcp-Session-Id: <sid> │
│ { method: "tools/list" } │
│ ──────────────────────────────────────► │
│ ◄────────────────────────────────────── │
│ │
│ DELETE /mcp/jsonrpc │
│ Mcp-Session-Id: <sid> │
│ ──────────────────────────────────────► │
│ │ remove session
│ ◄────────────────────────────────────── │
│ { result: { status: "closed" } } │
Sessions expire after a configurable idle timeout (default 30 minutes). Re-sending initialize always creates a fresh session.
Error Codes
flAPI returns standard JSON-RPC error codes plus two MCP-specific codes. The mapping is in mcp_route_handlers.cpp and mcp_error_builder.cpp.
| Code | Name | When |
|---|---|---|
-32700 | Parse error | Body is not valid JSON |
-32600 | Invalid Request | Missing/invalid method field |
-32601 | Method not found | Method name is not one of the supported methods |
-32602 | Invalid params | Required parameter missing or wrong shape (e.g. tools/call without name) |
-32603 | Internal error | Catch-all server-side failure during dispatch |
-32001 | Authentication required | Protocol-layer auth (mcp.auth) rejected the request |
-32000 | Session error | Malformed/missing Mcp-Session-Id on session-scoped operation (e.g. DELETE without header) |
Error responses include the message and may include context:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Invalid params: missing name"
}
}
Health Endpoint
GET /mcp/health is a plain HTTP route (not JSON-RPC) for liveness probes and quick smoke tests:
curl http://localhost:8080/mcp/health
{
"status": "healthy",
"server": "flapi-mcp-server",
"version": "0.3.0",
"protocol_version": "2025-11-25",
"mcp_available": true,
"tools_available": true,
"resources_available": true,
"tools_count": 5,
"resources_count": 2,
"arrow_available": true,
"arrow_active_streams": 0,
"arrow_total_requests": 0
}
Use this in container readiness checks and CI pre-flight steps.
End-to-End cURL Walkthrough
This is the complete protocol flow against a local flAPI server.
1. Initialize
curl -sS -i -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"clientInfo": {"name": "curl-demo", "version": "1.0.0"}
}
}'
Capture the Mcp-Session-Id response header:
HTTP/1.1 200 OK
Content-Type: application/json
Mcp-Session-Id: 7a1c-...-9f88
Export it for later requests:
SID=7a1c-...-9f88
2. List tools
curl -sS -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $SID" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | jq
3. Call a tool
curl -sS -X POST http://localhost:8080/mcp/jsonrpc \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $SID" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_campaign_performance",
"arguments": {"country": "US"}
}
}' | jq
4. Close the session
curl -sS -X DELETE http://localhost:8080/mcp/jsonrpc \
-H "Mcp-Session-Id: $SID" | jq
{
"jsonrpc": "2.0",
"id": null,
"result": { "session_id": "7a1c-...-9f88", "status": "closed" }
}
That is the full lifecycle: handshake, discover, invoke, close.
See Also
- MCP Overview — concepts and YAML mapping
- Claude Integration — wiring Claude Desktop / Claude Code to flAPI
- MCP Config Tools — the
flapi_*admin tool family - Authentication — securing the MCP transport