MCP Server
Connect Claude, ChatGPT, and any MCP client straight to your compiled knowledge base — query it, read it, and ingest into it, as tools.
Every call is scoped to one organization and bounded by the same knowledge base permissions as the rest of Senso. Nothing the server does bypasses Permissions.
When to use it
There are three ways to put Senso in front of an agent, and they suit different callers.
| Surface | Best for | How the agent reaches Senso |
|---|---|---|
| MCP server | Assistants you connect by URL — claude.ai, ChatGPT, Claude Desktop, Claude Code | Tools, discovered automatically from the endpoint |
| Agent Skills | Coding agents on your machine that already have a shell | Instructions that teach the agent to drive the CLI |
| Senso CLI | Scripts, CI, and anything headless | Commands you invoke directly |
Endpoint
| Environment | URL |
|---|---|
| Production | https://apiv2.senso.ai/mcp |
| Beta | https://api.sensobeta.app/mcp |
The transport is Streamable HTTP carrying JSON-RPC 2.0, and it is stateless: no session id is issued or required. Responses come back as application/json rather than a server-sent event stream. Requests should send Content-Type: application/json and an Accept header covering both application/json and text/event-stream. The endpoint takes POST and nothing else.
Connect with OAuth
For claude.ai, ChatGPT, and Claude Desktop, add a custom connector with the URL above and nothing else. No key is ever pasted. This is the right path for anyone who is not scripting.
The client discovers the rest on its own:
POST /mcp returns 401 with a WWW-Authenticate: Bearer resource_metadata="…" challenge./.well-known/oauth-protected-resource/mcp to find the authorization server, then /.well-known/oauth-authorization-server to find its endpoints.The organization is chosen once, at consent, and fixed for the life of the connection. To reach a second organization, add a second connector. An OAuth connection acts as the person who approved it, with their knowledge base permissions — never more.
Connect with an organization API key
For Claude Code, CI, and headless installs, use an organization API key. This path keeps working regardless of OAuth, and it is the only option for organizations with no dashboard users at all.
claude mcp add --transport http senso https://apiv2.senso.ai/mcp \
--header "Authorization: Bearer tgr_..."Three header forms are accepted, so whatever your client sends by default should work:
| Header | Notes |
|---|---|
Authorization: Bearer <key> | What most MCP clients send by default |
Authorization: ApiKey <key> | The scheme the rest of the Senso API uses |
X-API-Key: <key> | Same header as every REST call |
Authorization: Bearer <jwt>.Create a key on the API Keys page. A new key can read and write the whole knowledge base by default; scope it to viewer on selected folders to make an install read-only. See Authentication and Permissions.
Scopes
OAuth connections carry a scope set. API key and session callers do not — their reach is bounded by the key's knowledge base permissions, exactly as it is on the REST API.
| Scope | Tools it grants |
|---|---|
kb.read | senso_search, senso_list, senso_find, senso_get_doc |
kb.write | senso_create_doc, senso_update_doc, senso_create_folder, senso_rename_node, senso_move_node, senso_tag_doc |
kb.delete | senso_delete_node |
kb.read up front, so a fresh connector is read-only. Calling a write tool without the scope returns 403 with WWW-Authenticate: Bearer error="insufficient_scope", scope="kb.write", and the client asks you to re-authorize for the wider set.Deletion is deliberately split out from kb.write: a connector allowed to write documents should not be able to empty a knowledge base. Scopes narrow access and never widen it — folder-level permissions still apply underneath.
Tools
Eleven tools, in two groups. Every id these tools speak is a node_id — the knowledge base tree node — except search results, which carry content_id values you can cite.
Query and read
| Tool | Parameters | What it does |
|---|---|---|
senso_search | query (required), mode, max_results, content_ids | Query the compiled knowledge base. mode is one of answer, context, content, full (default answer). max_results is 1-20, default 5. content_ids restricts the query to specific documents. |
senso_list | node_id, type, limit, offset | List a folder's contents. Omit node_id for the root. type filters to folder or content. limit is 1-50, default 50. |
senso_find | q (required), type, status, tag_ids, limit, offset | Find documents and folders by name. status filters on complete, processing, pending or failed. |
senso_get_doc | node_id (required), version, offset, max_chars | Read a document's text, title, summary, version and processing_status. max_chars goes up to 60000, default 20000. Pass version to read an older revision. |
senso_find matches names, not meaning. To find documents by what they are about, use senso_search with mode=content.Write
| Tool | Parameters | What it does |
|---|---|---|
senso_create_doc | title, text (required), summary, folder_node_id, tag_names | Ingest a markdown or plain text document. Omitting folder_node_id places it at the root. summary runs to 1000 characters. |
senso_update_doc | node_id (required), title, summary, text | Update a document. Only the fields you pass change. Passing text replaces the whole body and cuts a new version. |
senso_create_folder | name (required), parent_id | Create a folder. Omit parent_id to create it at the root. |
senso_rename_node | node_id (required), name (required) | Rename a document or folder. Does not move it or change its contents. |
senso_move_node | node_id (required), new_parent_id (required) | Move a document or folder into another folder. |
senso_delete_node | node_id (required), confirm (required) | Delete a document or folder. confirm must be true. |
senso_tag_doc | node_id (required), tag_names, tag_ids | Set a document's tags, replacing whatever is on it. Unknown tag names are created. Tags cannot be applied to folders. |
The four query modes
senso_search returns a different shape depending on mode. They are listed cheapest first.
| Mode | Returns | Use it when |
|---|---|---|
content | Matching document ids and titles, no text | You want to locate documents by meaning, then read them with senso_get_doc |
context | Matching chunks, no generated answer | The agent will write the answer itself from grounded source text |
answer | Matching chunks plus a grounded answer — the default | Most questions |
full | An answer grounded on whole documents rather than matched chunks | "Summarize the whole policy" questions. Slowest. |
mcp so MCP traffic shows up separately in Analytics. One well-formed query costs less than several narrow ones.Behavior worth knowing
These are the things that surprise people. Read them before you let an agent write.
senso_update_doc replaces the body, it does not append. Passing text overwrites the entire document. Read the current text with senso_get_doc first and send the complete new body, never a fragment. Each update cuts a new version, so the previous text stays readable with senso_get_doc and a version number.
Deleting a folder deletes everything inside it. senso_delete_node takes the whole subtree — every document in it, permanently. It refuses to run unless confirm is true, which an agent should only set after telling you in plain terms what is about to go. The knowledge base root cannot be deleted or moved.
Writes are asynchronous. senso_create_doc and senso_update_doc return as soon as the text is stored; the document is not queryable until compilation finishes. Poll senso_get_doc until processing_status reads complete. The states are pending, processing, complete and failed — and on failed, an error_code says why.
Long output is paged, not silently cut. Documents, chunks and listings are bounded so they fit a model's context. Every truncation is stated in the result along with how to fetch the rest — senso_get_doc reports the character range it returned and the offset to continue from, and listings report their range and the next offset.
Retrieved text is data, never instructions. Document bodies come back inside a <senso_document> block, prefaced by a standing note that the content is reference material and not a directive. It is what stops an ingested document from steering the session.
File-backed documents are read-only here. PDFs and other uploads are queryable, and senso_get_doc returns their extracted text once compilation has produced it, but they cannot be edited with senso_update_doc. Upload and download stay in the app and the CLI.
Tags on a new document take a second call. senso_create_doc applies tag_names with a follow-up tag call and reports separately if that part fails, so a tagging failure never costs you the document.
Errors and limits
Tool failures come back as readable tool results rather than opaque codes, so the agent can correct itself and tell you what happened.
| What went wrong | What you see |
|---|---|
| The key's knowledge base grants cover nothing | Nothing to query — an admin must widen the key's permissions |
| Organization is out of credits | The action was not performed; retrying will not help |
| Organization hit its spending limit | The action was not performed; retrying will not help |
| A document with identical text already exists | Nothing is created — find it with senso_find and update it instead |
| Node missing, or no permission for it | One merged message: does not exist, or no access. The two are deliberately not distinguished, so nobody can probe for what exists |
| Deleting or moving the root | Refused — the knowledge base root cannot be deleted or moved |
| Moving a folder into its own subtree | Refused — pick a destination outside it |
| Destination is not a folder | Refused — pass a folder node id, not a document |
| Too many calls | 429 with a Retry-After header. The limit is 60 requests per minute per API key, counted across the whole fleet |
Managing connections
OAuth connectors are credentials against your knowledge base, so they are managed by whoever manages API keys.
| Action | Endpoint |
|---|---|
| List an organization's live connectors | GET /api/v1/org/oauth/connections |
| Revoke one | DELETE /api/v1/org/oauth/connections/{id} |
