Repository navigation
Conversation
`@tomic/mcp` (browser/mcp) is a stdio MCP server for Claude Code, Claude Desktop, Cursor and other clients. It runs locally and signs every edit with the user's own Agent key, so writes are ordinary signed commits. Tools: list_drives, get_resource (documents and meetings include their text), search, semantic_search, query, get_user_classes, get_schema, create_resource, edit_resource and delete_resource (never a whole drive). The data verbs behind those tools now live in @tomic/lib (assistant-tools.ts), and the in-app assistant calls the same functions, so there is one implementation behind both surfaces. The compact JSON-AD dialect, short subject refs and class helpers move from the data-browser to @tomic/lib for the same reason. Reads no longer include the genesis certificate, which is long and tells a model nothing. This is steps 1 and 2 of planning/mcp-endpoint.md; a hosted endpoint with OAuth (for claude.ai connectors) is not part of this change.
atomic-mcp now makes a key on the machine it runs on and prints a link. In the app (/app/connect-agent) the person picks which drives it may reach and whether it may edit, then clicks Allow. Account settings lists connected apps with a Revoke button. Only an agent may edit its own Agent resource, so the grant is not recorded there: the ACLs on the shared drives are the record. The app adds the key to read (and write), the MCP finds its access by searching for resources that list it, and revoking removes it everywhere, including from what it created. The app remembers which apps were connected on the private drive, so settings can list them. ATOMIC_AGENT_SECRET still works for scripts and CI.
Any app that makes its own key (a CLI, a script, the MCP server) can now ask for access the same way: connectAgentUrl builds the approval link, optionally asking for edit rights or specific resources, waitForGrant polls until the person clicks Allow, and publishAgentName sets the name shown under Connected apps. The approval page honours the write and target hints as preselections; the person still decides. The MCP server now uses these instead of its own copies.
atomic-cli connect makes a key on this machine, prints the approval link (/app/connect-agent), waits for Allow and writes the config. Without a config the CLI now points there instead of asking for the secret. ad-generate connect does the same for the codegen CLI, so private ontologies no longer need an agent secret in atomic.config.json, which often ends up in a repository. The key file helper moves from the MCP server into @tomic/lib/node (loadOrCreateLocalAgent), shared by both. Also adds the new screens' strings to the translation catalogs.
POST /mcp (Streamable HTTP) for clients that cannot run a local process. The node is the OAuth 2.1 authorization server (dynamic client registration, PKCE S256, RFC 9728 and 8414 metadata) with stateless signed tokens derived from the node key. The person approves in the app at /app/authorize-mcp, which gives a fresh issued agent read rights on the drives they pick, so revoking is removing it under Connected apps. The node never signs as the person. Tools: list_drives, get_resource (with document text) and search.
|
Review of the hosted MCP part (oauth.rs, tokens.rs, endpoint.rs, AuthorizeMcpRoute, hostedMcp.ts). The token design is sound (stateless MACs per kind, PKCE S256, redirect URIs checked against the registered list, single-use codes, read-only tools). One blocker, plus smaller points. Blocker: the consent page trusts
Fix: only accept a Smaller:
Everything else I read looks right. The local stdio server and the CLI connect flow have a smaller surface; I did not find problems there beyond the grant model above. Held back from merge until the blocker is fixed. Generated by Claude Code |
…writes signed as the issued agent The hosted /mcp endpoint now has every tool, including create, edit and delete when the person allowed editing; the node signs those commits as the issued agent behind the token and sends them through the normal commit pipeline. The local atomic-mcp is a stdio bridge to it with a token from an OAuth connect. The consent page only accepts the node the person is signed in to, and only redirects to exactly the registered redirect URI.
|
Pushed b2f4176 (develop merged in), which answers the review above and unifies the two MCP implementations. Blocker fixed. The consent page now refuses a Smaller points. The redirect host is in the heading, and the node host is in the text. One implementation. Checked: |
The consent page needs the identity the desktop app holds, which a browser on the same machine does not. connect --desktop opens atomic://authorize-mcp, the app routes it to the consent page, and after Allow it tells the loopback listener and stays in the app instead of navigating away.
…imports its bridge
|
Complexity review (about 8.4k changed lines; read the added files, not every test). 1. The compact JSON-AD layer now exists twice. The TS side ( 2. Document body read and write live in two different crates. 3. Three auth/consent surfaces for one grant. 4. Smaller: Biggest win is item 1; items 2 and 3 are cheap if done in this PR and expensive after it lands. Generated by Claude Code |
Combines #2123, #2127, #2133, #2134, #2135, #2136, #2138, #2140, #2141, #2142, #2143, #2147, #2149, #2132, #2121, #2129, #2146 and #1870. Includes fixes for the combination: Dagger mount for the form validation cases, drive mapping list without the flush sentinel, web_time in search, sidebar resize test at the touch bar height.
|
Landed on develop through the batch #2153 (d102056), with this PR's head unchanged. Closing as merged. Generated by Claude Code |
Requested by Joep · project thread
Before: only the in-app assistant could work with Atomic Data, the CLIs needed you to paste your agent secret, and no MCP client could reach a node.
After: a node serves
POST /mcpitself, and that is the one implementation of the MCP tools. A client that cannot run a process (claude.ai) connects to it directly. A local client (Claude Code, Cursor) runsnpx @tomic/mcp connect, which signs in to the same endpoint with OAuth and keeps a token in a file only you can read; the@tomic/mcpprocess is then only a stdio bridge to/mcp. In both cases the person approves at/app/authorize-mcp: which drives, and read only or read and edit. Account settings lists the connections under Connected apps, each with Revoke.atomic-cli connectandad-generate connectkeep using a key of their own (/app/connect-agent).How, server (
server/src/mcp/):resourcechecked) and/mcpthe resource server (Streamable HTTP, JSON-RPC). Client ids, codes and tokens are signed with a key derived from the node key, so nothing is stored./oauth/agent), gives itread(andwriteif allowed) on the drives picked, as the person, and completes with/oauth/approve. What a token may reach is what the ACLs give that agent.list_drives,get_resource(documents and meetings include their text),search,query,get_user_classes,get_schema, and, only when editing was allowed,create_resource,edit_resourceanddelete_resource(never a whole drive). Documents take Markdown as_documentText(lib/src/document_markdown.rs)./commitor the WebSocket.How, consent page: it only accepts a
serverthat is the app's own origin or the node the person is signed in to, and only redirects back to exactly the registeredredirect_uripluscode,stateandiss. The host the client returns to is in the heading. Tests inhostedMcp.test.ts.Not in this PR:
semantic_searchon/mcp(needs the embeddings index),format=compactshort refs, refresh-token rotation, a one-time code store that survives a restart. The in-app assistant still has its own tool list.Related Issues
Part of #1049. Follows
planning/mcp-endpoint.md(the plan from #1347).Checklist
CHANGELOG.md,browser/CHANGELOG.md)browser/lib/tests/hosted-mcp.integration.test.tsruns registration, approval, PKCE, reads, writes, revoking and the local bridge through real OAuth against a real server;browser/mcptests the connect flow and the bridge;hostedMcp.test.tsthe consent page checks)browser/mcp/README.md,planning/mcp-endpoint.md)