@bli-cockpit/mcp 0.1.45 → 0.1.48
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 +3 -2
- package/dist/notes-account-tools.js +6 -5
- package/dist/ops-tools.js +26 -1
- package/dist/verb-census.js +2 -1
- package/package.json +1 -1
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
|
-
**94 of
|
|
37
|
+
**94 of 99 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
|
|
@@ -152,7 +152,8 @@ A claim about the verb's nature, not a backlog.
|
|
|
152
152
|
| `cockpit brief edit` | opens the person's own $EDITOR on this machine and files what they changed; an agent has no editor to open (commands/editor.ts) |
|
|
153
153
|
| `cockpit cal add-ical` | carries a calendar's SECRET iCal ADDRESS — a permanent, unauthenticated, read-anything-on-that-calendar URL. The CLI reads it from STDIN precisely so it never lands in an argument list; an MCP tool argument travels through a model's context window and whatever transcript store sits behind it, so attaching a calendar stays a thing a person does at a terminal (BLI-3709) |
|
|
154
154
|
| `cockpit mail add-imap` | carries a Google app password. The CLI reads it from STDIN precisely so it never lands in an argument list; an MCP tool argument travels through a model's context window and whatever transcript store sits behind it, so attaching a mailbox stays a thing a person does at a terminal (BLI-3708) |
|
|
155
|
-
| `cockpit notes connect` | carries a notetaker API key (
|
|
155
|
+
| `cockpit notes connect` | carries a notetaker API key (Fellow or Circleback). The CLI reads it from STDIN precisely so it never lands in an argument list; an MCP tool argument travels through a model's context window and whatever transcript store sits behind it, so connecting a notetaker stays a thing a person does at a terminal or in Tower's Settings (BLI-4383) |
|
|
156
|
+
| `cockpit notes webhook` | carries the VENDOR's webhook signing secret, the key an HMAC over every delivered payload is checked against. Exactly the ruling `notes connect` already carries, for the same credential shape: the CLI reads it from STDIN so it never lands in an argument list, and an MCP tool argument travels through a model's context window and whatever transcript store sits behind it (BLI-4394) |
|
|
156
157
|
|
|
157
158
|
<!-- END GENERATED verb census -->
|
|
158
159
|
|
|
@@ -30,10 +30,11 @@ export function registerNotesAccountTools(server, deps) {
|
|
|
30
30
|
const register = registrarFor(server);
|
|
31
31
|
register("notes_accounts", {
|
|
32
32
|
title: "List connected notetakers",
|
|
33
|
-
description: "Every notetaker account (
|
|
34
|
-
+ "health and when it was last read. Start here when you
|
|
35
|
-
+ "here on purpose — it carries an API key, so it is done
|
|
36
|
-
+ "--provider
|
|
33
|
+
description: "Every notetaker account (Fellow or Circleback; Otter and Granola are named but not connectable) connected to "
|
|
34
|
+
+ "Tower that you may see: name, provider, workspace, health and when it was last read. Start here when you "
|
|
35
|
+
+ "need an account id. Connecting one is NOT available here on purpose — it carries an API key, so it is done "
|
|
36
|
+
+ "at a terminal with `cockpit notes connect --provider fellow --workspace <subdomain> --key-stdin` or in "
|
|
37
|
+
+ "Tower's Settings.",
|
|
37
38
|
inputSchema: {},
|
|
38
39
|
}, async () => withSession(deps, async (session) => {
|
|
39
40
|
const response = await callAgentDoor(session, deps.fetchImpl, "GET", "/api/notes/accounts");
|
|
@@ -41,7 +42,7 @@ export function registerNotesAccountTools(server, deps) {
|
|
|
41
42
|
return errorResult(doorFailureText("notes_accounts", response));
|
|
42
43
|
const accounts = (Array.isArray(response.body.accounts) ? response.body.accounts : []);
|
|
43
44
|
return textResult(accounts.length === 0
|
|
44
|
-
? "No notetaker is connected. A person connects one with `cockpit notes connect --provider
|
|
45
|
+
? "No notetaker is connected. A person connects one with `cockpit notes connect --provider fellow --workspace <subdomain> --key-stdin`, or in Tower's Settings."
|
|
45
46
|
: `${accounts.length} notetaker(s).\n${accounts.map(accountLine).join("\n")}`, { accounts });
|
|
46
47
|
}));
|
|
47
48
|
register("notes_sync", {
|
package/dist/ops-tools.js
CHANGED
|
@@ -57,6 +57,8 @@ export function registerOpsTools(server, deps) {
|
|
|
57
57
|
job: z.string().min(1).max(100).optional().describe("One pipeline id instead of the whole board."),
|
|
58
58
|
skips: z.boolean().optional().describe("Also return the open ingest-skip ledgers."),
|
|
59
59
|
memory: z.boolean().optional().describe("Also return memory adoption and observed prompt-hook outcomes, delay bounds and cache reuse. No memory text."),
|
|
60
|
+
turns: z.boolean().optional().describe("Also return 30-day JARVIS turn aggregates: latency, hops, tools, tokens and error classes."),
|
|
61
|
+
tool_router: z.boolean().optional().describe("Also return the seven-day shadow tool-router agreement board."),
|
|
60
62
|
},
|
|
61
63
|
}, async (args) => withSession(deps, async (session) => {
|
|
62
64
|
const params = new URLSearchParams();
|
|
@@ -64,6 +66,8 @@ export function registerOpsTools(server, deps) {
|
|
|
64
66
|
params.set("job", String(args.job));
|
|
65
67
|
if (args.skips)
|
|
66
68
|
params.set("skips", "1");
|
|
69
|
+
if (args.turns)
|
|
70
|
+
params.set("turns", "1");
|
|
67
71
|
const response = await callAgentDoor(session, deps.fetchImpl, "GET", `/api/ops/status${queryString(params)}`);
|
|
68
72
|
if (!response.ok)
|
|
69
73
|
return errorResult(doorFailureText("ops_status", response));
|
|
@@ -100,6 +104,11 @@ export function registerOpsTools(server, deps) {
|
|
|
100
104
|
? await callAgentDoor(session, deps.fetchImpl, "GET", "/api/ops/memory-usage") : null;
|
|
101
105
|
if (memory && !memory.ok)
|
|
102
106
|
return errorResult(doorFailureText("ops_status memory", memory));
|
|
107
|
+
const toolRouter = args.tool_router
|
|
108
|
+
? await callAgentDoor(session, deps.fetchImpl, "GET", "/api/ops/tool-router")
|
|
109
|
+
: null;
|
|
110
|
+
if (toolRouter && !toolRouter.ok)
|
|
111
|
+
return errorResult(doorFailureText("ops_status tool router", toolRouter));
|
|
103
112
|
const experience = memory?.ok ? asRecord(memory.body.experience) : null;
|
|
104
113
|
const experienceLines = experience ? ["EXPERIENCE", experience.summary, ...(Array.isArray(experience.lines) ? experience.lines : [])].join("\n") : "";
|
|
105
114
|
const hooks = memory?.ok ? asRecord(memory.body.hooks) : null;
|
|
@@ -108,6 +117,18 @@ export function registerOpsTools(server, deps) {
|
|
|
108
117
|
const row = asRecord(device);
|
|
109
118
|
return [row.line, row.performanceLine].filter((line) => typeof line === "string").join("\n");
|
|
110
119
|
}).join("\n") : "";
|
|
120
|
+
const turns = asRecord(body.turns);
|
|
121
|
+
const turnLine = args.turns
|
|
122
|
+
? typeof turns.turns === "number"
|
|
123
|
+
? `TURNS ${turns.turns} turns / ${typeof turns.windowDays === "number" ? turns.windowDays : 30}d`
|
|
124
|
+
: "TURNS not read (turns_section_absent)"
|
|
125
|
+
: "";
|
|
126
|
+
const toolRouterBoard = toolRouter?.ok ? asRecord(toolRouter.body.board) : null;
|
|
127
|
+
const toolRouterLine = args.tool_router
|
|
128
|
+
? toolRouterBoard && typeof toolRouterBoard.turnsRouted === "number"
|
|
129
|
+
? `TOOL ROUTER ${toolRouterBoard.turnsRouted} routed`
|
|
130
|
+
: "TOOL ROUTER not read (tool_router_section_absent)"
|
|
131
|
+
: "";
|
|
111
132
|
// Both branches say something. A board that is entirely green and
|
|
112
133
|
// reports nothing cannot answer "did anybody look today?".
|
|
113
134
|
return textResult(`${rows.length} pipeline(s), ${unhealthy.length} unhealthy`
|
|
@@ -115,7 +136,9 @@ export function registerOpsTools(server, deps) {
|
|
|
115
136
|
+ `${lines ? `\n${lines}` : ""}`
|
|
116
137
|
+ `${ladderLine ? `\n${ladderLine}` : ""}`
|
|
117
138
|
+ `${memoryLines ? `\n${memoryLines}` : ""}`
|
|
118
|
-
+ `${experienceLines ? `\n${experienceLines}` : ""}
|
|
139
|
+
+ `${experienceLines ? `\n${experienceLines}` : ""}`
|
|
140
|
+
+ `${turnLine ? `\n${turnLine}` : ""}`
|
|
141
|
+
+ `${toolRouterLine ? `\n${toolRouterLine}` : ""}`,
|
|
119
142
|
// The API owns the wording and the timing boundary on every surface.
|
|
120
143
|
{
|
|
121
144
|
pipelines: rows,
|
|
@@ -125,6 +148,8 @@ export function registerOpsTools(server, deps) {
|
|
|
125
148
|
...(body.skips ? { skips: body.skips } : {}),
|
|
126
149
|
...(body.ladder ? { ladder: body.ladder } : {}),
|
|
127
150
|
...(memory?.ok ? { memory: memory.body.memory, hooks: memory.body.hooks, experience: memory.body.experience } : {}),
|
|
151
|
+
...(args.turns ? { turns: body.turns ?? null } : {}),
|
|
152
|
+
...(toolRouter?.ok ? { toolRouter: toolRouter.body.board ?? null } : {}),
|
|
128
153
|
});
|
|
129
154
|
}));
|
|
130
155
|
register("slack_coverage", {
|
package/dist/verb-census.js
CHANGED
|
@@ -355,7 +355,8 @@ export const TERMINAL_ONLY = {
|
|
|
355
355
|
"mail add-imap": "carries a Google app password. The CLI reads it from STDIN precisely so it never lands in an argument list; an MCP tool argument travels through a model's context window and whatever transcript store sits behind it, so attaching a mailbox stays a thing a person does at a terminal (BLI-3708)",
|
|
356
356
|
"cal add-ical": "carries a calendar's SECRET iCal ADDRESS — a permanent, unauthenticated, read-anything-on-that-calendar URL. The CLI reads it from STDIN precisely so it never lands in an argument list; an MCP tool argument travels through a model's context window and whatever transcript store sits behind it, so attaching a calendar stays a thing a person does at a terminal (BLI-3709)",
|
|
357
357
|
"brief edit": "opens the person's own $EDITOR on this machine and files what they changed; an agent has no editor to open (commands/editor.ts)",
|
|
358
|
-
"notes connect": "carries a notetaker API key (
|
|
358
|
+
"notes connect": "carries a notetaker API key (Fellow or Circleback). The CLI reads it from STDIN precisely so it never lands in an argument list; an MCP tool argument travels through a model's context window and whatever transcript store sits behind it, so connecting a notetaker stays a thing a person does at a terminal or in Tower's Settings (BLI-4383)",
|
|
359
|
+
"notes webhook": "carries the VENDOR's webhook signing secret, the key an HMAC over every delivered payload is checked against. Exactly the ruling `notes connect` already carries, for the same credential shape: the CLI reads it from STDIN so it never lands in an argument list, and an MCP tool argument travels through a model's context window and whatever transcript store sits behind it (BLI-4394)",
|
|
359
360
|
};
|
|
360
361
|
/**
|
|
361
362
|
* Verbs owed a twin, with who owes it. This list should only ever shrink.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.48",
|
|
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",
|