Connect Castan to your assistant
Castan is a company memory for small companies and solo founders. It holds what a company knows across email, Slack, calendar, meetings, documents, code, customers and the books, and it answers questions about that material.
This page is the setup and usage guide for the Castan Model Context Protocol server, which opens that same memory to any MCP client. An assistant connected to it can ask what the company knows, see what is on the calendar, read recaps of recorded calls, list customers and open invoices, and check what the company is building. Every tool reads one workspace and no tool writes anything.
The endpoint
- Endpoint
https://castan.ai/api/mcp- Transport
- Streamable HTTP, one POST per request
- Session
- None. The server is stateless, so every request stands on its own
- Responses
- Plain JSON. The server does not open an SSE stream
- Authentication
- Bearer API key, created by a workspace owner in the Castan app
- Without a key
initialize,tools/list,pingand the initialized notification answer. Everytools/calldoes not- Server name and version
castan, version1.0.0- Writes
- None. Every tool is read only, and every tool says so in its annotations
- Scope
- One key opens exactly one workspace, and one role inside it
- Server card
https://castan.ai/.well-known/mcp/server-card.json, no key needed
The endpoint answers POST. GET and DELETE are accepted by the route and answered by the transport, but there is nothing to fetch or delete on a stateless server, so a client only ever needs POST.
The handshake works without a key
A directory that lists MCP servers, or a person deciding whether to sign up at all, has to be able to see what the server offers before anybody hands it a credential. Four methods answer a caller with no key: initialize, notifications/initialized, ping and tools/list. Every tools/call needs a key, always, and so does anything outside that list.
curl -s https://castan.ai/api/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'What comes back has the server name, the server version and the tool catalogue in it, and nothing else. There is no workspace name, no plan, no role, no count, no connected source, and no answer to the question whether a given company has an account. The code that answers a keyless request never opens a database connection, so none of that is available to leak. A batch is judged whole: a JSON-RPC array that puts a tools/call beside a tools/list is refused entirely rather than partly answered.
The catalogue a keyless caller sees is the full one, all eight tools, including the two an owner key gets and a member key does not. The keyless path is rate limited to 60 requests an hour per calling address. A caller past it gets HTTP 429 with a Retry-After header. A key lifts that limit.
Getting a key
Castan uses its own bearer API key. There is no OAuth flow, and none is required by any of the clients below. A key looks like ck_ followed by 32 characters, and it goes on every request.
Authorization: Bearer ck_your_key_here- Sign in to Castan as an owner of the workspace you want to read.
- Open Settings and go to the API and MCP tab. The whole tab is owner only, so a member account does not see it at all.
- Give the key a name, choose owner access or member access, and create it.
- Copy the key immediately. Castan stores only a SHA-256 hash of it, so the key itself is shown once and never again.
A key can be revoked in the same place at any time, and the list shows when each key was last used. A key belongs to the workspace it was created in. If an assistant is reading the wrong workspace, a new key will not fix that: sign in to the workspace you meant and create the key there.
What one key opens
One key opens exactly one workspace, with one role: owner or member. The role is fixed when the key is created and cannot be changed by the caller. A key is resolved to that workspace and that role before any tool code runs, every query then runs inside a transaction bound to the workspace, and row level security in the database sits behind the application as a second wall. There is no tool argument that names a workspace, so there is nothing for a caller to change, guess or traverse.
- It does not get the
open_receivablesorfinance_summarytools at all. They are absent from the tool list, not present and refusing. - It gets no money columns from
customers. Names and domains only. - It gets no invoice count from
workspace. - It never sees Stripe, QuickBooks or any other finance source in the connected sources list.
- It cannot retrieve invoice or payment text through
ask_brain. The restriction is applied inside the search itself, both in the vector pass and the full text pass, so out of scope material is never read even briefly.
An owner key sees everything above.
Everything is read only
There is no tool that creates, edits, deletes, sends, schedules or pays anything. The server exposes eight tools and all eight are queries. Every one of them carries readOnlyHint: true and destructiveHint: false in its annotations, with openWorldHint decided per tool: false on the seven that read only what the workspace already holds, true on upcoming_meetings, the one tool whose answer is a window on a calendar that people outside Castan own and can change between two identical calls. A key is a read credential and nothing more. Connecting an assistant to Castan cannot change what Castan holds.
The eight tools
Arguments are validated before a tool runs. Every tool answers for the one workspace the key opens, and every answer names that workspace, so a client is never guessing which company it is reading. Answers come back as JSON inside a text content block.
workspaceWorkspace and what it holdsThe workspace name and plan, whether the key has owner or member access, every connected source with its status and last sync time, and counts of the people, companies, messages, meetings, documents, tasks and projects held. Owner keys also get the invoice count. Worth calling first in any session.
No arguments
ask_brainSearch the company brainThe passages that best match the question, each with the kind of source it came from. Search is hybrid: vector similarity, full text and recency fused together. A member key gets results from threads, messages, documents, meetings and tasks only.
question (2 to 500 characters), limit (1 to 20, default 8)
upcoming_meetingsUpcoming meetingsMeetings starting between now and the end of the window, with title, start, end and which source they came from. Up to 50. Calendar events appear once Google Calendar is connected.
days (1 to 60, default 7)
recent_meetingsRecent meetingsThe most recent calls Castan recorded, newest first, with the recap text when one exists, trimmed to 2000 characters.
limit (1 to 25, default 10)
customersCustomers and companiesCompanies the workspace knows, up to 200. An owner key also gets the open receivable total and the overdue invoice count for each. A member key gets names and domains only.
No arguments
work_in_progressWork in progressActive projects with their outcome and every task with its status, plus live checklists with every item, each with a done count against a total.
No arguments
open_receivablesOpen receivablesOwner onlyUnpaid invoices, soonest due first, up to 100: invoice number, customer, amount, due date, and whether it is already overdue.
No arguments
finance_summaryFinance summaryOwner onlyFor the period: payments received with count and total, invoices issued with count and total, and open receivables with count and total. Every number comes from stored rows. Nothing is estimated or projected.
period (30d, 90d or ytd, default 30d)
Connecting a client
Claude Code
claude mcp add --transport http castan https://castan.ai/api/mcp \
--header "Authorization: Bearer ck_your_key_here"Or check it into a project, in .mcp.json at the repository root:
{
"mcpServers": {
"castan": {
"type": "http",
"url": "https://castan.ai/api/mcp",
"headers": {
"Authorization": "Bearer ck_your_key_here"
}
}
}
}Claude Code expands ${CASTAN_API_KEY} from your environment, so writing that in place of the key keeps the file safe to commit and the key in your shell profile.
Cursor
Put this in .cursor/mcp.json in the project, or in ~/.cursor/mcp.json for every project:
{
"mcpServers": {
"castan": {
"url": "https://castan.ai/api/mcp",
"headers": {
"Authorization": "Bearer ${env:CASTAN_API_KEY}"
}
}
}
}${env:CASTAN_API_KEY} reads the key from the environment so it does not sit in a file that gets committed. A literal Bearer ck_... works too. Cursor uses that syntax for environment variables, and remote servers there take no type field.
Any other client
Point it at https://castan.ai/api/mcp, choose streamable HTTP as the transport, and set a static Authorization: Bearer ck_... header. Nothing else is needed: no session id, no callback URL, no client registration.
Checking it works
In Claude Code, run /mcp. The castan server should be listed as connected. Then ask the assistant to call the workspace tool: the answer opens with the name of the workspace the key reads, lists the connected sources with their sync state, and counts what is indexed.
From a terminal, the transport requires an Accept header that names both JSON and the event stream type, even though the answer comes back as JSON.
curl -s https://castan.ai/api/mcp \
-H "Authorization: Bearer ck_your_key_here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'A working key returns the tool list, and so does a request with no key at all. Swap tools/list for a tools/call and the key starts to matter: a missing or revoked key returns HTTP 401 there.
When it does not work
The assistant says it found nothing. Ask it to call the workspace tool. That names the workspace the key opens, lists the connected sources with their sync state, and counts what is indexed. Most reports of an empty brain are either a workspace with no connected source yet or a first sync that has not finished.
It is reading the wrong company. A key is bound to the workspace it was created in. Create a key while signed in to the workspace you meant, and revoke the old one.
Finance questions come back empty and the money tools are missing. The key has member access. Create an owner key if the assistant should see invoices and payments.
HTTP 401. The header is missing, malformed, or the key has been revoked. The value must be the whole key including the ck_ prefix, after the word Bearer and one space. The reply carries a WWW-Authenticate: Bearer realm="castan" header and a short JSON body saying what to send. A 401 on initialize or tools/list means something else: those answer without a key, so the request is not the shape it looks like. A batch that carries a tools/call beside a tools/list is refused whole.
HTTP 429. Only the keyless path is limited, at 60 requests an hour per calling address. Send a key, or wait the number of seconds in the Retry-After header.
HTTP 406. The client did not send an Accept header naming both application/json and text/event-stream. Every real MCP client does this; a hand written curl needs it added.
A JSON-RPC error saying Castan could not answer. That is a fault on the Castan side, not a problem with the key. It is safe to retry.
What this server does not do
- No OAuth. Authentication is the static bearer key described above. The MCP specification treats authorization as optional, and the clients above accept a static header, so this connects today. There is no protected resource metadata document and no authorization server.
- No cross-origin headers on
/api/mcp, so a browser based client running on another origin cannot call the endpoint. Command line and desktop clients are unaffected. The server card does carry them, since a directory has to be able to read it from its own page. - No resources and no prompts. Tools only.
- No writes, no subscriptions, no notifications, no elicitation.
- No streaming. Answers arrive as one JSON response.
Where the data goes
Nowhere new. The server reads the workspace and answers the caller, and sends nothing outward. Keys are stored as SHA-256 hashes, so the plaintext key exists only in the client that holds it. Creation and revocation are both written to the workspace audit log, and each request stamps when the key was last used, which the owner sees in Settings. The rest of how Castan handles company data is on the security page and in the privacy policy. Questions about the connector go to hello@castan.ai.
- Operator
- OCULI OMNIUM SRL, societate cu răspundere limitată (SRL)
- Registration
- CUI 52198491 · Registrul Comerțului J2025054313009 · capital social 200 lei
- Registered office
- Intr. Gheorghe Simionescu 19 Ap. B26
- Contact
- hello@castan.ai
- VAT
- The company is not registered for VAT (small-enterprise exemption, art. 310 Cod fiscal), so prices are final and include no VAT.
- Licences
- None required for this activity. The service is delivered online; there are no delivery costs.
- Consumers
- Complaints go to hello@castan.ai first. If we cannot settle one, you may turn to ANPC (Bd. Aviatorilor 72, București, 021 9551, anpc.ro) and to its alternative dispute resolution service, SAL: reclamatiisal.anpc.ro.
- Businesses
- Business customers are not consumers; the consumer remedies and the right of withdrawal do not apply to them.
