# @vectros-ai/mcp-server [![npm](https://img.shields.io/npm/v/@vectros-ai/mcp-server)](https://www.npmjs.com/package/@vectros-ai/mcp-server) [![license](https://img.shields.io/npm/l/@vectros-ai/mcp-server)](https://www.apache.org/licenses/LICENSE-2.0) [![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=vectros&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB2ZWN0cm9zLWFpL21jcC1zZXJ2ZXIiXSwiZW52Ijp7IlZFQ1RST1NfQVBJX0tFWSI6IiJ9fQ%3D%3D) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=vectros&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40vectros-ai%2Fmcp-server%22%5D%2C%22env%22%3A%7B%22VECTROS_API_KEY%22%3A%22%22%7D%7D) [![Claude Desktop Extension](https://img.shields.io/badge/Claude_Desktop-Add_Extension-D97757)](https://github.com/vectros-ai/vectros-mcp-server/releases/latest/download/vectros.mcpb) > One-click badges install the **server entry** in your client. You still supply > a key — run `npx -y @vectros-ai/cli bootstrap` (recommended) or paste your > `ssk_...`. See [Connect from your client](#connect-from-your-client) and the > [honest caveats](#honest-caveats). A [Model Context Protocol](https://modelcontextprotocol.io) server for **Vectros** — a typed, multi-tenant **record store unified with hybrid search** and citation-grounded RAG. Deterministic lookups and enumeration *and* semantic search over one isolated, per-customer index of records and documents — so an agent gets memory that's precise, not just fuzzy recall. Reached agent-natively here over MCP (Claude Desktop, Cursor, Claude Code, Cline, Continue, VS Code, hosted platforms) — and the same data is human-accessible through the Vectros app + SDKs. ``` npx -y @vectros-ai/mcp-server ``` Your agent can search your indexed corpus, query structured records, ingest documents, and ask questions grounded against documents — reaching only your tenant's data, never the public web (there are no web tools). ## Quick start — one command The fastest way to set up is the [`@vectros-ai/cli`](https://www.npmjs.com/package/@vectros-ai/cli) `bootstrap` command. It mints a **least-privilege scoped key** (`ssk_*`) bound to a narrowed AccessProfile, optionally scaffolds a use-case data model, and safe-merges the `vectros` server into your MCP client config — no root key, and no hand-editing JSON: ```bash npx -y @vectros-ai/cli bootstrap ``` You pick what to set up (a blank read-only credential, or a **blueprint** like task tracking) and sign in once with a token from the developer portal. The command then: - mints a scoped `ssk_*` for **this machine** (independently rotatable), - creates the matching AccessProfile — **data-plane only**; the command refuses to provision control-plane scope (keys / profiles / billing / …), - backs up and merges the entry into `claude_desktop_config.json` (Claude Desktop, Cursor, Cline). For **Claude Code**, add `--client code`: it merges the project `.mcp.json` and prints the equivalent `claude mcp add` command. Restart your MCP client and you're done. It's idempotent (re-run any time); `--rotate` replaces this machine's key. **Want to browse the data yourself?** `bootstrap` sets up the key for your *agent*, not a login for *you* — so a blueprint's context won't appear in the data-plane app's switcher until you join your own user to it (the app lists only contexts your user has access in). Grant yourself a role once, either in the admin app (**Access → Contexts → _your context_ → Profiles → Create profile**, pick yourself from the by-email picker, choose a role — no raw id needed) or from the CLI with `--principal me` (resolves to your own user): ```bash vectros access grant --principal me --context --role ``` Blueprints that ship a human role (e.g. `agentic-sdlc`'s `editor`) let you use `--role`; otherwise grant inline scopes with `--actions records:r,search:r,…`. For scripted / agent use, set the sign-in token in the environment and skip the prompts: ```bash VECTROS_BOOTSTRAP_TOKEN=… npx -y @vectros-ai/cli bootstrap \ --blueprint task-management --yes ``` Prefer to wire it up by hand? See **Configure manually** below. ## Connect from your client | Client | One-click | Manual | |---|---|---| | **Claude Desktop** | [Desktop Extension (`.mcpb`)](https://github.com/vectros-ai/vectros-mcp-server/releases/latest/download/vectros.mcpb) — double-click, paste your key | [JSON snippet](#configure-manually-claude-desktop-or-any-mcp-client) | | **Cursor** | [![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=vectros&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB2ZWN0cm9zLWFpL21jcC1zZXJ2ZXIiXSwiZW52Ijp7IlZFQ1RST1NfQVBJX0tFWSI6IiJ9fQ%3D%3D) | `.cursor/mcp.json`, same shape as below | | **VS Code** | [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=vectros&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40vectros-ai%2Fmcp-server%22%5D%2C%22env%22%3A%7B%22VECTROS_API_KEY%22%3A%22%22%7D%7D) | `.vscode/mcp.json`, same shape | | **Claude Code** | `claude mcp add` (below) | [project `.mcp.json`](#configure-manually-claude-code) | | **Cline / Continue** | — | same JSON snippet as Claude Desktop | | **Smithery** | `npx -y @smithery/cli install @vectros-ai/mcp-server` | — | | **Codex** | — | TOML snippet (below) | The fastest path on **every** client is `npx -y @vectros-ai/cli bootstrap` — it mints a scoped key and writes the config for you. The one-click buttons install the server entry; you then supply the key (bootstrap, or paste your `ssk_...`). **Codex** (`~/.codex/config.toml`): ```toml [mcp_servers.vectros] command = "npx" args = ["-y", "@vectros-ai/mcp-server"] env = { VECTROS_API_KEY = "ssk_live_..." } ``` ## Honest caveats Precision is the pitch — what this server deliberately does *not* do: - **There's a human step.** Bootstrap needs a developer-portal sign-in / bridge token. One command, but a person signs in — there is no fully unattended provisioning. - **No web tools, on purpose.** The agent surface has no web-search or web-fetch tools at all. Vectros is the memory, not the browser. - **Agent document upload is text-inline today.** An agent ingests document text inline; on the stdio transport a jailed local-file upload is supported, but bulk file upload from the agent surface isn't the path today. - **Audit history is tamper-*evident*, not tamper-proof.** A state-continuity chain makes out-of-band alteration *detectable*; it is not continuous automated verification. ## Configure manually (Claude Desktop or any MCP client) If `@vectros-ai/cli` is installed **globally** (`npm install -g @vectros-ai/cli`, not a one-off `npx` run — the server needs `vectros` to still be on `PATH` later, when IT runs, not just while bootstrap ran) and you've run `vectros bootstrap` with it, omit the `env` block entirely — the server resolves your key from the local `vectros` CLI keyring automatically (see [Credential resolution](#credential-resolution) below). `vectros login` alone does **not** do this — it stores a separate sign-in session, not this key — so `bootstrap` is the step that actually has to have run: ```json { "mcpServers": { "vectros": { "command": "npx", "args": ["-y", "@vectros-ai/mcp-server"] } } } ``` No CLI installed, or a machine you can't log in on? Set the key directly instead: ```json { "mcpServers": { "vectros": { "command": "npx", "args": ["-y", "@vectros-ai/mcp-server"], "env": { "VECTROS_API_KEY": "ssk_live_..." } } } } ``` This file lives under Claude Desktop's own per-user app-support directory, not a shared repo — but a real key pasted into it is still a live secret at rest: don't paste it into a chat, ticket, or screenshot with the value intact, and prefer the keyring form above whenever you can. Restart Claude Desktop. The agent now sees the Vectros tools and two resources as callable surfaces. ## Configure manually (Claude Code) Claude Code reads a project-scoped `.mcp.json` with the same shape. **Never commit a real key into it** — `.mcp.json` is exactly the kind of file teams check in to share a project's tooling, and a live `ssk_*`/`sk_*` value inside it is a credential leak the moment it lands in git history, not just if the repo is public. The way to share this config safely: commit the entry with **no `env` block at all**, and let each developer's own `vectros` CLI keyring supply the key (see [Credential resolution](#credential-resolution) below — this is the same delegation `git credential` / `docker-credential-*` use). This needs each teammate to have `@vectros-ai/cli` installed **globally** and to have run `vectros bootstrap` with it — `npx`-ing the CLI once, or running `vectros login` alone (a separate sign-in session, not this key), leaves nothing on `PATH` or in the keyring for the server to find later: ```json { "mcpServers": { "vectros": { "command": "npx", "args": ["-y", "@vectros-ai/mcp-server"] } } } ``` Or let Claude Code's CLI write that keyring-based entry for you: ```bash claude mcp add vectros -- npx -y @vectros-ai/mcp-server ``` If a machine genuinely has no `vectros` CLI installed, you can pass the key directly with `-e VECTROS_API_KEY=ssk_live_...` — but then keep that config **local**: add `.mcp.json` to `.gitignore` first, rather than committing it with the key inside. Add `-e VECTROS_API_BASE_URL=https://api.staging.vectros.ai` for a non-production environment. **Load it into a session by restarting.** A Claude Code session that was already open when you added the server won't pick it up mid-session — fully quit and reopen the project (not just re-select the tab). The `/mcp` panel shows the connector marketplace, not locally-configured stdio servers, so it won't confirm the server is loaded — ask the agent to call a Vectros tool instead. Config is keyed by the **git common root**, so a linked worktree resolves to its main repo's `.mcp.json` — add and open from the same project. > **Windows note:** if your `.npmrc` (or a global npm config) points the > `@vectros-ai` scope at a private registry, a bare `npx -y @vectros-ai/mcp-server` > can resolve an unexpected internal build there instead of the public > release — and an internal build is not guaranteed to run on Windows. If the > command above fails to start, either remove the scoped-registry override > for a plain `npx` run, or pin an explicit version (`npx -y > @vectros-ai/mcp-server@`) known to work. ## Tools (23 tools) **Search & RAG** | Tool | What it does | |---|---| | `hybrid_search` | Hybrid BM25 + dense search across the tenant's indexed content (records + documents). Narrow by ownership (`scope` for one dimension, `scopeFilters` for several at once — e.g. one client within one org), folder, type, metadata filters, a created date window, and keyword-precision (`textMode`) / relevance floors. Returns the indexed projection of each hit. | | `rag_ask` | Ask a question grounded against the indexed corpus. Scope retrieval (ownership — `scope` or multi-dimension `scopeFilters` — / folder / type / metadata filters / date window) and steer generation (`instructions` / `temperature`). Streaming generation aggregated; progress notifications keep the call alive for the generation window. | | `document_ask` | Ask a question grounded against a single document. Same aggregation + progress-notification shape as `rag_ask`. | **Records** (structured, schema-validated data) | Tool | What it does | |---|---| | `list_schemas` | List the record-schema catalog the credential can see (filter by `surface` or resolve one by `recordType`). Makes `record_query` / `record_create` discoverable. | | `record_query` | Query records by lookup field — equality (`value`), range, or prefix, with `asc`/`desc` ordering and an optional `sortFrom`/`sortTo` window — or list mode, choosing one of `type`, `folderId` (every record in a folder, any type — combine with `type` to narrow), or `recent` (the account-wide recently-updated feed across all types), then optionally filtering the first two by ownership. Also supports composite equality across 2-3 fields (`values`), but only against a lookup the *schema* declares over those fields together (see `list_schemas`) — not any two fields you pick. | | `record_get` | Fetch one record by id, including its full payload (large payloads truncated to protect the agent context window). | | `record_batch_get` | Fetch several records by id (1-100) in one call, each with its full payload. Returns `missingIds` for any requested id you can't access, since the API silently omits them. | | `record_create` | Create a record of a given type; idempotent by `externalId`; optional per-record `indexMode`. | | `record_batch_write` | Create or upsert up to 50 records in one call, instead of N `record_create` round-trips. Items may mix types and are validated and scope-checked individually. `atomicity: all_or_nothing` commits them as one transaction (nothing is written if any item fails); the default `best_effort` writes each independently. Reports success whenever the batch was *processed* — read the per-item `results`, not just the absence of an error. | | `record_update` | Patch a record's payload (deep-merged; `null` deletes a key); optimistic concurrency via `expectedVersion`. | | `record_delete` | Permanently delete a record by id (leaves a tombstone). | **Documents** (text/file content, indexed for search + Q&A) | Tool | What it does | |---|---| | `document_ingest` | Create a document — inline text body OR local file upload (file mode is stdio-transport only). Idempotent by `externalId`; optional `schemaId` + `payload` for a typed, lookup-queryable document. | | `document_query` | Query documents by lookup field (equality / range / prefix, with `asc`/`desc` ordering) or list mode (filter by ownership + type). | | `document_get` | Fetch a document by id (metadata incl. lifecycle `status` + processing `indexStatus`; optional text truncated at ~8K tokens; optional presigned `downloadUrl` for file-backed documents — always forces a download, never inline rendering, regardless of file type). | | `document_update` | Patch a document's metadata / typed payload (deep-merged); archive/restore via `status` (`ARCHIVED` soft-retracts from search, `ACTIVE` restores); optimistic concurrency via `expectedVersion`. | | `document_delete` | Permanently delete a document by id (removes it and its indexed content). | **Folders** (group records + documents) | Tool | What it does | |---|---| | `folder_query` | Get a folder by id, or list folders (a parent's children for tree navigation, or a flat tenant list; paginated via `nextCursor`). | | `folder_create` | Create a folder. | | `folder_update` | Update a folder's name / description / ownership (merge-patch; optimistic concurrency via `expectedVersion`; folders cannot be re-parented). | | `folder_delete` | Delete a folder. It must be empty first — no documents, no records, and no sub-folders — and a context root is protected outright. | **Identity & history** | Tool | What it does | |---|---| | `current_identity` | Describe the credential: tenantId, environment, principalType, principalKeyId, principalLabel, and (for scoped credentials) allowedActions + dataScope. Does **not** yet include `granted_capabilities` (`member-lifecycle` / `forensic-read` / `context-directory-read` / `delegate-mint`, as of API 0.40.0, joined by `delegate-principal-stamp` in 0.42.0 and `trigger-control-plane-grant` in 0.44.0) — a separate reach dimension a scope clause can carry that `/v1/ping` doesn't report yet, so allowedActions + dataScope may understate a credential's true reach. Also reports this server's own version and the bundled SDK version (`mcpServerVersion`, `sdkVersion`). | | `lookup_principal` | Resolve a user, or an identity entity in a namespace (`org`/`client`/any namespace you registered), by your own `externalId` (→ its Vectros UUID, for the ownership filters) or by a schema lookup field. Pass `contextId` to target a specific app context for a context-owned namespace. Read-only. | | `version_history` | Read the audit/version trail (CREATE/UPDATE/DELETE, with actor + diff) for one record or document. Read-only. | All 23 tools wrap published Vectros HTTP API endpoints. JSON responses are what the agent sees as tool output. Per-call cost surfaces via the `usage` field on inference responses. ### Opting into a subset Pass `VECTROS_MCP_TOOLS=hybrid_search,rag_ask` to register only those two — useful for giving an agent read-only search access without exposing ingestion or inference costs to the credential. Unknown tool names fail fast at startup. ## Resources Two read-only resources for ambient context (no tool call required): | URI | What it returns | |---|---| | `vectros://schemas` | Same payload as `list_schemas`. Lets the agent preload schemas into context for ambient discovery. | | `vectros://identity` | Same payload as `current_identity`. Lets the agent self-describe without spending a tool call. | ## Recommended credential Use a **scoped permanent API key** (`ssk_*`), not a root key (`sk_*`). A scoped key is bound to a narrowed `AccessProfile` — e.g. read-only across one org scope (`scope:org`). If your MCP install is compromised, the blast radius is whatever the profile allows, not the whole tenant. The server emits a `warn` log line on startup when you pass a wildcard `sk_*` for exactly this reason. **The easiest way to get one is `npx -y @vectros-ai/cli bootstrap` (above)** — it mints a least-privilege `ssk_*` and an AccessProfile for you, no root key required. To do it by hand instead: mint a scoped key from the developer portal under **Keys → Create scoped key**, bind it to an AccessProfile titled `mcp-read-all` or `mcp-read-scoped`, and drop the resulting `ssk_live_...` into the config above. See the Vectros developer documentation on scoped tokens ("Recommended AccessProfile for MCP") for least-privilege credential setup — the `vectros bootstrap` flow provisions a scoped `ssk_*` key and its AccessProfile in one command. > **A root `sk_*` can no longer file into another app context, as of API 0.43.0.** > If you run this server on a root key and a tool call names a `folderId` / > `parentFolderId` — or a `schemaId` on a document — belonging to a context other > than `default`, it is now refused with a uniform `400 "Folder not found"` / > `"Schema not found"`. This affects `document_ingest`, `document_update`, > `record_create`, `record_update` and `folder_create`, and it is a change in > outcome: those calls used to succeed. They never did what they appeared to, > though — a root key's writes are always stamped `default`, so the row landed in > `default` while its folder or schema lived elsewhere, permanently invisible to > the context that owned them. Existing rows written the old way are untouched and > still readable, updatable and deletable. The fix is the same scoped key > recommended above: one bound to the target context can file into it and always > could. ## Credential resolution The server resolves its API key from the first source that yields one: 1. **`VECTROS_API_KEY`** — always wins when set. 2. **The `vectros` CLI keyring** — if the key is unset and [`@vectros-ai/cli`](https://www.npmjs.com/package/@vectros-ai/cli) **0.9.0+** is on your `PATH`, the server runs `vectros keyring show --format raw` as a subprocess and uses the key it prints. By default that is your **active** identity; set `VECTROS_KEYRING_ALIAS` to pick a specific entry. This is the same pattern as `git credential` / `docker-credential-*` / `aws credential_process`: the key lives in one place, and the server, your scripts, and your agent hooks all read it from there instead of each keeping a plaintext copy that drifts. 3. **Neither** — startup fails with a message naming both options. The resolved key is held in memory and never logged. Startup logs which alias it resolved (not the key), so you can tell at a glance which identity the server is running as — `vectros keyring doctor` shows the same view. > **Startup warns when it picks an identity you didn't name.** If `VECTROS_API_KEY` > is unset and no `VECTROS_KEYRING_ALIAS` is set, the server falls back to your > **active** keyring entry and logs a warning — it is running as whatever identity > `vectros switch` last selected, which may be a `ssk_live_*` key acting on real data > or a `ssk_test_*` one that isn't. Either can be an unwelcome surprise, because a > blank placeholder (`"VECTROS_API_KEY": ""` in a client config, or `-e VECTROS_API_KEY` > passing through an unset var in Docker) reads as "not configured yet" but resolves > like an unset key. Nothing is blocked — name an entry with `VECTROS_KEYRING_ALIAS`, > or set `VECTROS_API_KEY`, and the warning goes away. `vectros keyring doctor` shows > which entry is active and which of your keys are live. ## Environment variables | Var | Required | Default | Purpose | |---|---|---|---| | `VECTROS_API_KEY` | no\* | — | Vectros API key. Accepts `sk_*` / `ssk_*` / `st_*`; `ssk_*` recommended. \*Required **unless** the `vectros` CLI is installed with a usable keyring entry — see [Credential resolution](#credential-resolution). Takes precedence when set. | | `VECTROS_KEYRING_ALIAS` | no | (the active entry) | Resolve this `vectros` keyring entry instead of the active one. Ignored when `VECTROS_API_KEY` is set. | | `VECTROS_API_BASE_URL` | no | `https://api.vectros.ai` | Override for staging or other envs. Validated: must be `https://` (or `http://` to localhost) and an official `*.vectros.ai` host. | | `VECTROS_ALLOW_INSECURE_BASE_URL` | no | — | Set `1` to bypass the base-URL allow-list (e.g. a trusted local proxy). **Not recommended** — sends your key to an unvalidated host; logs a warning. | | `VECTROS_MCP_INGEST_ROOT` | no | process cwd | Directory `document_ingest`'s `filePath` mode is jailed to. Paths escaping it (traversal/absolute/symlink) or matching a sensitive pattern are rejected. | | `VECTROS_MCP_TOOLS` | no | (all tools) | Comma-separated tool names (e.g. `hybrid_search,rag_ask`). | | `VECTROS_MCP_DEBUG` | no | — | Set `1` for verbose stderr logs. | | `VECTROS_MCP_SKIP_PING_VALIDATION` | no | — | Set `1` to disable the startup `/v1/ping` check. | | `VECTROS_MCP_HTTP_PORT` | HTTP only | `8765` | Port for HTTP transport. | | `VECTROS_MCP_HTTP_HOST` | HTTP only | `127.0.0.1` | Bind address. Use `0.0.0.0` for all interfaces (then set a bearer token). | | `VECTROS_MCP_HTTP_BEARER_TOKEN` | HTTP only | — | Client→server bearer token. **Strongly recommended** beyond localhost; **required** for a non-loopback bind. | | `VECTROS_MCP_HTTP_ALLOWED_HOSTS` | HTTP only | — | Comma-separated extra `Host` values to allow (DNS-rebinding protection). Set to the public hostname(s) behind a reverse proxy. | | `VECTROS_MCP_HTTP_ALLOWED_ORIGINS` | HTTP only | — | Comma-separated extra `Origin` values to allow. | | `VECTROS_MCP_HTTP_ALLOW_INSECURE` | HTTP only | — | Set `1` to permit a non-loopback bind without a bearer token. **Not recommended.** | ## Startup credential validation Before the first tool call, the server runs a `GET /v1/ping` check against your credential. Bad keys fail at startup with a clear error instead of opaquely 401'ing mid-conversation. Set `VECTROS_MCP_SKIP_PING_VALIDATION=1` to disable. ## HTTP transport For hosted-MCP scenarios — running the server behind a network boundary, sharing it across multiple agent instances, deploying as a sidecar — the package also ships an HTTP binary: ```bash VECTROS_API_KEY=ssk_live_... \ VECTROS_MCP_HTTP_PORT=8765 \ VECTROS_MCP_HTTP_BEARER_TOKEN=$(openssl rand -hex 32) \ npx -y -p @vectros-ai/mcp-server vectros-mcp-server-http ``` > The HTTP binary is **not** the default — select it explicitly with > `npx -p vectros-mcp-server-http`. A bare `npx -y @vectros-ai/mcp-server` > always starts the stdio server. The server listens on `http://127.0.0.1:8765/mcp` by default. The bearer token is optional but **strongly recommended for any deployment beyond localhost** — without it, anyone who can reach the port can call Vectros with your credentials. Health probe lives at `GET /healthz` (always unauthenticated, k8s readiness-friendly). Current limitation: the server uses one upstream credential per process (the key resolved at startup). Per-request credential override via the incoming Authorization header is a planned enhancement. For now, deploy one server per credential boundary you want. ## Programmatic use (advanced) Most consumers use the CLI shape above. If you need to embed the server in your own Node process: ```ts import { VectrosMCPServer, createStdioTransport } from '@vectros-ai/mcp-server'; const server = new VectrosMCPServer({ apiKey: process.env.VECTROS_API_KEY!, tools: ['hybrid_search', 'rag_ask'], resources: ['schemas'], // opt-in resource filter; default = all validateOnStart: true, // default — set false to skip startup ping }); await server.connect(createStdioTransport()); ``` ## What this server deliberately doesn't expose This is a decision, not a backlog. An MCP server is a tool surface handed to an autonomous caller, so a capability the API offers is not automatically a tool — each one has to earn its place on an agent's surface. The line is the **data plane**: records, documents, folders and search are here in full. Anything that grants or administers authority is not, and neither is the design-time layer that defines the data model. - **Stored scripts** (`/v1/scripts` — push, list, fetch, delete). A stored script is code, not data. Authoring it is a design-time act, the same reason schema mutation lives in the CLI rather than here: an agent that can write the code that later runs under your credential is a different proposition from one that can write records. - **Synchronous script execution** (`POST /v1/scripts/execute`, the `scripts:x` scope). The closer call of the two, and excluded on operational grounds rather than reach — a `scripts:x:` grant is a deliberately narrow, per-script permission, and an ordinary scoped key can hold it. What an agent handles badly is the failure surface: a run whose outcome cannot be determined returns `500 EXECUTION_OUTCOME_UNKNOWN` with writes that may or may not have committed, which is not something a caller resolves by retrying — it has to go and look. Getting a retry right also means reusing an `Idempotency-Key` across attempts, and a tool call has no natural retry identity, so an agent re-invoking after a timeout would silently run the script a second time. Exposing this well needs a deliberate design for those two things, not a thin wrapper. Until then, run scripts from a caller that can handle them — the API, the SDK, or the CLI. - **Trigger rules** (`/v1/triggers`). Declaring a rule grants authority — a rule's `scopes`/`roleIds` are live, and declaring one is scope-monotonicity-checked like any other authority-granting surface. Minting authority is not an agent action. - **Trigger failure history** (`GET /v1/trigger-failures`) and **usage/billing** (`GET /v1/usage`). Both are read-only, and both are operational rather than data-plane — they describe how your automation and your account are behaving, not what your content says. That is a question for the developer portal or the CLI, where a person is looking at it, rather than a tool an agent reaches for mid-task. - **Identity, access and credential administration** — users, access profiles, roles, app contexts, issuer registrations, and scoped-key minting. Unchanged since launch: identity CRUD stays off the agent tool surface by design. `lookup_principal` resolves an identifier to an id and does nothing else. - **Compliance operations** (erasure, export). Same reason. If one of these belongs on your agent's surface, that's worth telling us — the line is drawn on purpose and can be redrawn with a reason. ## What this server doesn't do (yet) - **No prompts capability** — `/rag` and `/ingest_pdf` slash-command templates land in a future release. (Provisioning — the `bootstrap` command — lives in the separate [`@vectros-ai/cli`](https://www.npmjs.com/package/@vectros-ai/cli) package, above.) - **HTTP transport is single-tenant per process** — per-request credential override via incoming Authorization header is a v1.0+ enhancement. - **No Python implementation** — TS only. Python users can `npx` this server from any project. - **`rag_ask` and `document_ask` are not natively streaming** — full answer aggregated before the tool returns. Progress notifications cover the latency. Native MCP-spec streaming lands when the spec stabilizes. The server is on a pre-1.0 track toward a stable 1.0 release. ## Rate limits Tool calls hit the same per-account per-minute rate limit as any API client (writes, searches, and inference count against it; reads do not). On a `429` the server surfaces the error with its `Retry-After` hint so the agent can pace and retry rather than blind-retrying. See the [rate limits guide](https://docs.vectros.ai/guides/operations-trust/rate-limits) for the per-plan limits. ## Building from source ```sh git clone https://github.com/vectros-ai/vectros-mcp-server cd mcp-server npm install npm run build npm test ``` `npm install` pulls `@vectros-ai/sdk` from the configured npm registry. `npm run build` runs `tsup` to produce the dual ESM/CJS output in `dist/`. The SDK is bundled into the build (see [`tsup.config.ts`](./tsup.config.ts)) — the published npm package is self-contained and works without `.npmrc` config on the consumer's machine. ## Security & trust Vectros enforces per-customer, fail-closed isolation and least-privilege scoped keys, with a tamper-evident audit and version history. Customer-facing surfaces are hardened through extensive adversarial security review. For the full trust posture, drawn plainly with its boundaries, see the [compliance and trust guide](https://docs.vectros.ai/guides/operations-trust/compliance). ## License Apache-2.0. See the LICENSE file.