@vectros-ai/mcp-server 0.18.1 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,55 @@
3
3
  All notable changes to `@vectros-ai/mcp-server` are documented here.
4
4
  This project adheres to [Semantic Versioning](https://semver.org).
5
5
 
6
+ ## 0.19.0 — 2026-11-07
7
+
8
+ ### Added
9
+
10
+ - **Tools `agent_list`, `agent_run` and `run_get`** (23 to 26 tools, registered by default; `VECTROS_MCP_TOOLS` is an allow-list).
11
+ - `agent_list` lists the agents you can run (`id`, `name`, `description`, `latestVersion`, `status`; 10 per page by default, at most 100;
12
+ `includeRetired`) in your credential's app context. It never returns a system prompt or tools. Needs `runs:c` or `agents:r`.
13
+ - `agent_run` runs a stored agent on an `input` (1 to 100,000 characters, at most 240,000 bytes JSON-encoded) and returns
14
+ `{ runId, agentId, agentVersion, status, terminal, reason, errorCode, text, toolCalls, charged }`; `charged` is in milli-cents.
15
+ Parameters: `maxInferenceCents` (only lowers the agent's budget; below the minimum is `BUDGET_TOO_LOW` and nothing starts),
16
+ `readOnly` (refuse every tool call that changes data), `agentVersion`, and `idempotencyKey` (1 to 128 letters, digits, `.`, `_`,
17
+ `:` or `-`; the same key again returns that run with `alreadyStarted: true` and no answer text). Needs `runs:c` and agent runs
18
+ switched on for your tenant. **It spends money and may change data with your permissions,** so it is marked destructive.
19
+ - `run_get` reads a run by id (status, whether it ended, why, tool calls, charge; never the answer text). Needs `runs:r`. A result with
20
+ `terminal: false` means the stream ended early: read the run with `run_get`.
21
+ - **`document_query` takes `type` in list mode,** alongside `folderId`, `userId` and `scope`; the filter applies page by page, so a page
22
+ can be short or empty while `nextCursor` is set. A lookup argument without `field` is refused.
23
+
24
+ ### Changed
25
+
26
+ - **`rag_ask` and `document_ask` report a call's cost as `usage.inferenceBalanceCentsChargedMilli` (1 cent = 1000),** replacing
27
+ `inferenceBalanceCentsCharged`; divide by 1000 for cents.
28
+ - **`version_history` entries made by an agent run carry `actingVia`** (`kind`, `actorId`, `runId`, `tool`) beside `changedBy`.
29
+ - **`document_ingest` and `document_get` handle a file with no extractable text:** polling waits for any terminal `indexStatus`
30
+ (`INDEXED`, `SKIPPED`, `STORED` or `FAILED`); `extraction.outcome` says why a file ended `SKIPPED`.
31
+ - **The server runs on zod 4.** An integer argument beyond JavaScript's safe-integer range is refused, and the wording of argument
32
+ errors changes (`Invalid input: expected string, received number`): match on the argument name, not the text.
33
+ - **Every array argument has a size limit:** `scopes` at most 2 (`document_ingest`, `document_update`, `folder_create`,
34
+ `folder_update`, `record_create`, each `record_batch_write` item), `scopeFilters` 16 and `contentTypes` 2 (`hybrid_search` and the
35
+ `search` object of `rag_ask`); a longer array is refused.
36
+
37
+ ## 0.18.2 — 2026-10-25
38
+
39
+ ### Changed
40
+
41
+ - **The `providerAlias` description of `rag_ask` and `document_ask` names the three waiver refusals.** When a call routed
42
+ through your own provider is refused because the account's provider waiver is not in force, the `403` carries an
43
+ `errorCode`: `WAIVER_NOT_SIGNED`, `WAIVER_TEXT_CHANGED` or `WAIVER_REVOKED`. The two descriptions and the README say what
44
+ each means and that an account owner resolves each in the developer portal.
45
+ - **The `expectedVersion` descriptions of `record_update`, `document_update` and `folder_update` say what happens without it.**
46
+ An update that meets another change to the same item at the same moment is refused as a conflict (`409`,
47
+ `VERSION_CONFLICT`) whether or not `expectedVersion` is sent.
48
+ - **The README lists the refusals added in API 0.48.0 and what the tools return for them:** `429` `BALANCE_BUSY`, `503`
49
+ `BALANCE_UNAVAILABLE`, and a `503` with no `errorCode` for a `providerAlias` whose stored provider key cannot be opened. It
50
+ also describes the `409` of a concurrent update and the items of a deleted schema.
51
+ - **The `current_identity` tool and the `vectros://identity` resource list `trigger-control-plane-grant` among the capabilities
52
+ that the credential description omits.**
53
+ - **The comments in the shipped code describe the code as it is today.** Behaviour is unchanged.
54
+
6
55
  ## 0.18.1 — 2026-10-12
7
56
 
8
57
  ### Changed
@@ -264,7 +313,7 @@ This project adheres to [Semantic Versioning](https://semver.org).
264
313
  - **`folder_delete` no longer implies a record cannot be moved.** It said a record must be deleted
265
314
  because it cannot be re-filed. The API supports re-filing one (`folderId` is patchable); it is
266
315
  *this server* that does not expose it — `record_update` has no `folderId` argument. As written, an
267
- agent clearing a folder could have deleted partner data where a move was available, then reported
316
+ agent clearing a folder could have deleted a record where a move was available, then reported
268
317
  that a move was impossible. It now names the gap as this server's and says to move the record
269
318
  through the API/SDK rather than deleting it here.
270
319
  - **`record_batch_write` no longer claims duplicate `externalId`s within one batch are refused.**
package/README.md CHANGED
@@ -26,8 +26,12 @@ npx -y @vectros-ai/mcp-server
26
26
  ```
27
27
 
28
28
  Your agent can search your indexed corpus, query structured records,
29
- ingest documents, and ask questions grounded against documents — reaching
30
- only your tenant's data, never the public web (there are no web tools).
29
+ ingest documents, ask questions grounded against documents, and run the
30
+ agents you have stored. The server itself makes no call to the web; a stored
31
+ agent you run can search the web (`web_search`) or fetch a page (`web_fetch`)
32
+ when its definition lists that tool. Web fetch also needs your tenant's owner
33
+ to switch it on, and a run of an agent that lists `web_search` is refused while
34
+ the platform has web search disabled.
31
35
 
32
36
  ## Quick start — one command
33
37
 
@@ -112,11 +116,14 @@ Precision is the pitch — what this server deliberately does *not* do:
112
116
  - **There's a human step.** Bootstrap needs a developer-portal sign-in / bridge
113
117
  token. One command, but a person signs in — there is no fully unattended
114
118
  provisioning.
115
- - **No web tools, on purpose.** The agent surface has no web-search or web-fetch
116
- tools at all. Vectros is the memory, not the browser.
117
- - **Agent document upload is text-inline today.** An agent ingests document text
119
+ - **Web search comes through your agents.** The server itself makes no call to the web:
120
+ Vectros is the memory, not the browser. `agent_run` on a stored agent whose definition
121
+ lists `web_search` or `web_fetch` can search the web or fetch a page; web fetch also
122
+ needs your tenant's owner to switch it on, and web search needs the platform to have
123
+ it enabled (otherwise the run is refused).
124
+ - **Agent document upload is text-inline.** An agent ingests document text
118
125
  inline; on the stdio transport a jailed local-file upload is supported, but
119
- bulk file upload from the agent surface isn't the path today.
126
+ bulk file upload from the agent surface isn't the path.
120
127
  - **Audit history is tamper-*evident*, not tamper-proof.** A state-continuity
121
128
  chain makes out-of-band alteration *detectable*; it is not continuous
122
129
  automated verification.
@@ -225,7 +232,7 @@ resolves to its main repo's `.mcp.json` — add and open from the same project.
225
232
  > pin an explicit version (`npx -y @vectros-ai/mcp-server@<version>`) known to
226
233
  > work.
227
234
 
228
- ## Tools (23 tools)
235
+ ## Tools (26 tools)
229
236
 
230
237
  **Search & RAG**
231
238
 
@@ -253,7 +260,7 @@ resolves to its main repo's `.mcp.json` — add and open from the same project.
253
260
  | Tool | What it does |
254
261
  |---|---|
255
262
  | `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. An `externalId` with no `schemaId` is refused by platform 0.46.0 and later unless you also pass `confirmUntyped: true`. |
256
- | `document_query` | Query documents by lookup field (equality / range / prefix, with `asc`/`desc` ordering) or list mode (filter by folder and ownership). |
263
+ | `document_query` | Query documents by lookup field (equality / range / prefix, with `asc`/`desc` ordering) or list mode (filter by `type`, folder and ownership). The `type` list filter applies page by page: a page can be short or empty while `nextCursor` is set, so keep paging before concluding there are none, or use `hybrid_search` with `typeName` for a large collection. Lookup arguments without `field`, and an empty `type`, are refused. |
257
264
  | `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). |
258
265
  | `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`. |
259
266
  | `document_delete` | Permanently delete a document by id (removes it and its indexed content). |
@@ -271,13 +278,78 @@ resolves to its main repo's `.mcp.json` — add and open from the same project.
271
278
 
272
279
  | Tool | What it does |
273
280
  |---|---|
274
- | `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`). |
281
+ | `current_identity` | Describe the credential: tenantId, environment, principalType, principalKeyId, principalLabel, and (for scoped credentials) allowedActions + dataScope. Does **not** 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, so allowedActions + dataScope may understate a credential's true reach. Also reports this server's own version and the bundled SDK version (`mcpServerVersion`, `sdkVersion`). |
275
282
  | `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. |
276
283
  | `version_history` | Read the audit/version trail (CREATE/UPDATE/DELETE, with actor + diff) for one record or document. Read-only. |
277
284
 
278
- All 23 tools wrap published Vectros HTTP API endpoints. JSON
285
+ **Agents** (run the stored agents of your app context; defining or changing an agent is done through the API)
286
+
287
+ | Tool | What it does |
288
+ |---|---|
289
+ | `agent_list` | List the stored agents (running one needs `runs:c`), as each one's `id`, `name`, `description`, `latestVersion` and `status` (paginated via `nextCursor`; retired and purged agents only with `includeRetired`), in your credential's own app context, the one `agent_run` runs in. Needs `runs:c` or `agents:r`. Read-only. |
290
+ | `agent_run` | Run a stored agent on one `input` and return its answer: `{ runId, agentId, agentVersion, status, terminal, reason, errorCode, text, toolCalls, charged }`; `charged` carries the run's charge and refund in milli-cents (1 cent = 1000). `maxInferenceCents` caps the run's model cost (it can only lower the agent's own budget) and `readOnly` refuses every tool call that would change data. The run's tool calls act as you, with your permissions, and only through the tools the agent lists. Progress notifications keep the call alive while the run works (for a client that resets its timeout on progress); cancelling the call cancels the run once it is named. The server itself makes no call to the web; a stored agent can search the web or fetch a page when its definition lists that web tool (web fetch also needs your tenant's owner to switch it on, and web search needs the platform to have it enabled: otherwise the run is refused). Billed, and flagged destructive so your MCP client asks before it runs. Needs `runs:c`. |
291
+ | `run_get` | Read one run by id: `status`, `terminal`, `reason`, `errorCode`, its tool calls (never their arguments or results) and `usage`. Use it when `agent_run` returns `terminal: false`. Needs `runs:r`, which `runs:c` does not include. Read-only. |
292
+
293
+ **Running agents.** The three agent tools are registered by default, like every other tool, so **after upgrading,
294
+ an existing install (including `npx -y @vectros-ai/mcp-server`) offers them with no config change**, and one of
295
+ them, `agent_run`, **spends money and can change data**: it starts a billed run whose tool calls act with your
296
+ permissions. It is marked destructive, so an MCP client that honours tool annotations asks you before it runs; to
297
+ leave it out, use `VECTROS_MCP_TOOLS` below. A run is billed: its
298
+ model calls against your inference balance (a prepaid account reserves the budget when the run starts and returns
299
+ what was not used), and a fee per run, tool calls and run time against your plan. Three things on the platform side
300
+ decide whether a call can start a run at all:
301
+
302
+ 1. **The credential needs the `runs:c` scope.** Without it `agent_run` returns `403`. Reading a run with `run_get`
303
+ needs `runs:r` as well, which `runs:c` does not include: a credential with only `runs:c` learns how its runs end
304
+ only from `agent_run`'s own result. `agent_list` works with `runs:c` or `agents:r`; a credential with only
305
+ `agents:r` can list agents but not run them.
306
+ 2. **Agent runs must be switched on for your tenant by an account owner.** Otherwise `agent_run` returns `403` with
307
+ `errorCode: AGENT_RUNS_NOT_ENABLED`.
308
+ 3. **The platform's run limits apply.** It limits how many runs one credential has in progress at once and how much
309
+ budget they hold together; a call over either returns `429`. One MCP server runs on one credential, so all of its
310
+ clients' concurrent `agent_run` calls share those limits.
311
+
312
+ To leave `agent_run` out of a server, set `VECTROS_MCP_TOOLS` to the tools you **do** want: it is an allow-list (the
313
+ server registers only the tools it names), not an exclusion list. For example, a server that can find and read
314
+ agents and runs but never start one:
315
+
316
+ ```bash
317
+ VECTROS_MCP_TOOLS=hybrid_search,rag_ask,record_query,record_get,document_query,document_get,agent_list,run_get
318
+ ```
319
+
320
+ **Retries.** Every `agent_run` call sends an `Idempotency-Key`, so the SDK's own retries of a refused start never
321
+ begin a second run. Calling `agent_run` again without a key starts a new, billed run: to make your retry of a whole
322
+ call safe, pass the same `idempotencyKey` with the same arguments, and the call names the run that key already
323
+ started instead of starting another (its answer text is not returned again, and `run_get` cannot read it back; the
324
+ same key with different arguments is refused with `422`). A start that fails without a clear refusal (a dropped
325
+ connection, a timeout, a `408` or a `5xx`) may still have started a run, so its error names the `idempotencyKey` to retry with.
326
+
327
+ **Cancelling and long runs.** Cancelling the call cancels the run once the run is named (the response names it
328
+ almost at once; a cancel that arrives earlier waits for the name). If the start itself then fails, nothing could be
329
+ cancelled: retry with the key the error names to find the run. Progress notifications are sent only when the MCP
330
+ client supplies a `progressToken` with the call, and they keep a long call alive only for a client that resets its
331
+ request timeout on progress; a client with a fixed timeout ends the call (and so the run) when it expires. A result with `terminal: false` arrived before the run ended: read the run with `run_get` until
332
+ `terminal` is true. `run_get` returns the run as the API reports it and never returns the answer text.
333
+
334
+ All 26 tools wrap published Vectros HTTP API endpoints. JSON
279
335
  responses are what the agent sees as tool output. Per-call cost
280
- surfaces via the `usage` field on inference responses.
336
+ surfaces in the `usage` field of `rag_ask` and `document_ask` results: the token counts,
337
+ `platformCreditsCharged`, and the model cost as `inferenceBalanceCentsChargedMilli`, in
338
+ milli-cents (1 cent = 1000). `agent_run` reports a run's charge the same way, in its
339
+ `charged` field.
340
+
341
+ **Concurrent updates.** `record_update`, `document_update`, `folder_update` and `document_ingest` with `upsert: true`
342
+ return `409` (`errorCode: VERSION_CONFLICT`) when another request changed the same item at the same moment, whether or not
343
+ you pass `expectedVersion`. Nothing is written and the other change is kept: re-read the item and retry.
344
+ `expectedVersion` still refuses an update made against a version you read earlier, even if the other change finished long
345
+ ago. An update to an item that was deleted a moment earlier returns `404`. In `record_batch_write` with `upsert`, an item
346
+ that meets another change at the same moment is reported in the results with `status: conflict` and
347
+ `errorCode: VERSION_CONFLICT`; send that item again. Items written with `atomicity: all_or_nothing` are not covered.
348
+
349
+ **Items of a deleted schema.** An item whose schema no longer exists is not served: reading it (`record_get`,
350
+ `document_get`) returns an error, updating it, reading its `version_history`, and reading a document's text, download or
351
+ answers (`document_ask`) are refused, and `record_query`, `document_query` and `record_batch_get` leave it out. Delete the
352
+ item.
281
353
 
282
354
  ### Routing a call through your own model provider
283
355
 
@@ -288,7 +360,11 @@ provider config's default model when omitted). The server forwards `providerAlia
288
360
  never fills it in.
289
361
 
290
362
  It works only after your account has set up the provider and signed the platform's risk-acceptance waiver. Without
291
- both, the platform refuses the call with a `403`, which the tool returns to you as written.
363
+ both, the platform refuses the call with a `403`, which the tool returns to you as written. When the waiver is the
364
+ cause, the `403` carries an `errorCode` that says which case it is: `WAIVER_NOT_SIGNED` (the waiver has not been
365
+ signed), `WAIVER_TEXT_CHANGED` (Vectros now requires a newer version of the waiver than the one in force for your
366
+ account) or `WAIVER_REVOKED` (an account owner revoked it). An account owner resolves each in the developer portal
367
+ (**Model Providers**); retrying the call does not help.
292
368
 
293
369
  If your account has accepted the Business Associate Agreement with Vectros in the developer portal, an account owner must also attest each provider
294
370
  config in the developer portal (**Model Providers**) before a call can use it. Until then the platform refuses the
@@ -389,7 +465,7 @@ running as — `vectros keyring doctor` (CLI 0.10.0+) shows the same view.
389
465
  | `VECTROS_API_BASE_URL` | no | `https://api.vectros.ai` | Override for another environment. Validated: must be `https://` (or `http://` to localhost) and an official `*.vectros.ai` host. |
390
466
  | `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. |
391
467
  | `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. |
392
- | `VECTROS_MCP_TOOLS` | no | (all tools) | Comma-separated tool names (e.g. `hybrid_search,rag_ask`). |
468
+ | `VECTROS_MCP_TOOLS` | no | (all tools) | Allow-list of tool names, comma-separated (e.g. `hybrid_search,rag_ask`): only these are registered. |
393
469
  | `VECTROS_MCP_DEBUG` | no | — | Set `1` for verbose stderr logs. |
394
470
  | `VECTROS_MCP_SKIP_PING_VALIDATION` | no | — | Set `1` to disable the startup `/v1/ping` check. |
395
471
  | `VECTROS_MCP_HTTP_PORT` | HTTP only | `8765` | Port for HTTP transport. |
@@ -431,10 +507,9 @@ port can call Vectros with your credentials.
431
507
  Health probe lives at `GET /healthz` (always unauthenticated, k8s
432
508
  readiness-friendly).
433
509
 
434
- Current limitation: the server uses one upstream credential per process
435
- (the key resolved at startup). Per-request credential override via the
436
- incoming Authorization header is a planned enhancement. For now, deploy one
437
- server per credential boundary you want.
510
+ The server uses one upstream credential per process (the key resolved at
511
+ startup); the incoming Authorization header is not used to choose another.
512
+ Deploy one server per credential boundary you want.
438
513
 
439
514
  ## Programmatic use (advanced)
440
515
 
@@ -496,29 +571,31 @@ design-time layer that defines the data model.
496
571
  If one of these belongs on your agent's surface, that's worth telling us — the
497
572
  line is drawn on purpose and can be redrawn with a reason.
498
573
 
499
- ## What this server doesn't do (yet)
574
+ ## What this server doesn't do
500
575
 
501
- - **No prompts capability** — `/rag` and `/ingest_pdf` slash-command
502
- templates land in a future release. (Provisioning — the `bootstrap` command — lives
576
+ - **No prompts capability** — the server offers tools and resources, not
577
+ slash-command templates. (Provisioning — the `bootstrap` command — lives
503
578
  in the separate [`@vectros-ai/cli`](https://www.npmjs.com/package/@vectros-ai/cli)
504
579
  package, above.)
505
- - **HTTP transport is single-tenant per process** — per-request
506
- credential override via incoming Authorization header is a v1.0+
507
- enhancement.
580
+ - **HTTP transport is single-tenant per process** — it does not take a
581
+ per-request credential from the incoming Authorization header.
508
582
  - **No Python implementation** — TS only. Python users can `npx`
509
583
  this server from any project.
510
584
  - **`rag_ask` and `document_ask` are not natively streaming** —
511
585
  full answer aggregated before the tool returns. Progress
512
- notifications cover the latency. Native MCP-spec streaming lands
513
- when the spec stabilizes.
586
+ notifications cover the latency.
514
587
 
515
- The server is on a pre-1.0 track toward a stable 1.0 release.
588
+ The server is pre-1.0; the [CHANGELOG](./CHANGELOG.md) lists what changed in each release.
516
589
 
517
590
  ## Rate limits
518
591
 
519
592
  Tool calls hit the same per-minute rate limits as any API client; the
520
- [rate limits guide](https://docs.vectros.ai/guides/operations-trust/rate-limits) says which requests count. On a `429` the tool returns the error with `HTTP 429` and `errorCode: RATE_LIMITED`, so the agent can pace and retry
521
- rather than blind-retrying. The guide also lists
593
+ [rate limits guide](https://docs.vectros.ai/guides/operations-trust/rate-limits) says which requests count. On a rate-limit `429` the tool returns the error with `HTTP 429` and `errorCode: RATE_LIMITED`, so the agent can pace and retry
594
+ rather than blind-retrying. `rag_ask` and `document_ask` can also return `429` with `errorCode: BALANCE_BUSY` (your pre-paid
595
+ balance is momentarily busy with your other concurrent requests: not a rate limit and not a shortage, so do not top up;
596
+ retry shortly) or `503` with `errorCode: BALANCE_UNAVAILABLE` (a temporary fault interrupted the balance step; also not a
597
+ shortage; retry shortly). A `402` means the balance is short (`INSUFFICIENT_BALANCE`) or the plan's usage limit is reached (`SUBSCRIPTION_LIMIT_EXCEEDED`). A `503` with no `errorCode` on a call that names a `providerAlias` means the platform cannot open the stored provider key: retry shortly, and enter the key again in the developer portal if it persists. The tool returns the message, `errorCode` and
598
+ `requestId`, not the `Retry-After` header. The guide also lists
522
599
  the per-plan limits.
523
600
 
524
601
  ## Building from source