One librarian for every API your agents use.
Agents ask librarian for data instead of carrying their own API keys. It learns an API the first time one is needed, asks a person for the key once, serves reads within policy, and holds every write until a person approves it.
pip install librarian-a2a
docker pull ghcr.io/kultar/librarian:0.11.0Open source, Apache-2.0. Alpha: expect breaking changes before 1.0.
What happens on a request
Nothing is set up per API in advance. The registry fills itself as agents need things, and a person is asked only when a key is missing or data would change.
An agent asks for data from an API librarian doesn't know yet
Over A2A or MCP, through a gateway such as LiteLLM or directly. The agent names the API and what it wants; it never names a host, so it can't point librarian anywhere else.
librarian learns the API
From its OpenAPI spec, else its documentation (found by itself if needed, with every extracted operation quote-checked against the page), else the model's own knowledge. Reads work at once; a pull request is opened on your registry repo so a person can review the entry.
If the API needs a key, a person is asked once
The agent's task waits and approvers get a Slack card. Someone follows the one-time link, signs in and pastes the key. It goes straight to your secret store, never through Slack, an agent or a model, and the task carries on by itself.
Writes wait for a person's approval, every time
The approval page shows exactly what will be sent: method, path, arguments and body. Approve once, or allow similar writes with a narrow, expiring grant. DELETEs can only ever be approved one at a time.
Why it's safe to put between agents and your APIs
The design assumes that agents can be talked into anything. So nothing an agent, a document or a model says can change what librarian is allowed to do.
- The model never decides
- A deterministic policy engine with no LLM in it authorises every call. The optional planner can only plan reads and propose writes.
- Credentials never travel through agents
- Keys enter on a one-time page and go straight to the secret store. Agents, messages, logs and the model only ever see references like
jira/readonly. - Writes need a person
- A verified registry entry, a separate write credential, and a human approval or a grant pinned to an agent, a person and an operation. Each write is sent once, with no redirects and an idempotency key, and claimed atomically so replicas never run it twice.
- Untrusted input is fenced
- The API host only ever comes from the caller's
base_url, never from documentation or search results. Read versus write is decided by HTTP method. Search results are trust-ranked and third-party sites are skipped by default. - No way out to your network
- An SSRF guard with DNS pinning refuses private addresses unless you allow them, redirects stay on the same origin, and response sizes are capped.
- Approval pages are locked down
- A separate listener behind your SSO proxy, one-time HMAC links that expire, a strict content security policy with no external resources, and every decision recorded with who made it.
The full threat model lists each threat and its mitigation.
Get started
Three paths, depending on where you are. Each one is documented step by step and has been followed end to end.
On your laptop
Ten minutes with Docker. You see an API learned on demand, a key asked for out of band, and a write held for approval.
git clone https://github.com/kultar/librarian
cd librarian/examples/quickstart
docker compose up -d
./ask '{"skill":"capabilities"}'
Getting started
For your team
A Helm chart with oauth2-proxy sign-in, git-sync for the registry, Postgres for shared state and AWS Secrets Manager for keys. Two or more replicas, no volumes, nothing exposed to the internet.
helm install librarian ./deploy/helm/librarian \
-n librarian -f values.yaml
helm test librarian -n librarian
Deploying for a team
Connect your agents
Behind LiteLLM's agent gateway librarian is both an MCP server and an A2A agent. Any A2A or MCP client can also talk to it directly.
# LiteLLM config.yaml
mcp_servers:
librarian:
url: http://librarian.librarian.svc:8080/mcp
transport: http
auth_type: bearer_token
auth_value: os.environ/LIBRARIAN_GATEWAY_KEY
Integrations
What agents can ask for
The same five skills over A2A and as MCP tools. Only fetch uses a model; everything else is plain code.
| Skill | What it does |
|---|---|
capabilities | Which APIs and read operations this agent may use. |
execute | Run one read operation, with optional field selection and pagination. |
onboard | Teach librarian an API: a spec URL, a docs URL, or just a base URL. |
write | Change data, after a person approves it or a grant covers it. |
fetch | Plain language ("open bugs assigned to the payments team"), planned by a model and executed by the policy engine. |
Every result carries provenance: which API and operation, the URL with secrets redacted, when, for which agent and person, and which credential reference. The audit log is always on.
Documentation
- Getting startedThe laptop walkthrough with Docker Compose.
- Deploying for a teamKubernetes, step by step: registry App, Slack, SSO, secrets, database, replicas.
- IntegrationsLiteLLM, any A2A or MCP client, verified principals.
- Registry formatOne YAML file per API, reviewed by pull request.
- Threat modelAssets, actors, threats and mitigations.
- TroubleshootingWhat to check when agents, learning, Slack, sign-in or Kubernetes misbehave.
Roadmap
Done
- Reads within policy, writes with approval or grants
- Learning from specs, documentation and model knowledge, with change detection
- Slack cards, Helm chart, GitHub App for the registry repo
- MCP endpoint and the LiteLLM gateway
- Verified principals from your identity provider
- Replicas with shared state and no volumes
- Internal APIs learned on demand within the domains you list
Next
- Rate limits shared across replicas
Later
- Per-user OAuth for APIs that need the person's own access
- Vault, GCP Secret Manager and Azure Key Vault
- A community registry of reviewed, signed entries