XESO ships a Model Context Protocol (MCP) server so your saved library is
addressable from any MCP-aware client. This document is the canonical setup
guide; the in-app card at /settings/developer provides copy-paste configs
for the same thing.
What you get
When connected, your MCP client can call these tools (source of truth:
lib/services/mcp/tools.ts#MCP_TOOLS):
search— hybrid (semantic + lexical) search across your entire corpussearch_segment— same, scoped to a specific segment (folder)read_note— fetch the full content of one note by IDfind_notes— list recent notes, optionally filtered by segmentcite— resolve a passage ID to a human-readable citation (title, source, excerpt) so your MCP client can render footnotes
Everything is grounded. Every result carries citations; vault-protected content is never returned over MCP (tokens can't carry a vault passphrase).
Agents with the write scope can also file into your library — see
Write actions below.
Endpoint
- Server URL:
https://app.xeso.ai/api/mcp(swap for your own host if self-hosted; default is the production app) - Protocol: JSON-RPC 2.0 over HTTPS (
initialize,ping,tools/list,tools/call). Batching, notifications, andsampling/*are not yet implemented — XESO is a knowledge source, not a completion provider. - Rate limit: 60 requests per minute per token. On 429 we return a
JSON-RPC error (code
-32005) plus the HTTPRetry-Afterheader so clients can back off cleanly. - Request correlation: every response includes an
X-Request-Idheader; quote it when reporting a bug.
Authentication options
Option A — OAuth 2.0 PKCE (recommended)
Your MCP client will handshake against these URLs automatically when you point it at the server URL above:
- Authorization server metadata:
/.well-known/oauth-authorization-server - Protected resource metadata:
/.well-known/oauth-protected-resource - Dynamic client registration:
/api/mcp/oauth/register(RFC 7591) - Authorization:
/api/mcp/oauth/authorize(PKCE S256 required) - Token:
/api/mcp/oauth/token
The consent screen is served at /settings/mcp-connect — you'll see the
client name, the scopes it asked for, and approve or deny. Any client that
cannot prove it registered ahead of time is flagged as "unverified" on that
screen.
Scopes exposed today: read, write, ingest, chat, export, mcp.
For /api/mcp you need at least one of read or mcp; most clients will
ask for read only.
Option B — Personal API token
If your client doesn't speak OAuth yet, issue a token at
/settings/tokens with the read scope and paste it as a Bearer token in
your MCP config (Authorization: Bearer <token>).
Client configs
Cursor (~/.cursor/mcp.json)
{
"mcpServers": {
"xeso": {
"url": "https://app.xeso.ai/api/mcp",
"transport": "http"
}
}
}
Restart Cursor. When you first invoke an xeso tool, Cursor will pop a
browser window to /settings/mcp-connect; approve the connection and the
token is bound to that Cursor install.
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json on macOS / %APPDATA%\Claude\claude_desktop_config.json on Windows)
{
"mcpServers": {
"xeso": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-http", "https://app.xeso.ai/api/mcp"]
}
}
}
Restart Claude Desktop and approve the consent screen on first use.
Token-based (any HTTP MCP client)
{
"mcpServers": {
"xeso": {
"url": "https://app.xeso.ai/api/mcp",
"headers": {
"Authorization": "Bearer <paste-your-token>"
}
}
}
}
Write actions
External agents can write into your library — so what your agents learn in
Claude, ChatGPT, or Cursor is filed into XESO instead of evaporating when the
conversation ends. The write surface lives at POST /api/mcp/v2/actions
(JSON body: { "action": "<name>", "input": { … } }; source of truth:
lib/services/mcp/v2/actions.ts).
Available write actions:
xeso/note.create— create a note (title≤ 500 chars, markdowncontent≤ 100k chars, optionalsegmentId, optionaltagsup to 20). Without asegmentIdthe note is filed into your personal Inbox, exactly like an unfiled ingest — it never disappears into an invisible folder.xeso/note.patch— append markdown to an existing note (append≤ 50k chars) and/or update its title. Append-only by design: an external agent can add context to a note but can never replace or delete existing content. Destructive edits stay in the app, where full editing and history live — one bad tool call (or a prompt-injected agent) can add noise at worst, never destroy knowledge. Canonical note URLs are stable across retitles.xeso/segment.create— create a folder (name1–100 chars, optionalparentId), capped at 200 folders per account when created via MCP.
Every successful invocation returns the created/affected id plus a canonical
app URL (noteHref / segmentHref) so your agent can link you straight to
the result.
Scope and safety rules
writescope required. OAuth clients must requestwriteexplicitly (you approve it on the consent screen); personal tokens need thewritescope at creation. A read-only (read/mcp) token receives a clear403 insufficient_scopeerror — never a silent no-op.- Vault segments are refused (
403 VAULT_SEALED). Vault folders are end-to-end encrypted; an external agent can never hold your vault passphrase, so plaintext writes into a vault are rejected outright — the same seal that keeps vault content out of MCP reads. - Managed knowledge is refused (
403 READ_ONLY_SEGMENT). Provider-synced knowledge segments are read-only everywhere; MCP is no exception. - Plan limits apply (
402 PLAN_LIMIT_REACHED) — the same note/segment quotas as the app. - Rate limit: write invocations share your per-user write budget (30/min), separate from the 60/min read budget.
- Audit: every invocation is logged (action name, actor, client id); note bodies are never logged.
Troubleshooting
401 unauthorized/ JSON-RPC-32001— no Bearer token, canary hit, or the token was revoked. Re-run the OAuth flow from/settings/developer→ "Connect to an MCP client", or issue a new token.403/ JSON-RPC-32002— token is valid but lacksreadormcpscope. Re-consent with the correct scope on/settings/mcp-connect.423/ JSON-RPC-32003— your account is frozen. Unfreeze from/settings/privacybefore retrying.429 rate_limited/ JSON-RPC-32005— you're over 60 req/min. Clients usually back off automatically. Seelib/middleware/rate-limit.ts#RATE_LIMITS.mcp.- Empty tool list — check that consent was granted for the
readscope. Scopes are visible on the consent screen. - Self-hosted: rewrite every URL above to your deployment. The only
public-DNS prerequisite is that your MCP client can reach
/api/mcpover HTTPS.
Security model
- Tokens are SHA-256 hashed at rest; the raw value is shown once at creation and never logged.
- Every
tools/callemits anmcp_tool_invokedanalytics event tagged with the tool name; sensitive arguments and results are never logged. - Vault-protected segments and notes are refused at the tool layer — an MCP token is not sufficient to prove you know the vault passphrase.
- Scopes are never broadened automatically — expanding a scope requires a fresh consent grant and a new token.
- OAuth authorization codes are single-use, PKCE S256 is required, and the in-memory code store expires codes after 60 seconds.
redirect_uriis matched exactly against the value supplied at dynamic registration; mismatches returninvalid_grant.
