The MCP server
@hanji/mcp is the hosted half of the agent surface. The other half is git itself, which agents already read. This server is for the times a scoped, live read helps: an agent that should see some mounts and not others, searching and reading through the same permission check a person gets.
How it works
It is deliberately small and stateless. It speaks MCP over Streamable HTTP, bound to 127.0.0.1 only, and every request carries a bearer token. There is no session to hold and no state to corrupt. Each request authenticates its token to a principal, builds a fresh server scoped to that principal, answers, and tears down.
The token's scopes decide everything. The server hands the same principal to @hanji/core, so an agent sees exactly what its token allows and no more, and the permission logic lives in core, not here. This surface only exposes it.
The tools
Four for everyone, and a fifth you opt into - the surface stays small enough to hold in your head.
hanji_list_pages,hanji_get_page, andhanji_searchare the read side.hanji_proposeis the write side, and it does not write. It proposes a branch.hanji_list_commentsreads a page's comments, but only for a token minted with the opt-inread+commentscapability - comments are a human side-channel, off by default.
That last line is the whole design in one tool. An agent contributes by suggesting, never by overwriting. Read Agents for how to connect one, and The core for what sits behind these tools.
The curl aliases
The same four operations exist as plain HTTP endpoints beside /mcp - GET /pages, GET /page, GET /search, POST /propose - same bearer token, same principal, same permission check, only the wire dialect differs. They exist because the Streamable HTTP dialect is a poor fit for a shell one-liner, and half the point of an agent-native surface is that a bash script counts as an agent.