@thehammer/schema-mcp-server 1.0.0 → 1.0.2
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/index.js +560 -426
- package/package.json +12 -2
package/dist/index.js
CHANGED
|
@@ -14,14 +14,109 @@
|
|
|
14
14
|
* SCHEMA_API_TOKEN - Bearer token for SchemaMcpAuthMiddleware
|
|
15
15
|
* SCHEMA_DEFINITION_ID - ID of the schema being built
|
|
16
16
|
*/
|
|
17
|
+
import { createRequire } from "node:module";
|
|
17
18
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
18
19
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
19
20
|
import { z } from "zod";
|
|
20
21
|
import * as api from "./api-client.js";
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
const pkg = require("../package.json");
|
|
21
24
|
const server = new McpServer({
|
|
22
25
|
name: "schema-mcp-server",
|
|
23
|
-
version:
|
|
26
|
+
version: pkg.version,
|
|
24
27
|
});
|
|
28
|
+
/**
|
|
29
|
+
* Role-based tool registration.
|
|
30
|
+
*
|
|
31
|
+
* SCHEMA_ROLE controls which tools this MCP server instance registers.
|
|
32
|
+
* Each agent (orchestrator + sub-agents) gets its own MCP server instance
|
|
33
|
+
* with only the tools relevant to its role.
|
|
34
|
+
*
|
|
35
|
+
* Roles:
|
|
36
|
+
* orchestrator — Read-only + annotations + context + progress (no mutations)
|
|
37
|
+
* schema-builder — Schema mutations + reads (no directives/templates/annotations)
|
|
38
|
+
* behavior-builder — Directive mutations + reads (no schema/templates/annotations)
|
|
39
|
+
* template-builder — Template mutations + reads + styles (no schema/directives/annotations)
|
|
40
|
+
* full (default) — All tools (backwards compatible, used by reviewer agents)
|
|
41
|
+
*/
|
|
42
|
+
const SCHEMA_ROLE = process.env.SCHEMA_ROLE || "full";
|
|
43
|
+
// Tools shared by all roles (read-only schema + template inspection)
|
|
44
|
+
const COMMON_TOOLS = [
|
|
45
|
+
"schema_get",
|
|
46
|
+
"annotation_list",
|
|
47
|
+
"directive_list",
|
|
48
|
+
"template_list",
|
|
49
|
+
"template_get",
|
|
50
|
+
"template_get_example_pages",
|
|
51
|
+
"template_get_sample_data",
|
|
52
|
+
"template_preview",
|
|
53
|
+
"template_preview_html",
|
|
54
|
+
"quality_gate_list",
|
|
55
|
+
];
|
|
56
|
+
const ROLE_TOOLS = {
|
|
57
|
+
orchestrator: new Set([
|
|
58
|
+
...COMMON_TOOLS,
|
|
59
|
+
"post_progress",
|
|
60
|
+
"annotation_create",
|
|
61
|
+
"annotation_update",
|
|
62
|
+
"annotation_resolve",
|
|
63
|
+
"annotation_convert_to_rule",
|
|
64
|
+
"annotation_delete",
|
|
65
|
+
"blueprint_list",
|
|
66
|
+
"context_workflow_inputs",
|
|
67
|
+
"context_workflow_input_pages",
|
|
68
|
+
"context_chat_history",
|
|
69
|
+
]),
|
|
70
|
+
"schema-builder": new Set([
|
|
71
|
+
...COMMON_TOOLS,
|
|
72
|
+
"post_progress",
|
|
73
|
+
"schema_update_model",
|
|
74
|
+
"schema_remove_model",
|
|
75
|
+
"schema_update_root",
|
|
76
|
+
"quality_gate_submit_review",
|
|
77
|
+
]),
|
|
78
|
+
"behavior-builder": new Set([
|
|
79
|
+
...COMMON_TOOLS,
|
|
80
|
+
"post_progress",
|
|
81
|
+
"directive_create",
|
|
82
|
+
"directive_update",
|
|
83
|
+
"directive_delete",
|
|
84
|
+
"quality_gate_submit_review",
|
|
85
|
+
]),
|
|
86
|
+
"template-builder": new Set([
|
|
87
|
+
...COMMON_TOOLS,
|
|
88
|
+
"post_progress",
|
|
89
|
+
"template_create",
|
|
90
|
+
"template_update",
|
|
91
|
+
"template_patch",
|
|
92
|
+
"template_set_sample_data",
|
|
93
|
+
"quality_gate_submit_review",
|
|
94
|
+
"style_list",
|
|
95
|
+
]),
|
|
96
|
+
reviewer: new Set([
|
|
97
|
+
...COMMON_TOOLS,
|
|
98
|
+
"blueprint_list",
|
|
99
|
+
"style_list",
|
|
100
|
+
"context_workflow_inputs",
|
|
101
|
+
"context_workflow_input_pages",
|
|
102
|
+
]),
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Check if a tool should be registered for the current SCHEMA_ROLE.
|
|
106
|
+
*
|
|
107
|
+
* Unknown roles default to NO tools (fail-closed) to prevent accidental
|
|
108
|
+
* full access from typos or misconfiguration.
|
|
109
|
+
*/
|
|
110
|
+
function shouldRegister(toolName) {
|
|
111
|
+
if (SCHEMA_ROLE === "full")
|
|
112
|
+
return true;
|
|
113
|
+
const allowed = ROLE_TOOLS[SCHEMA_ROLE];
|
|
114
|
+
if (!allowed) {
|
|
115
|
+
console.error(`Unknown SCHEMA_ROLE "${SCHEMA_ROLE}" — no tools will be registered. Valid roles: full, ${Object.keys(ROLE_TOOLS).join(", ")}`);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return allowed.has(toolName);
|
|
119
|
+
}
|
|
25
120
|
/** Wrap API response data into MCP tool result format. */
|
|
26
121
|
function jsonResult(data) {
|
|
27
122
|
return {
|
|
@@ -114,459 +209,497 @@ const messageParam = z
|
|
|
114
209
|
// ============================================================================
|
|
115
210
|
// Progress Tool
|
|
116
211
|
// ============================================================================
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
212
|
+
if (shouldRegister("post_progress"))
|
|
213
|
+
server.tool("post_progress", "Post a progress update to share your current thinking, plans, and discoveries with the user. Call this before making changes to explain your plan, after making changes to explain what you did, and whenever you discover something that affects your approach.", {
|
|
214
|
+
message: z
|
|
215
|
+
.string()
|
|
216
|
+
.describe("Your progress update message for the user"),
|
|
217
|
+
phase: z
|
|
218
|
+
.string()
|
|
219
|
+
.optional()
|
|
220
|
+
.describe("Current phase (e.g., planning, implementing, reviewing)"),
|
|
221
|
+
}, async ({ message, phase }) => {
|
|
222
|
+
const result = await api.postProgress(message, phase);
|
|
223
|
+
return jsonResult(result);
|
|
224
|
+
});
|
|
129
225
|
// ============================================================================
|
|
130
226
|
// Schema Tools
|
|
131
227
|
// ============================================================================
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
data
|
|
174
|
-
if (
|
|
175
|
-
data.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (
|
|
182
|
-
data.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
228
|
+
if (shouldRegister("schema_get"))
|
|
229
|
+
server.tool("schema_get", "Get the full context for the current schema: schema JSON, annotations, directives, templates, and workflow inputs", {}, async () => {
|
|
230
|
+
const result = await api.getFullContext();
|
|
231
|
+
return jsonResult(result);
|
|
232
|
+
});
|
|
233
|
+
if (shouldRegister("schema_update_model"))
|
|
234
|
+
server.tool("schema_update_model", "Create or update a model and its fields. Two modes:\n" +
|
|
235
|
+
"**Model mode** (title provided): Creates model if it doesn't exist, then applies all fields. " +
|
|
236
|
+
"Pass fields as {field_name: {type, description, ...}} to set multiple fields in one call.\n" +
|
|
237
|
+
"**Field mode** (field_name provided): Updates a single field's properties via partial merge.\n" +
|
|
238
|
+
"Use dot-path notation for nested models (e.g., 'client' for fields under client).", {
|
|
239
|
+
path: z
|
|
240
|
+
.string()
|
|
241
|
+
.nullable()
|
|
242
|
+
.describe("Dot-path to the parent model (null for root level)"),
|
|
243
|
+
// Model mode params
|
|
244
|
+
title: z
|
|
245
|
+
.string()
|
|
246
|
+
.optional()
|
|
247
|
+
.describe("Human-readable title for the model (e.g., 'Medical Providers'). " +
|
|
248
|
+
"The slug name is auto-derived. Required for model mode."),
|
|
249
|
+
type: z
|
|
250
|
+
.enum(["object", "array"])
|
|
251
|
+
.optional()
|
|
252
|
+
.describe("Type of model to create (required when creating a new model, ignored for existing models)"),
|
|
253
|
+
fields: z
|
|
254
|
+
.record(z.string(), z.record(z.string(), z.unknown()))
|
|
255
|
+
.optional()
|
|
256
|
+
.describe("Fields to create/update on the model. Keys are field names, values are property objects " +
|
|
257
|
+
"(e.g., {type: 'string', description: '...', 'x-identity': true}). Each field is merged with existing properties."),
|
|
258
|
+
// Field mode params
|
|
259
|
+
field_name: z
|
|
260
|
+
.string()
|
|
261
|
+
.optional()
|
|
262
|
+
.describe("Name of a single field to update (field mode). Cannot be combined with title."),
|
|
263
|
+
properties: z
|
|
264
|
+
.record(z.string(), z.unknown())
|
|
265
|
+
.optional()
|
|
266
|
+
.describe("Properties to merge into the single field (field mode only)"),
|
|
267
|
+
message: messageParam,
|
|
268
|
+
}, async ({ path, title, type, fields, field_name, properties, message, }) => {
|
|
269
|
+
const data = { path };
|
|
270
|
+
if (title !== undefined) {
|
|
271
|
+
data.title = title;
|
|
272
|
+
if (type !== undefined)
|
|
273
|
+
data.type = type;
|
|
274
|
+
if (fields !== undefined)
|
|
275
|
+
data.fields = fields;
|
|
276
|
+
}
|
|
277
|
+
else if (field_name !== undefined) {
|
|
278
|
+
data.field_name = field_name;
|
|
279
|
+
if (properties !== undefined)
|
|
280
|
+
data.properties = properties;
|
|
281
|
+
}
|
|
282
|
+
const result = await api.updateModel(data, message);
|
|
283
|
+
return jsonResult(result);
|
|
284
|
+
});
|
|
285
|
+
if (shouldRegister("schema_remove_model"))
|
|
286
|
+
server.tool("schema_remove_model", "Remove a model at a path in the schema. Provide the human-readable title — the slug name is auto-derived.", {
|
|
287
|
+
path: z
|
|
288
|
+
.string()
|
|
289
|
+
.nullable()
|
|
290
|
+
.describe("Dot-path to the parent model (null for root level)"),
|
|
291
|
+
title: z
|
|
292
|
+
.string()
|
|
293
|
+
.describe("Human-readable title of the model to remove (e.g., 'Medical Providers'). The slug name is auto-derived."),
|
|
294
|
+
message: messageParam,
|
|
295
|
+
}, async ({ path, title, message }) => {
|
|
296
|
+
const result = await api.removeModel(path, title, message);
|
|
297
|
+
return jsonResult(result);
|
|
298
|
+
});
|
|
299
|
+
if (shouldRegister("schema_update_root"))
|
|
300
|
+
server.tool("schema_update_root", "Update root-level schema metadata (title, description, type). WARNING: This modifies the schema root object itself, NOT the fields inside it. To add fields to the root model, use schema_update_model with path=null in field mode. Only use this tool to change the root's title or description.", {
|
|
301
|
+
properties: z
|
|
302
|
+
.record(z.string(), z.unknown())
|
|
303
|
+
.describe("Properties to merge into the root schema definition"),
|
|
304
|
+
message: messageParam,
|
|
305
|
+
}, async ({ properties, message }) => {
|
|
306
|
+
const result = await api.updateRoot(properties, message);
|
|
307
|
+
return jsonResult(result);
|
|
308
|
+
});
|
|
209
309
|
// ============================================================================
|
|
210
310
|
// Annotation Tools
|
|
211
311
|
// ============================================================================
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
.describe("New
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
message
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
server.tool("
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
312
|
+
if (shouldRegister("annotation_list"))
|
|
313
|
+
server.tool("annotation_list", "List all annotations for the current schema", {}, async () => {
|
|
314
|
+
const result = await api.listAnnotations();
|
|
315
|
+
return jsonResult(result);
|
|
316
|
+
});
|
|
317
|
+
if (shouldRegister("annotation_create"))
|
|
318
|
+
server.tool("annotation_create", "Create a new annotation on the schema (note, rule, question, or research)", {
|
|
319
|
+
category: z
|
|
320
|
+
.enum(["note", "rule", "question", "research"])
|
|
321
|
+
.describe("Annotation category"),
|
|
322
|
+
title: z.string().describe("Short title for the annotation"),
|
|
323
|
+
content: z.string().describe("Markdown content of the annotation"),
|
|
324
|
+
target_fragment_selector: z
|
|
325
|
+
.record(z.string(), z.unknown())
|
|
326
|
+
.optional()
|
|
327
|
+
.describe("Fragment selector targeting a specific schema node"),
|
|
328
|
+
message: messageParam,
|
|
329
|
+
}, async ({ category, title, content, target_fragment_selector, message, }) => {
|
|
330
|
+
const result = await api.applyAnnotationAction(null, "create", {
|
|
331
|
+
category,
|
|
332
|
+
title,
|
|
333
|
+
content,
|
|
334
|
+
target_fragment_selector,
|
|
335
|
+
}, message);
|
|
336
|
+
return jsonResult(result);
|
|
337
|
+
});
|
|
338
|
+
if (shouldRegister("annotation_update"))
|
|
339
|
+
server.tool("annotation_update", "Update an existing annotation", {
|
|
340
|
+
annotation_id: z
|
|
341
|
+
.number()
|
|
342
|
+
.describe("ID of the annotation to update"),
|
|
343
|
+
title: z.string().optional().describe("New title"),
|
|
344
|
+
content: z.string().optional().describe("New content"),
|
|
345
|
+
category: z
|
|
346
|
+
.enum(["note", "rule", "question", "research"])
|
|
347
|
+
.optional()
|
|
348
|
+
.describe("New category"),
|
|
349
|
+
message: messageParam,
|
|
350
|
+
}, async ({ annotation_id, message, ...data }) => {
|
|
351
|
+
const updateData = definedOnly(data);
|
|
352
|
+
const result = await api.applyAnnotationAction(annotation_id, "update", updateData, message);
|
|
353
|
+
return jsonResult(result);
|
|
354
|
+
});
|
|
355
|
+
if (shouldRegister("annotation_resolve"))
|
|
356
|
+
server.tool("annotation_resolve", "Resolve a question annotation by providing an answer", {
|
|
357
|
+
annotation_id: z
|
|
358
|
+
.number()
|
|
359
|
+
.describe("ID of the question annotation to resolve"),
|
|
360
|
+
resolved_content: z.string().describe("The answer to the question"),
|
|
361
|
+
message: messageParam,
|
|
362
|
+
}, async ({ annotation_id, resolved_content, message }) => {
|
|
363
|
+
const result = await api.applyAnnotationAction(annotation_id, "resolve", { resolved_content }, message);
|
|
364
|
+
return jsonResult(result);
|
|
365
|
+
});
|
|
366
|
+
if (shouldRegister("annotation_convert_to_rule"))
|
|
367
|
+
server.tool("annotation_convert_to_rule", "Convert a question or note annotation to a rule", {
|
|
368
|
+
annotation_id: z
|
|
369
|
+
.number()
|
|
370
|
+
.describe("ID of the annotation to convert"),
|
|
371
|
+
message: messageParam,
|
|
372
|
+
}, async ({ annotation_id, message }) => {
|
|
373
|
+
const result = await api.applyAnnotationAction(annotation_id, "convert-to-rule", undefined, message);
|
|
374
|
+
return jsonResult(result);
|
|
375
|
+
});
|
|
376
|
+
if (shouldRegister("annotation_delete"))
|
|
377
|
+
server.tool("annotation_delete", "Soft-delete an annotation", {
|
|
378
|
+
annotation_id: z
|
|
379
|
+
.number()
|
|
380
|
+
.describe("ID of the annotation to delete"),
|
|
381
|
+
message: messageParam,
|
|
382
|
+
}, async ({ annotation_id, message }) => {
|
|
383
|
+
const result = await api.applyAnnotationAction(annotation_id, "delete", undefined, message);
|
|
384
|
+
return jsonResult(result);
|
|
385
|
+
});
|
|
274
386
|
// ============================================================================
|
|
275
387
|
// Blueprint Tools
|
|
276
388
|
// ============================================================================
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
389
|
+
if (shouldRegister("blueprint_list"))
|
|
390
|
+
server.tool("blueprint_list", "List all blueprints for the current schema. A blueprint groups behavior directives into an extraction pipeline. One is auto-created when you create your first directive.", {}, async () => {
|
|
391
|
+
const result = await api.listBlueprints();
|
|
392
|
+
return jsonResult(result);
|
|
393
|
+
});
|
|
281
394
|
// ============================================================================
|
|
282
395
|
// Directive Tools
|
|
283
396
|
// ============================================================================
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (!Object.values(typeMap).includes(resolvedType) &&
|
|
335
|
-
!resolvedType.startsWith("App\\")) {
|
|
336
|
-
return {
|
|
337
|
-
content: [
|
|
338
|
-
{
|
|
339
|
-
type: "text",
|
|
340
|
-
text: JSON.stringify({
|
|
341
|
-
error: `Unknown directive type '${type}'. Use one of: 'DataExtraction', 'InputOrganization', or 'ArtifactGeneration'.`,
|
|
342
|
-
}),
|
|
343
|
-
},
|
|
344
|
-
],
|
|
397
|
+
if (shouldRegister("directive_list"))
|
|
398
|
+
server.tool("directive_list", "List all behavior directives for the current schema", {}, async () => {
|
|
399
|
+
const result = await api.listDirectives();
|
|
400
|
+
return jsonResult(result);
|
|
401
|
+
});
|
|
402
|
+
if (shouldRegister("directive_create"))
|
|
403
|
+
server.tool("directive_create", "Create a new behavior directive. IMPORTANT: The 'type' parameter MUST be one of exactly these three shortcut strings: 'DataExtraction', 'InputOrganization', or 'ArtifactGeneration'. Do NOT use full class names (e.g., do NOT use 'ArtifactGenerationSchemaBehaviorDirective'). The blueprint is auto-resolved.", {
|
|
404
|
+
type: z
|
|
405
|
+
.string()
|
|
406
|
+
.describe("Behavior type: 'DataExtraction', 'InputOrganization', or 'ArtifactGeneration'."),
|
|
407
|
+
name: z.string().describe("Unique name for the directive"),
|
|
408
|
+
label: z.string().describe("Display label"),
|
|
409
|
+
target_fragment_selector: z
|
|
410
|
+
.record(z.string(), z.unknown())
|
|
411
|
+
.optional()
|
|
412
|
+
.describe("Fragment selector targeting a schema node. Determines which model in the hierarchy this directive operates on. Null = root level."),
|
|
413
|
+
data_fragment_selector: z
|
|
414
|
+
.record(z.string(), z.unknown())
|
|
415
|
+
.optional()
|
|
416
|
+
.describe("Fragment selector for which fields to extract (DataExtraction only). Auto-generated if omitted."),
|
|
417
|
+
prompt: z
|
|
418
|
+
.string()
|
|
419
|
+
.optional()
|
|
420
|
+
.describe("Prompt text for the directive. Required for ArtifactGeneration (LLM instruction for generating text) and InputOrganization (guidance for page grouping). Optional for DataExtraction (additional extraction guidance)."),
|
|
421
|
+
settings: z
|
|
422
|
+
.record(z.string(), z.unknown())
|
|
423
|
+
.optional()
|
|
424
|
+
.describe("Directive settings object. EXACT key names required: " +
|
|
425
|
+
"For DataExtraction: {'extraction_mode': 'skim'} or {'extraction_mode': 'exhaustive'} — key MUST be 'extraction_mode', NOT 'mode'. " +
|
|
426
|
+
"For IO/Artifact: {'agent_effort': 'high'} or 'very_high' or 'extreme'. " +
|
|
427
|
+
"For Artifact: optionally include 'editable': true, 'deletable': true for user-editable artifacts."),
|
|
428
|
+
message: messageParam,
|
|
429
|
+
}, async ({ type, name, label, target_fragment_selector, data_fragment_selector, prompt, settings, message, }) => {
|
|
430
|
+
// Map type names to FQCNs — accepts shortcuts and common variations
|
|
431
|
+
const typeMap = {
|
|
432
|
+
// Canonical shortcuts
|
|
433
|
+
DataExtraction: "App\\Models\\Schema\\DataExtractionSchemaBehaviorDirective",
|
|
434
|
+
InputOrganization: "App\\Models\\Schema\\InputOrganizationSchemaBehaviorDirective",
|
|
435
|
+
ArtifactGeneration: "App\\Models\\Schema\\ArtifactSchemaBehaviorDirective",
|
|
436
|
+
// Common variations agents try
|
|
437
|
+
Artifact: "App\\Models\\Schema\\ArtifactSchemaBehaviorDirective",
|
|
438
|
+
ArtifactGen: "App\\Models\\Schema\\ArtifactSchemaBehaviorDirective",
|
|
439
|
+
IO: "App\\Models\\Schema\\InputOrganizationSchemaBehaviorDirective",
|
|
440
|
+
Extraction: "App\\Models\\Schema\\DataExtractionSchemaBehaviorDirective",
|
|
441
|
+
// Accept FQCNs directly (agents sometimes pass full class names)
|
|
442
|
+
"App\\Models\\Schema\\DataExtractionSchemaBehaviorDirective": "App\\Models\\Schema\\DataExtractionSchemaBehaviorDirective",
|
|
443
|
+
"App\\Models\\Schema\\InputOrganizationSchemaBehaviorDirective": "App\\Models\\Schema\\InputOrganizationSchemaBehaviorDirective",
|
|
444
|
+
"App\\Models\\Schema\\ArtifactSchemaBehaviorDirective": "App\\Models\\Schema\\ArtifactSchemaBehaviorDirective",
|
|
445
|
+
// Common wrong FQCN the agent guesses
|
|
446
|
+
"App\\Models\\Schema\\ArtifactGenerationSchemaBehaviorDirective": "App\\Models\\Schema\\ArtifactSchemaBehaviorDirective",
|
|
345
447
|
};
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
.describe("
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
448
|
+
const resolvedType = typeMap[type] || type;
|
|
449
|
+
if (!Object.values(typeMap).includes(resolvedType) &&
|
|
450
|
+
!resolvedType.startsWith("App\\")) {
|
|
451
|
+
return {
|
|
452
|
+
content: [
|
|
453
|
+
{
|
|
454
|
+
type: "text",
|
|
455
|
+
text: JSON.stringify({
|
|
456
|
+
error: `Unknown directive type '${type}'. Use one of: 'DataExtraction', 'InputOrganization', or 'ArtifactGeneration'.`,
|
|
457
|
+
}),
|
|
458
|
+
},
|
|
459
|
+
],
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
const result = await api.applyDirectiveAction(null, "create", {
|
|
463
|
+
type: resolvedType,
|
|
464
|
+
name,
|
|
465
|
+
label,
|
|
466
|
+
target_fragment_selector,
|
|
467
|
+
data_fragment_selector,
|
|
468
|
+
prompt,
|
|
469
|
+
settings,
|
|
470
|
+
}, message);
|
|
471
|
+
return jsonResult(result);
|
|
472
|
+
});
|
|
473
|
+
if (shouldRegister("directive_update"))
|
|
474
|
+
server.tool("directive_update", "Update an existing behavior directive", {
|
|
475
|
+
directive_id: z.number().describe("ID of the directive to update"),
|
|
476
|
+
name: z.string().optional().describe("New name"),
|
|
477
|
+
label: z.string().optional().describe("New label"),
|
|
478
|
+
target_fragment_selector: z
|
|
479
|
+
.record(z.string(), z.unknown())
|
|
480
|
+
.optional()
|
|
481
|
+
.describe("Updated fragment selector targeting a schema node"),
|
|
482
|
+
data_fragment_selector: z
|
|
483
|
+
.record(z.string(), z.unknown())
|
|
484
|
+
.optional()
|
|
485
|
+
.describe("Updated data fragment selector (DataExtraction only)"),
|
|
486
|
+
settings: z
|
|
487
|
+
.record(z.string(), z.unknown())
|
|
488
|
+
.optional()
|
|
489
|
+
.describe("Updated settings"),
|
|
490
|
+
message: messageParam,
|
|
491
|
+
}, async ({ directive_id, message, ...data }) => {
|
|
492
|
+
const updateData = definedOnly(data);
|
|
493
|
+
const result = await api.applyDirectiveAction(directive_id, "update", updateData, message);
|
|
494
|
+
return jsonResult(result);
|
|
495
|
+
});
|
|
496
|
+
if (shouldRegister("directive_delete"))
|
|
497
|
+
server.tool("directive_delete", "Delete a behavior directive", {
|
|
498
|
+
directive_id: z.number().describe("ID of the directive to delete"),
|
|
499
|
+
message: messageParam,
|
|
500
|
+
}, async ({ directive_id, message }) => {
|
|
501
|
+
const result = await api.applyDirectiveAction(directive_id, "delete", undefined, message);
|
|
502
|
+
return jsonResult(result);
|
|
503
|
+
});
|
|
387
504
|
// ============================================================================
|
|
388
505
|
// Template Tools
|
|
389
506
|
// ============================================================================
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
.optional()
|
|
394
|
-
.describe("Template name (auto-generated if omitted, must be unique per team)"),
|
|
395
|
-
type: z
|
|
396
|
-
.enum(["document", "table"])
|
|
397
|
-
.optional()
|
|
398
|
-
.describe("Template type (default: document)"),
|
|
399
|
-
description: z
|
|
400
|
-
.string()
|
|
401
|
-
.optional()
|
|
402
|
-
.describe("Human-readable description of the template's purpose"),
|
|
403
|
-
template_json: z
|
|
404
|
-
.record(z.string(), z.unknown())
|
|
405
|
-
.optional()
|
|
406
|
-
.describe("Full template JSON structure with type, meta, styles, and document keys"),
|
|
407
|
-
message: messageParam,
|
|
408
|
-
}, async ({ message, ...data }) => {
|
|
409
|
-
const createData = definedOnly(data);
|
|
410
|
-
const result = await api.createTemplate(createData, message);
|
|
411
|
-
return jsonResult(result);
|
|
412
|
-
});
|
|
413
|
-
server.tool("template_list", "List all template definitions for the current schema", {}, async () => {
|
|
414
|
-
const result = await api.listTemplates();
|
|
415
|
-
return jsonResult(result);
|
|
416
|
-
});
|
|
417
|
-
server.tool("template_get", "Get full details of a template definition including template_json", {
|
|
418
|
-
template_id: z.number().describe("ID of the template to fetch"),
|
|
419
|
-
}, async ({ template_id }) => {
|
|
420
|
-
const result = await api.getTemplateDetails(template_id);
|
|
421
|
-
return jsonResult(result);
|
|
422
|
-
});
|
|
423
|
-
server.tool("template_update", "Update a template definition (e.g., template_json content)", {
|
|
424
|
-
template_id: z.number().describe("ID of the template to update"),
|
|
425
|
-
template_json: z
|
|
426
|
-
.record(z.string(), z.unknown())
|
|
427
|
-
.optional()
|
|
428
|
-
.describe("Updated template JSON structure"),
|
|
429
|
-
name: z.string().optional().describe("Updated template name"),
|
|
430
|
-
message: messageParam,
|
|
431
|
-
}, async ({ template_id, message, ...data }) => {
|
|
432
|
-
const updateData = definedOnly(data);
|
|
433
|
-
const result = await api.applyTemplateAction(template_id, "update", updateData, message);
|
|
434
|
-
return jsonResult(result);
|
|
435
|
-
});
|
|
436
|
-
server.tool("template_patch", "Apply targeted path/value edits to a template's JSON. Preferred over template_update for iterative changes — " +
|
|
437
|
-
"only specify the paths that need to change instead of rewriting the entire template_json. " +
|
|
438
|
-
"Read data-template-path attributes in template_preview HTML to find the correct paths.", {
|
|
439
|
-
template_id: z.number().describe("ID of the template to patch"),
|
|
440
|
-
edits: z
|
|
441
|
-
.array(z.object({
|
|
442
|
-
path: z
|
|
507
|
+
if (shouldRegister("template_create"))
|
|
508
|
+
server.tool("template_create", "Create a new template definition for the current schema", {
|
|
509
|
+
name: z
|
|
443
510
|
.string()
|
|
444
|
-
.describe("Dot-notation path into template_json (e.g. 'document.body.2.content')"),
|
|
445
|
-
value: z
|
|
446
|
-
.unknown()
|
|
447
511
|
.optional()
|
|
448
|
-
.describe("
|
|
449
|
-
|
|
450
|
-
.
|
|
512
|
+
.describe("Template name (auto-generated if omitted, must be unique per team)"),
|
|
513
|
+
type: z
|
|
514
|
+
.enum(["document", "table"])
|
|
451
515
|
.optional()
|
|
452
|
-
.describe("
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
server.tool("
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
})
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
})
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
.
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
+
.describe("Template type (default: document)"),
|
|
517
|
+
description: z
|
|
518
|
+
.string()
|
|
519
|
+
.optional()
|
|
520
|
+
.describe("Human-readable description of the template's purpose"),
|
|
521
|
+
template_json: z
|
|
522
|
+
.record(z.string(), z.unknown())
|
|
523
|
+
.optional()
|
|
524
|
+
.describe("Full template JSON structure with type, meta, styles, and document keys"),
|
|
525
|
+
message: messageParam,
|
|
526
|
+
}, async ({ message, ...data }) => {
|
|
527
|
+
const createData = definedOnly(data);
|
|
528
|
+
const result = await api.createTemplate(createData, message);
|
|
529
|
+
return jsonResult(result);
|
|
530
|
+
});
|
|
531
|
+
if (shouldRegister("template_list"))
|
|
532
|
+
server.tool("template_list", "List all template definitions for the current schema", {}, async () => {
|
|
533
|
+
const result = await api.listTemplates();
|
|
534
|
+
return jsonResult(result);
|
|
535
|
+
});
|
|
536
|
+
if (shouldRegister("template_get"))
|
|
537
|
+
server.tool("template_get", "Get full details of a template definition including template_json", {
|
|
538
|
+
template_id: z.number().describe("ID of the template to fetch"),
|
|
539
|
+
}, async ({ template_id }) => {
|
|
540
|
+
const result = await api.getTemplateDetails(template_id);
|
|
541
|
+
return jsonResult(result);
|
|
542
|
+
});
|
|
543
|
+
if (shouldRegister("template_update"))
|
|
544
|
+
server.tool("template_update", "Update a template definition (e.g., template_json content)", {
|
|
545
|
+
template_id: z.number().describe("ID of the template to update"),
|
|
546
|
+
template_json: z
|
|
547
|
+
.record(z.string(), z.unknown())
|
|
548
|
+
.optional()
|
|
549
|
+
.describe("Updated template JSON structure"),
|
|
550
|
+
name: z.string().optional().describe("Updated template name"),
|
|
551
|
+
message: messageParam,
|
|
552
|
+
}, async ({ template_id, message, ...data }) => {
|
|
553
|
+
const updateData = definedOnly(data);
|
|
554
|
+
const result = await api.applyTemplateAction(template_id, "update", updateData, message);
|
|
555
|
+
return jsonResult(result);
|
|
556
|
+
});
|
|
557
|
+
if (shouldRegister("template_patch"))
|
|
558
|
+
server.tool("template_patch", "Apply targeted path/value edits to a template's JSON. Preferred over template_update for iterative changes — " +
|
|
559
|
+
"only specify the paths that need to change instead of rewriting the entire template_json. " +
|
|
560
|
+
"Read data-template-path attributes in template_preview HTML to find the correct paths.", {
|
|
561
|
+
template_id: z.number().describe("ID of the template to patch"),
|
|
562
|
+
edits: z
|
|
563
|
+
.array(z.object({
|
|
564
|
+
path: z
|
|
565
|
+
.string()
|
|
566
|
+
.describe("Dot-notation path into template_json (e.g. 'document.body.2.content')"),
|
|
567
|
+
value: z
|
|
568
|
+
.unknown()
|
|
569
|
+
.optional()
|
|
570
|
+
.describe("New value (scalar, element object, or null to delete)"),
|
|
571
|
+
value_array: z
|
|
572
|
+
.array(z.unknown())
|
|
573
|
+
.optional()
|
|
574
|
+
.describe("Replace path with this array (for replacing children, body sections, etc.)"),
|
|
575
|
+
}))
|
|
576
|
+
.describe("Array of path/value edits to apply"),
|
|
577
|
+
message: messageParam,
|
|
578
|
+
}, async ({ template_id, edits, message }) => {
|
|
579
|
+
const result = await api.patchTemplate(template_id, edits, message);
|
|
580
|
+
return jsonResult(result);
|
|
581
|
+
});
|
|
582
|
+
if (shouldRegister("template_get_example_pages"))
|
|
583
|
+
server.tool("template_get_example_pages", "Get example output documents attached to a template. Returns transcribed text content AND image URLs for each file so you can see both the text and visual layout of what the template output should look like.", {
|
|
584
|
+
template_id: z
|
|
585
|
+
.number()
|
|
586
|
+
.describe("ID of the template to get example pages for"),
|
|
587
|
+
}, async ({ template_id }) => {
|
|
588
|
+
const result = await api.getTemplateExamplePages(template_id);
|
|
589
|
+
return multiPageImageResult(result);
|
|
590
|
+
});
|
|
591
|
+
if (shouldRegister("template_get_sample_data"))
|
|
592
|
+
server.tool("template_get_sample_data", "Get the sample data stored on a template. Sample data is used for rendering template previews when no real team object is available.", {
|
|
593
|
+
template_id: z
|
|
594
|
+
.number()
|
|
595
|
+
.describe("ID of the template to get sample data for"),
|
|
596
|
+
}, async ({ template_id }) => {
|
|
597
|
+
const result = await api.getTemplateSampleData(template_id);
|
|
598
|
+
return jsonResult(result);
|
|
599
|
+
});
|
|
600
|
+
if (shouldRegister("template_set_sample_data"))
|
|
601
|
+
server.tool("template_set_sample_data", "Set sample data on a template for preview rendering. Store representative extraction data that matches the schema structure so the template can render a realistic preview. This data is used by template_preview when no team_object_id is provided.", {
|
|
602
|
+
template_id: z
|
|
603
|
+
.number()
|
|
604
|
+
.describe("ID of the template to set sample data on"),
|
|
605
|
+
sample_data: z
|
|
606
|
+
.record(z.string(), z.unknown())
|
|
607
|
+
.describe("Sample data object matching the schema structure. Should contain realistic values " +
|
|
608
|
+
"for all template variables so the preview renders meaningful content."),
|
|
609
|
+
message: messageParam,
|
|
610
|
+
}, async ({ template_id, sample_data, message }) => {
|
|
611
|
+
const result = await api.setTemplateSampleData(template_id, sample_data, message);
|
|
612
|
+
return jsonResult(result);
|
|
613
|
+
});
|
|
614
|
+
if (shouldRegister("template_preview"))
|
|
615
|
+
server.tool("template_preview", "Capture a screenshot of the rendered template. Returns image URL(s) of the template as it would appear in a document. " +
|
|
616
|
+
"Use this to visually compare your template against the example output from template_get_example_pages. " +
|
|
617
|
+
"If no team_object_id is provided, uses the template's sample_data (set via template_set_sample_data) or auto-generated placeholders.", {
|
|
618
|
+
template_id: z.number().describe("ID of the template to preview"),
|
|
619
|
+
team_object_id: z
|
|
620
|
+
.number()
|
|
621
|
+
.optional()
|
|
622
|
+
.describe("Optional team object ID to render with real extraction data instead of sample data"),
|
|
623
|
+
message: messageParam,
|
|
624
|
+
}, async ({ template_id, team_object_id, message }) => {
|
|
625
|
+
const result = await api.getTemplatePreview(template_id, team_object_id, message);
|
|
626
|
+
return imageResult(result);
|
|
627
|
+
});
|
|
628
|
+
if (shouldRegister("template_preview_html"))
|
|
629
|
+
server.tool("template_preview_html", "Get the rendered template HTML for fast structural verification. " +
|
|
630
|
+
"Returns the full HTML of the rendered template as text (~1s, much faster than template_preview). " +
|
|
631
|
+
"Use this during iterative building to verify structure, field references, and layout. " +
|
|
632
|
+
"Use template_preview (screenshot) only once at the end for final visual verification.", {
|
|
633
|
+
template_id: z.number().describe("ID of the template to preview"),
|
|
634
|
+
team_object_id: z
|
|
635
|
+
.number()
|
|
636
|
+
.optional()
|
|
637
|
+
.describe("Optional team object ID to render with real extraction data instead of sample data"),
|
|
638
|
+
message: messageParam,
|
|
639
|
+
}, async ({ template_id, team_object_id, message }) => {
|
|
640
|
+
const result = await api.getTemplatePreviewHtml(template_id, team_object_id, message);
|
|
641
|
+
return jsonResult(result);
|
|
642
|
+
});
|
|
516
643
|
// ============================================================================
|
|
517
644
|
// Quality Gate Tools
|
|
518
645
|
// ============================================================================
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
646
|
+
if (shouldRegister("quality_gate_list"))
|
|
647
|
+
server.tool("quality_gate_list", "List all quality gate items for the current schema. Shows each item's key, category, label, description, status, and reviewer analysis. Use this to see which items are pending review.", {}, async () => {
|
|
648
|
+
const result = await api.listQualityGateItems();
|
|
649
|
+
return jsonResult(result);
|
|
650
|
+
});
|
|
651
|
+
if (shouldRegister("quality_gate_submit_review"))
|
|
652
|
+
server.tool("quality_gate_submit_review", "Submit a review for a quality gate item. Set status to 'passed' or 'failed' with detailed analysis explaining your reasoning and evidence.", {
|
|
653
|
+
quality_gate_item_id: z
|
|
654
|
+
.number()
|
|
655
|
+
.describe("ID of the quality gate item to review"),
|
|
656
|
+
status: z
|
|
657
|
+
.enum(["passed", "failed"])
|
|
658
|
+
.describe("Review result: 'passed' if the item meets criteria, 'failed' if not"),
|
|
659
|
+
analysis: z
|
|
660
|
+
.string()
|
|
661
|
+
.describe("Detailed review analysis with evidence. Explain what you checked, " +
|
|
662
|
+
"what you found, and why you passed or failed the item."),
|
|
663
|
+
message: messageParam,
|
|
664
|
+
}, async ({ quality_gate_item_id, status, analysis, message }) => {
|
|
665
|
+
const result = await api.submitQualityGateReview(quality_gate_item_id, status, analysis, message);
|
|
666
|
+
return jsonResult(result);
|
|
667
|
+
});
|
|
539
668
|
// ============================================================================
|
|
540
669
|
// Style Library Tools (read-only)
|
|
541
670
|
// ============================================================================
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
671
|
+
if (shouldRegister("style_list"))
|
|
672
|
+
server.tool("style_list", "List all available style variants organized by element type. Each variant includes a description and structural properties. Call this before building or modifying templates to discover what variants are available. Colors are controlled by the theme, not by variants.", {}, async () => {
|
|
673
|
+
const result = await api.getStyleList();
|
|
674
|
+
return jsonResult(result);
|
|
675
|
+
});
|
|
546
676
|
// ============================================================================
|
|
547
677
|
// Context Tools (read-only)
|
|
548
678
|
// ============================================================================
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
})
|
|
679
|
+
if (shouldRegister("context_workflow_inputs"))
|
|
680
|
+
server.tool("context_workflow_inputs", "List all workflow inputs associated with this schema, including file metadata", {}, async () => {
|
|
681
|
+
const result = await api.getWorkflowInputs();
|
|
682
|
+
return jsonResult(result);
|
|
683
|
+
});
|
|
684
|
+
if (shouldRegister("context_workflow_input_pages"))
|
|
685
|
+
server.tool("context_workflow_input_pages", "Get transcribed page content for a specific workflow input (text from document OCR/LLM transcription)", {
|
|
686
|
+
workflow_input_id: z
|
|
687
|
+
.number()
|
|
688
|
+
.describe("ID of the workflow input to get pages for"),
|
|
689
|
+
}, async ({ workflow_input_id }) => {
|
|
690
|
+
const result = await api.getWorkflowInputPages(workflow_input_id);
|
|
691
|
+
return jsonResult(result);
|
|
692
|
+
});
|
|
693
|
+
if (shouldRegister("context_chat_history"))
|
|
694
|
+
server.tool("context_chat_history", "Get recent chat messages from the schema's collaboration thread", {
|
|
695
|
+
limit: z
|
|
696
|
+
.number()
|
|
697
|
+
.optional()
|
|
698
|
+
.describe("Maximum number of messages to return (default 50, max 100)"),
|
|
699
|
+
}, async ({ limit }) => {
|
|
700
|
+
const result = await api.getChatHistory(limit);
|
|
701
|
+
return jsonResult(result);
|
|
702
|
+
});
|
|
570
703
|
// ============================================================================
|
|
571
704
|
// Start Server
|
|
572
705
|
// ============================================================================
|
|
@@ -574,6 +707,7 @@ async function main() {
|
|
|
574
707
|
const transport = new StdioServerTransport();
|
|
575
708
|
await server.connect(transport);
|
|
576
709
|
console.error("Schema MCP Server running on stdio");
|
|
710
|
+
console.error(` Role: ${SCHEMA_ROLE}`);
|
|
577
711
|
console.error(` API URL: ${process.env.SCHEMA_API_URL || "http://localhost:80"}`);
|
|
578
712
|
console.error(` Schema ID: ${api.SCHEMA_ID}`);
|
|
579
713
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thehammer/schema-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "MCP server for Schema Builder - translates Claude Code tool calls into Laravel API requests",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/newms87/gpt-manager.git",
|
|
9
|
+
"directory": "mcp-server"
|
|
10
|
+
},
|
|
5
11
|
"type": "module",
|
|
6
12
|
"main": "dist/index.js",
|
|
7
13
|
"types": "dist/index.d.ts",
|
|
@@ -11,13 +17,17 @@
|
|
|
11
17
|
"files": [
|
|
12
18
|
"dist"
|
|
13
19
|
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
14
23
|
"scripts": {
|
|
15
24
|
"build": "tsc",
|
|
16
25
|
"start": "node dist/index.js",
|
|
17
26
|
"dev": "tsx watch src/index.ts"
|
|
18
27
|
},
|
|
19
28
|
"dependencies": {
|
|
20
|
-
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
29
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
30
|
+
"zod": "^4.0.0"
|
|
21
31
|
},
|
|
22
32
|
"devDependencies": {
|
|
23
33
|
"tsx": "^4.0.0",
|