Skip to main content

MCP Gateway API

Complete API reference for the STOA Gateway MCP endpoints.

Configure your environment

The examples below use environment variables. Set them for your STOA instance:

export STOA_API_URL="https://api.gostoa.dev"       # Replace with your domain
export STOA_AUTH_URL="https://auth.gostoa.dev" # Keycloak OIDC provider
export STOA_GATEWAY_URL="https://mcp.gostoa.dev" # MCP Gateway endpoint

Self-hosted? Replace gostoa.dev with your domain.

Overview​

The STOA Gateway implements the Model Context Protocol (MCP) specification version 2025-03-26, with backward compatibility for 2024-11-05.

Two access patterns:

PatternTransportUse Case
RESTHTTP POSTScripts, simple integrations, one-shot calls
MCP ProtocolSSE (JSON-RPC)AI agents, streaming, session-based

Authentication​

All endpoints (except discovery) require a JWT Bearer token from Keycloak:

# Get token
TOKEN=$(curl -s -X POST "${STOA_AUTH_URL}/realms/stoa/protocol/openid-connect/token" \
-d "client_id=my-app" \
-d "client_secret=${CLIENT_SECRET}" \
-d "grant_type=client_credentials" | jq -r '.access_token')

# Use token
curl -H "Authorization: Bearer ${TOKEN}" "${STOA_GATEWAY_URL}/mcp/v1/tools"

Public endpoints (no auth required): initialize, ping, and OAuth discovery.


REST Endpoints​

Simple HTTP endpoints for tool operations.

List Tools​

POST /mcp/v1/tools
Authorization: Bearer <token>
Content-Type: application/json

Response:

{
"tools": [
{
"name": "get-weather",
"description": "Returns current weather for a given city",
"inputSchema": {
"type": "object",
"properties": {
"q": { "type": "string", "description": "City name" }
},
"required": ["q"]
},
"annotations": {
"readOnlyHint": true,
"destructiveHint": false,
"idempotentHint": true,
"openWorldHint": true
}
}
]
}

Invoke Tool​

POST /mcp/v1/tools/invoke
Authorization: Bearer <token>
Content-Type: application/json

{
"name": "get-weather",
"arguments": { "q": "Paris" }
}

Response:

{
"content": [
{
"type": "text",
"text": "{\"location\":{\"name\":\"Paris\"},\"current\":{\"temp_c\":12.0}}"
}
],
"isError": false
}

MCP Protocol Endpoints (JSON-RPC over SSE)​

Full MCP specification compliance via Server-Sent Events transport.

Initialize Session​

Handshake with protocol version negotiation:

POST /mcp/sse
Authorization: Bearer <token>
Content-Type: application/json

{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {
"tools": {}
},
"clientInfo": {
"name": "my-agent",
"version": "1.0.0"
}
},
"id": 1
}

Response:

{
"jsonrpc": "2.0",
"result": {
"protocolVersion": "2025-03-26",
"capabilities": {
"tools": { "listChanged": true },
"tokenOptimization": {
"supported": true,
"levels": ["none", "moderate", "aggressive"]
},
"elicitation": {}
},
"serverInfo": {
"name": "stoa-gateway",
"version": "0.1.0"
}
},
"id": 1
}

List Tools (JSON-RPC)​

POST /mcp/sse
Content-Type: application/json

{
"jsonrpc": "2.0",
"method": "tools/list",
"id": 2
}

Call Tool (JSON-RPC)​

POST /mcp/sse
Content-Type: application/json

{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "get-weather",
"arguments": { "q": "London" }
},
"id": 3
}

Batch Requests (MCP 2025-03-26)​

Send multiple JSON-RPC requests in a single call:

POST /mcp/sse
Content-Type: application/json

[
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": { "name": "get-weather", "arguments": { "q": "Paris" } },
"id": 1
},
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": { "name": "get-weather", "arguments": { "q": "London" } },
"id": 2
}
]

All requests are processed concurrently. Response is an array of JSON-RPC results.

Ping​

POST /mcp/sse
Content-Type: application/json

{ "jsonrpc": "2.0", "method": "ping", "id": 99 }

Close Session​

DELETE /mcp/sse?sessionId=<session-id>

SSE Stream (Legacy)​

GET /mcp/sse?sessionId=<session-id>

Opens a persistent SSE connection for streaming responses.

Supported JSON-RPC Methods​

MethodAuth RequiredDescription
initializeNoHandshake + version negotiation
pingNoKeepalive
notifications/initializedNoClient acknowledgment (no response)
tools/listYesList available tools
tools/callYesExecute a tool
resources/listYesList resources (returns [])

Discovery Endpoints​

MCP Server Discovery​

GET /mcp

Returns server metadata: name, version, protocol version, available endpoints.

MCP Capabilities​

GET /mcp/capabilities

Returns detailed capability information including supported features.

MCP Health​

GET /mcp/health

Returns MCP-specific health: tool count, active sessions, status.


OAuth 2.1 Discovery​

STOA implements OAuth 2.1 discovery per RFC 9728, enabling AI agents to authenticate automatically.

Protected Resource Metadata (RFC 9728)​

GET /.well-known/oauth-protected-resource
{
"resource": "https://mcp.<YOUR_DOMAIN>",
"authorization_servers": ["https://auth.<YOUR_DOMAIN>/realms/stoa"],
"scopes_supported": ["stoa:read", "stoa:write", "stoa:execute"]
}

Authorization Server Metadata (RFC 8414)​

GET /.well-known/oauth-authorization-server

OpenID Connect Discovery​

GET /.well-known/openid-configuration

Token Proxy​

POST /oauth/token

Transparent proxy to Keycloak token endpoint. Allows AI agents to obtain tokens without knowing the Keycloak URL.

Dynamic Client Registration​

POST /oauth/register

Proxy to Keycloak DCR endpoint for automated client registration.


Execution Pipeline​

Every tool invocation goes through this pipeline:

  1. JWT Auth β€” Bearer token validated against Keycloak JWKS
  2. Rate Limit β€” Per-consumer quota check (if configured)
  3. OPA Policy β€” Role-based access control with scopes
  4. Tool Execution β€” HTTP call to backend endpoint
  5. Kafka Metering β€” Event emitted for analytics (optional, feature-gated)

RBAC Scope Mapping​

RoleScopes
cpi-adminadmin, read, write, execute, deploy, audit
tenant-adminread, write, execute
devopsread, write, deploy
viewerread

Token Optimization​

Reduce LLM token usage with the X-Token-Optimization header:

curl -X POST "${STOA_GATEWAY_URL}/mcp/tools/call" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Token-Optimization: aggressive" \
-H "Content-Type: application/json" \
-d '{"name": "get-weather", "arguments": {"q": "Paris"}}'
LevelEffect
noneFull response (default)
moderateRemove redundant fields
aggressiveMinimal response, optimized for LLM context

Session Management​

SSE sessions have a configurable TTL (default: 30 minutes). Sessions are automatically cleaned up by a background task.

Session Stats (Admin)​

GET /admin/sessions/stats
Authorization: Bearer <admin-token>
{
"active_sessions": 12,
"zombie_sessions": 0,
"total_created": 1543
}

Error Responses​

StatusErrorCause
401UnauthorizedMissing/expired JWT token
403ForbiddenOPA policy denied the action
404Tool not foundTool name doesn't exist in registry
429Rate limitedConsumer quota exceeded
500Tool execution failedBackend endpoint returned error
502Backend unreachableBackend endpoint is down

JSON-RPC errors follow the MCP specification:

{
"jsonrpc": "2.0",
"error": {
"code": -32602,
"message": "Tool not found: unknown-tool"
},
"id": 3
}

Examples​

Python Client​

import os
import requests

STOA_AUTH_URL = os.environ['STOA_AUTH_URL']
STOA_GATEWAY_URL = os.environ['STOA_GATEWAY_URL']

# Authenticate
auth = requests.post(
f'{STOA_AUTH_URL}/realms/stoa/protocol/openid-connect/token',
data={
'client_id': 'my-app',
'client_secret': os.environ['STOA_CLIENT_SECRET'],
'grant_type': 'client_credentials'
}
)
token = auth.json()['access_token']

# Invoke tool
response = requests.post(
f'{STOA_GATEWAY_URL}/mcp/tools/call',
headers={'Authorization': f'Bearer {token}'},
json={'name': 'get-weather', 'arguments': {'q': 'Paris'}}
)

result = response.json()
print(result['content'][0]['text'])

JavaScript Client​

const STOA_GATEWAY_URL = process.env.STOA_GATEWAY_URL;

const response = await fetch(`${STOA_GATEWAY_URL}/mcp/tools/call`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'get-weather',
arguments: { q: 'Paris' }
})
});

const result = await response.json();
console.log(result.content[0].text);