MCP & A2A
Two protocols designed for AI clients. Same API key, different shape.
Authorization: Bearer kfl_....
Each tenant only ever sees their own agents, snapshots, and incidents.
1. Generate an API key
- Log in at kefal.dev/app.
- Open the Settings tab in the dashboard header.
- Click Generate new API key. Optionally label it (e.g. claude-desktop, ci-deploy-agent).
- The plaintext key (
kfl_+ 48 hex chars) is shown once — store it in your password manager immediately. You can revoke and re-issue at any time.
2. MCP — Model Context Protocol
MCP is the lightest path to use Kefal from a chat-style AI assistant: Claude Desktop, Cursor, Claude Code, or any client that speaks the streamable-HTTP MCP transport. The endpoint is:
https://kefal.dev/mcp/
Claude Desktop
Edit your Claude Desktop config (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json). Add a streamable-HTTP server:
{
"mcpServers": {
"kefal": {
"url": "https://kefal.dev/mcp/",
"headers": {
"Authorization": "Bearer kfl_your_key_here"
}
}
}
}
Restart Claude Desktop. The 6 Kefal tools appear in the tool picker.
Cursor
In Cursor settings → MCP → Add new MCP server, paste the same JSON shape under "url" + "headers". Cursor will auto-discover the tools on first connection.
Claude Code (CLI)
claude mcp add --transport http kefal https://kefal.dev/mcp/ \
--header "Authorization: Bearer kfl_your_key_here"
Then run claude as usual — the tools below are available inline.
The 6 tools
list_agents
List the agents enrolled under your account.
get_agent_status
Latest snapshot for one agent: hostname, OS, kernel, uptime, IPs, top processes, listening ports, logged-in users.
list_incidents
Filter incidents by status and severity, newest first.
get_incident
Full record for one incident: triggering data, causal chain, metadata, remediation state.
acknowledge_incident
Mark an incident as acknowledged (= seen, no action). Reversible from the dashboard.
get_topology
Topology graph: hosts, services, ports, identities, plus the edges between them.
Example exchange
You: Are any of my servers compromised right now?
Claude: [calls list_incidents with status="open"]
You have 3 open incidents:
• HIGH service_privilege_exposure on kefal (port 4444)
• MEDIUM transition_novelty (proc:nc appeared)
• LOW host_gone_silent (db-staging, last seen 2h ago)
Want me to acknowledge the first one or pull the causal chain?
3. A2A — Agent-to-Agent
A2A is for autonomous agents that need to delegate security checks without a human in the loop. Kefal advertises a public Agent Card and accepts JSON-RPC tasks at a single endpoint.
Discovery
Any peer can fetch the Agent Card unauthenticated:
GET https://kefal.dev/.well-known/agent.json
The card describes Kefal's name, description, two skills (server-audit, incident-management), the authentication scheme, and the JSON-RPC endpoint. CORS is wide-open on this resource specifically — discovery works from any origin.
Send a task
POST https://kefal.dev/a2a
Authorization: Bearer kfl_your_key
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": "1",
"method": "a2a.task.send",
"params": {
"task_id": "pre-deploy-check",
"message": {
"role": "user",
"content": "list open incidents"
}
}
}
The response is a synchronous completed task with a single text artifact:
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"task_id": "pre-deploy-check",
"status": "completed",
"artifacts": [
{"type": "text", "content": "3 open incident(s):\n - high/service_privilege_exposure detected …"}
]
}
}
Supported methods
a2a.agent.getAgentCard— programmatic mirror of/.well-known/agent.json.a2a.task.send— submit a task. Routesmessage.contentby keyword:- contains incident → list open incidents
- contains topology / graph / network → graph summary
- contains status / agent / server / host → latest agent snapshot
- contains acknowledge + a UUID → mark that incident as acknowledged
- otherwise → returns the agent's capability description
a2a.task.get— synchronous MVP. Every task is processed inline bya2a.task.send; this method always reports completion.
When to use A2A vs MCP
| Use case | Pick |
|---|---|
| Human in the loop, chat-style assistant calling tools | MCP |
| Autonomous agent doing pre-deploy gate checks | A2A |
| Need fine-grained access to specific tool params | MCP |
| Need a one-shot natural-language status check | A2A |
| Need cross-agent discovery (peer doesn't know Kefal exists yet) | A2A (the Agent Card is the discovery surface) |
4. Auth, errors, and limits
- Auth:
Authorization: Bearer kfl_...on every request. 401 if missing or revoked. - Tenant isolation: every query filters on the resolved
user_id. There is no path that crosses tenants. - MCP errors: business errors (agent not found, incident not yours) come back with
isError: truein the JSON-RPCresult. Protocol-level errors return a JSON-RPCerrorobject. - Rate limits: not yet enforced explicitly. The fair-use policy is the same as the API: don't poll faster than once per second per tool.
- Read vs write: MCP exposes
acknowledge_incidentas the only state-changing tool.remediateandrun_scanare deliberately not available over MCP — those require dashboard or CLI access.
5. Troubleshooting
401 Unauthorized
- The header isn't
Authorization: Bearer kfl_...(note the prefix and the space). - The key was revoked from the dashboard. Generate a new one.
- You pasted a session JWT instead of an API key — check the prefix is
kfl_and the length is 52 chars.
Tool calls return isError: true
- The UUID doesn't exist or doesn't belong to your account.
- For
get_agent_status: the agent is enrolled but hasn't sent its first snapshot yet — wait 60 seconds.
MCP client times out on connection
- The streamable-HTTP transport keeps the connection open. Check that your client supports it (Claude Desktop >= late-2025, Cursor >= 0.42, Claude Code >= 0.4).
- Old SSE-only clients can fall back via the
--transport sseCLI flag — Kefal serves both.