@bli-cockpit/mcp 0.1.110 → 0.1.111
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 +9 -1
- package/dist/account-tools.d.ts +2 -0
- package/dist/account-tools.js +19 -0
- package/dist/cal-tools-delete.js +21 -3
- package/dist/cal-tools.js +5 -2
- package/dist/mail-compose.js +2 -1
- package/dist/mail-tools.js +12 -8
- package/dist/notes-bot-upcoming-tool.d.ts +4 -0
- package/dist/notes-bot-upcoming-tool.js +14 -0
- package/dist/server.js +2 -0
- package/dist/tool-catalog.d.ts +2 -2
- package/dist/tool-catalog.js +2 -0
- package/dist/verb-census.js +8 -0
- package/package.json +1 -1
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
|
-
**
|
|
112
|
+
**147 of 152 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
|
|
@@ -126,6 +126,8 @@ three tables below.
|
|
|
126
126
|
| `cockpit brief status` | `brief_status` | `GET /api/ops/brief-status` |
|
|
127
127
|
| `cockpit brief undone` | `brief_undone` | `POST /api/jarvis/ticks` |
|
|
128
128
|
| `cockpit cal calendars` | `cal_calendars` | `GET /api/cal/calendars` |
|
|
129
|
+
| `cockpit cal cancel` | `cal_delete` | `DELETE /api/cal/events/[eventId]` |
|
|
130
|
+
| `cockpit cal change` | `cal_change` | `PATCH /api/cal/events/[eventId]` |
|
|
129
131
|
| `cockpit cal create` | `cal_create` | `POST /api/cal/events` |
|
|
130
132
|
| `cockpit cal delete` | `cal_delete` | `DELETE /api/cal/events/[eventId]` |
|
|
131
133
|
| `cockpit cal detach` | `cal_detach` | `DELETE /api/cal/calendars` |
|
|
@@ -177,10 +179,15 @@ three tables below.
|
|
|
177
179
|
| `cockpit logs` | `logs_digest` | `LOCAL @bli-cockpit/telemetry-core/log-digest (this machine's logs); `project` reads GET /api/logs (the stored digests)` |
|
|
178
180
|
| `cockpit mail accounts` | `mail_accounts` | `GET /api/mail/accounts` |
|
|
179
181
|
| `cockpit mail attachment` | `mail_attachment` | `GET /api/mail/attachments/[id]?meta=1` |
|
|
182
|
+
| `cockpit mail default` | `mail_default` | `PATCH /api/mail/accounts` |
|
|
180
183
|
| `cockpit mail detach` | `mail_detach` | `DELETE /api/mail/accounts` |
|
|
184
|
+
| `cockpit mail disable` | `mail_disable` | `PATCH /api/mail/accounts` |
|
|
181
185
|
| `cockpit mail draft` | `mail_draft` | `POST /api/mail/drafts` |
|
|
186
|
+
| `cockpit mail enable` | `mail_enable` | `PATCH /api/mail/accounts` |
|
|
182
187
|
| `cockpit mail inbox` | `mail_inbox` | `GET /api/mail/inbox` |
|
|
183
188
|
| `cockpit mail read` | `mail_read` | `GET /api/mail/threads/[id]` |
|
|
189
|
+
| `cockpit mail remove` | `mail_remove` | `DELETE /api/mail/accounts` |
|
|
190
|
+
| `cockpit mail rename` | `mail_rename` | `PATCH /api/mail/accounts` |
|
|
184
191
|
| `cockpit mail search` | `mail_search` | `GET /api/mail/search` |
|
|
185
192
|
| `cockpit mail send` | `mail_send` | `POST /api/mail/send` |
|
|
186
193
|
| `cockpit mail sync` | `mail_sync` | `POST /api/mail/accounts/[id]/sync` |
|
|
@@ -208,6 +215,7 @@ three tables below.
|
|
|
208
215
|
| `cockpit msg send` | `msg_send` | `POST /api/msg/channels/[id]/messages` |
|
|
209
216
|
| `cockpit msg thread` | `msg_thread` | `GET /api/msg/channels/[id]/messages?thread_parent_id=` |
|
|
210
217
|
| `cockpit notes accounts` | `notes_accounts` | `GET /api/notes/accounts` |
|
|
218
|
+
| `cockpit notes bot-upcoming` | `notes_bot_upcoming` | `GET /api/notetaker/upcoming` |
|
|
211
219
|
| `cockpit notes detach` | `notes_detach` | `DELETE /api/notes/accounts` |
|
|
212
220
|
| `cockpit notes folders` | `notes_folders` | `GET /api/notes/folders` |
|
|
213
221
|
| `cockpit notes granola-status` | `notes_granola_status` | `GET /api/notes/granola-status` |
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { callAgentDoor } from "./agent-door.js";
|
|
3
|
+
import { withSession, textResult, errorResult, doorFailureText } from "./tool-result.js";
|
|
4
|
+
export function registerAccountTools(register, deps) {
|
|
5
|
+
for (const action of ["rename", "enable", "disable", "default", "remove"]) {
|
|
6
|
+
register(`mail_${action}`, { title: `${action} a connected account`, description: "Manage the caller's shared mail/calendar account. Exact case-folded label, address or id. Removing disconnects the account and deletes Tower's stored copies; provider data is untouched.",
|
|
7
|
+
inputSchema: {
|
|
8
|
+
account: z.string().min(1).max(320).describe("The connected account: its exact label, address or id (mail_accounts lists them)."),
|
|
9
|
+
...(action === "rename" ? { name: z.string().trim().min(1).max(100).describe("The new label, e.g. personal 1.") } : {}),
|
|
10
|
+
...(["enable", "disable"].includes(action) ? { source: z.enum(["mail", "calendar"]).describe("Which source to switch: mail or calendar.") } : {}),
|
|
11
|
+
},
|
|
12
|
+
}, async (args) => withSession(deps, async (session) => {
|
|
13
|
+
const response = await callAgentDoor(session, deps.fetchImpl, action === "remove" ? "DELETE" : "PATCH", action === "remove" ? `/api/mail/accounts?account=${encodeURIComponent(String(args.account))}` : "/api/mail/accounts", action === "remove" ? undefined : { account: args.account, ...(action === "rename" ? { account_label: args.name } : action === "default" ? { is_default: true } : { [`${args.source}_enabled`]: action === "enable" }) });
|
|
14
|
+
if (!response.ok)
|
|
15
|
+
return errorResult(doorFailureText(`mail_${action}`, response));
|
|
16
|
+
return textResult(`Account ${args.account}: ${action} completed.`, response.body);
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
}
|
package/dist/cal-tools-delete.js
CHANGED
|
@@ -9,6 +9,22 @@ import { z } from "zod";
|
|
|
9
9
|
import { callAgentDoor } from "./agent-door.js";
|
|
10
10
|
import { CONFIRM_INPUT, doorFailureText, errorResult, textResult, unconfirmed, withSession, } from "./tool-result.js";
|
|
11
11
|
export function registerCalDeleteTool(register, deps) {
|
|
12
|
+
register("cal_change", { title: "Change an event", description: "Change a caller-owned event, checking the named account before writing to Google.", inputSchema: {
|
|
13
|
+
event_id: z.string().uuid().describe("Tower's event id (cal_today/cal_week/cal_next/cal_find return it as event_id)."),
|
|
14
|
+
account: z.string().min(1).max(100).optional().describe("Exact connected account label, address or id (mail_accounts lists them). Omit to use the account the event is on."),
|
|
15
|
+
title: z.string().min(1).max(500).optional().describe("The new title."),
|
|
16
|
+
starts_at: z.string().optional().describe("The new start, ISO 8601 with offset. Send with ends_at."),
|
|
17
|
+
ends_at: z.string().optional().describe("The new end, ISO 8601 with offset. Send with starts_at."),
|
|
18
|
+
location: z.string().max(1000).optional().describe("The new location."),
|
|
19
|
+
confirm: CONFIRM_INPUT,
|
|
20
|
+
} }, async (args) => withSession(deps, async (session) => {
|
|
21
|
+
const refusal = unconfirmed(args, "This changes the event at Google and may notify guests.");
|
|
22
|
+
if (refusal)
|
|
23
|
+
return refusal;
|
|
24
|
+
const { event_id, confirm: _confirm, ...changes } = args;
|
|
25
|
+
const response = await callAgentDoor(session, deps.fetchImpl, "PATCH", `/api/cal/events/${encodeURIComponent(String(event_id))}`, changes);
|
|
26
|
+
return response.ok ? textResult(`Event changed. Account: ${response.body.event?.account_name ?? "the event’s account"}.`, response.body) : errorResult(doorFailureText("cal_change", response));
|
|
27
|
+
}));
|
|
12
28
|
register("cal_delete", {
|
|
13
29
|
title: "Delete an event",
|
|
14
30
|
description: "Removes ONE event, AT GOOGLE first and then here — the same order every calendar write in this server "
|
|
@@ -16,6 +32,7 @@ export function registerCalDeleteTool(register, deps) {
|
|
|
16
32
|
+ "Attendees are notified (sendUpdates=all) only when the event has any. Google already having it gone "
|
|
17
33
|
+ "(404/410) is answered as success, not a refusal. Requires confirm: true.",
|
|
18
34
|
inputSchema: {
|
|
35
|
+
account: z.string().min(1).max(100).optional().describe("Exact connected account label, address or id (mail_accounts lists them). Omit to use the account the event is on."),
|
|
19
36
|
event_id: z.string().uuid().describe("Tower's event id (cal_today/cal_week/cal_next/cal_find return it as event_id)."),
|
|
20
37
|
confirm: CONFIRM_INPUT,
|
|
21
38
|
},
|
|
@@ -23,18 +40,19 @@ export function registerCalDeleteTool(register, deps) {
|
|
|
23
40
|
const refusal = unconfirmed(args, "This would remove that event at Google (emailing any attendees) and then here.");
|
|
24
41
|
if (refusal)
|
|
25
42
|
return refusal;
|
|
26
|
-
const response = await callAgentDoor(session, deps.fetchImpl, "DELETE", `/api/cal/events/${encodeURIComponent(String(args.event_id))}`);
|
|
43
|
+
const response = await callAgentDoor(session, deps.fetchImpl, "DELETE", `/api/cal/events/${encodeURIComponent(String(args.event_id))}${args.account ? `?account=${encodeURIComponent(String(args.account))}` : ""}`);
|
|
27
44
|
if (!response.ok)
|
|
28
45
|
return errorResult(doorFailureText("cal_delete", response));
|
|
29
46
|
const deleted = response.body.deleted;
|
|
30
47
|
if (!deleted)
|
|
31
48
|
return textResult("Tower answered without a result. Nothing to report.", response.body);
|
|
32
49
|
const alreadyGone = deleted.google === "already_gone_at_google";
|
|
50
|
+
const accountReceipt = deleted.account_name ? ` Account: ${deleted.account_name}.` : "";
|
|
33
51
|
const stored = deleted.local_store === "removed"
|
|
34
52
|
? "Tower's copy is removed."
|
|
35
53
|
: "Tower's copy is still there for now — the next sync will pick up that it is gone.";
|
|
36
54
|
return textResult(alreadyGone
|
|
37
|
-
? `Google already had that event gone. ${stored}`
|
|
38
|
-
: `Deleted at Google${deleted.notified === "all" ? " — attendees were notified." : "."} ${stored}`, { deleted });
|
|
55
|
+
? `Google already had that event gone. ${stored}${accountReceipt}`
|
|
56
|
+
: `Deleted at Google${deleted.notified === "all" ? " — attendees were notified." : "."} ${stored}${accountReceipt}`, { deleted });
|
|
39
57
|
}));
|
|
40
58
|
}
|
package/dist/cal-tools.js
CHANGED
|
@@ -169,7 +169,7 @@ export function registerCalTools(server, deps) {
|
|
|
169
169
|
? "No calendars are attached. A person attaches one with `cockpit cal add-ical` (personal) or by connecting "
|
|
170
170
|
+ "Google in the browser (work)."
|
|
171
171
|
: `${calendars.length} calendar(s).\n${calendars
|
|
172
|
-
.map((calendar) => `${calendar.name} ${calendar.provider} ${calendar.org_visible ? "shared" : "private"} ${calendar.status}${calendar.status_reason ? ` (${calendar.status_reason})` : ""} ${calendar.id}`)
|
|
172
|
+
.map((calendar) => `${calendar.account_label ?? calendar.provider} ${calendar.name} ${calendar.provider} ${calendar.org_visible ? "shared" : "private"} ${calendar.status}${calendar.status_reason ? ` (${calendar.status_reason})` : ""} ${calendar.id}`)
|
|
173
173
|
.join("\n")}`, { calendars });
|
|
174
174
|
}));
|
|
175
175
|
register("cal_create", {
|
|
@@ -179,7 +179,8 @@ export function registerCalTools(server, deps) {
|
|
|
179
179
|
+ "says so by name. Times are ISO instants, or plain dates with all_day. Requires confirm: true, because "
|
|
180
180
|
+ "attendees are emailed by Google the moment this succeeds.",
|
|
181
181
|
inputSchema: {
|
|
182
|
-
calendar_id: z.string().uuid().describe("A google_oauth calendar id you own (cal_calendars)."),
|
|
182
|
+
calendar_id: z.string().uuid().optional().describe("A google_oauth calendar id you own (cal_calendars)."),
|
|
183
|
+
account: z.string().min(1).max(100).optional().describe("Exact connected account label; omitted uses default."),
|
|
183
184
|
title: z.string().min(1).max(500).describe("The event title."),
|
|
184
185
|
starts_at: z.string().min(4).max(40).describe("An ISO instant, or a YYYY-MM-DD date with all_day."),
|
|
185
186
|
ends_at: z.string().min(4).max(40).describe("An ISO instant, or a YYYY-MM-DD date with all_day."),
|
|
@@ -196,6 +197,7 @@ export function registerCalTools(server, deps) {
|
|
|
196
197
|
return refusal;
|
|
197
198
|
const response = await callAgentDoor(session, deps.fetchImpl, "POST", "/api/cal/events", {
|
|
198
199
|
calendar_id: args.calendar_id,
|
|
200
|
+
...(args.account ? { account: args.account } : {}),
|
|
199
201
|
title: args.title,
|
|
200
202
|
starts_at: args.starts_at,
|
|
201
203
|
ends_at: args.ends_at,
|
|
@@ -209,6 +211,7 @@ export function registerCalTools(server, deps) {
|
|
|
209
211
|
return errorResult(doorFailureText("cal_create", response));
|
|
210
212
|
const event = response.body.event;
|
|
211
213
|
return textResult(`Created "${event?.title ?? String(args.title)}" at ${event?.starts_at ?? String(args.starts_at)}.`
|
|
214
|
+
+ (event?.account_name ? `\nAccount: ${event.account_name}.` : "")
|
|
212
215
|
+ towerIdLine(event)
|
|
213
216
|
+ (event?.html_link ? `\n${event.html_link}` : "")
|
|
214
217
|
+ (args.meet === true
|
package/dist/mail-compose.js
CHANGED
|
@@ -28,7 +28,8 @@ export const ATTACHMENTS_INPUT = z
|
|
|
28
28
|
/** The JSON both tools post. `attachments` is present only when there are files. */
|
|
29
29
|
export function composedBody(args, attachments = []) {
|
|
30
30
|
return {
|
|
31
|
-
account_id: args.account_id,
|
|
31
|
+
...(args.account_id ? { account_id: args.account_id } : {}),
|
|
32
|
+
...(args.account ? { account: args.account } : {}),
|
|
32
33
|
to: args.to.map((address) => ({ address })),
|
|
33
34
|
...(Array.isArray(args.cc) && args.cc.length > 0
|
|
34
35
|
? { cc: args.cc.map((address) => ({ address })) }
|
package/dist/mail-tools.js
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
* call, so a machine with no `cockpit login` pairing still serves this
|
|
35
35
|
* server's other tools and only a `mail_` call fails, by name.
|
|
36
36
|
*/
|
|
37
|
+
import { registerAccountTools } from "./account-tools.js";
|
|
37
38
|
import { z } from "zod";
|
|
38
39
|
import { callAgentDoor } from "./agent-door.js";
|
|
39
40
|
import { ATTACHMENTS_INPUT, attachmentResult, prepareMessage, unconfirmedAttachments } from "./mail-compose.js";
|
|
@@ -45,10 +46,11 @@ function messageLine(message) {
|
|
|
45
46
|
const ADDRESS = EMAIL_INPUT.describe("An email address.");
|
|
46
47
|
export function registerMailTools(server, deps) {
|
|
47
48
|
const register = registrarFor(server);
|
|
49
|
+
registerAccountTools(register, deps);
|
|
48
50
|
register("mail_accounts", {
|
|
49
51
|
title: "List attached mailboxes",
|
|
50
52
|
description: "Every mailbox attached to Tower that you may see — address, provider (gmail_oauth or imap), health and last sync. "
|
|
51
|
-
+ "One person may have several
|
|
53
|
+
+ "One person may have several, each with a label (e.g. personal 1) and per-source switches; one may be marked default. Start here when you need an account name or id.",
|
|
52
54
|
inputSchema: {},
|
|
53
55
|
}, async () => withSession(deps, async (session) => {
|
|
54
56
|
const response = await callAgentDoor(session, deps.fetchImpl, "GET", "/api/mail/accounts");
|
|
@@ -56,7 +58,7 @@ export function registerMailTools(server, deps) {
|
|
|
56
58
|
return errorResult(doorFailureText("mail_accounts", response));
|
|
57
59
|
const accounts = (Array.isArray(response.body.accounts) ? response.body.accounts : []);
|
|
58
60
|
const lines = accounts
|
|
59
|
-
.map((account) => `${account.address} ${account.provider} ${account.status}${account.status_reason ? ` (${account.status_reason})` : ""} ${account.id}`)
|
|
61
|
+
.map((account) => `${account.account_label ?? account.address} ${account.is_default ? "default" : ""} mail=${account.mail_enabled !== false} calendar=${account.calendar_enabled !== false} ${account.address} ${account.provider} ${account.status}${account.status_reason ? ` (${account.status_reason})` : ""} ${account.id}`)
|
|
60
62
|
.join("\n");
|
|
61
63
|
return textResult(accounts.length === 0
|
|
62
64
|
? "No mailboxes are attached. A person attaches one with `cockpit mail add-imap` (personal) or the browser (work)."
|
|
@@ -187,7 +189,8 @@ export function registerMailTools(server, deps) {
|
|
|
187
189
|
+ "see that argument for what it refuses. "
|
|
188
190
|
+ "This actually sends mail to real people: confirm must be true.",
|
|
189
191
|
inputSchema: {
|
|
190
|
-
account_id: z.string().uuid().describe("The mailbox
|
|
192
|
+
account_id: z.string().uuid().optional().describe("The mailbox id, or use account name/default."),
|
|
193
|
+
account: z.string().min(1).max(100).optional().describe("Exact connected account label."),
|
|
191
194
|
to: z.array(ADDRESS).min(1).max(50).describe("Recipient email addresses."),
|
|
192
195
|
cc: z.array(ADDRESS).max(50).optional().describe("Copied email addresses."),
|
|
193
196
|
subject: z.string().max(998).describe("The subject line."),
|
|
@@ -213,14 +216,14 @@ export function registerMailTools(server, deps) {
|
|
|
213
216
|
if (notConfirmed)
|
|
214
217
|
return errorResult(notConfirmed);
|
|
215
218
|
const files = attachmentResult(message.summary);
|
|
216
|
-
return textResult(`Sent from ${sent?.address ?? "that mailbox"} to ${args.to.join(", ")}${sent?.threaded ? " (as a reply)" : ""}.${files.sentence}`, { sent, ...files.structured });
|
|
219
|
+
return textResult(`Sent from ${sent?.account_name ?? sent?.address ?? "that mailbox"} to ${args.to.join(", ")}${sent?.threaded ? " (as a reply)" : ""}.${files.sentence}`, { sent, ...files.structured });
|
|
217
220
|
}));
|
|
218
221
|
register("mail_draft", {
|
|
219
222
|
title: "Save a draft in one mailbox",
|
|
220
223
|
description: "Saves a message as a DRAFT in one of YOUR mailboxes, for a person to read, edit and send themselves. Use it "
|
|
221
224
|
+ "when you are preparing mail on somebody's behalf and they should be the one to press send. NOTHING IS SENT and "
|
|
222
|
-
+ "nobody is notified, so unlike mail_send there is no confirm flag. `
|
|
223
|
-
+ "draft is saved in (mail_accounts)
|
|
225
|
+
+ "nobody is notified, so unlike mail_send there is no confirm flag. `account` is an exact label; `account_id` selects a mailbox id. Omit both for your default. The "
|
|
226
|
+
+ "draft is saved in that mailbox (mail_accounts). With several accounts and no default, Tower asks which one. "
|
|
224
227
|
+ "`in_reply_to_message_id` (a message id from mail_read) threads the draft into that conversation the way mail_send "
|
|
225
228
|
+ "threads a reply; Gmail files it there only when the subject matches the original's, and the answer says whether it "
|
|
226
229
|
+ "did (`threaded`). `attachments` ([{ path }]) puts files from this machine in the draft, up to 10 and 3,000,000 bytes "
|
|
@@ -228,7 +231,8 @@ export function registerMailTools(server, deps) {
|
|
|
228
231
|
+ "mailboxes can take one: an IMAP mailbox is refused as imap_drafts_unsupported. Answers the provider draft id, "
|
|
229
232
|
+ "the thread id and the account id.",
|
|
230
233
|
inputSchema: {
|
|
231
|
-
account_id: z.string().uuid().describe("The mailbox
|
|
234
|
+
account_id: z.string().uuid().optional().describe("The mailbox id, or use account name/default."),
|
|
235
|
+
account: z.string().min(1).max(100).optional().describe("Exact account label, e.g. work 1."),
|
|
232
236
|
to: z.array(ADDRESS).min(1).max(50).describe("Recipient email addresses, so the draft is ready to send as it is."),
|
|
233
237
|
cc: z.array(ADDRESS).max(50).optional().describe("Copied email addresses."),
|
|
234
238
|
subject: z.string().max(998).describe("The subject line. For a reply, keep the original's subject or Gmail will not thread it."),
|
|
@@ -252,7 +256,7 @@ export function registerMailTools(server, deps) {
|
|
|
252
256
|
const files = attachmentResult(message.summary);
|
|
253
257
|
// Both halves carry the ids (BLI-10432): a client that hands the model only
|
|
254
258
|
// `content`, or only `structuredContent`, must still learn where the draft is.
|
|
255
|
-
return textResult(`Saved a draft in ${draft?.address ?? "that mailbox"} for ${args.to.join(", ")}`
|
|
259
|
+
return textResult(`Saved a draft in ${draft?.account_name ?? draft?.address ?? "that mailbox"} for ${args.to.join(", ")}`
|
|
256
260
|
+ `${draft?.threaded ? " (in the reply's thread)" : args.in_reply_to_message_id ? " (Gmail did NOT file it in that thread: its subject has to match the original's)" : ""}. `
|
|
257
261
|
+ "Nothing was sent: it waits in Drafts for a person to read, edit and send."
|
|
258
262
|
+ `${files.sentence} `
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { callAgentDoor } from "./agent-door.js";
|
|
3
|
+
import { registrarFor, withSession, textResult, errorResult, doorFailureText } from "./tool-result.js";
|
|
4
|
+
export function registerNotesBotUpcomingTool(server, deps) {
|
|
5
|
+
registrarFor(server)("notes_bot_upcoming", {
|
|
6
|
+
title: "Bot meetings today", description: "Your own Google Meet meetings today the Tower bot will join, with claim state. Decline the event or mark it private to opt out.",
|
|
7
|
+
inputSchema: { tz: z.string().optional().describe("Your IANA time zone; defaults to UTC.") },
|
|
8
|
+
}, async (args) => withSession(deps, async (session) => {
|
|
9
|
+
const response = await callAgentDoor(session, deps.fetchImpl, "GET", `/api/notetaker/upcoming?tz=${encodeURIComponent(String(args.tz ?? "UTC"))}`);
|
|
10
|
+
if (!response.ok)
|
|
11
|
+
return errorResult(doorFailureText("notes_bot_upcoming", response));
|
|
12
|
+
return textResult(JSON.stringify(response.body), response.body);
|
|
13
|
+
}));
|
|
14
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -17,6 +17,7 @@ import { registerCalTools } from "./cal-tools.js";
|
|
|
17
17
|
import { registerMailTools } from "./mail-tools.js";
|
|
18
18
|
import { registerNotesAccountTools } from "./notes-account-tools.js";
|
|
19
19
|
import { registerNotesTools } from "./notes-tools.js";
|
|
20
|
+
import { registerNotesBotUpcomingTool } from "./notes-bot-upcoming-tool.js";
|
|
20
21
|
import { registerNotesGranolaStatusTool } from "./notes-granola-status-tool.js";
|
|
21
22
|
import { registerNotesWriteTools } from "./notes-write-tools.js";
|
|
22
23
|
import { registerMemoryConsolidationTools } from "./memory-consolidation-tools.js";
|
|
@@ -476,6 +477,7 @@ export function createServer(deps, options = {}) {
|
|
|
476
477
|
registerNotesTools(server, { fetchImpl: deps.fetchImpl });
|
|
477
478
|
// Ticket 10718: the Granola cron's own health, read-only, over the shared
|
|
478
479
|
// server-side key rather than a `notes_accounts` row.
|
|
480
|
+
registerNotesBotUpcomingTool(server, { fetchImpl: deps.fetchImpl });
|
|
479
481
|
registerNotesGranolaStatusTool(server, { fetchImpl: deps.fetchImpl });
|
|
480
482
|
registerOpsTools(server, { fetchImpl: deps.fetchImpl });
|
|
481
483
|
registerMemoryExperienceTools(server, { fetchImpl: deps.fetchImpl });
|
package/dist/tool-catalog.d.ts
CHANGED
|
@@ -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", "speed_read", "speed_seen", "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"];
|
|
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", "speed_read", "speed_seen", "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", "notes_bot_upcoming", "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).
|
|
@@ -21,7 +21,7 @@ export declare const DRY_RUN_TOOLS: readonly ["ops_recompile", "memory_requeue"]
|
|
|
21
21
|
* candidates, share calendars. Never called by the smoke; covered by the unit
|
|
22
22
|
* suites (`write-tools.test.ts` and each family's own).
|
|
23
23
|
*/
|
|
24
|
-
export declare const WRITE_TOOLS: readonly ["brain_retry", "emit_event", "docs_create", "docs_update", "docs_delete", "docs_link", "msg_create_channel", "msg_dm", "msg_send", "work_create_issue", "work_update_issue", "work_move_issue", "work_comment_issue", "careers_rescreen", "careers_send_takehome", "careers_invite", "careers_grade", "careers_decide", "careers_followup", "careers_interview", "careers_takehome_set", "careers_settings_set", "rename_resolve", "github_merge", "github_retitle", "github_rerun", "mail_send", "mail_draft", "mail_sync", "mail_detach", "cal_create", "cal_share", "cal_sync", "cal_detach", "cal_delete", "jarvis_dispatch", "glossary_add", "glossary_remove", "notes_mkdir", "notes_rmdir", "notes_rename", "notes_upload", "notes_paste", "notes_share", "notes_unshare", "notes_move", "notes_sync", "notes_detach", "memory_experience", "scout_start", "scout_dismiss", "scout_undo", "brief_rewrite", "brief_correct", "brief_done", "brief_undone", "settings_set", "settings_delete", "model_set", "team_invite", "team_role", "team_device_revoke", "team_device_doctor"];
|
|
24
|
+
export declare const WRITE_TOOLS: readonly ["brain_retry", "emit_event", "docs_create", "docs_update", "docs_delete", "docs_link", "msg_create_channel", "msg_dm", "msg_send", "work_create_issue", "work_update_issue", "work_move_issue", "work_comment_issue", "careers_rescreen", "careers_send_takehome", "careers_invite", "careers_grade", "careers_decide", "careers_followup", "careers_interview", "careers_takehome_set", "careers_settings_set", "rename_resolve", "github_merge", "github_retitle", "github_rerun", "mail_send", "mail_draft", "mail_rename", "mail_enable", "mail_disable", "mail_default", "mail_remove", "cal_change", "mail_sync", "mail_detach", "cal_create", "cal_share", "cal_sync", "cal_detach", "cal_delete", "jarvis_dispatch", "glossary_add", "glossary_remove", "notes_mkdir", "notes_rmdir", "notes_rename", "notes_upload", "notes_paste", "notes_share", "notes_unshare", "notes_move", "notes_sync", "notes_detach", "memory_experience", "scout_start", "scout_dismiss", "scout_undo", "brief_rewrite", "brief_correct", "brief_done", "brief_undone", "settings_set", "settings_delete", "model_set", "team_invite", "team_role", "team_device_revoke", "team_device_doctor"];
|
|
25
25
|
/** Reads that spend a model turn. The smoke's `--no-model` leaves these out. */
|
|
26
26
|
export declare const MODEL_SPENDING_TOOLS: readonly ["jarvis_ask", "jarvis_check"];
|
|
27
27
|
/**
|
package/dist/tool-catalog.js
CHANGED
|
@@ -71,6 +71,7 @@ export const READ_TOOLS = [
|
|
|
71
71
|
"notes_recording",
|
|
72
72
|
"notes_sync_status",
|
|
73
73
|
"notes_granola_status",
|
|
74
|
+
"notes_bot_upcoming",
|
|
74
75
|
"ops_status",
|
|
75
76
|
"slack_coverage",
|
|
76
77
|
"slack_read",
|
|
@@ -131,6 +132,7 @@ export const WRITE_TOOLS = [
|
|
|
131
132
|
"mail_send",
|
|
132
133
|
// BLI-12530: writes into a mailbox (a draft), reaches nobody. Never smoked.
|
|
133
134
|
"mail_draft",
|
|
135
|
+
"mail_rename", "mail_enable", "mail_disable", "mail_default", "mail_remove", "cal_change",
|
|
134
136
|
"mail_sync",
|
|
135
137
|
"mail_detach",
|
|
136
138
|
"cal_create",
|
package/dist/verb-census.js
CHANGED
|
@@ -273,6 +273,11 @@ export const MCP_TWINS = {
|
|
|
273
273
|
"issue comment": { tool: "work_comment_issue", door: "POST /api/work/issues/[id]/comments" },
|
|
274
274
|
"issue history": { tool: "work_issue_history", door: "GET /api/work/issues/[id]/history" },
|
|
275
275
|
"project list": { tool: "work_list_projects", door: "GET /api/work/projects" },
|
|
276
|
+
"mail rename": { tool: "mail_rename", door: "PATCH /api/mail/accounts" },
|
|
277
|
+
"mail enable": { tool: "mail_enable", door: "PATCH /api/mail/accounts" },
|
|
278
|
+
"mail disable": { tool: "mail_disable", door: "PATCH /api/mail/accounts" },
|
|
279
|
+
"mail default": { tool: "mail_default", door: "PATCH /api/mail/accounts" },
|
|
280
|
+
"mail remove": { tool: "mail_remove", door: "DELETE /api/mail/accounts" },
|
|
276
281
|
"mail accounts": { tool: "mail_accounts", door: "GET /api/mail/accounts" },
|
|
277
282
|
"mail inbox": { tool: "mail_inbox", door: "GET /api/mail/inbox" },
|
|
278
283
|
"mail read": { tool: "mail_read", door: "GET /api/mail/threads/[id]" },
|
|
@@ -289,6 +294,8 @@ export const MCP_TWINS = {
|
|
|
289
294
|
"cal next": { tool: "cal_next", door: "GET /api/cal/next" },
|
|
290
295
|
"cal find": { tool: "cal_find", door: "GET /api/cal/find" },
|
|
291
296
|
"cal calendars": { tool: "cal_calendars", door: "GET /api/cal/calendars" },
|
|
297
|
+
"cal change": { tool: "cal_change", door: "PATCH /api/cal/events/[eventId]" },
|
|
298
|
+
"cal cancel": { tool: "cal_delete", door: "DELETE /api/cal/events/[eventId]" },
|
|
292
299
|
"cal create": { tool: "cal_create", door: "POST /api/cal/events" },
|
|
293
300
|
"cal share": { tool: "cal_share", door: "PATCH /api/cal/calendars" },
|
|
294
301
|
"cal sync": { tool: "cal_sync", door: "POST /api/cal/calendars/[id]/sync" },
|
|
@@ -326,6 +333,7 @@ export const MCP_TWINS = {
|
|
|
326
333
|
"notes sync": { tool: "notes_sync", door: "POST /api/notes/accounts/[id]/sync" },
|
|
327
334
|
"notes sync-status": { tool: "notes_sync_status", door: "GET /api/notes/sync-status" },
|
|
328
335
|
// Ticket 10718: Granola's own cron health, over its shared server-side key.
|
|
336
|
+
"notes bot-upcoming": { tool: "notes_bot_upcoming", door: "GET /api/notetaker/upcoming" },
|
|
329
337
|
"notes granola-status": { tool: "notes_granola_status", door: "GET /api/notes/granola-status" },
|
|
330
338
|
"memory log": { tool: "memory_experience", door: "POST /api/memory/experience" },
|
|
331
339
|
// BLI-4047, BLI-12927: the memory STORE at a terminal. Its twins live on the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.111",
|
|
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",
|