@vectros-ai/mcp-server 0.17.0 → 0.17.1

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,110 @@
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.17.1 — 2026-09-17
7
+
8
+ ### Security
9
+
10
+ - **README no longer instructs committing a live API key.** Both "Configure manually" examples
11
+ (Claude Desktop and Claude Code) led with a JSON snippet embedding a real `ssk_live_...` value,
12
+ and the Claude Code section explicitly said to commit the resulting `.mcp.json` "to share the
13
+ server with the repo" — on the page that renders as this package's npm landing page. Both
14
+ sections now lead with the keyring-based config (no `env` block, no secret in the file — the
15
+ server resolves the key from the local `vectros` CLI keyring, same as before) and explicitly warn
16
+ against committing a config that does carry a real key.
17
+
18
+ ### Added
19
+
20
+ - **All 23 tools now declare MCP annotations** (`readOnlyHint`/`destructiveHint`/`idempotentHint`)
21
+ in the actual `tools/list` response, not just their own source — a host previously had nothing
22
+ to gate a confirmation prompt on, so every tool looked alike including the deletes and the
23
+ batch-write. Annotated per tool against what its handler actually calls, not its name:
24
+ - Reads with no real-money leg (`hybrid_search`, `record_get`/`_query`/`_batch_get`,
25
+ `document_get`/`_query`, `folder_query`, `list_schemas`, `current_identity`,
26
+ `lookup_principal`, `version_history`) are `readOnlyHint: true`.
27
+ - `rag_ask` and `document_ask` are **not** read-only: both reserve an atomic hold against the
28
+ caller's prepaid inference balance before generation and debit it on completion, which can
29
+ trigger a configured auto-recharge against a payment method on file. Also not idempotent —
30
+ every repeat charges again, and generation is non-deterministic.
31
+ - `record_create`, `document_ingest`, and `record_batch_write` each dedupe by an OPTIONAL
32
+ `externalId` — supplying it makes a retry converge, omitting it does not — so all three are
33
+ annotated for that less-safe default (`idempotentHint: false`), not the safer opt-in;
34
+ `document_ingest` and `record_batch_write` are additionally flagged destructive because their
35
+ `upsert:true` paths overwrite existing content.
36
+ - `folder_create` is idempotent **only when the caller supplies `slug` explicitly** — an omitted
37
+ slug is derived through a collision-probing suffix loop that returns only a value already
38
+ proved free, so a retry with no `slug` creates a new sibling folder rather than converging.
39
+ Annotated `idempotentHint: false` for that default, the same standard as the optional-key
40
+ create tools above.
41
+ - The three `*_update` tools (JSON Merge Patch) and the three `*_delete` tools are all flagged
42
+ destructive.
43
+
44
+ Verified against the real, over-the-wire `tools/list` response from the compiled binary, not the
45
+ source that builds it.
46
+
47
+ ### Fixed
48
+
49
+ - **`document_ingest` in file mode now works against an API that makes presigned upload URLs
50
+ single-use.** Such an API bakes a conditional-write header into the upload URL's signature and
51
+ names it in the upload response (`requiredHeaderName` / `requiredHeaderValue`); the tool's PUT
52
+ omitted it, so storage rejected the upload with a 403 and the tool reported the document as
53
+ created but incomplete. The tool now sends whatever header the response names, and no extra
54
+ header when the response names none, so it works against API versions on either side of the
55
+ change.
56
+
57
+ - **A failed startup could abort the whole process with a native Windows crash instead of the
58
+ server's own exit code.** Both entry points (`vectros-mcp-server`, `vectros-mcp-server-http`)
59
+ end EVERY startup failure path — a missing/invalid credential, a bad `--` env config, a rejected
60
+ `GET /v1/ping` check (enabled by default; `VECTROS_MCP_SKIP_PING_VALIDATION` to opt out) — with a
61
+ raw `process.exit()`. On Windows, an async operation still settling (a `fetch` for the ping check;
62
+ an `execFile` spawn out to the local CLI keyring helper for credential resolution) when
63
+ `process.exit()` runs can race libuv and abort the process, printing an `Assertion failed` line
64
+ and replacing the real exit code with `127` — the same class of defect fixed in `@vectros-ai/cli`
65
+ around the same time. Every startup-failure exit in both files now sets `process.exitCode` and
66
+ lets the event loop drain naturally, instead of hard-exiting.
67
+
68
+ This needed one adjustment `@vectros-ai/cli`'s equivalent fix didn't: both entry points register
69
+ `SIGINT`/`SIGTERM` handlers for graceful shutdown, and Node keeps a process alive for as long as
70
+ either signal has a registered listener. Registering them before the connect attempt would mean a
71
+ failed connect never actually exits under the new idiom — it hangs forever instead, waiting for a
72
+ signal that will never come. Both files register those handlers only after a successful connect,
73
+ so a failed startup still exits promptly; the alternative (register early, make the shutdown
74
+ handler itself exit-code-safe too) doesn't work here, because the ping check's underlying fetch
75
+ has no timeout and no cancellation — that path trades the crash for a possible silent hang on a
76
+ stuck connection instead of fixing it.
77
+
78
+ - **Two integration tests carried an internal issue number and internal review-process wording**
79
+ (a bare tracker reference in two test names/comments describing the exit-code fix above, and one
80
+ comment describing a defect an earlier internal review pass had caught). This package's GitHub
81
+ source mirror ships `tests/` verbatim, so both leaked into the public repo. Reworded to
82
+ self-contained descriptive text; no behavioral change.
83
+
84
+ - **Four more source comments carried an internal workstream/finding code**, on the base-URL
85
+ SSRF/credential-exfil guard in `cli.ts`, `cli-http.ts`, `server.ts`, and its test — found on a
86
+ later sweep with a wider scan pattern. The substantive rationale was already self-contained in
87
+ each comment; only the bare internal code was dropped. No behavioral change.
88
+
89
+ - **One more source comment on that same base-URL guard named a sibling package's file by
90
+ monorepo-relative path** (`base-url.ts`'s own doc comment, describing that the same guard is
91
+ ported into another package's CLI) — found by a post-merge audit. Reworded to describe the
92
+ sibling generically. No behavioral change.
93
+
94
+ - **One source comment named an internal backend class by name** (`record_query.ts`, describing
95
+ how a composite field's identity is joined on the backend). Reworded to describe the mechanism
96
+ without the class name. No behavioral change.
97
+
98
+ ### Docs
99
+
100
+ - **`current_identity`'s capability-gap list now includes `trigger-control-plane-grant`**, the
101
+ sixth named `granted_capabilities` value, alongside the five it already tracked. **`document_get`'s
102
+ `downloadUrl` description now notes the platform always forces `attachment` disposition** on
103
+ download, so a caller expecting inline rendering of a safe type knows to expect a save prompt
104
+ instead. No behavior changed — both were description-only gaps.
105
+
106
+ ### Changed
107
+
108
+ - **Dependency maintenance** — repinned the bundled `@vectros-ai/sdk` to `0.44.0`.
109
+
6
110
  ## 0.17.0 — 2026-09-07
7
111
 
8
112
  ### Added
package/README.md CHANGED
@@ -123,6 +123,29 @@ Precision is the pitch — what this server deliberately does *not* do:
123
123
 
124
124
  ## Configure manually (Claude Desktop or any MCP client)
125
125
 
126
+ If `@vectros-ai/cli` is installed **globally** (`npm install -g @vectros-ai/cli`,
127
+ not a one-off `npx` run — the server needs `vectros` to still be on `PATH`
128
+ later, when IT runs, not just while bootstrap ran) and you've run
129
+ `vectros bootstrap` with it, omit the `env` block entirely — the server
130
+ resolves your key from the local `vectros` CLI keyring automatically (see
131
+ [Credential resolution](#credential-resolution) below). `vectros login` alone
132
+ does **not** do this — it stores a separate sign-in session, not this key —
133
+ so `bootstrap` is the step that actually has to have run:
134
+
135
+ ```json
136
+ {
137
+ "mcpServers": {
138
+ "vectros": {
139
+ "command": "npx",
140
+ "args": ["-y", "@vectros-ai/mcp-server"]
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ No CLI installed, or a machine you can't log in on? Set the key directly
147
+ instead:
148
+
126
149
  ```json
127
150
  {
128
151
  "mcpServers": {
@@ -137,34 +160,53 @@ Precision is the pitch — what this server deliberately does *not* do:
137
160
  }
138
161
  ```
139
162
 
163
+ This file lives under Claude Desktop's own per-user app-support directory,
164
+ not a shared repo — but a real key pasted into it is still a live secret at
165
+ rest: don't paste it into a chat, ticket, or screenshot with the value
166
+ intact, and prefer the keyring form above whenever you can.
167
+
140
168
  Restart Claude Desktop. The agent now sees the Vectros tools and
141
169
  two resources as callable surfaces.
142
170
 
143
171
  ## Configure manually (Claude Code)
144
172
 
145
- Claude Code reads a project-scoped `.mcp.json` with the same shape — drop this
146
- at your project root (commit it to share the server with the repo):
173
+ Claude Code reads a project-scoped `.mcp.json` with the same shape.
174
+ **Never commit a real key into it** — `.mcp.json` is exactly the kind of file
175
+ teams check in to share a project's tooling, and a live `ssk_*`/`sk_*` value
176
+ inside it is a credential leak the moment it lands in git history, not just
177
+ if the repo is public.
178
+
179
+ The way to share this config safely: commit the entry with **no `env` block
180
+ at all**, and let each developer's own `vectros` CLI keyring supply the key
181
+ (see [Credential resolution](#credential-resolution) below — this is the
182
+ same delegation `git credential` / `docker-credential-*` use). This needs
183
+ each teammate to have `@vectros-ai/cli` installed **globally** and to have
184
+ run `vectros bootstrap` with it — `npx`-ing the CLI once, or running
185
+ `vectros login` alone (a separate sign-in session, not this key), leaves
186
+ nothing on `PATH` or in the keyring for the server to find later:
147
187
 
148
188
  ```json
149
189
  {
150
190
  "mcpServers": {
151
191
  "vectros": {
152
192
  "command": "npx",
153
- "args": ["-y", "@vectros-ai/mcp-server"],
154
- "env": {
155
- "VECTROS_API_KEY": "ssk_live_..."
156
- }
193
+ "args": ["-y", "@vectros-ai/mcp-server"]
157
194
  }
158
195
  }
159
196
  }
160
197
  ```
161
198
 
162
- Or let Claude Code's CLI write it for you:
199
+ Or let Claude Code's CLI write that keyring-based entry for you:
163
200
 
164
201
  ```bash
165
- claude mcp add vectros -e VECTROS_API_KEY=ssk_live_... -- npx -y @vectros-ai/mcp-server
202
+ claude mcp add vectros -- npx -y @vectros-ai/mcp-server
166
203
  ```
167
204
 
205
+ If a machine genuinely has no `vectros` CLI installed, you can pass the key
206
+ directly with `-e VECTROS_API_KEY=ssk_live_...` — but then keep that config
207
+ **local**: add `.mcp.json` to `.gitignore` first, rather than committing it
208
+ with the key inside.
209
+
168
210
  Add `-e VECTROS_API_BASE_URL=https://api.staging.vectros.ai` for a non-production
169
211
  environment.
170
212
 
@@ -213,7 +255,7 @@ resolves to its main repo's `.mcp.json` — add and open from the same project.
213
255
  |---|---|
214
256
  | `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. |
215
257
  | `document_query` | Query documents by lookup field (equality / range / prefix, with `asc`/`desc` ordering) or list mode (filter by ownership + type). |
216
- | `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). |
258
+ | `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). |
217
259
  | `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`. |
218
260
  | `document_delete` | Permanently delete a document by id (removes it and its indexed content). |
219
261
 
@@ -230,7 +272,7 @@ resolves to its main repo's `.mcp.json` — add and open from the same project.
230
272
 
231
273
  | Tool | What it does |
232
274
  |---|---|
233
- | `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) — 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`). |
275
+ | `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`). |
234
276
  | `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. |
235
277
  | `version_history` | Read the audit/version trail (CREATE/UPDATE/DELETE, with actor + diff) for one record or document. Read-only. |
236
278