specguard-mcp 0.1.25 → 0.1.27
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/README.md +28 -1
- package/dist/src/config.d.ts +76 -8
- package/dist/src/config.js +41 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +5 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/support/specguard-api.d.ts +8 -3
- package/dist/src/support/specguard-api.js +71 -7
- package/dist/src/support/specguard-api.js.map +1 -1
- package/dist/src/tools/get-server-version.d.ts +50 -0
- package/dist/src/tools/get-server-version.js +88 -0
- package/dist/src/tools/get-server-version.js.map +1 -0
- package/dist/src/tools/index.d.ts +20 -0
- package/dist/src/tools/index.js +22 -0
- package/dist/src/tools/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ refuses to boot and takes the tools that needed no configuration down with it.
|
|
|
32
32
|
|
|
33
33
|
| Variable | Needed by | Default | What it is |
|
|
34
34
|
| --- | --- | --- | --- |
|
|
35
|
-
| `SPECGUARD_ENDPOINT` | `get_repository_overview`, `list_repositories`, `add_repository`, `registrable_repositories` | — | your SpecGuard instance's root URL, **including the scheme** — e.g. `https://specguard.example.com`, or `http://localhost:3000`. A value with no scheme is refused by name (`SPECGUARD_ENDPOINT is not a usable URL: "sg.example.com"`) rather than surfacing later as an opaque failure. `SPECGUARD_URL` is accepted as an alias, and is the name every message uses when it is the one you set. A blank value counts as unset, so leaving `SPECGUARD_ENDPOINT` empty in a templated config falls through to `SPECGUARD_URL` instead of suppressing it |
|
|
35
|
+
| `SPECGUARD_ENDPOINT` | `get_repository_overview`, `get_server_version`, `list_repositories`, `add_repository`, `registrable_repositories` | — | your SpecGuard instance's root URL, **including the scheme** — e.g. `https://specguard.example.com`, or `http://localhost:3000`. A value with no scheme is refused by name (`SPECGUARD_ENDPOINT is not a usable URL: "sg.example.com"`) rather than surfacing later as an opaque failure. `SPECGUARD_URL` is accepted as an alias, and is the name every message uses when it is the one you set. A blank value counts as unset, so leaving `SPECGUARD_ENDPOINT` empty in a templated config falls through to `SPECGUARD_URL` instead of suppressing it. `get_server_version` needs only this variable — it sends no API key, because the version route is unauthenticated by design |
|
|
36
36
|
| `SPECGUARD_API_KEY` | `get_repository_overview`, `near_duplicate_clusters` (default calls) | — | an agent/CI API key (`sgk_…`) issued by that deployment — a **per-repository** key, which is the single repository those tools answer about by default |
|
|
37
37
|
| `SPECGUARD_USER_API_KEY` | `list_repositories` (fallback), `add_repository`, `registrable_repositories`, `remove_repository` (fallback), `create_repository_api_key` (fallback), `revoke_repository_api_key` (fallback), `list_repository_api_keys` (fallback), `list_repository_agent_keys` (fallback), `revoke_repository_agent_key` (fallback), `list_repository_agent_keys_presented_revoked` (fallback), `list_repository_members` (fallback), `add_repository_member` (fallback), `update_repository_member_permissions` (fallback), `remove_repository_member` (fallback), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` (fallback), `rename_repository` | — | a **user** API key (`sgu_…`), minted from that deployment's account page. A different credential from the one above, not a second place to put the same value: SpecGuard decides which of them a request may use from the token's prefix, before it reads anything, and answers `401` for the other one. Set whichever your tools need — both, if you use both |
|
|
38
38
|
| `SPECGUARD_AGENT_API_KEY` | `list_repositories` (preferred), `remove_repository` (preferred), `create_repository_api_key` (preferred), `revoke_repository_api_key` (preferred), `list_repository_api_keys` (preferred), `list_repository_agent_keys` (preferred), `revoke_repository_agent_key` (preferred), `list_repository_agent_keys_presented_revoked` (preferred), `list_repository_members` (preferred), `add_repository_member` (preferred), `update_repository_member_permissions` (preferred), `remove_repository_member` (preferred), `get_repository_overview` / `near_duplicate_clusters` **with** `repository` (preferred) | — | an **agent** API key (`sga_…`), minted from that deployment's account page (Agent keys panel) with an explicit set of repositories and permissions. It speaks for nobody: its reach is exactly the set granted onto it, fixed at mint time, and every read is bounded by that set server-side. This is the credential to give an automated agent — one key, many repositories, none of a person's rights. When it and `SPECGUARD_USER_API_KEY` are both set, every tool that answers either key — `list_repositories`, `remove_repository`, the members tools, the key-lifecycle tools, and `get_repository_overview` / `near_duplicate_clusters` **with** `repository` — uses **this** one, so discovery stays inside the set the other tools can reach |
|
|
@@ -350,6 +350,33 @@ a finding and not a disclosure someone forgot.
|
|
|
350
350
|
Figures are `null` where CI did not report them. A `null` means *not measured*; it is never a zero,
|
|
351
351
|
because a zero would read as a measurement that was taken.
|
|
352
352
|
|
|
353
|
+
### `get_server_version`
|
|
354
|
+
|
|
355
|
+
Reports **which build of the SpecGuard deployment is answering**, read from the deployment's own
|
|
356
|
+
unauthenticated root-level `GET /version` — the figure the release bot's `VERSION` file carries,
|
|
357
|
+
served as `{"version": "0.1.46"}`-shaped JSON and passed through verbatim as `{version}`.
|
|
358
|
+
|
|
359
|
+
**This is the server's build, not this bridge's.** The version in the initialize handshake's
|
|
360
|
+
`serverInfo` and the `specguard-mcp/<version>` User-Agent describe *this bridge* — a different
|
|
361
|
+
component, released on its own cadence — so never read one as the other. Pinning which build's
|
|
362
|
+
crafted 404/400 message sentence a contract suite asserts, verifying that a deployment upgrade took
|
|
363
|
+
effect, or naming the build that produced a behavior is *this* tool's question; the handshake cannot
|
|
364
|
+
answer it.
|
|
365
|
+
|
|
366
|
+
**`version: null` is an honest answer, not an error.** The deployment is up but cannot say its own
|
|
367
|
+
build — its `VERSION` file was missing or unreadable at boot — and the platform serves that
|
|
368
|
+
deliberately, because an unverifiable identity beats a 500 from the one endpoint whose whole job is
|
|
369
|
+
to be askable. The null is passed through exactly as served, never replaced with a guessed value.
|
|
370
|
+
|
|
371
|
+
**A 404 means the deployment predates the route: the endpoint is right and the build is old.** The
|
|
372
|
+
error text names the endpoint as possibly misconfigured, because a non-contract 404 body names no
|
|
373
|
+
cause — when the other tools work against the same endpoint, read that error as *"the deployment
|
|
374
|
+
needs upgrading"*, not as a wrong URL.
|
|
375
|
+
|
|
376
|
+
**Needs no API key of any kind** — the route is unauthenticated by design — so it works with
|
|
377
|
+
`SPECGUARD_ENDPOINT` alone, and it is the one tool here that sends no `Authorization` header. Takes
|
|
378
|
+
no arguments.
|
|
379
|
+
|
|
353
380
|
### `list_repositories`
|
|
354
381
|
|
|
355
382
|
Lists the SpecGuard repositories this server's key may open — *what can I ask about*, which is the
|
package/dist/src/config.d.ts
CHANGED
|
@@ -107,7 +107,25 @@ export declare const DEFAULT_LINT_COMMAND: readonly string[];
|
|
|
107
107
|
export declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
108
108
|
/** Reads config from an environment. Never throws — see the note above. */
|
|
109
109
|
export declare function loadConfig(env?: NodeJS.ProcessEnv): Config;
|
|
110
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* What a tool that talks to the SpecGuard API needs, once both halves are known.
|
|
112
|
+
*
|
|
113
|
+
* `apiKey` and `credential` are OPTIONAL here, and that is the credential-free
|
|
114
|
+
* ask speaking (`requireEndpointApiConfig` below): an unauthenticated endpoint
|
|
115
|
+
* needs an endpoint and no key, so the type a transport function accepts cannot
|
|
116
|
+
* demand a credential the request will never present. `undefined` is a
|
|
117
|
+
* first-class value, never a gap — the transport reads it as "send no
|
|
118
|
+
* `Authorization` header", and `describeFailure` reads it as "this ask cannot
|
|
119
|
+
* have a key problem".
|
|
120
|
+
*
|
|
121
|
+
* Every credentialled `require*` helper returns the NARROWED shape,
|
|
122
|
+
* `CredentialledApiConfig` — the same object with both halves bound, which is
|
|
123
|
+
* what they have always built. Narrowing in the return type rather than keeping
|
|
124
|
+
* `ApiConfig` strict is what lets the optional fields exist without loosening
|
|
125
|
+
* the 18 existing tools: a caller holding a credentialled config still knows
|
|
126
|
+
* `apiKey` is a `string` and `credential` is a `Credential`, and TypeScript
|
|
127
|
+
* keeps enforcing that where it is true.
|
|
128
|
+
*/
|
|
111
129
|
export interface ApiConfig {
|
|
112
130
|
readonly endpoint: string;
|
|
113
131
|
/**
|
|
@@ -126,7 +144,15 @@ export interface ApiConfig {
|
|
|
126
144
|
* added later inherits correct naming the same way it inherits the URL check.
|
|
127
145
|
*/
|
|
128
146
|
readonly endpointVariable: EndpointVariable;
|
|
129
|
-
|
|
147
|
+
/**
|
|
148
|
+
* The key this request presents, when it presents one.
|
|
149
|
+
*
|
|
150
|
+
* `undefined` means the request presents NO `Authorization` header — never
|
|
151
|
+
* "a key we forgot to fill in". Every credentialled helper binds a `string`
|
|
152
|
+
* here (see `CredentialledApiConfig`), so for the 18 existing tools nothing
|
|
153
|
+
* about the wire changes.
|
|
154
|
+
*/
|
|
155
|
+
readonly apiKey: string | undefined;
|
|
130
156
|
/**
|
|
131
157
|
* WHICH credential `apiKey` is — the variable it was read from, the prefix
|
|
132
158
|
* that variable is expected to hold, and how to say both in a sentence.
|
|
@@ -139,11 +165,28 @@ export interface ApiConfig {
|
|
|
139
165
|
* sentences that are all false of it — naming a variable its operator may
|
|
140
166
|
* never have set. Carrying the answer rather than re-deriving it per tool is
|
|
141
167
|
* what makes the next credential-scoped tool inherit correct naming the same
|
|
142
|
-
* way it inherits the URL check.
|
|
168
|
+
* way it inherits the URL check. Optional here for exactly that reason and
|
|
169
|
+
* no other: a credential-free ask has no credential to describe, and
|
|
170
|
+
* inventing one would invent a requirement the deployment does not have.
|
|
143
171
|
*/
|
|
144
|
-
readonly credential: Credential;
|
|
172
|
+
readonly credential: Credential | undefined;
|
|
145
173
|
readonly requestTimeoutMs: number;
|
|
146
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* `ApiConfig` with BOTH halves bound — the shape every credentialled `require*`
|
|
177
|
+
* helper has always returned, now said in the type.
|
|
178
|
+
*
|
|
179
|
+
* A NARROWING, not a parallel type: `CredentialledApiConfig` extends
|
|
180
|
+
* `ApiConfig`, so it flows into every transport function unchanged, while a
|
|
181
|
+
* caller holding one still knows `apiKey` is a `string` and `credential` is a
|
|
182
|
+
* `Credential` — the guarantee every credentialled call site and test relies
|
|
183
|
+
* on. Only `requireEndpointApiConfig` returns the wider shape, and only the
|
|
184
|
+
* transport reads the two optional fields there.
|
|
185
|
+
*/
|
|
186
|
+
export interface CredentialledApiConfig extends ApiConfig {
|
|
187
|
+
readonly apiKey: string;
|
|
188
|
+
readonly credential: Credential;
|
|
189
|
+
}
|
|
147
190
|
export type EndpointVariable = "SPECGUARD_ENDPOINT" | "SPECGUARD_URL";
|
|
148
191
|
export type ApiKeyVariable = "SPECGUARD_API_KEY" | "SPECGUARD_USER_API_KEY" | "SPECGUARD_AGENT_API_KEY";
|
|
149
192
|
/**
|
|
@@ -213,7 +256,7 @@ export declare const AGENT_CREDENTIAL: Credential;
|
|
|
213
256
|
* before this file grew a second credential calls exactly this, and gets exactly
|
|
214
257
|
* what it got.
|
|
215
258
|
*/
|
|
216
|
-
export declare function requireApiConfig(config: Config):
|
|
259
|
+
export declare function requireApiConfig(config: Config): CredentialledApiConfig;
|
|
217
260
|
/**
|
|
218
261
|
* What a tool needing the `sgu_` USER key requires — the endpoint and
|
|
219
262
|
* `SPECGUARD_USER_API_KEY`.
|
|
@@ -226,7 +269,7 @@ export declare function requireApiConfig(config: Config): ApiConfig;
|
|
|
226
269
|
* diagnostics reaches both and they cannot drift into describing the same
|
|
227
270
|
* situation differently.
|
|
228
271
|
*/
|
|
229
|
-
export declare function requireUserApiConfig(config: Config):
|
|
272
|
+
export declare function requireUserApiConfig(config: Config): CredentialledApiConfig;
|
|
230
273
|
/**
|
|
231
274
|
* What a tool needing the `sga_` AGENT key requires — the endpoint and
|
|
232
275
|
* `SPECGUARD_AGENT_API_KEY`.
|
|
@@ -238,7 +281,7 @@ export declare function requireUserApiConfig(config: Config): ApiConfig;
|
|
|
238
281
|
* tool asked about a repository its `sgk_` slot does not name calls this, and
|
|
239
282
|
* reads the plural endpoints the agent credential is served by.
|
|
240
283
|
*/
|
|
241
|
-
export declare function requireAgentApiConfig(config: Config):
|
|
284
|
+
export declare function requireAgentApiConfig(config: Config): CredentialledApiConfig;
|
|
242
285
|
/**
|
|
243
286
|
* What a tool EITHER credential serves requires — the endpoint and at least one
|
|
244
287
|
* of `SPECGUARD_AGENT_API_KEY` / `SPECGUARD_USER_API_KEY`.
|
|
@@ -271,7 +314,32 @@ export declare function requireAgentApiConfig(config: Config): ApiConfig;
|
|
|
271
314
|
* every caller because no caller describes the situation itself — holds for
|
|
272
315
|
* this helper too. The endpoint joins the same sentence when it is missing too.
|
|
273
316
|
*/
|
|
274
|
-
export declare function requireUserOrAgentApiConfig(config: Config):
|
|
317
|
+
export declare function requireUserOrAgentApiConfig(config: Config): CredentialledApiConfig;
|
|
318
|
+
/**
|
|
319
|
+
* What a tool that needs NO credential requires — just the endpoint.
|
|
320
|
+
*
|
|
321
|
+
* The fourth sibling, and the first whose answer carries no key and no
|
|
322
|
+
* `Credential`: the server's root-level `GET /version` (SPGD-1197, specguard
|
|
323
|
+
* d434c2a) answers unauthenticated BY DESIGN — the platform's own doctrine
|
|
324
|
+
* places it outside the credential seam, at the root where the no-account
|
|
325
|
+
* reads (`/up`, the schema mirror) already live. Demanding a key here would
|
|
326
|
+
* invent a requirement the deployment does not have, and the
|
|
327
|
+
* credential-free config this returns is what keeps the transport from
|
|
328
|
+
* sending an `Authorization` header at all.
|
|
329
|
+
*
|
|
330
|
+
* The endpoint is REQUIRED and PARSED through the shared `requireHttpUrl`,
|
|
331
|
+
* exactly as the credentialled body does — a malformed value is the same
|
|
332
|
+
* config typo with the same legible answer, and a helper that skipped the
|
|
333
|
+
* parse would defer it to a bare `TypeError` at request time, read by the
|
|
334
|
+
* server's error boundary as a defect in the bridge.
|
|
335
|
+
*
|
|
336
|
+
* The missing-endpoint message is its OWN sentence rather than the shared
|
|
337
|
+
* body's, and that is deliberate: the shared body's sentence exists to name
|
|
338
|
+
* the key variables an operator must choose between, and this ask has none —
|
|
339
|
+
* folding it through would produce a message demanding a key nobody needs to
|
|
340
|
+
* set. One sentence, naming only the endpoint variable the operator can fix.
|
|
341
|
+
*/
|
|
342
|
+
export declare function requireEndpointApiConfig(config: Config): ApiConfig;
|
|
275
343
|
/**
|
|
276
344
|
* Splits a configured command into argv WITHOUT a shell, honouring single and
|
|
277
345
|
* double quotes so a path with a space survives.
|
package/dist/src/config.js
CHANGED
|
@@ -184,8 +184,48 @@ export function requireUserOrAgentApiConfig(config) {
|
|
|
184
184
|
return requireCredentialledApiConfig(config, undefined, USER_CREDENTIAL, [AGENT_CREDENTIAL]);
|
|
185
185
|
}
|
|
186
186
|
/**
|
|
187
|
-
*
|
|
187
|
+
* What a tool that needs NO credential requires — just the endpoint.
|
|
188
|
+
*
|
|
189
|
+
* The fourth sibling, and the first whose answer carries no key and no
|
|
190
|
+
* `Credential`: the server's root-level `GET /version` (SPGD-1197, specguard
|
|
191
|
+
* d434c2a) answers unauthenticated BY DESIGN — the platform's own doctrine
|
|
192
|
+
* places it outside the credential seam, at the root where the no-account
|
|
193
|
+
* reads (`/up`, the schema mirror) already live. Demanding a key here would
|
|
194
|
+
* invent a requirement the deployment does not have, and the
|
|
195
|
+
* credential-free config this returns is what keeps the transport from
|
|
196
|
+
* sending an `Authorization` header at all.
|
|
188
197
|
*
|
|
198
|
+
* The endpoint is REQUIRED and PARSED through the shared `requireHttpUrl`,
|
|
199
|
+
* exactly as the credentialled body does — a malformed value is the same
|
|
200
|
+
* config typo with the same legible answer, and a helper that skipped the
|
|
201
|
+
* parse would defer it to a bare `TypeError` at request time, read by the
|
|
202
|
+
* server's error boundary as a defect in the bridge.
|
|
203
|
+
*
|
|
204
|
+
* The missing-endpoint message is its OWN sentence rather than the shared
|
|
205
|
+
* body's, and that is deliberate: the shared body's sentence exists to name
|
|
206
|
+
* the key variables an operator must choose between, and this ask has none —
|
|
207
|
+
* folding it through would produce a message demanding a key nobody needs to
|
|
208
|
+
* set. One sentence, naming only the endpoint variable the operator can fix.
|
|
209
|
+
*/
|
|
210
|
+
export function requireEndpointApiConfig(config) {
|
|
211
|
+
const endpointVariable = config.endpointVariable ?? DEFAULT_ENDPOINT_VARIABLE;
|
|
212
|
+
if (config.endpoint === undefined) {
|
|
213
|
+
throw new ConfigError(`This tool talks to a SpecGuard deployment, and ${endpointVariable} ` +
|
|
214
|
+
"is not set in the MCP server's environment. Set it in your MCP client's server config " +
|
|
215
|
+
`(${endpointVariable} is your deployment's root URL). This tool needs no API key — the ` +
|
|
216
|
+
"endpoint it reads answers unauthenticated by design — so no key variable is required " +
|
|
217
|
+
"here. Tools that do not reach the deployment are unaffected.");
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
endpoint: requireHttpUrl(config.endpoint, endpointVariable),
|
|
221
|
+
endpointVariable,
|
|
222
|
+
apiKey: undefined,
|
|
223
|
+
credential: undefined,
|
|
224
|
+
requestTimeoutMs: config.requestTimeoutMs,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Both halves or a legible failure — never one half and a surprise later.
|
|
189
229
|
* Reported together rather than one at a time: an operator who set neither
|
|
190
230
|
* should learn that in one round trip instead of fixing a variable, re-calling,
|
|
191
231
|
* and being told about the next one. That property is why the two `require*`
|
package/dist/src/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA4G1C,MAAM,CAAC,MAAM,oBAAoB,GAAsB,CAAC,gBAAgB,CAAC,CAAC;AAC1E,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAEjD,2EAA2E;AAC3E,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAC5D,6EAA6E;IAC7E,qEAAqE;IACrE,4EAA4E;IAC5E,8EAA8E;IAC9E,0EAA0E;IAC1E,6EAA6E;IAC7E,8EAA8E;IAC9E,8EAA8E;IAC9E,6EAA6E;IAC7E,mEAAmE;IACnE,8EAA8E;IAC9E,MAAM,gBAAgB,GACpB,QAAQ,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,KAAK,SAAS;QAC/C,CAAC,CAAC,oBAAoB;QACtB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,KAAK,SAAS;YAC5C,CAAC,CAAC,eAAe;YACjB,CAAC,CAAC,SAAS,CAAC;IAElB,OAAO;QACL,QAAQ,EAAE,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC/F,gBAAgB;QAChB,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAC1C,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACnD,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACrD,WAAW,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,oBAAoB;QACxE,gBAAgB,EAAE,eAAe,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,IAAI,0BAA0B;KAC7F,CAAC;AACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createServer, SERVER_NAME, SERVER_VERSION, type CreateServerOptions } from "./server.js";
|
|
2
|
-
export { loadConfig, requireApiConfig, requireUserApiConfig, requireAgentApiConfig, requireUserOrAgentApiConfig, tokenise, type ApiConfig, type ApiKeyVariable, type Config, type Credential, } from "./config.js";
|
|
2
|
+
export { loadConfig, requireApiConfig, requireUserApiConfig, requireAgentApiConfig, requireUserOrAgentApiConfig, requireEndpointApiConfig, tokenise, type ApiConfig, type ApiKeyVariable, type Config, type Credential, type CredentialledApiConfig, } from "./config.js";
|
|
3
3
|
export { ApiError, ArgumentError, CommandError, ConfigError, SpecGuardMcpError } from "./errors.js";
|
|
4
4
|
export { TOOLS } from "./tools/index.js";
|
|
5
5
|
export type { ToolContext, ToolDefinition, ToolResult } from "./tools/types.js";
|
package/dist/src/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export { createServer, SERVER_NAME, SERVER_VERSION } from "./server.js";
|
|
2
2
|
// The require* helpers are re-exported together rather than left behind each
|
|
3
3
|
// other: they are one seam over one credential machinery, now with three
|
|
4
|
-
// variables, and a consumer that can name only
|
|
5
|
-
// deep-import past this entrypoint to reach the rest
|
|
6
|
-
// unnameable-but-typed state `test/index.test.ts` exists to keep
|
|
7
|
-
// error taxonomy.
|
|
8
|
-
export { loadConfig, requireApiConfig, requireUserApiConfig, requireAgentApiConfig, requireUserOrAgentApiConfig, tokenise, } from "./config.js";
|
|
4
|
+
// variables and one credential-free sibling, and a consumer that can name only
|
|
5
|
+
// part of it would have to deep-import past this entrypoint to reach the rest
|
|
6
|
+
// — the same unnameable-but-typed state `test/index.test.ts` exists to keep
|
|
7
|
+
// out of the error taxonomy.
|
|
8
|
+
export { loadConfig, requireApiConfig, requireUserApiConfig, requireAgentApiConfig, requireUserOrAgentApiConfig, requireEndpointApiConfig, tokenise, } from "./config.js";
|
|
9
9
|
export { ApiError, ArgumentError, CommandError, ConfigError, SpecGuardMcpError } from "./errors.js";
|
|
10
10
|
export { TOOLS } from "./tools/index.js";
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAA4B,MAAM,aAAa,CAAC;AAClG,6EAA6E;AAC7E,yEAAyE;AACzE
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAA4B,MAAM,aAAa,CAAC;AAClG,6EAA6E;AAC7E,yEAAyE;AACzE,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,6BAA6B;AAC7B,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC3B,wBAAwB,EACxB,QAAQ,GAMT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpG,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { requireAgentApiConfig, requireApiConfig, requireUserApiConfig, requireUserOrAgentApiConfig, type ApiConfig, type Config } from "../config.js";
|
|
1
|
+
import { requireAgentApiConfig, requireApiConfig, requireEndpointApiConfig, requireUserApiConfig, requireUserOrAgentApiConfig, type ApiConfig, type Config, type CredentialledApiConfig } from "../config.js";
|
|
2
2
|
/**
|
|
3
3
|
* The SpecGuard HTTP client — a Bearer key and a path, and nothing else.
|
|
4
4
|
*
|
|
@@ -6,6 +6,11 @@ import { requireAgentApiConfig, requireApiConfig, requireUserApiConfig, requireU
|
|
|
6
6
|
* here: this carries the operator's key and reports what came back. The bridge
|
|
7
7
|
* adds no credentials of its own and makes no access decisions, so there is no
|
|
8
8
|
* second place for the permission model to be got wrong.
|
|
9
|
+
*
|
|
10
|
+
* The key is PRESENT-CONDITIONAL since SPGD-1200: every credentialled helper
|
|
11
|
+
* binds one and it rides every request as before, while a credential-free ask
|
|
12
|
+
* (`requireEndpointApiConfig`, the unauthenticated `/version`) presents NO
|
|
13
|
+
* `Authorization` header at all rather than `Bearer ` with nothing after it.
|
|
9
14
|
*/
|
|
10
15
|
export declare function getJson(api: ApiConfig, path: string, query: Record<string, string | undefined>, fetchImpl: typeof globalThis.fetch): Promise<unknown>;
|
|
11
16
|
/**
|
|
@@ -139,7 +144,7 @@ export declare function getJsonObject(api: ApiConfig, path: string, query: Recor
|
|
|
139
144
|
* one spelling of "no ask".
|
|
140
145
|
*/
|
|
141
146
|
export declare function repositoryTarget(config: Config, repository: string | undefined): {
|
|
142
|
-
api:
|
|
147
|
+
api: CredentialledApiConfig;
|
|
143
148
|
path: string;
|
|
144
149
|
};
|
|
145
|
-
export { requireApiConfig, requireUserApiConfig, requireAgentApiConfig, requireUserOrAgentApiConfig };
|
|
150
|
+
export { requireApiConfig, requireUserApiConfig, requireAgentApiConfig, requireUserOrAgentApiConfig, requireEndpointApiConfig, };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { requireAgentApiConfig, requireApiConfig, requireUserApiConfig, requireUserOrAgentApiConfig, } from "../config.js";
|
|
1
|
+
import { requireAgentApiConfig, requireApiConfig, requireEndpointApiConfig, requireUserApiConfig, requireUserOrAgentApiConfig, } from "../config.js";
|
|
2
2
|
import { ApiError } from "../errors.js";
|
|
3
3
|
/**
|
|
4
4
|
* The SpecGuard HTTP client — a Bearer key and a path, and nothing else.
|
|
@@ -7,6 +7,11 @@ import { ApiError } from "../errors.js";
|
|
|
7
7
|
* here: this carries the operator's key and reports what came back. The bridge
|
|
8
8
|
* adds no credentials of its own and makes no access decisions, so there is no
|
|
9
9
|
* second place for the permission model to be got wrong.
|
|
10
|
+
*
|
|
11
|
+
* The key is PRESENT-CONDITIONAL since SPGD-1200: every credentialled helper
|
|
12
|
+
* binds one and it rides every request as before, while a credential-free ask
|
|
13
|
+
* (`requireEndpointApiConfig`, the unauthenticated `/version`) presents NO
|
|
14
|
+
* `Authorization` header at all rather than `Bearer ` with nothing after it.
|
|
10
15
|
*/
|
|
11
16
|
export async function getJson(api, path, query, fetchImpl) {
|
|
12
17
|
const url = new URL(`${api.endpoint}${path}`);
|
|
@@ -181,6 +186,35 @@ export async function getJsonObject(api, path, query, fetchImpl) {
|
|
|
181
186
|
* mode `errors.ts` exists to avoid.
|
|
182
187
|
*/
|
|
183
188
|
const TIMED_OUT = Symbol("specguard-api deadline");
|
|
189
|
+
/**
|
|
190
|
+
* This bridge's wire identity, resolved at REQUEST time.
|
|
191
|
+
*
|
|
192
|
+
* `server.ts` owns `SERVER_VERSION` (manifest-derived since SPGD-1190) and this
|
|
193
|
+
* transport needs it on every request — but a STATIC import would close the
|
|
194
|
+
* graph's existing cycle the one way it cannot survive: `server.ts` imports the
|
|
195
|
+
* tool registry, the tools import this transport, and the edge back would make
|
|
196
|
+
* `tools/index.js` evaluate while whichever tool module started the load is
|
|
197
|
+
* still mid-evaluation. `tools/index.js` builds its registry in its own module
|
|
198
|
+
* body, dereferencing those in-flight tool bindings before they are
|
|
199
|
+
* initialized — a TDZ ReferenceError at boot (`Cannot access 'addRepository'
|
|
200
|
+
* before initialization`), hit the moment this import went static, in every
|
|
201
|
+
* load order that enters through a tool module rather than through
|
|
202
|
+
* `server.ts`. A lazy READ of the constant is not enough; the LOAD itself has
|
|
203
|
+
* to wait until a request.
|
|
204
|
+
*
|
|
205
|
+
* Loading at request time is safe in every order: by the time any request can
|
|
206
|
+
* run, the whole module graph has finished evaluating, so `import()` is a
|
|
207
|
+
* module-cache hit that hands back the already-initialized export. The promise
|
|
208
|
+
* is memoized — and the `import()` call kept inside this function, never at
|
|
209
|
+
* module scope, where it would start the same evaluation re-entry at load
|
|
210
|
+
* time. The per-request cost is one awaited, already-resolved promise.
|
|
211
|
+
*/
|
|
212
|
+
let serverIdentity;
|
|
213
|
+
async function requestUserAgent() {
|
|
214
|
+
serverIdentity ??= import("../server.js");
|
|
215
|
+
const { SERVER_VERSION } = await serverIdentity;
|
|
216
|
+
return `specguard-mcp/${SERVER_VERSION}`;
|
|
217
|
+
}
|
|
184
218
|
/**
|
|
185
219
|
* Headers AND body under ONE deadline.
|
|
186
220
|
*
|
|
@@ -214,6 +248,10 @@ const TIMED_OUT = Symbol("specguard-api deadline");
|
|
|
214
248
|
async function fetchWithTimeout(url, api, fetchImpl, request) {
|
|
215
249
|
const controller = new AbortController();
|
|
216
250
|
let timer;
|
|
251
|
+
// Assembled BEFORE the deadline is armed: the deadline bounds the network
|
|
252
|
+
// call, not our own header assembly (which is a module-cache hit in every
|
|
253
|
+
// real order — see `requestUserAgent`).
|
|
254
|
+
const userAgent = await requestUserAgent();
|
|
217
255
|
const deadline = new Promise((resolve) => {
|
|
218
256
|
timer = setTimeout(() => {
|
|
219
257
|
controller.abort();
|
|
@@ -228,9 +266,20 @@ async function fetchWithTimeout(url, api, fetchImpl, request) {
|
|
|
228
266
|
fetchImpl(url, {
|
|
229
267
|
method: request.method,
|
|
230
268
|
headers: {
|
|
231
|
-
Authorization: `Bearer ${api.apiKey}`,
|
|
232
269
|
Accept: "application/json",
|
|
233
|
-
|
|
270
|
+
// The version rides the identity the platform's rejection triage
|
|
271
|
+
// stores verbatim (`specguard-mcp/<version>`), the same shape the
|
|
272
|
+
// sibling clients already send. Resolved per request — see
|
|
273
|
+
// `requestUserAgent` for why the load, not just the read, is lazy.
|
|
274
|
+
"User-Agent": userAgent,
|
|
275
|
+
// Sent only when there IS a key. The credential-free ask (SPGD-1200,
|
|
276
|
+
// `requireEndpointApiConfig`) presents nothing rather than `Bearer `
|
|
277
|
+
// with nothing after it — precisely the present-but-empty value
|
|
278
|
+
// `presence()` refuses on the way in, because a header announcing a
|
|
279
|
+
// key that is not there is a malformed request waiting for a proxy
|
|
280
|
+
// to notice. This is `Content-Type`'s conditional-header pattern,
|
|
281
|
+
// one key below, for the mirrored reason.
|
|
282
|
+
...(api.apiKey === undefined ? {} : { Authorization: `Bearer ${api.apiKey}` }),
|
|
234
283
|
// Sent only when there IS a body. A `Content-Type` on a GET announces
|
|
235
284
|
// a payload that is not there, and some deployments and proxies treat
|
|
236
285
|
// that as a malformed request rather than as a harmless header.
|
|
@@ -311,6 +360,16 @@ function timedOut(api) {
|
|
|
311
360
|
* `endpointVariable` fixes one branch down, and it gets the same remedy rather
|
|
312
361
|
* than a second hardcoded string: a tool added later inherits correct naming
|
|
313
362
|
* from the `require*` helper it already calls.
|
|
363
|
+
*
|
|
364
|
+
* The canned sentence is CREDENTIAL-CONDITIONAL since SPGD-1200: a
|
|
365
|
+
* credential-free ask cannot have a KEY problem — it presented no key, and the
|
|
366
|
+
* endpoint it reads (`/version`) never authenticates — so sentencing it to a
|
|
367
|
+
* `must be an … key` lecture would name a variable its operator never needed
|
|
368
|
+
* to set. With no credential bound the branch falls through to the generic
|
|
369
|
+
* sentence below, which shows what actually came back. The revoked-key arm
|
|
370
|
+
* above stays unconditional on purpose: it is keyed on the BODY the platform
|
|
371
|
+
* served, not on what this side sent, and surfacing the platform's own
|
|
372
|
+
* sentence is never the wrong answer.
|
|
314
373
|
*/
|
|
315
374
|
function describeFailure(status, body, api) {
|
|
316
375
|
if (status === 401) {
|
|
@@ -320,9 +379,14 @@ function describeFailure(status, body, api) {
|
|
|
320
379
|
const revoked = revokedCredentialMessage(body);
|
|
321
380
|
if (revoked !== undefined)
|
|
322
381
|
return new ApiError(revoked, status);
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
382
|
+
// A credential-free ask falls through to the generic sentence — see the
|
|
383
|
+
// header above. This branch only speaks when there is a credential whose
|
|
384
|
+
// variable and prefix a sentence about a key can truthfully name.
|
|
385
|
+
if (api.credential !== undefined) {
|
|
386
|
+
const { variable, prefix, rejection } = api.credential;
|
|
387
|
+
return new ApiError(`SpecGuard rejected the API key (401). ${variable} must be an ${prefix}… key issued by ` +
|
|
388
|
+
`${api.endpoint} ${rejection}.`, status);
|
|
389
|
+
}
|
|
326
390
|
}
|
|
327
391
|
if (status === 404) {
|
|
328
392
|
// Order by certainty: a body that names its own cause beats the heuristic.
|
|
@@ -537,5 +601,5 @@ export function repositoryTarget(config, repository) {
|
|
|
537
601
|
: `/api/v1/repositories/${encodeURIComponent(repository)}`;
|
|
538
602
|
return { api, path };
|
|
539
603
|
}
|
|
540
|
-
export { requireApiConfig, requireUserApiConfig, requireAgentApiConfig, requireUserOrAgentApiConfig };
|
|
604
|
+
export { requireApiConfig, requireUserApiConfig, requireAgentApiConfig, requireUserOrAgentApiConfig, requireEndpointApiConfig, };
|
|
541
605
|
//# sourceMappingURL=specguard-api.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specguard-api.js","sourceRoot":"","sources":["../../../src/support/specguard-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,
|
|
1
|
+
{"version":3,"file":"specguard-api.js","sourceRoot":"","sources":["../../../src/support/specguard-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ToolDefinition } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /version` as a tool — the server's OWN identity, askable at last
|
|
4
|
+
* (shipped: SPGD-1197, specguard `d434c2a`, root-level and unauthenticated by
|
|
5
|
+
* design — `config/routes.rb` mounts it beside `/up` and the schema mirror,
|
|
6
|
+
* exactly because the credential seam under `api/` fails closed and this read
|
|
7
|
+
* is the platform's deliberate no-account exception at the root).
|
|
8
|
+
*
|
|
9
|
+
* == What it answers, and the one distinction the whole tool exists to carry
|
|
10
|
+
*
|
|
11
|
+
* "Which build is answering me?" has a second answer in this bridge, and the
|
|
12
|
+
* two are routinely confused because both are called a version. The
|
|
13
|
+
* `serverInfo.version` in the initialize handshake and the
|
|
14
|
+
* `specguard-mcp/<version>` User-Agent are THIS BRIDGE's build — its own
|
|
15
|
+
* manifest, released on its own cadence (SPGD-1190/1192). The deployment
|
|
16
|
+
* behind `SPECGUARD_ENDPOINT` is a different component built from a different
|
|
17
|
+
* tree, and before this tool nothing here could say which build of IT was
|
|
18
|
+
* answering. The consumers the platform's own controller names — a client
|
|
19
|
+
* author verifying an upgrade took effect, an agent pinning which build's
|
|
20
|
+
* crafted 404/400 message sentences its contract suite asserts, a bug
|
|
21
|
+
* reporter stating which build produced the behavior — are all asking about
|
|
22
|
+
* the DEPLOYMENT, and this tool is their channel.
|
|
23
|
+
*
|
|
24
|
+
* == The two non-happy arms are in the schema's description, not just here
|
|
25
|
+
*
|
|
26
|
+
* `version: null` is an HONEST answer the server deliberately serves (its
|
|
27
|
+
* VERSION file was missing or unreadable at boot — the controller memoizes
|
|
28
|
+
* even the failure): an unverifiable identity beats a 500 from the one
|
|
29
|
+
* endpoint whose whole job is to be askable. This bridge passes it through as
|
|
30
|
+
* `null` and never substitutes a guessed value — inventing one would be the
|
|
31
|
+
* exact defect the nil arm exists to prevent.
|
|
32
|
+
*
|
|
33
|
+
* A 404 means the deployment PREDATES the route: the endpoint is right and
|
|
34
|
+
* the build is old. `describeFailure` cannot know that — a non-contract 404
|
|
35
|
+
* body names no cause, so its canned hint names the endpoint as possibly
|
|
36
|
+
* misconfigured. The description pre-empts the wrong reading: when every
|
|
37
|
+
* other tool works against the same `SPECGUARD_ENDPOINT`, that error is an
|
|
38
|
+
* upgrade request, not a URL fix.
|
|
39
|
+
*
|
|
40
|
+
* == No arguments, no credential — the thin-client shape at its thinnest
|
|
41
|
+
*
|
|
42
|
+
* The endpoint takes no parameters and the route authenticates nothing, so
|
|
43
|
+
* the tool advertises no argument and requires no key: it is the first tool
|
|
44
|
+
* here served by `requireEndpointApiConfig`, and the transport sends no
|
|
45
|
+
* `Authorization` header for it. The body is passed through verbatim —
|
|
46
|
+
* reshaping `{version}` would be a second copy of the platform's own
|
|
47
|
+
* identity answer, one release behind it.
|
|
48
|
+
*/
|
|
49
|
+
declare const getServerVersion: ToolDefinition;
|
|
50
|
+
export default getServerVersion;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { getJsonObject, requireEndpointApiConfig } from "../support/specguard-api.js";
|
|
2
|
+
/**
|
|
3
|
+
* `GET /version` as a tool — the server's OWN identity, askable at last
|
|
4
|
+
* (shipped: SPGD-1197, specguard `d434c2a`, root-level and unauthenticated by
|
|
5
|
+
* design — `config/routes.rb` mounts it beside `/up` and the schema mirror,
|
|
6
|
+
* exactly because the credential seam under `api/` fails closed and this read
|
|
7
|
+
* is the platform's deliberate no-account exception at the root).
|
|
8
|
+
*
|
|
9
|
+
* == What it answers, and the one distinction the whole tool exists to carry
|
|
10
|
+
*
|
|
11
|
+
* "Which build is answering me?" has a second answer in this bridge, and the
|
|
12
|
+
* two are routinely confused because both are called a version. The
|
|
13
|
+
* `serverInfo.version` in the initialize handshake and the
|
|
14
|
+
* `specguard-mcp/<version>` User-Agent are THIS BRIDGE's build — its own
|
|
15
|
+
* manifest, released on its own cadence (SPGD-1190/1192). The deployment
|
|
16
|
+
* behind `SPECGUARD_ENDPOINT` is a different component built from a different
|
|
17
|
+
* tree, and before this tool nothing here could say which build of IT was
|
|
18
|
+
* answering. The consumers the platform's own controller names — a client
|
|
19
|
+
* author verifying an upgrade took effect, an agent pinning which build's
|
|
20
|
+
* crafted 404/400 message sentences its contract suite asserts, a bug
|
|
21
|
+
* reporter stating which build produced the behavior — are all asking about
|
|
22
|
+
* the DEPLOYMENT, and this tool is their channel.
|
|
23
|
+
*
|
|
24
|
+
* == The two non-happy arms are in the schema's description, not just here
|
|
25
|
+
*
|
|
26
|
+
* `version: null` is an HONEST answer the server deliberately serves (its
|
|
27
|
+
* VERSION file was missing or unreadable at boot — the controller memoizes
|
|
28
|
+
* even the failure): an unverifiable identity beats a 500 from the one
|
|
29
|
+
* endpoint whose whole job is to be askable. This bridge passes it through as
|
|
30
|
+
* `null` and never substitutes a guessed value — inventing one would be the
|
|
31
|
+
* exact defect the nil arm exists to prevent.
|
|
32
|
+
*
|
|
33
|
+
* A 404 means the deployment PREDATES the route: the endpoint is right and
|
|
34
|
+
* the build is old. `describeFailure` cannot know that — a non-contract 404
|
|
35
|
+
* body names no cause, so its canned hint names the endpoint as possibly
|
|
36
|
+
* misconfigured. The description pre-empts the wrong reading: when every
|
|
37
|
+
* other tool works against the same `SPECGUARD_ENDPOINT`, that error is an
|
|
38
|
+
* upgrade request, not a URL fix.
|
|
39
|
+
*
|
|
40
|
+
* == No arguments, no credential — the thin-client shape at its thinnest
|
|
41
|
+
*
|
|
42
|
+
* The endpoint takes no parameters and the route authenticates nothing, so
|
|
43
|
+
* the tool advertises no argument and requires no key: it is the first tool
|
|
44
|
+
* here served by `requireEndpointApiConfig`, and the transport sends no
|
|
45
|
+
* `Authorization` header for it. The body is passed through verbatim —
|
|
46
|
+
* reshaping `{version}` would be a second copy of the platform's own
|
|
47
|
+
* identity answer, one release behind it.
|
|
48
|
+
*/
|
|
49
|
+
const getServerVersion = {
|
|
50
|
+
name: "get_server_version",
|
|
51
|
+
title: "Server version",
|
|
52
|
+
description: "Reports WHICH BUILD of the SpecGuard DEPLOYMENT is answering, read from the deployment's own " +
|
|
53
|
+
"unauthenticated root-level `GET /version` — the figure the release bot's VERSION file carries, " +
|
|
54
|
+
'served as `{"version": "0.1.46"}`-shaped JSON and passed through verbatim as `{version}`. ' +
|
|
55
|
+
"This is the SERVER's build, NOT this bridge's: the version in the initialize handshake's " +
|
|
56
|
+
"`serverInfo` and the `specguard-mcp/<version>` User-Agent describe this bridge, a different " +
|
|
57
|
+
"component released on its own cadence, so never read one as the other. Pinning which build's " +
|
|
58
|
+
"crafted 404/400 message sentence a contract suite asserts, verifying that a deployment upgrade " +
|
|
59
|
+
"took effect, or naming the build that produced a behavior is this tool's question — the " +
|
|
60
|
+
"handshake cannot answer it. `version: null` is an honest answer, not an error: the deployment " +
|
|
61
|
+
"is up but cannot say its own build (its VERSION file was missing or unreadable at boot), and " +
|
|
62
|
+
"null is passed through exactly as served — never replaced with a guessed value. A 404 means " +
|
|
63
|
+
"this deployment PREDATES the route: the endpoint is right and the build is old. The error text " +
|
|
64
|
+
"names the endpoint as possibly misconfigured because a non-contract 404 body names no cause — " +
|
|
65
|
+
"when the other tools work against the same endpoint, read that error as 'the deployment needs " +
|
|
66
|
+
"upgrading', not as a wrong URL. Needs NO API key of any kind — the route is unauthenticated by " +
|
|
67
|
+
"design — so it works with `SPECGUARD_ENDPOINT` alone, and it is the one tool here that sends " +
|
|
68
|
+
"no `Authorization` header. Takes no arguments.",
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: "object",
|
|
71
|
+
// No properties, deliberately — see this file's header. Still CLOSED rather
|
|
72
|
+
// than merely empty, for the reason `registrable-repositories.ts` states:
|
|
73
|
+
// `server.ts` forwards `arguments` unvalidated and `run` ignores them, so
|
|
74
|
+
// an open schema would let an invented argument be silently dropped while
|
|
75
|
+
// the call is answered as if it had been honoured.
|
|
76
|
+
additionalProperties: false,
|
|
77
|
+
},
|
|
78
|
+
async run(_args, context) {
|
|
79
|
+
const api = requireEndpointApiConfig(context.config);
|
|
80
|
+
const answer = await getJsonObject(api, "/version", {}, context.fetch);
|
|
81
|
+
return {
|
|
82
|
+
text: JSON.stringify(answer, null, 2),
|
|
83
|
+
structured: answer,
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
export default getServerVersion;
|
|
88
|
+
//# sourceMappingURL=get-server-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-server-version.js","sourceRoot":"","sources":["../../../src/tools/get-server-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAGtF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,MAAM,gBAAgB,GAAmB;IACvC,IAAI,EAAE,oBAAoB;IAC1B,KAAK,EAAE,gBAAgB;IACvB,WAAW,EACT,+FAA+F;QAC/F,iGAAiG;QACjG,4FAA4F;QAC5F,2FAA2F;QAC3F,8FAA8F;QAC9F,+FAA+F;QAC/F,iGAAiG;QACjG,0FAA0F;QAC1F,gGAAgG;QAChG,+FAA+F;QAC/F,8FAA8F;QAC9F,iGAAiG;QACjG,gGAAgG;QAChG,gGAAgG;QAChG,iGAAiG;QACjG,+FAA+F;QAC/F,gDAAgD;IAClD,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,4EAA4E;QAC5E,0EAA0E;QAC1E,0EAA0E;QAC1E,0EAA0E;QAC1E,mDAAmD;QACnD,oBAAoB,EAAE,KAAK;KAC5B;IAED,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO;QACtB,MAAM,GAAG,GAAG,wBAAwB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAErD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAEvE,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACrC,UAAU,EAAE,MAAM;SACnB,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -180,6 +180,26 @@ import type { ToolDefinition } from "./types.js";
|
|
|
180
180
|
* minting is deliberately web-only at /account, so unlike the `sgk_` pair
|
|
181
181
|
* there is no create response to read an id from — the list and revoke
|
|
182
182
|
* descriptions say so rather than leaving it implicit.
|
|
183
|
+
*
|
|
184
|
+
* == The first tool that needs NO credential
|
|
185
|
+
*
|
|
186
|
+
* - `get_server_version` wraps the server's root-level `GET /version`
|
|
187
|
+
* (shipped: SPGD-1197, specguard `d434c2a`).
|
|
188
|
+
*
|
|
189
|
+
* The platform's own doctrine placed this read OUTSIDE the credential seam
|
|
190
|
+
* rather than inside with an exception: every controller under `api/` must
|
|
191
|
+
* declare an accepted credential or answer 401 to everything, so the
|
|
192
|
+
* unauthenticated identity read lives at the root, beside `/up` and the
|
|
193
|
+
* schema mirror. The bridge meets it where it stands — a fourth `require*`
|
|
194
|
+
* helper (`requireEndpointApiConfig`) demands an endpoint and no key, the
|
|
195
|
+
* transport's `Authorization` header became conditional on a present key
|
|
196
|
+
* (mirroring the conditional `Content-Type` one key below it), and
|
|
197
|
+
* `describeFailure`'s canned 401 sentence — a diagnosis of a wrong-kind key —
|
|
198
|
+
* falls to the generic sentence when no credential is bound, because a
|
|
199
|
+
* credential-free ask cannot have a key problem. The standing rule is
|
|
200
|
+
* unchanged and still binding: the endpoint was verified-shipped on
|
|
201
|
+
* `origin/main` before this entry wrapped it. What moved was the platform,
|
|
202
|
+
* not the bar.
|
|
183
203
|
*/
|
|
184
204
|
export declare const TOOLS: readonly ToolDefinition[];
|
|
185
205
|
export type { ToolContext, ToolDefinition, ToolResult } from "./types.js";
|
package/dist/src/tools/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import addRepository from "./add-repository.js";
|
|
2
2
|
import addRepositoryMember from "./add-repository-member.js";
|
|
3
3
|
import createRepositoryApiKey from "./create-repository-api-key.js";
|
|
4
|
+
import getServerVersion from "./get-server-version.js";
|
|
4
5
|
import lintIntentAnnotations from "./lint-intent-annotations.js";
|
|
5
6
|
import listRepositories from "./list-repositories.js";
|
|
6
7
|
import listRepositoryAgentKeys from "./list-repository-agent-keys.js";
|
|
@@ -197,10 +198,31 @@ import updateRepositoryMemberPermissions from "./update-repository-member-permis
|
|
|
197
198
|
* minting is deliberately web-only at /account, so unlike the `sgk_` pair
|
|
198
199
|
* there is no create response to read an id from — the list and revoke
|
|
199
200
|
* descriptions say so rather than leaving it implicit.
|
|
201
|
+
*
|
|
202
|
+
* == The first tool that needs NO credential
|
|
203
|
+
*
|
|
204
|
+
* - `get_server_version` wraps the server's root-level `GET /version`
|
|
205
|
+
* (shipped: SPGD-1197, specguard `d434c2a`).
|
|
206
|
+
*
|
|
207
|
+
* The platform's own doctrine placed this read OUTSIDE the credential seam
|
|
208
|
+
* rather than inside with an exception: every controller under `api/` must
|
|
209
|
+
* declare an accepted credential or answer 401 to everything, so the
|
|
210
|
+
* unauthenticated identity read lives at the root, beside `/up` and the
|
|
211
|
+
* schema mirror. The bridge meets it where it stands — a fourth `require*`
|
|
212
|
+
* helper (`requireEndpointApiConfig`) demands an endpoint and no key, the
|
|
213
|
+
* transport's `Authorization` header became conditional on a present key
|
|
214
|
+
* (mirroring the conditional `Content-Type` one key below it), and
|
|
215
|
+
* `describeFailure`'s canned 401 sentence — a diagnosis of a wrong-kind key —
|
|
216
|
+
* falls to the generic sentence when no credential is bound, because a
|
|
217
|
+
* credential-free ask cannot have a key problem. The standing rule is
|
|
218
|
+
* unchanged and still binding: the endpoint was verified-shipped on
|
|
219
|
+
* `origin/main` before this entry wrapped it. What moved was the platform,
|
|
220
|
+
* not the bar.
|
|
200
221
|
*/
|
|
201
222
|
export const TOOLS = [
|
|
202
223
|
lintIntentAnnotations,
|
|
203
224
|
getRepositoryOverview,
|
|
225
|
+
getServerVersion,
|
|
204
226
|
listRepositories,
|
|
205
227
|
addRepository,
|
|
206
228
|
registrableRepositories,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,uBAAuB,MAAM,iCAAiC,CAAC;AACtE,OAAO,uCAAuC,MAAM,mDAAmD,CAAC;AACxG,OAAO,qBAAqB,MAAM,+BAA+B,CAAC;AAClE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AACnE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,wBAAwB,MAAM,kCAAkC,CAAC;AACxE,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,iCAAiC,MAAM,2CAA2C,CAAC;AAG1F
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,uBAAuB,MAAM,iCAAiC,CAAC;AACtE,OAAO,uCAAuC,MAAM,mDAAmD,CAAC;AACxG,OAAO,qBAAqB,MAAM,+BAA+B,CAAC;AAClE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,qBAAqB,MAAM,0BAA0B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,+BAA+B,CAAC;AACpE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AACnE,OAAO,gBAAgB,MAAM,wBAAwB,CAAC;AACtD,OAAO,wBAAwB,MAAM,kCAAkC,CAAC;AACxE,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,iCAAiC,MAAM,2CAA2C,CAAC;AAG1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyMG;AACH,MAAM,CAAC,MAAM,KAAK,GAA8B;IAC9C,qBAAqB;IACrB,qBAAqB;IACrB,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,uBAAuB;IACvB,gBAAgB;IAChB,sBAAsB;IACtB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,qBAAqB;IACrB,mBAAmB;IACnB,iCAAiC;IACjC,sBAAsB;IACtB,gBAAgB;IAChB,uBAAuB;IACvB,uCAAuC;IACvC,wBAAwB;CACzB,CAAC"}
|