@bli-cockpit/mcp 0.1.99 → 0.1.102

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
- **135 of 140 Tower verbs have an MCP twin.**
112
+ **136 of 141 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
@@ -191,6 +191,7 @@ three tables below.
191
191
  | `cockpit memory profile` | `memory_profile` | `GET /api/memory/profile` |
192
192
  | `cockpit memory public` | `set_memory_visibility` (`bli-memory`) | `POST /api/memory/visibility` |
193
193
  | `cockpit memory requeue` | `memory_requeue` | `POST /api/memory/requeue` |
194
+ | `cockpit memory rules` | `memory_rules` | `GET /api/memory/rules` |
194
195
  | `cockpit memory save` | `save_memory` (`bli-memory`) | `POST /api/memory/save` |
195
196
  | `cockpit memory search` | `search_memory` (`bli-memory`) | `POST /api/memory/search` |
196
197
  | `cockpit memory update` | `update_memory` (`bli-memory`) | `POST /api/memory/update` |
@@ -0,0 +1,4 @@
1
+ import { type ToolDeps } from "./tool-result.js";
2
+ export declare function registerMemoryRulesTools(server: {
3
+ registerTool: (...args: never[]) => unknown;
4
+ }, deps: ToolDeps): void;
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ import { callAgentDoor } from "./agent-door.js";
3
+ import { doorFailureText, errorResult, queryString, registrarFor, textResult, withSession } from "./tool-result.js";
4
+ export function registerMemoryRulesTools(server, deps) {
5
+ registrarFor(server)("memory_rules", {
6
+ title: "Read BLI agent ground rules",
7
+ description: "Standing instructions grouped by whose rule it is, with project and date. Reads only memories visible to you, over the same door as cockpit memory rules. Default 200, max 1000; capped means narrow the filters or increase the bound.",
8
+ inputSchema: { person: z.string().min(1).optional().describe("Exact roster name, or unattributed for memories with no author."), project: z.string().min(1).optional().describe("Exact project label, for example Pearl Portal or BLI-wide."), limit: z.number().int().min(1).max(1000).optional().describe("Maximum rows, default 200, maximum 1000. A full page is marked capped.") },
9
+ }, async (args) => withSession(deps, async (session) => {
10
+ const params = new URLSearchParams();
11
+ for (const key of ["person", "project", "limit"])
12
+ if (args[key] !== undefined)
13
+ params.set(key, String(args[key]));
14
+ const response = await callAgentDoor(session, deps.fetchImpl, "GET", `/api/memory/rules${queryString(params)}`);
15
+ if (!response.ok)
16
+ return errorResult(doorFailureText("memory_rules", response));
17
+ const body = response.body;
18
+ const lines = body.groups.flatMap((group) => [group.owner, ...group.rules.map((rule) => `[${rule.created_at.slice(0, 10)}] ${rule.project ? `[${rule.project}] ` : ""}${rule.text}${group.owner === "unattributed" ? ` (space: ${rule.container})` : ""}`)]);
19
+ if (!lines.length)
20
+ lines.push("No ground rules matched.");
21
+ if (body.capped)
22
+ lines.push("Result capped; narrow by person/project or increase limit (max 1000).");
23
+ return textResult(lines.join("\n"), response.body);
24
+ }));
25
+ }
@@ -97,16 +97,25 @@ export function registerNotesAccountTools(server, deps) {
97
97
  + "alternates, each one's transcript length, its notetaker, and the sentence saying why it holds its role "
98
98
  + "(BLI-12926). Open an alternate with `notes_recording`. Read-only; you only see recordings of meetings you "
99
99
  + "can already read.",
100
- inputSchema: { note_id: z.string().uuid().describe("A note's id, as notes_list returns it.") },
100
+ inputSchema: {
101
+ note_id: z.string().uuid().optional().describe("A note id; supply exactly one of note_id or calendar_event_id."),
102
+ calendar_event_id: z.string().min(1).max(512).optional().describe("Bot outcomes even when no note exists."),
103
+ },
101
104
  }, async (args) => withSession(deps, async (session) => {
102
- const response = await callAgentDoor(session, deps.fetchImpl, "GET", `/api/notes/recordings?note_id=${encodeURIComponent(String(args.note_id))}`);
105
+ if (Boolean(args.note_id) === Boolean(args.calendar_event_id))
106
+ return errorResult("Supply exactly one of note_id or calendar_event_id.");
107
+ const response = await callAgentDoor(session, deps.fetchImpl, "GET", args.calendar_event_id
108
+ ? `/api/notes/recordings?calendar_event_id=${encodeURIComponent(String(args.calendar_event_id))}`
109
+ : `/api/notes/recordings?note_id=${encodeURIComponent(String(args.note_id))}`);
103
110
  if (!response.ok)
104
111
  return errorResult(doorFailureText("notes_recordings", response));
105
112
  const recordings = (Array.isArray(response.body.recordings) ? response.body.recordings : []);
106
113
  const lines = recordings.map((row) => `${row.role === "primary" ? "SHOWN " : "alternate"} ${row.source_namespace} ${row.transcript_chars === null ? "length unknown" : `${row.transcript_chars} chars`} ${row.started_at ?? "no start time"} ${row.id}${row.chosen_reason ? ` (${row.chosen_reason})` : ""}`);
114
+ const missed = (Array.isArray(response.body.missed) ? response.body.missed : []);
115
+ const outcomes = missed.map((row) => `No bot transcript: ${row.status} (${row.reason}), ${row.started_at}`).join("\n");
107
116
  return dataResult(recordings.length === 0
108
- ? "No recording is indexed for this note."
109
- : `${recordings.length} recording(s) of this meeting.\n${lines.join("\n")}`, { note_id: String(args.note_id), recordings });
117
+ ? outcomes || (args.calendar_event_id ? "No recording or missed-meeting record for this calendar event." : "No recording is indexed for this note.")
118
+ : `${recordings.length} recording(s) of this meeting.\n${lines.join("\n")}\n${outcomes}`, { note_id: args.note_id, calendar_event_id: args.calendar_event_id, recordings, missed });
110
119
  }));
111
120
  register("notes_recording", {
112
121
  title: "Open one recording of a meeting",
package/dist/server.js CHANGED
@@ -21,6 +21,7 @@ import { registerNotesGranolaStatusTool } from "./notes-granola-status-tool.js";
21
21
  import { registerNotesWriteTools } from "./notes-write-tools.js";
22
22
  import { registerMemoryConsolidationTools } from "./memory-consolidation-tools.js";
23
23
  import { registerMemoryExperienceTools } from "./memory-experience-tools.js";
24
+ import { registerMemoryRulesTools } from "./memory-rules-tools.js";
24
25
  import { registerMemoryProfileTools } from "./memory-profile-tools.js";
25
26
  import { registerMemoryRequeueTools } from "./memory-requeue-tools.js";
26
27
  import { registerModelsTools } from "./models-tools.js";
@@ -475,6 +476,7 @@ export function createServer(deps, options = {}) {
475
476
  registerNotesGranolaStatusTool(server, { fetchImpl: deps.fetchImpl });
476
477
  registerOpsTools(server, { fetchImpl: deps.fetchImpl });
477
478
  registerMemoryExperienceTools(server, { fetchImpl: deps.fetchImpl });
479
+ registerMemoryRulesTools(server, { fetchImpl: deps.fetchImpl });
478
480
  // BLI-4533: the compiled one-page profile, the twin of `cockpit memory profile`.
479
481
  registerMemoryProfileTools(server, { fetchImpl: deps.fetchImpl });
480
482
  // BLI-4534: the nightly consolidation receipts, twin of `cockpit memory
@@ -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", "setup_read", "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", "glossary_list", "notes_show", "notes_shelf", "notes_shelves", "notes_place", "notes_accounts", "notes_recordings", "notes_recording", "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"];
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", "setup_read", "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", "glossary_list", "notes_show", "notes_shelf", "notes_shelves", "notes_place", "notes_accounts", "notes_recordings", "notes_recording", "notes_sync_status", "notes_granola_status", "ops_status", "slack_coverage", "slack_read", "memory_rules", "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).
@@ -72,6 +72,7 @@ export const READ_TOOLS = [
72
72
  "ops_status",
73
73
  "slack_coverage",
74
74
  "slack_read",
75
+ "memory_rules",
75
76
  "memory_profile",
76
77
  "memory_consolidation",
77
78
  "settings_show",
@@ -329,6 +329,7 @@ export const MCP_TWINS = {
329
329
  // BLI-4533: the compiled one-page profile. Its twin is on `bli-tower`, not
330
330
  // `bli-memory`: that server's four tools are the vendor-compatible set the
331
331
  // Claude Code plugin expects, and this page is ours.
332
+ "memory rules": { tool: "memory_rules", door: "GET /api/memory/rules" },
332
333
  "memory profile": { tool: "memory_profile", door: "GET /api/memory/profile" },
333
334
  // BLI-4534: the nightly consolidation receipts. This twin lives on
334
335
  // `bli-tower` rather than `bli-memory`, because it is a read of a JOB s
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/mcp",
3
- "version": "0.1.99",
3
+ "version": "0.1.102",
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",