Skip to main content

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:

MethodPathPurpose
POST/mcp/jsonrpcSend any MCP request (initialize, tools, resources, prompts...)
DELETE/mcp/jsonrpcClose an MCP session (requires Mcp-Session-Id header)
GET/mcp/healthPlain 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": {}
}
FieldTypeRequiredNotes
jsonrpcstringyesMust be "2.0"
idstring or numberyesEchoed back in the response. Use null only for notifications.
methodstringyesOne of the methods in the table below
paramsobjectnoMethod-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.

DirectionHeaderBehaviour
Response → ClientMcp-Session-IdServer returns the new (or existing) session id on every response
Client → ServerMcp-Session-IdEcho 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.

MethodPurposeAuth-able
initializeHandshake, protocol negotiation, capability exchangeyes
pingLiveness check inside an MCP sessionyes
tools/listDiscover available toolsyes
tools/callInvoke a tool by name with argumentsyes
resources/listDiscover available resourcesyes
resources/readRead a resource by URI (flapi://<name>)yes
prompts/listDiscover available prompt templatesyes
prompts/getRender a prompt template with argumentsyes
logging/setLevelSet server log level for the sessionyes
completion/completeAuto-complete tool/prompt argumentsyes

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-18
  • 2025-03-26
  • 2024-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, not parameters. 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.

CodeNameWhen
-32700Parse errorBody is not valid JSON
-32600Invalid RequestMissing/invalid method field
-32601Method not foundMethod name is not one of the supported methods
-32602Invalid paramsRequired parameter missing or wrong shape (e.g. tools/call without name)
-32603Internal errorCatch-all server-side failure during dispatch
-32001Authentication requiredProtocol-layer auth (mcp.auth) rejected the request
-32000Session errorMalformed/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

🍪 Cookie Settings