@bli-cockpit/mcp 0.1.11 → 0.1.13
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 +66 -2
- package/dist/index.d.ts +15 -11
- package/dist/index.js +24 -28
- package/dist/startup-auth.d.ts +44 -0
- package/dist/startup-auth.js +61 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -367,7 +367,13 @@ The server resolves an access_token before every authenticated request using the
|
|
|
367
367
|
1. `BLI_OPERATOR_TOKEN` (verbatim, no refresh) — CI path.
|
|
368
368
|
2. Session helper — shells out to `node scripts/bli-event-session.mjs get-token`, which reads `~/.config/bli-event/session.json` and refreshes the access_token when near expiry. Run `bli-event login` once on your laptop to create the session. Tokens are cached in-process for 30s to avoid spawning a subprocess on every tool call.
|
|
369
369
|
|
|
370
|
-
If both paths are unavailable (no env override, and no session file on disk),
|
|
370
|
+
If both paths are unavailable (no env override, and no session file on disk),
|
|
371
|
+
the server **still starts** and only those three tools refuse, by name, when
|
|
372
|
+
called — every device-token tool is unaffected (BLI-3804). It used to exit at
|
|
373
|
+
startup, which meant a machine that installed the published package registered
|
|
374
|
+
a `bli-tower` server with NO tools at all: `scripts/bli-event-session.mjs`
|
|
375
|
+
exists in the bli-cockpit repo and nowhere else. `src/startup-auth.ts` carries
|
|
376
|
+
the account.
|
|
371
377
|
|
|
372
378
|
## Install
|
|
373
379
|
|
|
@@ -453,10 +459,68 @@ The server surfaces API error codes from the canonical catalog
|
|
|
453
459
|
| `BLI-E403` | Authenticated caller cannot access the requested ticket. |
|
|
454
460
|
| `BLI-W003` | Idempotency replay (informational; not an error). |
|
|
455
461
|
|
|
462
|
+
## The smoke — does this server actually answer? (BLI-3804)
|
|
463
|
+
|
|
464
|
+
The unit suites prove each tool's shape against an injected fetch, and
|
|
465
|
+
`verb-census.test.ts` proves a twin EXISTS for every Tower CLI verb. Neither
|
|
466
|
+
starts a server, opens a transport or reaches Tower, which is how five QA ticks
|
|
467
|
+
(`docs/reports/jarvis-qa-loop/tick15.md` … `tick19.md`) recorded these tools as
|
|
468
|
+
untested end to end while the published server was exiting at startup.
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
npm run mcp:smoke --workspace=@bli-cockpit/mcp # all six families
|
|
472
|
+
npm run mcp:smoke --workspace=@bli-cockpit/mcp -- --skip jarvis_ask # no model spend
|
|
473
|
+
npm run mcp:smoke --workspace=@bli-cockpit/mcp -- --only docs_list --json
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
It builds the server, spawns `dist/index.js` over stdio the way an agent host
|
|
477
|
+
does, lists the tools, and calls one cheap READ per family — `docs_list`
|
|
478
|
+
(limit 1), `msg_channels`, `work_list_issues` (limit 1), `cal_calendars`,
|
|
479
|
+
`mail_accounts`, `jarvis_ask` — never a write, never a dispatch. The device
|
|
480
|
+
token is never passed to it: the server reads
|
|
481
|
+
`~/.config/bli-cockpit/session.json` itself, so the smoke exercises the real
|
|
482
|
+
auth path. Output is one line per tool — name, verdict, the door's own reason
|
|
483
|
+
label, milliseconds:
|
|
484
|
+
|
|
485
|
+
```
|
|
486
|
+
bli-tower smoke — 78 tools registered, 6 called
|
|
487
|
+
tool verdict reason ms
|
|
488
|
+
docs_list ok answered 719
|
|
489
|
+
msg_channels ok answered 795
|
|
490
|
+
work_list_issues ok answered 760
|
|
491
|
+
cal_calendars ok answered 762
|
|
492
|
+
mail_accounts ok answered 478
|
|
493
|
+
jarvis_ask ok answered 6483
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**A refusal by name is a pass.** The question is whether the server answers,
|
|
497
|
+
not whether this account has a mailbox: `cal_calendars` and `mail_accounts`
|
|
498
|
+
answering "nothing is attached" is a healthy machine. The exit code turns
|
|
499
|
+
non-zero only when something never answered — the server would not start, the
|
|
500
|
+
transport broke, a call timed out, a tool was not registered, or Tower could
|
|
501
|
+
not be reached.
|
|
502
|
+
|
|
503
|
+
`--server <path>` points it at an INSTALLED server instead of this checkout's
|
|
504
|
+
build, which matters more than it sounds: the repo build resolves a credential
|
|
505
|
+
the published install cannot, so a green smoke here has never proven the
|
|
506
|
+
fleet's server starts.
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
npm run mcp:smoke --workspace=@bli-cockpit/mcp -- \
|
|
510
|
+
--server "$(npm root -g)/@bli-cockpit/cli/node_modules/@bli-cockpit/mcp/dist/index.js"
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
On a laptop, `cockpit doctor`'s `mcp-answers` row asks the same first question
|
|
514
|
+
of the REGISTERED server every run
|
|
515
|
+
(`packages/cockpit-local-collector/src/commands/doctor-mcp.ts`), so a machine
|
|
516
|
+
whose MCP is registered and not answering says so without anyone running this
|
|
517
|
+
script.
|
|
518
|
+
|
|
456
519
|
## Development
|
|
457
520
|
|
|
458
521
|
```bash
|
|
459
|
-
npm run typecheck --workspace=@bli-cockpit/mcp
|
|
522
|
+
npm run typecheck --workspace=@bli-cockpit/mcp # also typechecks scripts/
|
|
460
523
|
npm test --workspace=@bli-cockpit/mcp
|
|
461
524
|
npm run build --workspace=@bli-cockpit/mcp
|
|
525
|
+
npm run mcp:smoke --workspace=@bli-cockpit/mcp # needs a paired machine
|
|
462
526
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @bli-cockpit/mcp —
|
|
3
|
+
* @bli-cockpit/mcp — `bli-tower`, the MCP entry point.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* `POST /api/events/emit` (see docs/plans/cockpit-agent-ops-control-plane.md §6).
|
|
5
|
+
* TWO credentials, and only one of them is needed to serve (BLI-3804):
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
7
|
+
* * Every agent-door tool — `docs_*`, `msg_*`, `work_*`, `mail_*`, `cal_*`,
|
|
8
|
+
* `jarvis_*`, `brief_*`, `notes_*`, `ops_*`, `settings_*`, `scout_*`,
|
|
9
|
+
* `search`, `workbook_*` — reads this machine's COLLECTOR DEVICE TOKEN
|
|
10
|
+
* per call from `~/.config/bli-cockpit/session.json`
|
|
11
|
+
* (`agent-door-session.ts`). Nothing about it is resolved here.
|
|
12
|
+
* * `emit_event` / `get_ticket_timeline` / `get_active_tickets` — the legacy
|
|
13
|
+
* event stream — need `BLI_OPERATOR_TOKEN`, or `scripts/bli-event-session.mjs`
|
|
14
|
+
* found by walking up from this module (set `BLI_SESSION_HELPER` to point
|
|
15
|
+
* at it directly).
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
+
* When the second one is absent the server STILL STARTS and those three tools
|
|
18
|
+
* refuse by name when called. It used to exit 1 before connecting the
|
|
19
|
+
* transport, which meant no tools at all on every machine outside the repo —
|
|
20
|
+
* `startup-auth.ts` carries the full account.
|
|
17
21
|
*/
|
|
18
22
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,42 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @bli-cockpit/mcp —
|
|
3
|
+
* @bli-cockpit/mcp — `bli-tower`, the MCP entry point.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* `POST /api/events/emit` (see docs/plans/cockpit-agent-ops-control-plane.md §6).
|
|
5
|
+
* TWO credentials, and only one of them is needed to serve (BLI-3804):
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
7
|
+
* * Every agent-door tool — `docs_*`, `msg_*`, `work_*`, `mail_*`, `cal_*`,
|
|
8
|
+
* `jarvis_*`, `brief_*`, `notes_*`, `ops_*`, `settings_*`, `scout_*`,
|
|
9
|
+
* `search`, `workbook_*` — reads this machine's COLLECTOR DEVICE TOKEN
|
|
10
|
+
* per call from `~/.config/bli-cockpit/session.json`
|
|
11
|
+
* (`agent-door-session.ts`). Nothing about it is resolved here.
|
|
12
|
+
* * `emit_event` / `get_ticket_timeline` / `get_active_tickets` — the legacy
|
|
13
|
+
* event stream — need `BLI_OPERATOR_TOKEN`, or `scripts/bli-event-session.mjs`
|
|
14
|
+
* found by walking up from this module (set `BLI_SESSION_HELPER` to point
|
|
15
|
+
* at it directly).
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
+
* When the second one is absent the server STILL STARTS and those three tools
|
|
18
|
+
* refuse by name when called. It used to exit 1 before connecting the
|
|
19
|
+
* transport, which meant no tools at all on every machine outside the repo —
|
|
20
|
+
* `startup-auth.ts` carries the full account.
|
|
17
21
|
*/
|
|
18
22
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
19
23
|
import { createServer } from "./server.js";
|
|
20
|
-
import {
|
|
24
|
+
import { resolveStartupAuth } from "./startup-auth.js";
|
|
21
25
|
async function main() {
|
|
22
26
|
const baseUrl = process.env.BLI_API_BASE_URL ?? "http://127.0.0.1:3100";
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
? "BLI_OPERATOR_TOKEN env var"
|
|
31
|
-
: `session helper at ${result.helperPath}`;
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
process.stderr.write(`[bli-cockpit-mcp] ${err instanceof Error ? err.message : String(err)}\n`);
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
process.stderr.write(`[bli-cockpit-mcp] auth source: ${sourceLabel}\n`);
|
|
27
|
+
// BLI-3804: a missing LEGACY credential degrades three tools, it does not
|
|
28
|
+
// kill the server. This used to `process.exit(1)` before the transport was
|
|
29
|
+
// connected, so every machine that installed the published package — where
|
|
30
|
+
// `scripts/bli-event-session.mjs` does not exist — registered no `bli-tower`
|
|
31
|
+
// tools at all. See `startup-auth.ts` for the whole story.
|
|
32
|
+
const auth = resolveStartupAuth({ env: process.env });
|
|
33
|
+
process.stderr.write(`[bli-cockpit-mcp] auth source: ${auth.sourceLabel}\n`);
|
|
38
34
|
const deps = {
|
|
39
|
-
resolveToken: resolver,
|
|
35
|
+
resolveToken: auth.resolver,
|
|
40
36
|
baseUrl,
|
|
41
37
|
fetchImpl: globalThis.fetch,
|
|
42
38
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this server does when the LEGACY event-stream credential is missing
|
|
3
|
+
* (BLI-3804).
|
|
4
|
+
*
|
|
5
|
+
* Two auth paths live on this one server and they are unrelated
|
|
6
|
+
* (`agent-door-session.ts` says why): every `docs_*`, `msg_*`, `work_*`,
|
|
7
|
+
* `mail_*`, `cal_*`, `jarvis_*`, `brief_*`, `notes_*`, `ops_*`, `settings_*`,
|
|
8
|
+
* `scout_*`, `search` and `workbook_*` tool — 78 of the 81 — authenticates
|
|
9
|
+
* with this machine's COLLECTOR DEVICE TOKEN, read per call from
|
|
10
|
+
* `~/.config/bli-cockpit/session.json`. Only `emit_event`,
|
|
11
|
+
* `get_ticket_timeline` and `get_active_tickets` need `BLI_OPERATOR_TOKEN` or
|
|
12
|
+
* the `bli-event-session.mjs` helper.
|
|
13
|
+
*
|
|
14
|
+
* Until this module existed, `index.ts` resolved that legacy credential at
|
|
15
|
+
* STARTUP and called `process.exit(1)` when it could not — before the
|
|
16
|
+
* transport was connected and before a single tool was registered. The helper
|
|
17
|
+
* is discovered by walking up from this module's own location looking for
|
|
18
|
+
* `scripts/bli-event-session.mjs`, which exists in the bli-cockpit repo and
|
|
19
|
+
* nowhere else, so on every machine that installed the published package the
|
|
20
|
+
* server died at startup and the agent host reported no `bli-tower` tools at
|
|
21
|
+
* all. Proven 2026-09-06 against the registered bin on the reference Mac:
|
|
22
|
+
* `[bli-cockpit-mcp] No auth available: …`, exit 1. Five QA ticks
|
|
23
|
+
* (`docs/reports/jarvis-qa-loop/tick15.md` … `tick19.md`) recorded the
|
|
24
|
+
* symptom — "no `mcp__bli-tower__*` in this session" — as a client-side gap.
|
|
25
|
+
*
|
|
26
|
+
* `server.ts` already stated the intended behaviour in a comment beside the
|
|
27
|
+
* agent-door registrations: "Registered unconditionally — … a machine with no
|
|
28
|
+
* `cockpit login` pairing yet still serves the three event tools; only a
|
|
29
|
+
* docs/msg call on that machine fails, by name." This module makes the
|
|
30
|
+
* converse true as well: a machine with no LEGACY operator token still serves
|
|
31
|
+
* every agent-door tool, and only the three event-stream tools fail — by name,
|
|
32
|
+
* with the reason, when they are called.
|
|
33
|
+
*/
|
|
34
|
+
import type { TokenResolver } from "./token-resolver.js";
|
|
35
|
+
export interface StartupAuth {
|
|
36
|
+
resolver: TokenResolver;
|
|
37
|
+
/** One line for stderr. Says which half of the server is live and which is not. */
|
|
38
|
+
sourceLabel: string;
|
|
39
|
+
/** `true` when only the three legacy event-stream tools are unavailable. */
|
|
40
|
+
legacyToolsDegraded: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare function resolveStartupAuth(options: {
|
|
43
|
+
env: NodeJS.ProcessEnv;
|
|
44
|
+
}): StartupAuth;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this server does when the LEGACY event-stream credential is missing
|
|
3
|
+
* (BLI-3804).
|
|
4
|
+
*
|
|
5
|
+
* Two auth paths live on this one server and they are unrelated
|
|
6
|
+
* (`agent-door-session.ts` says why): every `docs_*`, `msg_*`, `work_*`,
|
|
7
|
+
* `mail_*`, `cal_*`, `jarvis_*`, `brief_*`, `notes_*`, `ops_*`, `settings_*`,
|
|
8
|
+
* `scout_*`, `search` and `workbook_*` tool — 78 of the 81 — authenticates
|
|
9
|
+
* with this machine's COLLECTOR DEVICE TOKEN, read per call from
|
|
10
|
+
* `~/.config/bli-cockpit/session.json`. Only `emit_event`,
|
|
11
|
+
* `get_ticket_timeline` and `get_active_tickets` need `BLI_OPERATOR_TOKEN` or
|
|
12
|
+
* the `bli-event-session.mjs` helper.
|
|
13
|
+
*
|
|
14
|
+
* Until this module existed, `index.ts` resolved that legacy credential at
|
|
15
|
+
* STARTUP and called `process.exit(1)` when it could not — before the
|
|
16
|
+
* transport was connected and before a single tool was registered. The helper
|
|
17
|
+
* is discovered by walking up from this module's own location looking for
|
|
18
|
+
* `scripts/bli-event-session.mjs`, which exists in the bli-cockpit repo and
|
|
19
|
+
* nowhere else, so on every machine that installed the published package the
|
|
20
|
+
* server died at startup and the agent host reported no `bli-tower` tools at
|
|
21
|
+
* all. Proven 2026-09-06 against the registered bin on the reference Mac:
|
|
22
|
+
* `[bli-cockpit-mcp] No auth available: …`, exit 1. Five QA ticks
|
|
23
|
+
* (`docs/reports/jarvis-qa-loop/tick15.md` … `tick19.md`) recorded the
|
|
24
|
+
* symptom — "no `mcp__bli-tower__*` in this session" — as a client-side gap.
|
|
25
|
+
*
|
|
26
|
+
* `server.ts` already stated the intended behaviour in a comment beside the
|
|
27
|
+
* agent-door registrations: "Registered unconditionally — … a machine with no
|
|
28
|
+
* `cockpit login` pairing yet still serves the three event tools; only a
|
|
29
|
+
* docs/msg call on that machine fails, by name." This module makes the
|
|
30
|
+
* converse true as well: a machine with no LEGACY operator token still serves
|
|
31
|
+
* every agent-door tool, and only the three event-stream tools fail — by name,
|
|
32
|
+
* with the reason, when they are called.
|
|
33
|
+
*/
|
|
34
|
+
import { createDefaultTokenResolver } from "./token-resolver.js";
|
|
35
|
+
export function resolveStartupAuth(options) {
|
|
36
|
+
try {
|
|
37
|
+
const result = createDefaultTokenResolver({ env: options.env });
|
|
38
|
+
return {
|
|
39
|
+
resolver: result.resolver,
|
|
40
|
+
sourceLabel: result.source === "env"
|
|
41
|
+
? "BLI_OPERATOR_TOKEN env var"
|
|
42
|
+
: `session helper at ${result.helperPath}`,
|
|
43
|
+
legacyToolsDegraded: false,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
48
|
+
return {
|
|
49
|
+
// Not a startup failure — a per-call one. `server.ts`'s `callApi` turns
|
|
50
|
+
// this throw into BLI-E003 on the ONE tool that needed it, which is the
|
|
51
|
+
// difference between three unavailable tools and no server at all.
|
|
52
|
+
resolver: async () => {
|
|
53
|
+
throw new Error(reason);
|
|
54
|
+
},
|
|
55
|
+
sourceLabel: "none for the legacy event-stream tools (emit_event, get_ticket_timeline, get_active_tickets); "
|
|
56
|
+
+ `they will refuse by name when called — ${reason} `
|
|
57
|
+
+ "Every device-token tool (docs_*, msg_*, work_*, mail_*, cal_*, jarvis_*, …) is unaffected.",
|
|
58
|
+
legacyToolsDegraded: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "bli-tower \u2014 an MCP server over BLI Cockpit's agent doors: JARVIS (jarvis_*), documents (docs_*), channels (msg_*), issues (work_*), the daily page (brief_*), meeting notes (notes_*), the ops board (ops_status/slack_*), settings/team/model, Scout and the workbook, plus the legacy event-stream tools (emit_event, get_ticket_timeline, get_active_tickets).",
|
|
6
6
|
"type": "module",
|
|
@@ -22,14 +22,15 @@
|
|
|
22
22
|
"build": "tsc",
|
|
23
23
|
"prepack": "node ../../scripts/build-workspace-dep.mjs @bli-cockpit/telemetry-core && rm -rf dist && tsc",
|
|
24
24
|
"pretypecheck": "node ../../scripts/build-workspace-dep.mjs @bli-cockpit/telemetry-core",
|
|
25
|
-
"typecheck": "tsc --noEmit",
|
|
25
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json",
|
|
26
26
|
"pretest": "node ../../scripts/build-workspace-dep.mjs @bli-cockpit/telemetry-core",
|
|
27
27
|
"test": "vitest run",
|
|
28
28
|
"start": "node dist/index.js",
|
|
29
|
+
"mcp:smoke": "npm run build --silent && node scripts/smoke.ts",
|
|
29
30
|
"readme": "npm run build && node scripts/write-readme-census.mjs"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@bli-cockpit/telemetry-core": "0.1.
|
|
33
|
+
"@bli-cockpit/telemetry-core": "0.1.32",
|
|
33
34
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
34
35
|
"zod": "^4.3.6"
|
|
35
36
|
},
|