WeaveForge MCP implementation
Status
The WeaveForge MCP is a browser-paired, encrypted relay for the Codex plugin. It is model-agnostic at the protocol boundary; Codex is the first supported client. It is not an in-app chat or server-side model proxy.
Connection model
- The user enables AI & MCP access, selects sources, and starts a time-limited browser session.
- The app provides a dedicated revocable MCP token and a per-session pairing secret; the latter can optionally be remembered in encrypted settings.
- The local plugin encrypts every tool call with the pairing secret and sends an opaque envelope to the relay.
- Only the unlocked browser claims, decrypts, permission-checks, executes, encrypts, and returns the result.
The server sees only encrypted envelopes plus owner/session IDs, expiry, and status. It never receives research plaintext, encryption keys, pairing secrets, or third-party credentials.
Implemented tools
Read-only tools operate only on granted sources: paper metadata and notes, Zotero annotations and notes, reading lists, vault notes, logbook entries, experiments and milestones. PDFs, report content, settings, credentials and unselected sources are excluded.
Read-only (3): search_workspace, get_source_excerpt, get_workspace_outline
Proposal-only (10) — each saves an encrypted pending proposal, and
/ai-review is the only approval path: propose_zotero_import, propose_append_paper_note, propose_create_vault_note, propose_create_log_entry, propose_paper_update, propose_paper_field_value, propose_reading_list_change, propose_relation, propose_milestone_follow_up, propose_experiment_follow_up
The desktop workspace server (8): search_workspace, list_workspace, get_report_section, list_experiments, get_experiment, get_paper, propose_report_edit, read_entry
A typed browser-local executor performs the normal app write after approval, and an encrypted audit entry records the outcome.
Safety and privacy guarantees
Opt-in, explicit source selection, and permission re-checking per request.
Requests are owner-scoped, short-lived, size-limited, and atomically claimed with a conditional
pending → claimedupdate, and stop on expiry, revocation, encryption lock, or sign-out.A refused call is answered with its reason, sealed under the same key, so a client learns it was denied rather than watching the request expire. The relay still sees only ciphertext; a call the browser cannot even decrypt is cancelled, because there is nothing to answer with.
MCP tokens are revocable and grant no direct database, storage, account, or credential access.
Third-party credentials remain client-encrypted and are sent directly to their provider when an approved operation needs them.
No direct AI writes, silent autonomous actions, deletes, PDF access, report access, or server-side model proxy exist.
Every read tool declares
resultsAreUntrusted, and results go out throughmcpReadResult: a nonce-carrying fence, a notice saying the block is quoted material rather than instructions, and a counted truncation. The content is somebody else's writing, and the agent receiving it may hold shell and write tools of its own. Seedocs/SECURITY.mdfor what this does and does not guarantee.
The local workspace server
Separate from the relay above, and much smaller. The desktop app can serve the
workspace folder as an MCP server on loopback, behind the same token as the
local HTTP surface and off until the user switches that on. The tool list is
generated above from the source, so it stays true as tools are added. Seven of
the eight only read: search_workspace and list_workspace sweep, and
get_report_section, get_experiment, get_paper, list_experiments and
read_entry fetch one thing. kind is a real filter -- papers, reading lists,
experiments and the logbook are separate kinds in the folder layout, not
directories that happen to hold markdown.
search_workspace is re-ranked by meaning when the window has an encoder
loaded, and left in the order the word search found them when it does not: the
server asks the renderer, waits briefly, and takes silence as "keep this order"
rather than failing the call.
The eighth, propose_report_edit, is the only one that writes, and it writes
only into .weaveforge/proposals/ -- never into a file the reader owns.
Nothing reads those back automatically; a person opens the proposal and
decides. An agent that wants to change the workspace itself uses the HTTP
surface's PUT, where the user has at least chosen to open the door. Every
result goes through mcpReadResult, the same wrapper the relay uses.
Verification
npm run check:mcp-plugindrives the stdio server the way a client does and fails on protocol misbehaviour. It is part ofcheck:boundaries, so it runs in CI.npm run check:deployment-surfacefails when a tool is added toAI_TOOL_NAMESwithout being declared in the plugin server.- Unit tests: policy gates, grants, bounded retrieval, proposals, executors, and relay lifecycle.
- Live loop:
mcp-live-loop.test.tsruns the shipped stdio server against the real browser-side claim, decrypt, and dispatch path, with the relay standing on an in-memory store and encryption forced unlocked. It needs no credentials, so it runs in CI, and it covers the one seam the unit tests sit either side of. - Supabase RLS integration: owner isolation and atomic relay claims.
- Browser E2E: opt-in, encrypted browser-approved read, revocation, and sign-out stopping a live relay.
- Core/web tests, typechecks, production build, SOLID/DRY checks, and plugin tool-list validation have been run during implementation.
Remaining work
Annotation provenance in an answer UI is deferred product work; there is no in-app answer UI in this release.