@littlebigbrain/mcp 0.13.0 → 0.15.0
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 +4 -4
- package/dist/files-tool.d.ts +9 -0
- package/dist/files-tool.js +70 -8
- package/dist/tools.js +109 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -155,10 +155,10 @@ its original identifiers; inspect it with SPARQL when choosing query predicates.
|
|
|
155
155
|
| `lbb_fit_sources` | Inspect fit from text and preview the text the fit reads. |
|
|
156
156
|
| `lbb_fit_sources_manage` | Declare, dry-run or refresh a fit source. |
|
|
157
157
|
| `lbb_fit_sources_delete` | Delete a fit source; its suggestions stay. |
|
|
158
|
-
| `lbb_workflows` | List the starter workflows this server offers and the workflows created from them on a graph (triggered workflows), read one with its status, and preview a new one. |
|
|
159
|
-
| `lbb_workflows_manage` | Create a workflow from a starter workflow on a class (a developer workflow with its workflow type, owned outputs and batch), ask it to run now, or pause and resume a developer workflow. |
|
|
160
|
-
| `lbb_workflows_delete` | Delete a triggered workflow. What it wrote stays. |
|
|
161
|
-
| `lbb_files` | List the files of a graph, and read the parsed pages of one: each line with its id, its box on the page and its text. |
|
|
158
|
+
| `lbb_workflows` | List the starter workflows this server offers and the workflows created from them on a graph (triggered workflows), read one with its status, and preview a new one. Read the workflows with triggers (target type, shards, routing, window, trigger) and what each watch has not sent yet, with origins. |
|
|
159
|
+
| `lbb_workflows_manage` | Create a workflow from a starter workflow on a class (a developer workflow with its workflow type, owned outputs and batch), ask it to run now, or pause and resume a developer workflow. Define a workflow with triggers of your worker (shards, routing field, window) and run it now. |
|
|
160
|
+
| `lbb_workflows_delete` | Delete a triggered workflow, or a workflow with triggers by its name. What it wrote stays. |
|
|
161
|
+
| `lbb_files` | List the files of a graph, all or by parse status or a part of the name, and read the parsed pages of one: each line with its id, its box on the page and its text. |
|
|
162
162
|
| `lbb_commit` | Write or retract JSON facts, or record search feedback. |
|
|
163
163
|
| `lbb_configure` | Define record types and relationships, list and apply ontology starters (CRM, documents, work), publish validation rules, or keep the graph's notes and worked examples for questions in plain words (`get_rewrite_profile`, `set_rewrite_profile`). |
|
|
164
164
|
| `lbb_evals` | Label query results and check whether later queries return the expected answers. Read the model checks of a graph, and agree with or correct a check that the user confirmed. |
|
package/dist/files-tool.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import type { LbbClient, Schemas } from "@littlebigbrain/client";
|
|
3
|
+
/** Files one `list` call returns: one page, newest upload first. */
|
|
4
|
+
export declare const FILES_PER_LIST = 50;
|
|
5
|
+
/**
|
|
6
|
+
* Files `pages` reads to find a name: one page of the list filtered by the
|
|
7
|
+
* name, the most one page holds.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FILES_PER_NAME_LOOKUP = 1000;
|
|
10
|
+
/** The parse statuses `list` filters by; `waiting` is a file without one. */
|
|
11
|
+
export declare const FILE_PARSE_STATUSES: readonly ["parsed", "waiting", "unsupported", "failed"];
|
|
3
12
|
/** Lines one `pages` call returns by default, and at most. */
|
|
4
13
|
export declare const FILE_LINES_DEFAULT = 200;
|
|
5
14
|
export declare const FILE_LINES_MAX = 1000;
|
package/dist/files-tool.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { READ_ONLY, detailSchema, graphScope } from "./tool-contracts.js";
|
|
3
3
|
import { enrichError, errorResult, run, scoped, toolResult, } from "./tool-runtime.js";
|
|
4
|
+
/** Files one `list` call returns: one page, newest upload first. */
|
|
5
|
+
export const FILES_PER_LIST = 50;
|
|
6
|
+
/**
|
|
7
|
+
* Files `pages` reads to find a name: one page of the list filtered by the
|
|
8
|
+
* name, the most one page holds.
|
|
9
|
+
*/
|
|
10
|
+
export const FILES_PER_NAME_LOOKUP = 1_000;
|
|
11
|
+
/** The parse statuses `list` filters by; `waiting` is a file without one. */
|
|
12
|
+
export const FILE_PARSE_STATUSES = [
|
|
13
|
+
"parsed",
|
|
14
|
+
"waiting",
|
|
15
|
+
"unsupported",
|
|
16
|
+
"failed",
|
|
17
|
+
];
|
|
4
18
|
/** Lines one `pages` call returns by default, and at most. */
|
|
5
19
|
export const FILE_LINES_DEFAULT = 200;
|
|
6
20
|
export const FILE_LINES_MAX = 1_000;
|
|
@@ -62,7 +76,17 @@ export function pageLines(pages, window) {
|
|
|
62
76
|
return answer;
|
|
63
77
|
}
|
|
64
78
|
const SHA256 = /^[0-9a-fA-F]{64}$/;
|
|
65
|
-
/** The
|
|
79
|
+
/** The files of `files` named `name` exactly (both composed, NFC). */
|
|
80
|
+
function namedExactly(files, name) {
|
|
81
|
+
const wanted = name.normalize("NFC");
|
|
82
|
+
return files.filter((file) => file.name.normalize("NFC") === wanted);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The SHA-256 of the file a call names, by `sha256` or by its exact name.
|
|
86
|
+
* A name is looked up in the list filtered by it, which finds a file of any
|
|
87
|
+
* age; that list reads the published generation, so a file uploaded since
|
|
88
|
+
* is looked up in the newest files of the plain list.
|
|
89
|
+
*/
|
|
66
90
|
async function fileSha(target, args) {
|
|
67
91
|
if (args.sha256) {
|
|
68
92
|
if (!SHA256.test(args.sha256.trim()))
|
|
@@ -71,8 +95,16 @@ async function fileSha(target, args) {
|
|
|
71
95
|
}
|
|
72
96
|
if (!args.name)
|
|
73
97
|
throw new Error("pages needs sha256 or name");
|
|
74
|
-
const
|
|
75
|
-
|
|
98
|
+
const filtered = await target.files.list({
|
|
99
|
+
name: args.name,
|
|
100
|
+
limit: FILES_PER_NAME_LOOKUP,
|
|
101
|
+
});
|
|
102
|
+
let files = filtered.files;
|
|
103
|
+
let named = namedExactly(files, args.name);
|
|
104
|
+
if (named.length === 0) {
|
|
105
|
+
({ files } = await target.files.list({ limit: FILES_PER_LIST }));
|
|
106
|
+
named = namedExactly(files, args.name);
|
|
107
|
+
}
|
|
76
108
|
if (named.length === 1)
|
|
77
109
|
return { sha256: named[0].sha256, name: named[0].name };
|
|
78
110
|
if (named.length > 1)
|
|
@@ -82,9 +114,17 @@ async function fileSha(target, args) {
|
|
|
82
114
|
}
|
|
83
115
|
export function registerFilesTool(server, client) {
|
|
84
116
|
server.registerTool("lbb_files", {
|
|
85
|
-
description: "Files of the graph, read only. A file is a document the graph holds (its bytes and a Document entity); the documents.parse workflow (lbb_workflows) reads the text layer of each PDF into pages with every line and its box. list shows
|
|
117
|
+
description: "Files of the graph, read only. A file is a document the graph holds (its bytes and a Document entity); the documents.parse workflow (lbb_workflows) reads the text layer of each PDF into pages with every line and its box. list shows 50 files a call, newest upload first, with their sha256, name, size, Document IRI and parse (status parsed, unsupported or failed, page_count); when more follow, next names the after of the next call (with the same filters). parse_status keeps the files of one parse status; waiting is a file not parsed yet. name keeps the files whose name holds a text, in any case. A filtered list reads the Documents of the published generation and names its commit (as_of_commit_seq). A file uploaded, renamed or parsed a moment ago can be missing from it until publication. pages reads parsed pages of one file (sha256, or name for an exact file name): from is the first 0-based page index (the page of a region and of a DocEntry or DocMention), to the page after the last one (default from+1). Each line comes as `<line id> [x0,y0,x1,y1] <text>`: the id is p<page number>-l<line number>, both from 1, and the box is normalized to the page (0 to 1, origin top left). contains keeps the lines that hold a text; max_lines caps the lines (default 200). When lines were left out, next names the from and line_offset of the next call. A file not parsed yet answers file_not_parsed.",
|
|
86
118
|
inputSchema: {
|
|
87
119
|
action: z.enum(["list", "pages"]),
|
|
120
|
+
after: z
|
|
121
|
+
.string()
|
|
122
|
+
.optional()
|
|
123
|
+
.describe("list: the next 50 files, from a previous call's next (pass the same parse_status and name)."),
|
|
124
|
+
parse_status: z
|
|
125
|
+
.enum(FILE_PARSE_STATUSES)
|
|
126
|
+
.optional()
|
|
127
|
+
.describe("list: only the files of this parse status; waiting is a file not parsed yet."),
|
|
88
128
|
sha256: z
|
|
89
129
|
.string()
|
|
90
130
|
.optional()
|
|
@@ -92,7 +132,7 @@ export function registerFilesTool(server, client) {
|
|
|
92
132
|
name: z
|
|
93
133
|
.string()
|
|
94
134
|
.optional()
|
|
95
|
-
.describe("pages: the file's exact name, when you do not have its sha256."),
|
|
135
|
+
.describe("list: only the files whose name holds this text, in any case. pages: the file's exact name, when you do not have its sha256."),
|
|
96
136
|
from: z
|
|
97
137
|
.number()
|
|
98
138
|
.int()
|
|
@@ -129,10 +169,32 @@ export function registerFilesTool(server, client) {
|
|
|
129
169
|
}, async (args) => {
|
|
130
170
|
const target = scoped(client, args.graph);
|
|
131
171
|
if (args.action === "list") {
|
|
172
|
+
// The server binds a cursor to its filters: the next call repeats them.
|
|
173
|
+
const filters = {
|
|
174
|
+
...(args.parse_status ? { parse_status: args.parse_status } : {}),
|
|
175
|
+
...(args.name ? { name: args.name } : {}),
|
|
176
|
+
};
|
|
177
|
+
let next;
|
|
132
178
|
return run(client, "lbb_files.list", args.detail, async () => {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
179
|
+
const page = await target.files.list({
|
|
180
|
+
limit: FILES_PER_LIST,
|
|
181
|
+
...(args.after ? { after: args.after } : {}),
|
|
182
|
+
...(args.parse_status ? { parseStatus: args.parse_status } : {}),
|
|
183
|
+
...(args.name ? { name: args.name } : {}),
|
|
184
|
+
});
|
|
185
|
+
next = page.next ?? undefined;
|
|
186
|
+
return {
|
|
187
|
+
files: page.files,
|
|
188
|
+
...(page.as_of_commit_seq != null
|
|
189
|
+
? { as_of_commit_seq: page.as_of_commit_seq }
|
|
190
|
+
: {}),
|
|
191
|
+
};
|
|
192
|
+
}, () => next
|
|
193
|
+
? {
|
|
194
|
+
truncated: true,
|
|
195
|
+
next: { action: "list", ...filters, after: next },
|
|
196
|
+
}
|
|
197
|
+
: {});
|
|
136
198
|
}
|
|
137
199
|
try {
|
|
138
200
|
const file = await fileSha(target, args);
|
package/dist/tools.js
CHANGED
|
@@ -613,7 +613,7 @@ export function registerLbbTools(server, client, options = {}) {
|
|
|
613
613
|
starter: z
|
|
614
614
|
.string()
|
|
615
615
|
.optional()
|
|
616
|
-
.describe("The starter workflow's catalog id from action=starters, e.g. search.embed (embeddings on a class), ontology.fit (fit from text) or workflow (a developer workflow: your worker's workflow gets the instances). get/preview/use/refresh
|
|
616
|
+
.describe("The starter workflow's catalog id from action=starters, e.g. search.embed (embeddings on a class), ontology.fit (fit from text) or workflow (a developer workflow: your worker's workflow gets the instances). get/preview/use/refresh: required. pause/resume: omit to name a workflow with triggers."),
|
|
617
617
|
class: z
|
|
618
618
|
.string()
|
|
619
619
|
.optional()
|
|
@@ -690,15 +690,90 @@ export function registerLbbTools(server, client, options = {}) {
|
|
|
690
690
|
}
|
|
691
691
|
return { starter: args.starter, name: args.name };
|
|
692
692
|
};
|
|
693
|
+
const workflowName = (args) => {
|
|
694
|
+
if (!args.name)
|
|
695
|
+
throw new Error("this action requires name");
|
|
696
|
+
return args.name;
|
|
697
|
+
};
|
|
698
|
+
// A workflow with triggers (`/v1/workflows/named`): your worker's
|
|
699
|
+
// workflow type, one watch trigger, shards, routing and window.
|
|
700
|
+
const namedSetup = {
|
|
701
|
+
shards: z
|
|
702
|
+
.number()
|
|
703
|
+
.int()
|
|
704
|
+
.min(1)
|
|
705
|
+
.max(16)
|
|
706
|
+
.optional()
|
|
707
|
+
.describe("define: engine identities that receive the messages, 1 to 16 (default 1). A change needs every shard's inbox empty."),
|
|
708
|
+
route_by: z
|
|
709
|
+
.string()
|
|
710
|
+
.optional()
|
|
711
|
+
.describe("define: a field of the class whose value keeps work in order: the changes of one value go to one shard. Default: the instance."),
|
|
712
|
+
window: z
|
|
713
|
+
.number()
|
|
714
|
+
.int()
|
|
715
|
+
.min(1)
|
|
716
|
+
.max(128)
|
|
717
|
+
.optional()
|
|
718
|
+
.describe("define: messages the watch keeps queued per shard, 1 to 128 (default 4)."),
|
|
719
|
+
trigger: z
|
|
720
|
+
.string()
|
|
721
|
+
.optional()
|
|
722
|
+
.describe("define: the watch trigger's id (default watch). queue: the trigger whose queue to read."),
|
|
723
|
+
};
|
|
724
|
+
const namedRequest = (args) => {
|
|
725
|
+
if (!args.name || !args.class || !args.workflow) {
|
|
726
|
+
throw new Error("define requires name, class and workflow");
|
|
727
|
+
}
|
|
728
|
+
return {
|
|
729
|
+
name: args.name,
|
|
730
|
+
workflow: args.workflow,
|
|
731
|
+
triggers: [
|
|
732
|
+
{
|
|
733
|
+
...(args.trigger ? { id: args.trigger } : {}),
|
|
734
|
+
watch: {
|
|
735
|
+
class: args.class,
|
|
736
|
+
...(args.fields ? { fields: args.fields } : {}),
|
|
737
|
+
},
|
|
738
|
+
},
|
|
739
|
+
],
|
|
740
|
+
...(args.owns ? { owns: args.owns } : {}),
|
|
741
|
+
...(args.batch !== undefined ? { batch: args.batch } : {}),
|
|
742
|
+
...(args.shards !== undefined ? { shards: args.shards } : {}),
|
|
743
|
+
...(args.route_by ? { route_by: args.route_by } : {}),
|
|
744
|
+
...(args.window !== undefined ? { window: args.window } : {}),
|
|
745
|
+
};
|
|
746
|
+
};
|
|
693
747
|
server.registerTool("lbb_workflows", {
|
|
694
|
-
description: "Starter workflows and triggered workflows, read only. A starter workflow is a template; a triggered workflow is a workflow created from one on the graph. It watches a class: when a published commit adds or changes instances of the class (or changes the watched fields), the workflow reads them and does its work. search.embed keeps an embedding of the class (the same as lbb_embeddings); ontology.fit reads text fields and files ontology suggestions (the same as lbb_fit_sources); workflow (a developer workflow) sends the new and changed instances to a workflow of the developer's worker as trigger messages, and that code writes the facts the workflow owns. documents.parse reads uploaded PDF files into pages with line boxes, documents.link connects mentions of the same thing across the documents (it writes DocEntry and DocMention instances and links each mention to the entry that defines or describes it), documents.map proposes each link as a FactProposal in the graph's own ontology (fact_subject, fact_predicate, fact_object, fact_confidence, fact_evidence) for a review workflow, and values.extract fills chosen properties from text, each value with a quote; read the files and their pages with lbb_files. starters lists the starter workflows this server offers with their group, settings and whether each can run here. list shows every triggered workflow of the graph with its state (backfilling, ready, paused, failed, unavailable), lag, counters, this month's spend and last error; get shows one (starter and name) with its own status in details (for workflow: the messages sent, the instances waiting, the message in flight and whether it is paused). preview shows what creating one would do (the resolved watch, the instance count and the workflow's own preview; for workflow, the first messages it would send), calls no model and stores nothing. Message workflows of the workflow engine are not listed here. Create, refresh, pause or resume with lbb_workflows_manage; delete with lbb_workflows_delete.",
|
|
748
|
+
description: "Starter workflows and triggered workflows, read only. A starter workflow is a template; a triggered workflow is a workflow created from one on the graph. It watches a class: when a published commit adds or changes instances of the class (or changes the watched fields), the workflow reads them and does its work. search.embed keeps an embedding of the class (the same as lbb_embeddings); ontology.fit reads text fields and files ontology suggestions (the same as lbb_fit_sources); workflow (a developer workflow) sends the new and changed instances to a workflow of the developer's worker as trigger messages, and that code writes the facts the workflow owns. documents.parse reads uploaded PDF files into pages with line boxes, documents.link connects mentions of the same thing across the documents (it writes DocEntry and DocMention instances and links each mention to the entry that defines or describes it), documents.map proposes each link as a FactProposal in the graph's own ontology (fact_subject, fact_predicate, fact_object, fact_confidence, fact_evidence) for a review workflow, and values.extract fills chosen properties from text, each value with a quote; read the files and their pages with lbb_files. starters lists the starter workflows this server offers with their group, settings and whether each can run here. list shows every triggered workflow of the graph with its state (backfilling, ready, paused, failed, unavailable), lag, counters, this month's spend and last error; get shows one (starter and name) with its own status in details (for workflow: the messages sent, the instances waiting, the message in flight and whether it is paused). preview shows what creating one would do (the resolved watch, the instance count and the workflow's own preview; for workflow, the first messages it would send), calls no model and stores nothing. workflows lists the same workflows as workflows with triggers (/v1/workflows/named): each one's target workflow type (LBB's own are lbb.* types), its shards (engine identities starter.<name> and starter.<name>.<k>), its routing field, its window, its one watch trigger, its status and each shard's inbox; name for one. queue (name) shows what a workflow's watch has not sent yet: each waiting instance with its shard and its origin (a backfill, a commit range with the watched fields and the requests that changed it, a run now, a schema change), the pass in progress, and per shard its message in flight and its first unfinished turns with their origins; page with after and limit. Message workflows of the workflow engine are not listed here. Create, refresh, pause or resume with lbb_workflows_manage; delete with lbb_workflows_delete.",
|
|
695
749
|
inputSchema: {
|
|
696
|
-
action: z.enum([
|
|
750
|
+
action: z.enum([
|
|
751
|
+
"starters",
|
|
752
|
+
"list",
|
|
753
|
+
"get",
|
|
754
|
+
"preview",
|
|
755
|
+
"workflows",
|
|
756
|
+
"queue",
|
|
757
|
+
]),
|
|
697
758
|
name: z
|
|
698
759
|
.string()
|
|
699
760
|
.optional()
|
|
700
|
-
.describe("get: the triggered workflow's name. preview: the name a new workflow would get."),
|
|
761
|
+
.describe("get: the triggered workflow's name. preview: the name a new workflow would get. workflows: one workflow's name (omit for all). queue: required."),
|
|
701
762
|
...workflowSetup,
|
|
763
|
+
trigger: namedSetup.trigger,
|
|
764
|
+
after: z
|
|
765
|
+
.number()
|
|
766
|
+
.int()
|
|
767
|
+
.nonnegative()
|
|
768
|
+
.optional()
|
|
769
|
+
.describe("queue: the position to start from (next_after)."),
|
|
770
|
+
limit: z
|
|
771
|
+
.number()
|
|
772
|
+
.int()
|
|
773
|
+
.min(1)
|
|
774
|
+
.max(100)
|
|
775
|
+
.optional()
|
|
776
|
+
.describe("queue: items per page, 1 to 100 (default 50)."),
|
|
702
777
|
sample: z
|
|
703
778
|
.number()
|
|
704
779
|
.int()
|
|
@@ -729,12 +804,22 @@ export function registerLbbTools(server, client, options = {}) {
|
|
|
729
804
|
...(args.sample ? { sample: args.sample } : {}),
|
|
730
805
|
...(args.iris ? { iris: args.iris } : {}),
|
|
731
806
|
});
|
|
807
|
+
case "workflows":
|
|
808
|
+
return args.name
|
|
809
|
+
? workflows.named.get(args.name)
|
|
810
|
+
: workflows.named.list();
|
|
811
|
+
case "queue":
|
|
812
|
+
return workflows.named.queue(workflowName(args), {
|
|
813
|
+
...(args.trigger ? { trigger: args.trigger } : {}),
|
|
814
|
+
...(args.after !== undefined ? { after: args.after } : {}),
|
|
815
|
+
...(args.limit !== undefined ? { limit: args.limit } : {}),
|
|
816
|
+
});
|
|
732
817
|
}
|
|
733
818
|
}));
|
|
734
819
|
server.registerTool("lbb_workflows_manage", {
|
|
735
|
-
description: "Create a workflow from a starter workflow, or refresh, pause or resume a triggered workflow. Run lbb_workflows action=preview first and show the user the watch and the instance count. use creates a workflow from a starter workflow of action=starters, under a name (default: the class's local name), with its watch (class, fields) and params; the workflow then reads every instance of the class and follows each published commit. A developer workflow (starter=workflow) also takes workflow (workflow_type and version of the developer's worker), owns and batch; it needs a server with the workflow engine. use again with the same starter and name changes only what you name, and the same request again changes nothing. A workflow that calls models (ontology.fit, documents.link, documents.map, values.extract) spends model budget as it reads. refresh asks the workflow to run now and returns at once with queued; poll lbb_workflows action=get for progress. pause stops a workflow (a developer workflow, documents.parse, documents.link, documents.map or values.extract) from reading and sending; resume lets it catch up. search.embed and ontology.fit cannot be paused.",
|
|
820
|
+
description: "Create a workflow from a starter workflow, or refresh, pause or resume a triggered workflow. Run lbb_workflows action=preview first and show the user the watch and the instance count. use creates a workflow from a starter workflow of action=starters, under a name (default: the class's local name), with its watch (class, fields) and params; the workflow then reads every instance of the class and follows each published commit. A developer workflow (starter=workflow) also takes workflow (workflow_type and version of the developer's worker), owns and batch; it needs a server with the workflow engine. use again with the same starter and name changes only what you name, and the same request again changes nothing. A workflow that calls models (ontology.fit, documents.link, documents.map, values.extract) spends model budget as it reads. refresh asks the workflow to run now and returns at once with queued; poll lbb_workflows action=get for progress. pause stops a workflow (a developer workflow, documents.parse, documents.link, documents.map or values.extract) from reading and sending, and stops the claims of a developer workflow's shards; resume lets it catch up. Without starter, pause and resume name a workflow with triggers. search.embed and ontology.fit cannot be paused. define creates or changes a workflow with triggers of the developer's worker (/v1/workflows/named): name, workflow, class and fields (its watch trigger), owns, batch, and shards (engine identities, 1 to 16), route_by (a field that keeps work in order) and window (messages queued per shard, default 4); it needs a server with the workflow engine, and a change of shards waits for empty inboxes. run (name) runs a workflow with triggers now: its watch sends every instance again.",
|
|
736
821
|
inputSchema: {
|
|
737
|
-
action: z.enum(["use", "refresh", "pause", "resume"]),
|
|
822
|
+
action: z.enum(["use", "refresh", "pause", "resume", "define", "run"]),
|
|
738
823
|
name: z
|
|
739
824
|
.string()
|
|
740
825
|
.optional()
|
|
@@ -751,6 +836,7 @@ export function registerLbbTools(server, client, options = {}) {
|
|
|
751
836
|
.nonnegative()
|
|
752
837
|
.optional()
|
|
753
838
|
.describe("use: a monthly model budget in USD for this workflow, below the stack's own."),
|
|
839
|
+
...namedSetup,
|
|
754
840
|
detail: detailSchema,
|
|
755
841
|
...graphScope,
|
|
756
842
|
},
|
|
@@ -763,17 +849,26 @@ export function registerLbbTools(server, client, options = {}) {
|
|
|
763
849
|
case "refresh":
|
|
764
850
|
return workflows.triggered.refresh(workflowRef(args));
|
|
765
851
|
case "pause":
|
|
766
|
-
return
|
|
852
|
+
return args.starter
|
|
853
|
+
? workflows.triggered.pause(workflowRef(args), true)
|
|
854
|
+
: workflows.named.pause(workflowName(args), true);
|
|
767
855
|
case "resume":
|
|
768
|
-
return
|
|
856
|
+
return args.starter
|
|
857
|
+
? workflows.triggered.pause(workflowRef(args), false)
|
|
858
|
+
: workflows.named.pause(workflowName(args), false);
|
|
859
|
+
case "define":
|
|
860
|
+
return workflows.named.put(namedRequest(args));
|
|
861
|
+
case "run":
|
|
862
|
+
return workflows.named.run(workflowName(args));
|
|
769
863
|
}
|
|
770
864
|
}));
|
|
771
865
|
server.registerTool("lbb_workflows_delete", {
|
|
772
|
-
description: "Delete a triggered workflow: it stops following its class, and what it wrote stays. Deleting search.embed deletes the embedding and its vectors, so its class stops being searchable; the suggestions an ontology.fit filed stay; a developer workflow leaves its workflow instance and the facts its code wrote. Ask the user first; confirm must repeat the name.",
|
|
866
|
+
description: "Delete a triggered workflow: it stops following its class, and what it wrote stays. Deleting search.embed deletes the embedding and its vectors, so its class stops being searchable; the suggestions an ontology.fit filed stay; a developer workflow leaves its workflow instance and the facts its code wrote. Without starter it deletes a workflow with triggers by its name, and its shards stay. Ask the user first; confirm must repeat the name.",
|
|
773
867
|
inputSchema: {
|
|
774
868
|
starter: z
|
|
775
869
|
.string()
|
|
776
|
-
.
|
|
870
|
+
.optional()
|
|
871
|
+
.describe("The starter workflow's catalog id, e.g. search.embed. Omit for a workflow with triggers."),
|
|
777
872
|
name: z.string().describe("The triggered workflow's name."),
|
|
778
873
|
confirm: z.string().describe("The same name again, to confirm."),
|
|
779
874
|
detail: detailSchema,
|
|
@@ -784,10 +879,10 @@ export function registerLbbTools(server, client, options = {}) {
|
|
|
784
879
|
if (confirm !== name) {
|
|
785
880
|
throw new Error("confirm must repeat the workflow name");
|
|
786
881
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
name
|
|
790
|
-
|
|
882
|
+
const workflows = scoped(client, graph).workflows;
|
|
883
|
+
return starter
|
|
884
|
+
? workflows.triggered.delete({ starter, name })
|
|
885
|
+
: workflows.named.delete(name);
|
|
791
886
|
}));
|
|
792
887
|
const modelUse = z
|
|
793
888
|
.enum(["ask", "route", "rerank", "fit", "label"])
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@littlebigbrain/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "MCP server for little big brain: search, graph queries, and data import",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"test:coverage": "npm run clean:test && tsc -p tsconfig.test.json && node --test --experimental-test-coverage --test-coverage-include=test-dist/*.js --test-coverage-exclude=test-dist/*.test.js --test-coverage-exclude=test-dist/stdio.js --test-coverage-exclude=test-dist/test-support.js --test-coverage-lines=90 --test-coverage-branches=70 --test-coverage-functions=85 \"test-dist/**/*.test.js\""
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@littlebigbrain/client": "^0.
|
|
55
|
+
"@littlebigbrain/client": "^0.27.0",
|
|
56
56
|
"@modelcontextprotocol/sdk": "^1",
|
|
57
57
|
"zod": "^3"
|
|
58
58
|
},
|