Saybooks is a place Claude can keep your records, under rules it cannot break, with everything it does written down where you can check it. This page covers what a person needs: connecting Claude, what keys and roles mean, documents, getting your data out, and running it yourself. The rules themselves are in the specs.
Claude Code: claude mcp add books -t http https://saybooks.io/mcp, then /mcp in a session to sign in. Any client that speaks MCP over streamable HTTP with OAuth works the same way; the endpoint publishes its discovery metadata and accepts both dynamic registration and metadata-document client ids.
Claude allows one connector per address, and one Saybooks connection opens one space. So each kind of books has an address of its own, and you can hold several connectors side by side, say invoices and a job hunt:
https://saybooks.io/mcp | any of your spaces; consent asks which |
https://saybooks.io/mcp/invoices | your invoicing spaces only |
https://saybooks.io/mcp/hunt | your job-hunt spaces only |
https://saybooks.io/mcp/books | your full order-to-cash spaces only |
https://saybooks.io/mcp/s/<space id> | exactly that space, for two of the same kind; the id is the ws= part of the space's URL |
Each one signs in the same way and mints the same kind of key; the address only decides which spaces consent offers.
If you are building a server of your own and want the same shape: every door publishes its own protected-resource metadata at /.well-known/oauth-protected-resource/<path> and answers 401 with a pointer to it. The client sends that URL back as the resource parameter (RFC 8707) on the authorization request; the server stores it with the pending request and the consent page reads the path from it. Claude sends it. The code is in src/oauth.js.
A script, a second agent, or a client without OAuth can use a key directly. In the sidebar open Share this space…, type a name for the agent, pick its role, press Mint key, and use the URL that appears: https://saybooks.io/mcp/m-…. The link is the key: whoever holds it acts as your delegate with that role. Revoke it from the same dialog; the connection made through sign-in above is a key of exactly this kind, minted for you at consent, and shows up in the same list.
Say what happened, in your own words. Claude calls the same commands the buttons call, under the same rules, and every action lands in your audit log attributed to the agent.
Claude cannot invent an amount, a date, a name or an address: when it does not have a fact it asks you, and if it tries to write one anyway the system refuses. Everything Claude does also appears in your browser, as normal pages, the moment it happens.
| Role | Can | Cannot |
|---|---|---|
| owner | Everything, including inviting people, minting keys, setting credit limits, deleting the space | — |
| controller | Every business act: customers, orders, invoices, payments, credit authority | Invite, mint, delete the space, change the company profile |
| clerk | Day-to-day writes: orders, shipments, invoices, payments | Credit authority, everything an owner keeps |
| viewer | Read everything | Write anything |
A key is minted for a role. An agent holding a controller key is a controller; a command outside its role is refused with a sentence naming who to ask, and the attempt is logged. People are invited by email and sign in with Google; agents get keys. Both show up in the audit log by name.
A space is one set of books with its own rules, its own members and its own audit log. Sign-in gives you a full space ("My books"). The free doors give you a kind-matched space: invoicing for freelancers, a job hunt for people open to work. You can have more than one, and each key opens exactly one.
Anonymous demo sandboxes at /app?demo=1 are private to your browser, seeded with example books, and deleted after 24 hours. Sign in while one is open and you keep it.
.pdf appended.Every rule in your books applies to Claude exactly as it applies to you. When a command is not allowed, the answer is one sentence with the reason, shown identically on the button's tooltip, in the thrown error and in the agent's reply, and written to the audit log. A real one:
Claude relays it and asks a person what to do. It does not split the order or quietly raise the limit; raising a limit is its own logged act by someone with the authority.
Saybooks is open source under AGPL-3.0. Node 20 and nothing else.
git clone https://github.com/alviso/saybooks.git
cd saybooks && npm ci
node server.js # workbench at http://127.0.0.1:8140, one local workspace, you are the owner
npm test # the 16-gate contract and every conformance scenario
Environment: SAYBOOKS_PORT (default 8140); SAYBOOKS_DEMO=1 turns on the hosted mode with sandboxes, Google sign-in and the public pages; SAYBOOKS_PUBLIC_URL is the origin printed into document links; SAYBOOKS_ADMIN is the Google account allowed to open /admin. Google sign-in needs OAuth client credentials; see src/auth.js. A Dockerfile is included and is what runs saybooks.io.
Local MCP for development: node mcp-server.js speaks stdio. Over HTTP, each key's URL is its own endpoint; a sandbox's bare id is a key too.
No. It produces documents and records payments you received. It never emails anyone, never charges a card, never moves money. You send the link or the PDF yourself.
USD and one company per space, today. Multi-currency and a second entity are on the roadmap, not in the product.
No. It keeps operational records upstream of the ledger: quotes, orders, shipments, invoices, receivables, pipeline. The journal export feeds your accounting system.
Export takes everything with you, in JSON, any day. The code is public and runnable. Your data does not depend on the hosted service existing.
hello@saybooks.io, or open an issue on GitHub. If it is a rule that let something through that it should have refused, say so first: that is the bug we care most about.