Skip to main content

Model Context Protocol Endpoint

The Model Context Protocol (MCP) endpoint lets AI agents and LLMs interact with Haste Health's FHIR API through a structured, tool-based interface instead of raw REST calls.

Endpoint

POST https://api.haste.health/w/[tenant]/[project]/api/v1/mcp

Replace [tenant] with your tenant name and [project] with your project ID — the same path convention used by the FHIR REST API, just with mcp in place of fhir/r4.

Transport

The endpoint is a single JSON-RPC 2.0 POST endpoint — every request is one HTTP POST with a JSON-RPC body, and every response is one JSON body (Content-Type: application/json). There is no Server-Sent Events stream and no chunked/Streamable HTTP framing; each MCP method call is a normal request/response cycle.

Authentication

Every request needs an Authorization header. OAuth 2.0 is the recommended path — it's the same mechanism used in the Claude integration guide: register a ClientApplication, then exchange credentials for a short-lived bearer token. HTTP Basic Auth also works, but it can only ever authenticate as the client application itself (never a specific user), so treat it as a shortcut for local development, not production.

Supported methods

MethodDescription
initializeNegotiates protocol version and returns server capabilities/info.
notifications/initializedClient acknowledgement after initialize. Returns a bare 200 OK with no body.
tools/listReturns the full list of available tools (see MCP Tools).
tools/callInvokes a named tool with arguments and returns its result.

Any other JSON-RPC method (ping, resources/*, prompts/*, completion/*, etc.) currently returns a not-supported error — the server implements the tool-calling subset of MCP, not the full spec.

Initialize

curl -X POST "https://api.haste.health/w/[tenant]/[project]/api/v1/mcp" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": { "protocolVersion": "2025-03-26", "capabilities": {}, "clientInfo": { "name": "my-agent", "version": "1.0.0" } }
}'
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"protocolVersion": "2025-03-26",
"capabilities": { "tools": { "listChanged": false } },
"serverInfo": { "name": "Haste Health MCP Server", "title": "Haste Health MCP Server", "version": "0.0.1" }
}
}

Listing tools

curl -X POST "https://api.haste.health/w/[tenant]/[project]/api/v1/mcp" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'

Returns { "result": { "tools": [...], "nextCursor": null } } — see MCP Tools for the live, generated list. Every tool's inputSchema.resourceType enum is populated from your server's live CapabilityStatement, so it only lists resource types your deployment actually supports.

Calling a tool

curl -X POST "https://api.haste.health/w/[tenant]/[project]/api/v1/mcp" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "fhir_r4_read",
"arguments": { "resourceType": "Patient", "id": "12345" }
}
}'

A successful call returns both a text content block and a structuredContent field with the same value already parsed as JSON, so agents can use whichever is more convenient:

{
"id": 3,
"jsonrpc": "2.0",
"result": {
"content": [
{ "type": "text", "text": "{\"resourceType\":\"Patient\",\"id\":\"12345\", ...}" }
],
"isError": false,
"structuredContent": { "resourceType": "Patient", "id": "12345" }
}
}

Error Handling

Errors show up at three different layers, and each has its own shape.

Authentication errors

A missing, malformed, or expired bearer token never reaches JSON-RPC handling at all — the JWT verification middleware rejects it with a bare 401 Unauthorized and no response body, carrying the WWW-Authenticate discovery header described above:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://api.haste.health/.well-known/oauth-protected-resource/w/[tenant]/[project]/api/v1/mcp"

Errors from the OAuth token endpoint itself (bad client_id/client_secret, invalid grant, unauthorized scope) come back as JSON with a code/description pair, not a JSON-RPC envelope:

{
"code": "access_denied",
"description": "Invalid credentials"
}
codeHTTP statusMeaning
invalid_request400Missing or malformed parameter
invalid_client400Unknown client_id, or client not authorized for the grant type used
invalid_grant400The code/refresh token is invalid, expired, or was issued to a different client
invalid_scope400Requested scope is invalid or not authorized for this client
unauthorized_client401Client isn't allowed to use this grant type
access_denied403Credentials are well-formed but incorrect
unsupported_response_type422Unsupported response_type in an authorize request
server_error500Unexpected server-side failure
temporarily_unavailable503Server temporarily can't process auth requests

MCP / JSON-RPC errors

Once a request is authenticated, tools/call and other MCP-method errors reuse the same numeric code for both the HTTP status and the JSON-RPC error.code field — a 404 from a failed read comes back as HTTP 404 with error.code: 404, not the negative JSON-RPC-spec codes like -32600. Most errors also carry the underlying FHIR OperationOutcome in error.data.

{
"jsonrpc": "2.0",
"error": {
"code": 400,
"message": "Unknown tool name: 'not_a_real_tool'"
}
}
{
"jsonrpc": "2.0",
"error": {
"code": 400,
"message": "Invalid resource type: 'NotAResource'"
}
}

Related Documentation: