@bli-cockpit/mcp 0.1.21 → 0.1.22

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 CHANGED
@@ -34,7 +34,7 @@ about what an agent can reach.
34
34
 
35
35
  <!-- BEGIN GENERATED verb census — `npm run mcp:readme` -->
36
36
 
37
- **74 of 77 Tower verbs have an MCP twin.**
37
+ **76 of 79 Tower verbs have an MCP twin.**
38
38
  Each tool goes through the SAME door its CLI verb calls, with the same
39
39
  collector device token — never a second route and never a service-role
40
40
  reader. `src/verb-census.test.ts` fails when a verb is in none of the
@@ -81,6 +81,8 @@ three tables below.
81
81
  | `cockpit memory log` | `memory_experience` | `POST /api/memory/experience` |
82
82
  | `cockpit model set` | `model_set` | `POST /api/settings/jarvis-model` |
83
83
  | `cockpit model show` | `model_show` | `GET /api/settings/jarvis-model` |
84
+ | `cockpit models list` | `models_list` | `GET /api/models/cards` |
85
+ | `cockpit models show` | `models_card` | `GET /api/models/cards?id=` |
84
86
  | `cockpit msg channels` | `msg_channels` | `GET /api/msg/channels` |
85
87
  | `cockpit msg create` | `msg_create_channel` | `POST /api/msg/channels` |
86
88
  | `cockpit msg dm` | `msg_dm` | `POST /api/msg/channels (dm)` |
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `models_list` / `models_card` (BLI-3912) — the model-card shelf, for an
3
+ * agent, over the same `/api/models/cards` door `cockpit models` calls.
4
+ *
5
+ * These are the twins of `cockpit models list` and `cockpit models show`. They
6
+ * exist because "which model should I use for this, and what will it refuse"
7
+ * is a question an agent asks more often than a person does: the card carries
8
+ * the documented window, price, reasoning modes and tool support beside our own
9
+ * measured latency and probe verdicts, and a `stale:<field>` mark wherever the
10
+ * two disagree.
11
+ *
12
+ * The LINES come from the server, so the sentence an agent reads is the sentence
13
+ * a person reads in a terminal. Nothing is computed here beyond counting.
14
+ *
15
+ * Not to be confused with `model_show` / `model_set` next door, which are the
16
+ * ORG SETTING for which model a slot runs on. This is the shelf that setting
17
+ * picks from, and there is deliberately no write here: a card is changed by
18
+ * re-reading the provider (`npm run models:card add <id> --refresh`), never by
19
+ * an agent editing a number.
20
+ */
21
+ import { type ToolDeps } from "./tool-result.js";
22
+ export type ModelsDeps = ToolDeps;
23
+ export declare function registerModelsTools(server: {
24
+ registerTool: (...args: never[]) => unknown;
25
+ }, deps: ModelsDeps): void;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * `models_list` / `models_card` (BLI-3912) — the model-card shelf, for an
3
+ * agent, over the same `/api/models/cards` door `cockpit models` calls.
4
+ *
5
+ * These are the twins of `cockpit models list` and `cockpit models show`. They
6
+ * exist because "which model should I use for this, and what will it refuse"
7
+ * is a question an agent asks more often than a person does: the card carries
8
+ * the documented window, price, reasoning modes and tool support beside our own
9
+ * measured latency and probe verdicts, and a `stale:<field>` mark wherever the
10
+ * two disagree.
11
+ *
12
+ * The LINES come from the server, so the sentence an agent reads is the sentence
13
+ * a person reads in a terminal. Nothing is computed here beyond counting.
14
+ *
15
+ * Not to be confused with `model_show` / `model_set` next door, which are the
16
+ * ORG SETTING for which model a slot runs on. This is the shelf that setting
17
+ * picks from, and there is deliberately no write here: a card is changed by
18
+ * re-reading the provider (`npm run models:card add <id> --refresh`), never by
19
+ * an agent editing a number.
20
+ */
21
+ import { z } from "zod";
22
+ import { callAgentDoor } from "./agent-door.js";
23
+ import { doorFailureText, errorResult, registrarFor, textResult, queryString, withSession, } from "./tool-result.js";
24
+ export function registerModelsTools(server, deps) {
25
+ const register = registrarFor(server);
26
+ register("models_list", {
27
+ title: "List the model cards",
28
+ description: "Every model Tower knows about: the provider's documented context window, price per million, reasoning "
29
+ + "modes and tool support, beside our measured latency, observed tokens/s and last probe verdict. "
30
+ + "`STALE:<field>` means a measurement contradicted the documentation, with the command that re-reads the "
31
+ + "provider. Read-only.",
32
+ inputSchema: {},
33
+ }, async () => withSession(deps, async (session) => {
34
+ const response = await callAgentDoor(session, deps.fetchImpl, "GET", "/api/models/cards");
35
+ if (!response.ok)
36
+ return errorResult(doorFailureText("models_list", response));
37
+ const body = response.body;
38
+ const cards = (Array.isArray(body.cards) ? body.cards : []);
39
+ const lines = (Array.isArray(body.lines) ? body.lines : []);
40
+ const stale = cards.filter((card) => (card.stale?.length ?? 0) > 0).map((card) => card.id ?? "?");
41
+ const unreadable = (Array.isArray(body.unreadable) ? body.unreadable : []);
42
+ return textResult(`${cards.length} model card(s)`
43
+ + `${stale.length > 0 ? `, ${stale.length} stale: ${stale.join(", ")}` : ", none stale"}`
44
+ + `${unreadable.length > 0 ? `, ${unreadable.length} unreadable: ${unreadable.join(", ")}` : ""}`
45
+ + `${lines.length > 0 ? `\n${lines.join("\n")}` : ""}`, { cards, stale, unreadable });
46
+ }));
47
+ register("models_card", {
48
+ title: "Read one model card",
49
+ description: "One model in full: every documented value with the provider page it was read from, the quirks quoted "
50
+ + "verbatim, our measured latency and tokens/s, each probe verdict, and any stale mark. A field the "
51
+ + "provider does not state reads unknown with the reason — never a guess.",
52
+ inputSchema: {
53
+ id: z
54
+ .string()
55
+ .min(1)
56
+ .max(200)
57
+ .describe("The card id, `provider:model` (e.g. openai:gpt-5.6-terra), or one of its aliases."),
58
+ },
59
+ }, async (args) => withSession(deps, async (session) => {
60
+ const params = new URLSearchParams();
61
+ params.set("id", String(args.id));
62
+ const response = await callAgentDoor(session, deps.fetchImpl, "GET", `/api/models/cards${queryString(params)}`);
63
+ // A 404 here is the door's own sentence naming the id and the command
64
+ // that would add it, which is more useful than anything this file
65
+ // could compose.
66
+ if (!response.ok)
67
+ return errorResult(doorFailureText("models_card", response));
68
+ const body = response.body;
69
+ const card = (body.card ?? {});
70
+ const lines = (Array.isArray(body.lines) ? body.lines : []);
71
+ return textResult(lines.join("\n") || `Model card ${card.id ?? args.id}.`, { card });
72
+ }));
73
+ }
package/dist/server.js CHANGED
@@ -15,6 +15,7 @@ import { registerMailTools } from "./mail-tools.js";
15
15
  import { registerNotesTools } from "./notes-tools.js";
16
16
  import { registerNotesWriteTools } from "./notes-write-tools.js";
17
17
  import { registerMemoryExperienceTools } from "./memory-experience-tools.js";
18
+ import { registerModelsTools } from "./models-tools.js";
18
19
  import { registerOpsTools } from "./ops-tools.js";
19
20
  import { registerPagesTools } from "./pages-tools.js";
20
21
  import { registerSearchTool } from "./search-tool.js";
@@ -404,6 +405,10 @@ export function createServer(deps) {
404
405
  // as the three families above, over the doors `cockpit jarvis` already
405
406
  // calls. It is the last Tower surface that had a CLI door and no MCP one.
406
407
  registerJarvisTools(server, { fetchImpl: deps.fetchImpl });
408
+ // BLI-3912: `models_*` — the model-card shelf, over the same door
409
+ // `cockpit models` calls. Read-only: a card is changed by re-reading the
410
+ // provider, never by an agent editing a number.
411
+ registerModelsTools(server, { fetchImpl: deps.fetchImpl });
407
412
  // BLI-3756 batch 1: the READS the CLI already had and this server did not —
408
413
  // the daily page, the meeting-notes library, the ops board, Slack coverage,
409
414
  // settings/team/model, Scout and the workbook. Same doors, same device
@@ -237,6 +237,10 @@ export const MCP_TWINS = {
237
237
  "team device-revoke": { tool: "team_device_revoke", door: "POST /api/ambient/devices/[deviceId]/revoke" },
238
238
  "model show": { tool: "model_show", door: "GET /api/settings/jarvis-model" },
239
239
  "model set": { tool: "model_set", door: "POST /api/settings/jarvis-model" },
240
+ // BLI-3912: the model-card shelf. `models` is the shelf; `model` next door is
241
+ // the org setting that picks from it.
242
+ "models list": { tool: "models_list", door: "GET /api/models/cards" },
243
+ "models show": { tool: "models_card", door: "GET /api/models/cards?id=" },
240
244
  "scout board": { tool: "scout_board", door: "GET /api/cockpit/scout" },
241
245
  "scout start": { tool: "scout_start", door: "POST /api/cockpit/scout (start)" },
242
246
  "scout dismiss": { tool: "scout_dismiss", door: "POST /api/cockpit/scout (dismiss)" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/mcp",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
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",