# Vruum MCP (`@vruum/mcp`) [![npm](https://img.shields.io/npm/v/@vruum/mcp)](https://www.npmjs.com/package/@vruum/mcp) [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE) [![registry](https://img.shields.io/badge/MCP%20registry-ai.vruum%2Fmcp-6E56CF)](https://registry.modelcontextprotocol.io) Official MCP access to [**Vruum**](https://vruum.ai), the AI revenue platform. Give your agent the whole revenue motion — research prospects, build pipeline, run email and LinkedIn outreach, triage replies, manage deals through close, and read Stripe-backed revenue truth — through **35 compound tools** rather than a sprawl of endpoints. Outreach runs inside **objectives**: a goal, the people it targets, and the policy for reaching them. This package is a **stdio bridge**: it serves the tool surface locally (no credentials needed to introspect) and proxies execution to `https://api.vruum.ai/mcp` under your token. Every call is authorized server-side — the bridge grants no authority your Vruum account doesn't already have. > [!TIP] > **Using a client that supports remote MCP? Connect directly instead.** > Claude Code, Claude Desktop, Cursor, Codex and friends should point straight at `https://api.vruum.ai/mcp` (OAuth 2.1). Fewer moving parts and no token in an env var. This bridge exists for **stdio-only clients** and for **credential-free tool introspection**. See [vruum.ai/docs/mcp](https://vruum.ai/docs/mcp). ## Quickstart You need Node 20+ and a Vruum account. Create a personal access token in the web app under **Settings → API tokens** (`vk_live_…`).
Claude Desktop / Claude Code — claude_desktop_config.json or .mcp.json ```json { "mcpServers": { "vruum": { "command": "npx", "args": ["-y", "@vruum/mcp"], "env": { "VRUUM_MCP_TOKEN": "vk_live_…" } } } } ```
Cursor — ~/.cursor/mcp.json ```json { "mcpServers": { "vruum": { "command": "npx", "args": ["-y", "@vruum/mcp"], "env": { "VRUUM_MCP_TOKEN": "vk_live_…" } } } } ```
Codex CLI — ~/.codex/config.toml ```toml [mcp_servers.vruum] command = "npx" args = ["-y", "@vruum/mcp"] env = { VRUUM_MCP_TOKEN = "vk_live_…" } ```
Already use the Vruum CLI? — no token needed here ```sh npx @vruum/cli login --token vk_live_… ``` The CLI needs Node 22+. Credentials land in `~/.vruum/credentials` and the bridge picks them up automatically — omit the `env` block entirely.
Verify it works without configuring anything: ```sh npx -y @modelcontextprotocol/inspector --cli npx -y @vruum/mcp --method tools/list ``` ## Reliability diagnostics The bridge records content-free operational metadata: generated attempt IDs, the declared client family (Claude/Codex/ChatGPT/unknown), known tool name, start/outcome, timestamp and duration. It never records tool arguments, results, credentials, raw error text or conversations. The private outbox is under `~/.vruum/mcp-diagnostics/` (or `VRUUM_CONFIG_DIR`), separated by endpoint. Records survive bridge restarts and upload to that same endpoint's authenticated `/diagnostics` route after connectivity returns. Only a durable acknowledgement removes them. A restored connection drains the backlog in bounded batches. Transient failures retry once per minute while the bridge is alive; authentication or unsupported-endpoint responses wait for subsequent activity/startup. Uploads never follow redirects or transmit credentials over non-local HTTP. The queue retains at most 500 records per endpoint and reports overflow; disk failures print a coverage warning on stderr. Stdout remains MCP JSON-RPC. Missing-token, connection, protocol, cancellation, invalid-cursor and call failures are observable when the bridge runs. An offline machine cannot deliver reports until it reconnects, and an old installed package has none of these diagnostics. A bridge success means it received the remote result, not that the host used it correctly. Business calls are never automatically replayed after an ambiguous failure. Server and bridge evidence correlate by attempt ID. ## What you can ask for Once connected, these are ordinary requests to your agent: | You say | What happens | | --- | --- | | *"What should I work on today?"* | `get_daily_briefing` — pending approvals, new replies, stalled deals, warm paths, one recommended next action | | *"Review my outreach drafts"* | `get_outreach_review` → you approve, edit, or reject each one | | *"Research Acme Corp and tell me if they fit"* | `research` — website, funding, careers signals, ICP match with reasoning | | *"Find a warm intro to this person"* | `find_warm_path` — separates verified paths from unverified connector candidates | | *"Which objectives are actually working?"* | `get_objective_outcomes` — contacted, replied, and meetings booked, compared across objectives | | *"What's at risk in my pipeline?"* | `inspect_pipeline` — the 5 most at-risk deals, risk-first | | *"Draft a LinkedIn post about X"* | `manage_content` — your agent writes it, you approve, Vruum schedules and publishes | Your harness authors outreach copy, replies, LinkedIn posts, and comments through their review surfaces. It can also chat with Vruum through `manage_assistant` (`start_conversation`, `append_message`): the same chat as the app's floating panel, which reads your records and applies reversible record changes with Undo. The chat does not draft or send messages. ## Tool surface 35 compound tools. Read operations inspect saved data; write operations mutate it. Some writes buy provider work or produce external effects. Each tool describes its own authorization and retry contract. | Area | Tools | | --- | --- | | **Daily operating** | `get_daily_briefing` · `get_next_actions` · `inspect_pipeline` | | **Search & research** | `search` · `fetch` · `research` · `research_lookup` · `import_prospects` · `find_warm_path` | | **People** | `get_person_360` · `manage_person` | | **Relationship identity** | `get_network_identity_review` · `manage_network_identity_resolution` | | **Objectives & outreach** | `inspect_objective` · `get_outreach_review` · `manage_messages` · `manage_outreach` · `manage_relationship_action` | | **Engagement & content** | `get_engagement_review` · `manage_engagements` · `get_content_review` · `manage_content` | | **Performance** | `get_objective_outcomes` · `get_performance_metrics` | | **Deals** | `get_deal_360` · `manage_deal` | | **Revenue** | `get_revenue` · `manage_revenue` | | **Accounts & knowledge** | `manage_account` · `manage_kb` | | **Imports & assistant** | `manage_history_import` · `manage_assistant` | | **Workspaces, config & skills** | `get_operator_companies` · `manage_settings` · `skill` | `manage_outreach` also creates, configures, launches, and pauses objectives; `inspect_objective` reads an objective's setup, audience, forecast, and sourcing plan. No tool mixes reads with writes: `research_lookup` holds the external lookups (work email, LinkedIn profile, company website, careers page, LinkedIn people search), which can spend provider credits or LinkedIn budget. `get_operator_companies` lists the workspaces your login can act in; it is not limited to Vruum staff. Full schemas, descriptions and MCP safety annotations live in [`tools.json`](tools.json) — generated from the live server definition, never hand-edited. The current package also carries the retained-email decision instructions in `manage_messages`. A saved email uses its displayed Action version, proposal revision, and fingerprint. Approval is not a delivery receipt; changed content requires new work. Chat with Vruum through `manage_assistant`. `start_conversation` takes `payload={request_id, message, context?}` and waits up to 50 seconds for the answer; `append_message` takes `id=` and the same payload. The result names the chat, the turn's state, the question, the answer, `changes` (each record change the chat applied, with its Undo state) and `cards`. A turn still running after 50 seconds returns `running`; read the chat later with `inspect_assistant action=read id=`. Actions Undo cannot reverse, and actions that reach a customer or spend, come back as a card with the exact call, and the turn returns `awaiting_approval`. `manage_assistant action=decide_card id= payload={decision: approved|declined}` decides one, only with the user's own answer: approved runs that exact call once under your credentials, declined never runs it; it waits up to 50 seconds for the turn. `manage_assistant action=undo id=` runs a change's exact inverse and is refused when the record was edited since; `action=rate id=` rates an answer. Keep the same `request_id` on a retry after an uncertain response: the server runs each request once. ## Configuration | Env var | Meaning | Default | | --- | --- | --- | | `VRUUM_MCP_TOKEN` | Vruum personal access token | falls back to `VRUUM_TOKEN`, then `~/.vruum/credentials` | | `VRUUM_MCP_URL` | Hosted MCP endpoint | `https://api.vruum.ai/mcp` | | `VRUUM_MCP_TIMEOUT_MS` | Per-call timeout — research and imports run long | `300000` | | `VRUUM_CONFIG_DIR` | Credentials directory | `~/.vruum` | ## How it works ``` your agent ──stdio/JSON-RPC──▶ @vruum/mcp │ tools/list ──────┤ served locally from tools.json │ (no network, no credentials) │ tools/call ──────┴──HTTPS+Bearer──▶ api.vruum.ai/mcp (authorized server-side) ``` Listings are a **static snapshot** bundled at release. That's what makes credential-free introspection possible, and it means a newly added tool won't *appear* until the next release — calls still execute correctly, since they proxy through. In the monorepo, a snapshot test fails any change that lets `tools.json` drift from the server definition, so a release never ships a stale listing. ## Safety and credentials - **Server-side authorization.** The bridge adds no permissions. Your token is exactly your Vruum account, and role/tenant checks happen on the server. - **No automatic retries.** A failed `tools/call` is never replayed. Many of these tools send outreach or spend money, and an ambiguous failure may mean the server already executed — a silent retry could double-send. The connection is discarded, the error says so, and your agent decides whether re-running is safe. - **Your token never leaves your machine** except as a `Bearer` header to `api.vruum.ai`. > [!WARNING] > **The bridge picks up ambient credentials.** With no `VRUUM_MCP_TOKEN` set it falls back to `~/.vruum/credentials`. If you are logged in with the Vruum CLI, then running this server — via the MCP Inspector, a client, or a script — executes **against your real account and real data**. Write tools will really write. > > To poke at it with no credentials, pass an explicit env that reaches the process: > > ```sh > env -i PATH="$PATH" HOME=/tmp/empty node dist/index.js > ``` > > Note that MCP clients following the SDK default only forward an allowlist (`HOME`, `PATH`, `SHELL`, `TERM`, `USER`, `LOGNAME`) to spawned servers — so setting `VRUUM_CONFIG_DIR` in your shell may be **stripped before it reaches the bridge**, while `HOME` survives and the credentials file is found anyway. Set credentials in the client's own `env` block instead. ## Development This repo is a **build artifact of the Vruum monorepo**, resynced automatically on release. `tools.json` is generated from the server definition, and a snapshot test in the monorepo fails when the two differ. Between releases, the hosted server can be ahead of this snapshot. ``` src/index.ts the bridge — token resolution, static listings, proxied calls tools.json generated tool surface (do not edit by hand) test/ black-box tests: spawn the built binary, speak raw JSON-RPC ``` ```sh npm install npm test # builds, then runs the black-box suite npm run typecheck ``` Tests drive the built binary over stdin/stdout and assert **at the wire level** rather than through an SDK client — an SDK-mediated test hides protocol mistakes, since it will happily hand back a result object whether the server returned `result` or `error`. They cover the initialize handshake (including negotiation down to older clients on earlier spec revisions), credential-free listing, protocol-vs-execution error semantics, cursor rejection, capability declaration, and stdout hygiene. **Issues and PRs are welcome here.** Maintainers apply accepted changes upstream in the monorepo and they flow back on the next sync — so a merged fix here may appear as part of a sync commit rather than your original one. Changes to `tools.json` must come from the generator, not by hand. ## Links [Vruum](https://vruum.ai) · [MCP docs](https://vruum.ai/docs/mcp) · [Getting started](https://vruum.ai/docs/getting-started) · [CLI reference](https://vruum.ai/docs/cli-reference) Registry entry `ai.vruum/mcp` · Claude & Codex plugin [`vruum-gtm/skills`](https://github.com/vruum-gtm/skills) ## License [MIT](LICENSE)