@bli-cockpit/mcp 0.1.104 → 0.1.105
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/dist/search-tool.d.ts +1 -1
- package/dist/search-tool.js +46 -10
- package/package.json +1 -1
package/dist/search-tool.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `tower_search` — one bar over
|
|
2
|
+
* `tower_search` — one bar over every corpus, as an MCP tool (BLI-3728).
|
|
3
3
|
*
|
|
4
4
|
* The same `GET /api/search` door the browser's search bar and `cockpit
|
|
5
5
|
* search` press, over this machine's device token
|
package/dist/search-tool.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `tower_search` — one bar over
|
|
2
|
+
* `tower_search` — one bar over every corpus, as an MCP tool (BLI-3728).
|
|
3
3
|
*
|
|
4
4
|
* The same `GET /api/search` door the browser's search bar and `cockpit
|
|
5
5
|
* search` press, over this machine's device token
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
import { z } from "zod";
|
|
26
26
|
import { loadAgentDoorSession } from "./agent-door-session.js";
|
|
27
27
|
import { callAgentDoor } from "./agent-door.js";
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
|
|
28
|
+
// What `kinds` may name is the SERVER's to say (BLI-13027): this used to be a
|
|
29
|
+
// z.enum copy of the dashboard's list, so an installed MCP server refused a
|
|
30
|
+
// corpus the day it shipped. Kinds are forwarded as typed; the door answers
|
|
31
|
+
// `unknown_kind` with the list, and `categories: true` asks for it up front.
|
|
32
32
|
const KIND_LABELS = {
|
|
33
33
|
doc: "Document",
|
|
34
34
|
msg: "Message",
|
|
@@ -37,6 +37,8 @@ const KIND_LABELS = {
|
|
|
37
37
|
mail: "Email",
|
|
38
38
|
cal: "Calendar event",
|
|
39
39
|
memory: "Memory",
|
|
40
|
+
scout: "Scout card",
|
|
41
|
+
careers: "Applicant",
|
|
40
42
|
};
|
|
41
43
|
function textResult(text, structured) {
|
|
42
44
|
return {
|
|
@@ -51,13 +53,22 @@ export function registerSearchTool(server, deps) {
|
|
|
51
53
|
const register = server.registerTool.bind(server);
|
|
52
54
|
register("tower_search", {
|
|
53
55
|
title: "Search everything in Tower",
|
|
54
|
-
description: "One search over
|
|
56
|
+
description: "One search over Tower tickets, documents, meeting notes, messages, the caller's own mail, their calendar, BLI Memory, Scout and (only where the caller may read applications) Careers. Use it when you know WHAT you are looking for but not WHERE it lives. Every result names the corpus it came from and where to open it; a memory has no page, so its text is the whole record. Mail and calendar are the caller's OWN — their mailboxes, their calendars and the ones shared with the organisation — never the whole company's. A calendar hit is the stored event, so a recurring meeting comes back once as its series rather than once per occurrence. A corpus that could not answer is reported separately from one that found nothing — do not read a failure as silence.",
|
|
55
57
|
inputSchema: {
|
|
56
|
-
query: z
|
|
58
|
+
query: z
|
|
59
|
+
.string()
|
|
60
|
+
.min(2)
|
|
61
|
+
.max(1000)
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("What to look for, in the words a person would type. Required unless categories is true."),
|
|
57
64
|
kinds: z
|
|
58
|
-
.array(z.
|
|
65
|
+
.array(z.string().min(1).max(40))
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("Narrow to these categories (issue, doc, note, msg, mail, cal, memory, scout, careers; ticket works for issue). Omit to search every one. Call with categories: true for the exact list this account is offered."),
|
|
68
|
+
categories: z
|
|
69
|
+
.boolean()
|
|
59
70
|
.optional()
|
|
60
|
-
.describe("
|
|
71
|
+
.describe("True returns the categories this account can narrow to, instead of searching."),
|
|
61
72
|
limit: z.number().int().min(1).max(50).optional().describe("Results to return (default 20)."),
|
|
62
73
|
},
|
|
63
74
|
}, async (args) => {
|
|
@@ -66,10 +77,15 @@ export function registerSearchTool(server, deps) {
|
|
|
66
77
|
if (!loaded.ok) {
|
|
67
78
|
return errorResult(`This machine is not paired with Tower (${loaded.reason}). ${loaded.message}`);
|
|
68
79
|
}
|
|
80
|
+
if (args.categories === true)
|
|
81
|
+
return await listCategories(loaded.session, deps);
|
|
69
82
|
const query = String(args.query ?? "");
|
|
83
|
+
if (query.trim().length < 2) {
|
|
84
|
+
return errorResult("tower_search needs a query of at least 2 characters, or categories: true to list the categories.");
|
|
85
|
+
}
|
|
70
86
|
const params = new URLSearchParams({ q: query });
|
|
71
87
|
if (Array.isArray(args.kinds) && args.kinds.length > 0) {
|
|
72
|
-
params.set("kinds", args.kinds.map((kind) => (
|
|
88
|
+
params.set("kinds", args.kinds.map((kind) => kind.trim().toLowerCase()).join(","));
|
|
73
89
|
}
|
|
74
90
|
if (typeof args.limit === "number")
|
|
75
91
|
params.set("limit", String(args.limit));
|
|
@@ -94,6 +110,26 @@ export function registerSearchTool(server, deps) {
|
|
|
94
110
|
});
|
|
95
111
|
});
|
|
96
112
|
}
|
|
113
|
+
/** `categories: true` — the list the browser's Command-K chips are drawn from. */
|
|
114
|
+
async function listCategories(session, deps) {
|
|
115
|
+
const response = await callAgentDoor(session, deps.fetchImpl, "GET", "/api/search?categories=1");
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
if (response.transportError) {
|
|
118
|
+
return errorResult(`Tower could not be reached for tower_search (${response.transportError}). The categories were not read.`);
|
|
119
|
+
}
|
|
120
|
+
const reason = typeof response.body.reason === "string" ? response.body.reason : "unknown_error";
|
|
121
|
+
return errorResult(`Tower refused tower_search categories (${reason}).`);
|
|
122
|
+
}
|
|
123
|
+
const categories = (Array.isArray(response.body.categories) ? response.body.categories : []);
|
|
124
|
+
const lines = [
|
|
125
|
+
`${categories.length} categories this account can search. Name them in kinds; omit kinds to search all of them.`,
|
|
126
|
+
...categories.map((entry) => {
|
|
127
|
+
const aliases = (entry.aliases ?? []).length > 0 ? ` (also: ${(entry.aliases ?? []).join(", ")})` : "";
|
|
128
|
+
return `- ${entry.kind}: ${entry.label}${aliases}`;
|
|
129
|
+
}),
|
|
130
|
+
];
|
|
131
|
+
return textResult(lines.join("\n"), { categories });
|
|
132
|
+
}
|
|
97
133
|
/**
|
|
98
134
|
* The sentence a model reads.
|
|
99
135
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.105",
|
|
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",
|