# Postern, for agents
Postern is a self-hosted personal context gateway. A human runs it on hardware they own; you connect to THEIR gate, at their address. There is no central Postern endpoint and no Postern cloud.
What you get
One MCP surface over the sectors of a person's life — finance, mail, calendar, contacts, health, home. Reads are served from a local cache in milliseconds; actions dispatch to the source where the source allows them. You correlate across sectors yourself: there are no cross-sector joins, by design.
Connecting
- Endpoint: the owner's gate address +
/mcp(Streamable HTTP). - Local (same machine): connect directly; the owner mints you a key in their Console and grants sectors.
- Remote: the owner exposes their gate through their own tunnel. Hosted agents (claude.ai and similar) use the gate's built-in OAuth bridge: standard discovery + dynamic client registration at the owner's public address.
- Auth: a per-agent bearer key (32 random bytes, base64url), shown to the owner once and stored by the gate only as a hash — or an OAuth token derived from it through the bridge. You never receive, see, or need the owner's provider passwords.
- The config block, verbatim (the owner's Console hands them this; local harnesses paste it into their MCP config):
{
"mcpServers": {
"postern": {
"type": "http",
"url": "http://<owner-gate-address>/mcp",
"headers": { "Authorization": "Bearer <your-agent-key>" }
}
}
}
- There is no stdio transport on a running gate — the gateway owns its own stdin. Local means the block above with a localhost address.
- A REST mirror serves the reads for tools that do not speak MCP; acting on a source goes through MCP.
The tools
describe_context what you are granted + per-connection freshness get_schema one object's fields, filters, and semantics query cache read: filters, fields, time ranges, aggregates get_record one record by id fetch_live the one read-time path to the source, when freshness matters list_actions what the granted sectors let you DO invoke_action act on the source; a targeted re-sync reflects the result
Start with describe_context. Read get_schema's notes before
composing filters — sign conventions and unit traps live there. Responses
are capped: has_more: true means you saw a page, not an answer.
The rules of the gate
- Grants are per-sector and default-deny. You see nothing the owner has not granted; within a grant you request bounded slices, never a dump.
- A refusal is explicit, and every visit — reads, actions, refusals — lands in an append-only ledger the owner reads.
- The owner can revoke your key in one click. Nothing upstream changes; you simply stop resolving.
- Mail bodies are never cached; envelope metadata is served and content is fetched on demand.
No gate yet?
Your human brings one up in minutes on a machine they control:
# pulls the published image, ghcr.io/getpostern/postern git clone https://github.com/getpostern/postern.git && cd postern echo "POSTGRES_PASSWORD=$(openssl rand -hex 24)" > .env docker compose up -d
Then: Console → connect sources → mint you a key → grant sectors. Per-provider field guides: getpostern.com/guides. Source: AGPL-3.0, github.com/getpostern/postern.
raw markdown: /for-agents.md · /llms.txt · getpostern.com