API

MCP API

The Streamable-HTTP JSON-RPC endpoint that exposes Alaf Server's API to AI clients as tools, re-authenticating every call.

The MCP API is a single Model Context Protocol endpoint that lets AI agents (Claude, Cursor, and any MCP-compatible client) drive Alaf Server as a set of tools. Each tool maps onto a permission-tagged REST route, and every call re-runs the full auth and permission stack — so an agent only ever sees and does what its token allows. For client setup (OAuth flow, config snippets), see the MCP overview.

Base path & auth

The endpoint lives at /api/mcp on your instance — e.g. https://your-host/api/mcp. It accepts either a personal access token (Authorization: Bearer <token>, created with alaf server token create) or an OAuth 2.1 access token that an MCP client obtains for you. There is no separate MCP credential. See the API overview and auth model for details.

Available on both self-hosted and Alaf Server Cloud (mounted in the shared route set).

Endpoints

Method & pathPermissionWhat it does
POST /api/mcppublicStateless Streamable-HTTP JSON-RPC 2.0 endpoint. Authenticates the bearer itself, then handles initialize, ping, tools/list, and tools/call.
GET /api/mcppublicReturns 405 — this server never pushes messages, so there is no SSE stream to open.

Both routes are declared public (no auto-injected auth middleware): the POST handler authenticates the bearer credential itself, and each tools/call dispatches an internal request that re-authenticates through the real permission stack.

How authentication works

A missing or invalid bearer returns 401 with a WWW-Authenticate header pointing at /.well-known/oauth-protected-resource, so OAuth-2.1 MCP clients can discover the authorization server and start the PKCE flow. A valid credential resolves the caller's effective capability — this is used only to filter tools/list so the endpoint doesn't advertise tools the token can't use.

The capability is not the authorization gate. Every tools/call builds an internal HTTP request and dispatches it through the real Hono app, forwarding the caller's bearer, so routing, validation, auth, and the per-resource permission check all run exactly as they do over HTTP. A read-only token can only reach read tools; a scoped token stays confined to the projects, servers, and repositories it was granted.

The endpoint is rate-limited per-IP (the mcp policy: 300 requests/minute) because even an unauthenticated probe costs a credential lookup.

Request body (JSON-RPC 2.0 envelope)

The POST body is a single JSON-RPC 2.0 message (batching was removed in protocol 2025-06-18 — an array body returns -32600).

Prop

Type

Methods

MethodResult
initializeNegotiates the protocol version (default 2025-06-18; also speaks 2025-03-26 and 2024-11-05) and returns capabilities: { tools: { listChanged: false } } and serverInfo: { name: "alaf server", version: "1.0.0" }.
pingReturns {}.
tools/listReturns the tools the caller's token can actually use (filtered by read-only flag, role, and grants).
tools/callDispatches the named tool through the real API and returns its response as JSON text content.
notifications/initializedAcknowledged only (notification, no reply → 202).

List available tools

POST /api/mcp
curl -s https://your-host/api/mcp \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# Register the same endpoint with an MCP client (Claude Code):
claude mcp add --transport http alaf server https://your-host/api/mcp \
  --header "Authorization: Bearer $ALAFSERVER_TOKEN"

The tool set is derived from Alaf Server's permission-tagged routes that opt in with an mcp block; the credential/auth surfaces (tokens, auth, mcp itself) are never exposed.

Call a tool

params.name is the tool name from tools/list; params.arguments carries any path parameters, an optional query object, an optional body object (for POST/PUT/PATCH tools), and an optional organizationId (sent as the x-organization-id header).

curl -s https://your-host/api/mcp \
  -H "Authorization: Bearer $ALAFSERVER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
       "params":{"name":"get_projects","arguments":{}}}'

The result wraps the underlying API response as text content, with isError: true when the dispatched request failed.

Errors you might see

401 — missing or invalid access token

No bearer, or one that's expired/revoked. The response carries a WWW-Authenticate header so OAuth clients can start discovery; PAT clients should mint a fresh token with alaf server token create.

405 on GET /api/mcp

Expected. This is a request/response server with no server→client stream, so GET is not supported — always POST your JSON-RPC message.

-32600 / -32700 — bad request

-32700 is a JSON parse error; -32600 is an invalid envelope or a batch (array) body, which this server does not accept. -32601 means the JSON-RPC method is unknown, and -32602 means the tool name in tools/call doesn't exist.

A tool call returns 404 for a resource

tools/list succeeded but a specific tools/call reports 404 — that's the token's scope working as intended: it wasn't granted that project, server, or repository.

On this page