@bli-cockpit/mcp 0.1.94 → 0.1.95

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
@@ -109,7 +109,7 @@ about what an agent can reach.
109
109
 
110
110
  <!-- BEGIN GENERATED verb census — `npm run mcp:readme` -->
111
111
 
112
- **125 of 130 Tower verbs have an MCP twin.**
112
+ **126 of 131 Tower verbs have an MCP twin.**
113
113
  Each tool goes through the SAME door its CLI verb calls, with the same
114
114
  collector device token — never a second route and never a service-role
115
115
  reader. `src/verb-census.test.ts` fails when a verb is in none of the
@@ -117,6 +117,7 @@ three tables below.
117
117
 
118
118
  | CLI verb | MCP tool | Door |
119
119
  | --- | --- | --- |
120
+ | `cockpit brain status` | `brain_status` | `GET /api/brain/incidents` |
120
121
  | `cockpit brief done` | `brief_done` | `POST /api/jarvis/ticks` |
121
122
  | `cockpit brief history` | `brief_history` | `GET /api/jarvis/brief?history=1` |
122
123
  | `cockpit brief read` | `brief_read` | `GET /api/jarvis/brief` |
@@ -0,0 +1,4 @@
1
+ import { type ToolDeps } from "./tool-result.js";
2
+ export declare function registerBrainTools(server: {
3
+ registerTool: (...args: never[]) => unknown;
4
+ }, deps: ToolDeps): void;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * `brain_status`, the twin of `cockpit brain status` (BLI-12859, slice 1).
3
+ *
4
+ * Tower's incident queue over the SAME door the CLI reads: `GET /api/brain/incidents`, on the
5
+ * collector's device token, never a second route. Per project: how many incidents are open, being
6
+ * worked, waiting on a person, fixed, not actionable or cleared; the newest ones (default open)
7
+ * with their Tower issue, count, last-seen time and masked template; and the last 7 days of
8
+ * verdicts. Read-only. The text half is plain words; the structured half carries the raw labels.
9
+ */
10
+ import { z } from "zod";
11
+ import { callAgentDoor } from "./agent-door.js";
12
+ import { dataResult, doorFailureText, errorResult, registrarFor, withSession } from "./tool-result.js";
13
+ const STATUSES = ["open", "running", "needs_human", "fixed", "not_actionable", "cleared"];
14
+ export function registerBrainTools(server, deps) {
15
+ registrarFor(server)("brain_status", {
16
+ title: "Read Tower's incident queue",
17
+ description: "Tower's incident queue over every project's log digests. Every 15 minutes the log-digest cron turns each recurring problem (classes our_bug, config_drift, capacity, "
18
+ + "unknown) into ONE incident with ONE Tower issue; a repeat adds to its count and never opens a twin, and a template quiet for 24 hours is cleared. Returns, per project, "
19
+ + "the count of incidents by status (open, running, needs_human, fixed, not_actionable, cleared), the newest incidents in the `show` status (default open) with their Tower "
20
+ + "issue identifier, class, how many times each was seen, when it was last seen and its masked template, and how many verdicts landed in the last 7 days. "
21
+ + "`project` narrows to one project (see logs_digest for the ids). Read-only. `cockpit brain status`, same door.",
22
+ inputSchema: {
23
+ project: z.string().regex(/^[a-z][a-z0-9-]{1,40}$/).optional().describe("A registry project id, like pearl-portal or kolm. Omit for every project with an incident."),
24
+ show: z.enum(STATUSES).optional().describe("Which status the newest-incidents list shows. Default open."),
25
+ },
26
+ }, async (args) => withSession(deps, async (session) => {
27
+ const query = new URLSearchParams();
28
+ if (typeof args.project === "string")
29
+ query.set("project", args.project);
30
+ if (typeof args.show === "string")
31
+ query.set("status", args.show);
32
+ const asked = query.toString();
33
+ const response = await callAgentDoor(session, deps.fetchImpl, "GET", asked ? `/api/brain/incidents?${asked}` : "/api/brain/incidents");
34
+ if (!response.ok)
35
+ return errorResult(doorFailureText("brain_status", response));
36
+ const text = typeof response.body.text === "string" ? response.body.text : "";
37
+ return dataResult(text, response.body);
38
+ }));
39
+ }
package/dist/server.js CHANGED
@@ -35,6 +35,7 @@ import { registerCareersTools } from "./careers-tools.js";
35
35
  import { registerRenameTools } from "./rename-tools.js";
36
36
  import { registerUsageTools } from "./usage-tools.js";
37
37
  import { registerLogsTools } from "./logs-tools.js";
38
+ import { registerBrainTools } from "./brain-tools.js";
38
39
  import { registerSourcesTools } from "./sources-tools.js";
39
40
  import { TOWER_SERVER_ICONS } from "./server-icons.js";
40
41
  import { installToolRegistration } from "./tool-registration.js";
@@ -504,5 +505,8 @@ export function createServer(deps, options = {}) {
504
505
  // BLI-12833: a token-cheap digest of Tower's own logs, read on this machine
505
506
  // with the shared `@bli-cockpit/telemetry-core/log-digest`. Read-only; not on the hosted server.
506
507
  registerLogsTools(server, { fetchImpl: deps.fetchImpl });
508
+ // BLI-12859: Tower's incident queue (one incident, one issue, per recurring log problem), over
509
+ // the same GET /api/brain/incidents door `cockpit brain status` reads. Read-only.
510
+ registerBrainTools(server, { fetchImpl: deps.fetchImpl });
507
511
  return server;
508
512
  }
@@ -10,7 +10,7 @@
10
10
  * from `src/` under Node's type stripping, so it may import nothing.
11
11
  */
12
12
  /** Tools that change nothing. The smoke calls every one. */
13
- export declare const READ_TOOLS: readonly ["get_ticket_timeline", "get_active_tickets", "docs_list", "docs_tree", "docs_read", "docs_sync_status", "msg_channels", "msg_read", "msg_thread", "work_list_issues", "work_get_issue", "work_issue_history", "work_list_projects", "careers_list", "careers_show", "careers_resume_url", "careers_takehome_show", "careers_settings_show", "rename_pending", "github_pr", "usage_people", "usage_sessions", "mail_accounts", "mail_inbox", "mail_read", "mail_search", "mail_attachment", "mail_sync_status", "cal_today", "cal_week", "cal_next", "cal_find", "cal_calendars", "cal_sync_status", "jarvis_ask", "jarvis_trace", "jarvis_check", "models_list", "models_card", "models_compare", "brief_read", "brief_history", "brief_status", "brief_missed", "notes_folders", "notes_list", "notes_show", "notes_shelf", "notes_shelves", "notes_place", "notes_accounts", "notes_sync_status", "notes_granola_status", "ops_status", "slack_coverage", "slack_read", "memory_profile", "memory_consolidation", "settings_show", "settings_list", "model_show", "team_members", "team_device_list", "scout_board", "workbook_read", "tower_search", "sources_check", "logs_digest"];
13
+ export declare const READ_TOOLS: readonly ["get_ticket_timeline", "get_active_tickets", "docs_list", "docs_tree", "docs_read", "docs_sync_status", "msg_channels", "msg_read", "msg_thread", "work_list_issues", "work_get_issue", "work_issue_history", "work_list_projects", "careers_list", "careers_show", "careers_resume_url", "careers_takehome_show", "careers_settings_show", "rename_pending", "github_pr", "usage_people", "usage_sessions", "mail_accounts", "mail_inbox", "mail_read", "mail_search", "mail_attachment", "mail_sync_status", "cal_today", "cal_week", "cal_next", "cal_find", "cal_calendars", "cal_sync_status", "jarvis_ask", "jarvis_trace", "jarvis_check", "models_list", "models_card", "models_compare", "brief_read", "brief_history", "brief_status", "brief_missed", "notes_folders", "notes_list", "notes_show", "notes_shelf", "notes_shelves", "notes_place", "notes_accounts", "notes_sync_status", "notes_granola_status", "ops_status", "slack_coverage", "slack_read", "memory_profile", "memory_consolidation", "settings_show", "settings_list", "model_show", "team_members", "team_device_list", "scout_board", "workbook_read", "tower_search", "sources_check", "logs_digest", "brain_status"];
14
14
  /**
15
15
  * Tools that write, but answer a dry run that writes nothing. The smoke calls
16
16
  * each one ONLY with its dry-run flag set (`scripts/smoke.ts` says which).
@@ -80,6 +80,8 @@ export const READ_TOOLS = [
80
80
  "sources_check",
81
81
  // BLI-12833: a digest of Tower's own logs, read on this machine. Reads only.
82
82
  "logs_digest",
83
+ // BLI-12859: Tower's incident queue, per project. Reads only.
84
+ "brain_status",
83
85
  ];
84
86
  /**
85
87
  * Tools that write, but answer a dry run that writes nothing. The smoke calls
@@ -243,6 +243,7 @@ export const MCP_TWINS = {
243
243
  // this machine's collector logs and the `vercel` / `railway` CLIs.
244
244
  // BLI-12855: a project name (or --stored, or a local CLI that is missing) reads the digests Tower's cron stored, through GET /api/logs.
245
245
  "logs": { tool: "logs_digest", door: "LOCAL @bli-cockpit/telemetry-core/log-digest (this machine's logs); `project` reads GET /api/logs (the stored digests)" },
246
+ "brain status": { tool: "brain_status", door: "GET /api/brain/incidents" },
246
247
  "usage sessions": { tool: "usage_sessions", door: "GET /api/usage/sessions" },
247
248
  "usage people": { tool: "usage_people", door: "GET /api/usage/people" },
248
249
  "docs list": { tool: "docs_list", door: "GET /api/docs/documents" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/mcp",
3
- "version": "0.1.94",
3
+ "version": "0.1.95",
4
4
  "private": false,
5
5
  "description": "bli-tower: 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",
@@ -37,7 +37,7 @@
37
37
  "readme": "npm run build && node scripts/write-readme-census.mjs"
38
38
  },
39
39
  "dependencies": {
40
- "@bli-cockpit/telemetry-core": "0.1.64",
40
+ "@bli-cockpit/telemetry-core": "0.1.65",
41
41
  "@modelcontextprotocol/sdk": "^1.29.0",
42
42
  "zod": "^4.3.6"
43
43
  },