MCP Server
This tutorial demonstrates Kavach MCP through automated tests, direct APIs, stdio, native Streamable HTTP, and MCPO.
Overview
The Kavach MCP server is a stateless transport adapter over the REST control plane. It exposes governed read and controlled-write operations to agents through the Model Context Protocol. This tutorial shows six ways to interact with it.
Level 1: Automated tests
Run the MCP test suite:
uv run pytest tests/mcpLevel 2: Python API (no REST)
Use the MCP server object directly with its configured REST client. This expects KAVACH_API_URL to point to a running Kavach REST API (default: http://127.0.0.1:8000).
from kavach import create_mcp_server
server = create_mcp_server()
# List available tools
print([tool.name for tool in server.list_tools()])
# Call a tool
result = server.call_tool("provider.list")
print(result.model_dump())Level 3: With REST API running
Start the REST API in one terminal:
uvicorn kavach.api.app:app --reloadThen in another shell, interact with the MCP server:
from kavach import create_mcp_server
server = create_mcp_server()
# Provider discovery
print(server.call_tool("provider.list").model_dump())
# List jobs
print(server.call_tool("job.list", {"limit": 10}).model_dump())
# Registry lookup
print(server.call_tool("registry.list_models").model_dump())
# Evaluation history
print(server.call_tool("evaluation.history", {"execution_id": "exec-1"}).model_dump())Level 4: JSON-RPC via stdio
Pipe line-delimited JSON-RPC messages into a tiny Python runner. This is how MCP clients communicate with the server.
List tools, no REST required:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
| uv run python -c 'from kavach import create_mcp_server; create_mcp_server().run_stdio()'Call a tool through stdio (REST must be running):
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"job.list","arguments":{"limit":10}}}' \
| KAVACH_API_URL=http://127.0.0.1:8000 uv run python -c 'from kavach import create_mcp_server; create_mcp_server().run_stdio()'It expects one JSON-RPC message per line and writes one JSON-RPC response per line. notifications/initialized intentionally returns no output.
Level 5: Native Streamable HTTP
Use the native HTTP endpoint when an MCP-aware client runs outside the local machine or when each request needs a user identity. Start the local stack, then run the MCP service separately:
# Terminal 1: Keycloak and the Kavach REST API
./kavach-local.sh
# Terminal 2: native MCP endpoint
uv run kavach-mcp --transport streamable-http --host 127.0.0.1 --port 8002The endpoint is http://127.0.0.1:8002/mcp. Fetch a local service token and use it as the client's Authorization header:
uv run python scripts/mcp/fetch-access-token.pyFor a visual client, start ./scripts/mcp/start-inspector.sh, open the complete URL it prints (including its proxy token), then configure Streamable HTTP, Direct connection, the endpoint above, and Authorization: Bearer <access-token>. Leave the Inspector OAuth form empty: the bearer token is already supplied as a custom header. See the Streamable HTTP guide for the full client example and troubleshooting.
Level 6: MCPO over HTTP
MCPO wraps the stdio MCP server in an OpenAPI-compatible HTTP surface. Start it through the repository helper after Keycloak and the REST stack are running:
./scripts/mcp/start-mcp.sh
open http://127.0.0.1:8001/docsCalls made through MCPO still require the kavach-mcp service account to be a tenant member with the required role assignments. A valid token can still receive 403 when the actor lacks the corresponding permission.
