MCP transport

~3 min read

MCP transport

Lettuce exposes its agent surface via the Model Context Protocol — a JSON-RPC 2.0 schema designed by Anthropic specifically for tool-calling LLMs.

Endpoint

POST http://127.0.0.1:51234/mcp

The port is set with lettuce serve --port. The default 51234 was chosen to be memorable and unlikely to collide.

Authentication

Every request must carry its token in the Authorization header — there is no query-string fallback:

Authorization: Bearer kJ8x2Vn-Qe7r...

The token is the URL-safe base64 of 32 random bytes (no lp_/lt_ prefix). A missing or bad token gets a flat HTTP 401. See Agent reference/03 Authentication for token management.

Request shape

Standard JSON-RPC 2.0:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_notes",
    "arguments": {"limit": 10}
  }
}

Response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{"type": "text", "text": "{...}"}]
  }
}

The content array is the MCP-spec response format. Lettuce’s tools return a single text part with a JSON-encoded payload — clients should JSON.parse it.

Discovery

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

Returns every tool the authenticated key can invoke, with full input schemas. A read-only key sees only read tools; a propose-only key sees read tools plus the normal write tools (write_note, apply_edits, patch_section) — which queue proposals instead of committing — and the suggestion tools (list_my_proposals, withdraw_proposal). See Agent reference/03 Authentication for scope details.

Connection lifecycle

There is no persistent connection; every request is one HTTP round-trip. This makes Lettuce’s server stateless across requests — restart it any time without losing client state. The MCP clients re-issue their tools/list on connect.

The server is not an HTTPS endpoint by default. It binds to 127.0.0.1 only, so this is safe — nothing outside your machine can reach it. If you need TLS (for tunnel-routed access), front it with cloudflared, tailscale serve, or similar.

The same MCP endpoint is reachable remotely over Tailscale, which is how agents on other machines and the iPhone app connect. Run tailscale serve --bg --https=8443 127.0.0.1:51234 and the endpoint becomes https://<mac>.ts.net:8443/mcp, with the same Authorization: Bearer <token> auth. Localhost binding remains the default — nothing is public; only your own tailnet devices can reach it.

Concurrency

The server is fully async (built on Hummingbird 2 + Swift NIO). Many simultaneous tool calls are fine. Writes are serialised per-note via soft locks.

Rate limits

Only the paid AI tools (LLM/embeddings spend) carry a rate limit — a generous per-key runaway backstop that returns the rate-limited kind with retry_after_ms. Everything else is unlimited: the server runs locally, writes are bottlenecked by disk and serialised per-note. See Agent reference/08 Errors and rate limits.

Activity & logging

Committed agent writes are recorded in <vault>/.lettuce/agent-edits.json — a revert-able timeline (path, before/after, agent label, timestamp) that survives restarts and backs the Agents sidebar (see Core concepts/02 The .lettuce directory). There’s no separate per-call request log; unhandled server errors print to the lettuce serve process’s stderr.