MCP — tools both ways
Precursor is both an MCP client and an MCP server, with working transports in each direction. Model Context Protocol is the open standard for connecting AI apps to tools and data.


As a client — attaching tool servers
Precursor holds a registry of MCP tool servers. Each is toggled in Settings → MCP; enabled servers are opened per chat turn and their tools are advertised to the model, which can then call them inside the streamed tool loop.
Built-in servers ship in-tree:
| Server | What it does |
|---|---|
github | GitHub issue/PR/repo operations. |
fetch | Fetch and read web content. |
workspace-fs | Sandboxed file operations inside a workspace. |
cmd-runner | Run bash / python / node in a Docker jail. |
workiq | Microsoft 365 (mail, calendar, …) — read-only locally, or full read/write via the hosted preview. |
precursor | Precursor's own data (see below). |
You can also add your own servers (stdio or streamable-HTTP). A host-dependency preflight gates enabling a server — for example, cmd-runner needs Docker when its jail is on.
WorkIQ preview & OAuth
workiq has a preview toggle: off, it runs the local stdio launcher (read-only ask); on, it switches to the hosted, OAuth-protected HTTP endpoint for the full read and write surface. The sign-in is a browser flow driven by the SDK's OAuthClientProvider, with tokens cached in settings and silently refreshed when possible. When a full sign-in is required, an inline McpAuthBanner surfaces it right in the app — chat, topic, workspace, and agent turns pause and stream an auth prompt rather than failing. A background keep-alive ticker refreshes the token before it expires so the hosted session survives without frequent re-sign-in.
As a server — exposing your conversations
Precursor runs a FastMCP server named precursor that exposes its own data to MCP hosts (VS Code, CLI agents): topics, messages, search, skills, memory (read + write), post_message (runs a full turn), schedules, and reminders.
Every tool is gated by a per-section mcp_expose toggle — off by default, because exposing conversation history outbound is opt-in.
Two transports serve the same tools:
- stdio —
python -m precursor.backend.services.mcp.precursor_server; how a host launches it as a subprocess. - HTTP — mounted in-process at
/mcp(streamable-http). Off by default, loopback-only, with a Host-header allowlist (DNS-rebinding protection) and no auth — so it never answers on a non-loopback bind.
Keep MCP-over-HTTP local
The HTTP transport has no authentication and only binds to loopback. Leave it that way unless you front it with your own authenticating proxy.
See the architecture reference for the full picture of both directions.