@burdenoff/mcp-libs 2026.627.3 → 2026.627.5

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.
Files changed (61) hide show
  1. package/dist/modules/cosmicintersection/index.cjs +1984 -0
  2. package/dist/modules/cosmicintersection/index.cjs.map +1 -0
  3. package/dist/modules/cosmicintersection/index.d.cts +8 -0
  4. package/dist/modules/cosmicintersection/index.d.ts +8 -0
  5. package/dist/modules/cosmicintersection/index.js +1923 -0
  6. package/dist/modules/cosmicintersection/index.js.map +1 -0
  7. package/dist/modules/ecoimpacthub/index.cjs +2042 -0
  8. package/dist/modules/ecoimpacthub/index.cjs.map +1 -0
  9. package/dist/modules/ecoimpacthub/index.d.cts +8 -0
  10. package/dist/modules/ecoimpacthub/index.d.ts +8 -0
  11. package/dist/modules/ecoimpacthub/index.js +1981 -0
  12. package/dist/modules/ecoimpacthub/index.js.map +1 -0
  13. package/dist/modules/govcitizenhub/index.cjs +1686 -0
  14. package/dist/modules/govcitizenhub/index.cjs.map +1 -0
  15. package/dist/modules/govcitizenhub/index.d.cts +8 -0
  16. package/dist/modules/govcitizenhub/index.d.ts +8 -0
  17. package/dist/modules/govcitizenhub/index.js +1625 -0
  18. package/dist/modules/govcitizenhub/index.js.map +1 -0
  19. package/dist/modules/intelwatchtower/index.cjs +1919 -0
  20. package/dist/modules/intelwatchtower/index.cjs.map +1 -0
  21. package/dist/modules/intelwatchtower/index.d.cts +8 -0
  22. package/dist/modules/intelwatchtower/index.d.ts +8 -0
  23. package/dist/modules/intelwatchtower/index.js +1858 -0
  24. package/dist/modules/intelwatchtower/index.js.map +1 -0
  25. package/dist/modules/manufacturedops/index.cjs +1884 -0
  26. package/dist/modules/manufacturedops/index.cjs.map +1 -0
  27. package/dist/modules/manufacturedops/index.d.cts +8 -0
  28. package/dist/modules/manufacturedops/index.d.ts +8 -0
  29. package/dist/modules/manufacturedops/index.js +1823 -0
  30. package/dist/modules/manufacturedops/index.js.map +1 -0
  31. package/dist/modules/mybodyshield/index.cjs +1834 -0
  32. package/dist/modules/mybodyshield/index.cjs.map +1 -0
  33. package/dist/modules/mybodyshield/index.d.cts +8 -0
  34. package/dist/modules/mybodyshield/index.d.ts +8 -0
  35. package/dist/modules/mybodyshield/index.js +1773 -0
  36. package/dist/modules/mybodyshield/index.js.map +1 -0
  37. package/dist/modules/semanticfed/index.cjs +1846 -0
  38. package/dist/modules/semanticfed/index.cjs.map +1 -0
  39. package/dist/modules/semanticfed/index.d.cts +8 -0
  40. package/dist/modules/semanticfed/index.d.ts +8 -0
  41. package/dist/modules/semanticfed/index.js +1785 -0
  42. package/dist/modules/semanticfed/index.js.map +1 -0
  43. package/dist/modules/technospam/index.cjs +1962 -0
  44. package/dist/modules/technospam/index.cjs.map +1 -0
  45. package/dist/modules/technospam/index.d.cts +8 -0
  46. package/dist/modules/technospam/index.d.ts +8 -0
  47. package/dist/modules/technospam/index.js +1901 -0
  48. package/dist/modules/technospam/index.js.map +1 -0
  49. package/dist/modules/theculturepost/index.cjs +1587 -0
  50. package/dist/modules/theculturepost/index.cjs.map +1 -0
  51. package/dist/modules/theculturepost/index.d.cts +8 -0
  52. package/dist/modules/theculturepost/index.d.ts +8 -0
  53. package/dist/modules/theculturepost/index.js +1526 -0
  54. package/dist/modules/theculturepost/index.js.map +1 -0
  55. package/dist/modules/theglobalfuel/index.cjs +1678 -0
  56. package/dist/modules/theglobalfuel/index.cjs.map +1 -0
  57. package/dist/modules/theglobalfuel/index.d.cts +8 -0
  58. package/dist/modules/theglobalfuel/index.d.ts +8 -0
  59. package/dist/modules/theglobalfuel/index.js +1617 -0
  60. package/dist/modules/theglobalfuel/index.js.map +1 -0
  61. package/package.json +1 -1
@@ -0,0 +1,1919 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+ require('graphql-request');
5
+ require('cross-fetch');
6
+ require('@modelcontextprotocol/sdk/server/mcp.js');
7
+ require('@modelcontextprotocol/sdk/types.js');
8
+
9
+ // src/modules/intelwatchtower/tools/sources.ts
10
+
11
+ // src/core/errors.ts
12
+ var McpInternalError = class extends Error {
13
+ cause;
14
+ constructor(message, cause) {
15
+ super(message);
16
+ this.name = "McpInternalError";
17
+ this.cause = cause;
18
+ }
19
+ };
20
+
21
+ // src/core/result.ts
22
+ function jsonResult(data, structured) {
23
+ const result = {
24
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
25
+ };
26
+ return result;
27
+ }
28
+ function errorResult(message, hint) {
29
+ const text = hint ? `${message}
30
+
31
+ Hint: ${hint}` : message;
32
+ return { content: [{ type: "text", text }], isError: true };
33
+ }
34
+
35
+ // src/core/tool-name.ts
36
+ var MAX_TOOL_NAME_LENGTH = 63;
37
+ function assertSafeName(name, kind) {
38
+ if (name.length > MAX_TOOL_NAME_LENGTH) {
39
+ throw new McpInternalError(
40
+ `Tool name '${name}' exceeds ${MAX_TOOL_NAME_LENGTH} characters (some MCP clients truncate at 64).`
41
+ );
42
+ }
43
+ return name;
44
+ }
45
+ function mcpToolName(productName, ...parts) {
46
+ if (!productName) {
47
+ throw new McpInternalError("mcpToolName: productName is required");
48
+ }
49
+ const name = [productName, ...parts].filter(Boolean).join("_");
50
+ return assertSafeName(name);
51
+ }
52
+ function mcpResourceUri(productName, ...parts) {
53
+ if (!productName) {
54
+ throw new McpInternalError("mcpResourceUri: productName is required");
55
+ }
56
+ return `${productName}://${parts.filter(Boolean).join("/")}`;
57
+ }
58
+ function mcpPromptName(productName, ...parts) {
59
+ if (!productName) {
60
+ throw new McpInternalError("mcpPromptName: productName is required");
61
+ }
62
+ return [productName, ...parts].filter(Boolean).join("-");
63
+ }
64
+
65
+ // src/modules/intelwatchtower/operations.ts
66
+ var PAGE_INFO = `pageInfo { cursor hasMore }`;
67
+ var SOURCE_FIELDS = `
68
+ id name codename description discipline status classification region reliability
69
+ operatorId lastSeenAt tags createdAt updatedAt workspaceId
70
+ `;
71
+ var FEED_FIELDS = `
72
+ id name endpoint format status ingestCount lastIngestAt sourceId
73
+ createdAt updatedAt workspaceId
74
+ `;
75
+ var REQUIREMENT_FIELDS = `
76
+ id title description classification priority status dueDate satisfiedAt
77
+ missionId requestedById tags createdAt updatedAt workspaceId
78
+ `;
79
+ var TASK_FIELDS = `
80
+ id status instructions sourceId requirementId resultSummary
81
+ startAt endAt dispatchedAt completedAt createdAt updatedAt workspaceId
82
+ `;
83
+ var OBSERVATION_FIELDS = `
84
+ id summary classification observedAt latitude longitude payload
85
+ entityId sourceId taskId createdAt updatedAt workspaceId
86
+ `;
87
+ var MISSION_FIELDS = `
88
+ id name codename objective classification status commanderId
89
+ startAt endAt tags createdAt updatedAt workspaceId
90
+ `;
91
+ var ENTITY_FIELDS = `
92
+ id name type classification confidence description aliases threatScore
93
+ latitude longitude lastSeenAt attributes tags createdAt updatedAt workspaceId
94
+ `;
95
+ var INDICATOR_FIELDS = `
96
+ id type value classification confidence description isActive entityId
97
+ validFrom validUntil createdAt updatedAt workspaceId
98
+ `;
99
+ var ALERT_FIELDS = `
100
+ id title description classification severity status detectedAt resolvedAt
101
+ entityId indicatorId missionId caseId assignedToId triageNotes
102
+ createdAt updatedAt workspaceId
103
+ `;
104
+ var CASE_ENTRY_FIELDS = `
105
+ id caseId kind body createdAt updatedAt workspaceId file { id }
106
+ `;
107
+ var CASE_FIELDS = `
108
+ id title summary reference classification priority status missionId
109
+ leadAnalystId tags openedAt closedAt createdAt updatedAt workspaceId
110
+ `;
111
+ var REPORT_FIELDS = `
112
+ id title summary body type status classification authorId caseId missionId
113
+ tags releasedAt createdAt updatedAt workspaceId file { id }
114
+ `;
115
+ var GET_SOURCE = `
116
+ query IntelwatchtowerGetSource($id: ID!) {
117
+ intSource(id: $id) {
118
+ ${SOURCE_FIELDS}
119
+ feeds { ${FEED_FIELDS} }
120
+ tasks { ${TASK_FIELDS} }
121
+ }
122
+ }
123
+ `;
124
+ var LIST_SOURCES = `
125
+ query IntelwatchtowerListSources(
126
+ $discipline: IntSourceDiscipline
127
+ $status: IntSourceStatus
128
+ $pagination: PaginationInput
129
+ ) {
130
+ intListSources(discipline: $discipline, status: $status, pagination: $pagination) {
131
+ items { ${SOURCE_FIELDS} }
132
+ ${PAGE_INFO}
133
+ }
134
+ }
135
+ `;
136
+ var CREATE_SOURCE = `
137
+ mutation IntelwatchtowerCreateSource($input: IntCreateSourceInput!) {
138
+ intCreateSource(input: $input) { ${SOURCE_FIELDS} }
139
+ }
140
+ `;
141
+ var UPDATE_SOURCE = `
142
+ mutation IntelwatchtowerUpdateSource($id: ID!, $input: IntUpdateSourceInput!) {
143
+ intUpdateSource(id: $id, input: $input) { ${SOURCE_FIELDS} }
144
+ }
145
+ `;
146
+ var RETIRE_SOURCE = `
147
+ mutation IntelwatchtowerRetireSource($id: ID!) {
148
+ intRetireSource(id: $id)
149
+ }
150
+ `;
151
+ var CREATE_FEED = `
152
+ mutation IntelwatchtowerCreateFeed($input: IntCreateFeedInput!) {
153
+ intCreateFeed(input: $input) { ${FEED_FIELDS} }
154
+ }
155
+ `;
156
+ var LIST_REQUIREMENTS = `
157
+ query IntelwatchtowerListRequirements($missionId: ID, $status: IntRequirementStatus) {
158
+ intListRequirements(missionId: $missionId, status: $status) {
159
+ ${REQUIREMENT_FIELDS}
160
+ tasks { ${TASK_FIELDS} }
161
+ }
162
+ }
163
+ `;
164
+ var CREATE_REQUIREMENT = `
165
+ mutation IntelwatchtowerCreateRequirement($input: IntCreateRequirementInput!) {
166
+ intCreateRequirement(input: $input) { ${REQUIREMENT_FIELDS} }
167
+ }
168
+ `;
169
+ var LIST_TASKS = `
170
+ query IntelwatchtowerListTasks(
171
+ $requirementId: ID
172
+ $sourceId: ID
173
+ $status: IntTaskStatus
174
+ $pagination: PaginationInput
175
+ ) {
176
+ intListTasks(
177
+ requirementId: $requirementId
178
+ sourceId: $sourceId
179
+ status: $status
180
+ pagination: $pagination
181
+ ) {
182
+ items { ${TASK_FIELDS} }
183
+ ${PAGE_INFO}
184
+ }
185
+ }
186
+ `;
187
+ var CREATE_TASK = `
188
+ mutation IntelwatchtowerCreateTask($input: IntCreateTaskInput!) {
189
+ intCreateTask(input: $input) { ${TASK_FIELDS} }
190
+ }
191
+ `;
192
+ var TRANSITION_TASK = `
193
+ mutation IntelwatchtowerTransitionTask($id: ID!, $status: IntTaskStatus!) {
194
+ intTransitionTask(id: $id, status: $status) { ${TASK_FIELDS} }
195
+ }
196
+ `;
197
+ var LIST_OBSERVATIONS = `
198
+ query IntelwatchtowerListObservations(
199
+ $entityId: ID
200
+ $sourceId: ID
201
+ $taskId: ID
202
+ $pagination: PaginationInput
203
+ ) {
204
+ intListObservations(
205
+ entityId: $entityId
206
+ sourceId: $sourceId
207
+ taskId: $taskId
208
+ pagination: $pagination
209
+ ) {
210
+ items { ${OBSERVATION_FIELDS} }
211
+ ${PAGE_INFO}
212
+ }
213
+ }
214
+ `;
215
+ var RECORD_OBSERVATION = `
216
+ mutation IntelwatchtowerRecordObservation($input: IntRecordObservationInput!) {
217
+ intRecordObservation(input: $input) { ${OBSERVATION_FIELDS} }
218
+ }
219
+ `;
220
+ var GET_MISSION = `
221
+ query IntelwatchtowerGetMission($id: ID!) {
222
+ intMission(id: $id) {
223
+ ${MISSION_FIELDS}
224
+ cases { ${CASE_FIELDS} }
225
+ reports { ${REPORT_FIELDS} }
226
+ }
227
+ }
228
+ `;
229
+ var LIST_MISSIONS = `
230
+ query IntelwatchtowerListMissions($status: IntMissionStatus) {
231
+ intListMissions(status: $status) { ${MISSION_FIELDS} }
232
+ }
233
+ `;
234
+ var CREATE_MISSION = `
235
+ mutation IntelwatchtowerCreateMission($input: IntCreateMissionInput!) {
236
+ intCreateMission(input: $input) { ${MISSION_FIELDS} }
237
+ }
238
+ `;
239
+ var TRANSITION_MISSION = `
240
+ mutation IntelwatchtowerTransitionMission($id: ID!, $status: IntMissionStatus!) {
241
+ intTransitionMission(id: $id, status: $status) { ${MISSION_FIELDS} }
242
+ }
243
+ `;
244
+ var GET_ENTITY = `
245
+ query IntelwatchtowerGetEntity($id: ID!) {
246
+ intEntity(id: $id) {
247
+ ${ENTITY_FIELDS}
248
+ indicators { ${INDICATOR_FIELDS} }
249
+ alerts { ${ALERT_FIELDS} }
250
+ }
251
+ }
252
+ `;
253
+ var LIST_ENTITIES = `
254
+ query IntelwatchtowerListEntities(
255
+ $type: IntEntityType
256
+ $confidence: IntConfidence
257
+ $pagination: PaginationInput
258
+ ) {
259
+ intListEntities(type: $type, confidence: $confidence, pagination: $pagination) {
260
+ items { ${ENTITY_FIELDS} }
261
+ ${PAGE_INFO}
262
+ }
263
+ }
264
+ `;
265
+ var CREATE_ENTITY = `
266
+ mutation IntelwatchtowerCreateEntity($input: IntCreateEntityInput!) {
267
+ intCreateEntity(input: $input) { ${ENTITY_FIELDS} }
268
+ }
269
+ `;
270
+ var UPDATE_ENTITY = `
271
+ mutation IntelwatchtowerUpdateEntity($id: ID!, $input: IntUpdateEntityInput!) {
272
+ intUpdateEntity(id: $id, input: $input) { ${ENTITY_FIELDS} }
273
+ }
274
+ `;
275
+ var LIST_INDICATORS = `
276
+ query IntelwatchtowerListIndicators(
277
+ $entityId: ID
278
+ $type: IntIndicatorType
279
+ $isActive: Boolean
280
+ ) {
281
+ intListIndicators(entityId: $entityId, type: $type, isActive: $isActive) {
282
+ ${INDICATOR_FIELDS}
283
+ }
284
+ }
285
+ `;
286
+ var CREATE_INDICATOR = `
287
+ mutation IntelwatchtowerCreateIndicator($input: IntCreateIndicatorInput!) {
288
+ intCreateIndicator(input: $input) { ${INDICATOR_FIELDS} }
289
+ }
290
+ `;
291
+ var DEACTIVATE_INDICATOR = `
292
+ mutation IntelwatchtowerDeactivateIndicator($id: ID!) {
293
+ intDeactivateIndicator(id: $id) { ${INDICATOR_FIELDS} }
294
+ }
295
+ `;
296
+ var LIST_ALERTS = `
297
+ query IntelwatchtowerListAlerts(
298
+ $entityId: ID
299
+ $severity: IntAlertSeverity
300
+ $status: IntAlertStatus
301
+ $pagination: PaginationInput
302
+ ) {
303
+ intListAlerts(
304
+ entityId: $entityId
305
+ severity: $severity
306
+ status: $status
307
+ pagination: $pagination
308
+ ) {
309
+ items { ${ALERT_FIELDS} }
310
+ ${PAGE_INFO}
311
+ }
312
+ }
313
+ `;
314
+ var RAISE_ALERT = `
315
+ mutation IntelwatchtowerRaiseAlert($input: IntRaiseAlertInput!) {
316
+ intRaiseAlert(input: $input) { ${ALERT_FIELDS} }
317
+ }
318
+ `;
319
+ var TRANSITION_ALERT = `
320
+ mutation IntelwatchtowerTransitionAlert(
321
+ $id: ID!
322
+ $status: IntAlertStatus!
323
+ $triageNotes: String
324
+ ) {
325
+ intTransitionAlert(id: $id, status: $status, triageNotes: $triageNotes) {
326
+ ${ALERT_FIELDS}
327
+ }
328
+ }
329
+ `;
330
+ var GET_CASE = `
331
+ query IntelwatchtowerGetCase($id: ID!) {
332
+ intCase(id: $id) {
333
+ ${CASE_FIELDS}
334
+ alerts { ${ALERT_FIELDS} }
335
+ entries { ${CASE_ENTRY_FIELDS} }
336
+ }
337
+ }
338
+ `;
339
+ var LIST_CASES = `
340
+ query IntelwatchtowerListCases(
341
+ $missionId: ID
342
+ $status: IntCaseStatus
343
+ $pagination: PaginationInput
344
+ ) {
345
+ intListCases(missionId: $missionId, status: $status, pagination: $pagination) {
346
+ items { ${CASE_FIELDS} }
347
+ ${PAGE_INFO}
348
+ }
349
+ }
350
+ `;
351
+ var CREATE_CASE = `
352
+ mutation IntelwatchtowerCreateCase($input: IntCreateCaseInput!) {
353
+ intCreateCase(input: $input) { ${CASE_FIELDS} }
354
+ }
355
+ `;
356
+ var ADD_CASE_ENTRY = `
357
+ mutation IntelwatchtowerAddCaseEntry($input: IntAddCaseEntryInput!) {
358
+ intAddCaseEntry(input: $input) { ${CASE_ENTRY_FIELDS} }
359
+ }
360
+ `;
361
+ var CLOSE_CASE = `
362
+ mutation IntelwatchtowerCloseCase($id: ID!) {
363
+ intCloseCase(id: $id) { ${CASE_FIELDS} }
364
+ }
365
+ `;
366
+ var LIST_REPORTS = `
367
+ query IntelwatchtowerListReports(
368
+ $missionId: ID
369
+ $type: IntReportType
370
+ $status: IntReportStatus
371
+ $pagination: PaginationInput
372
+ ) {
373
+ intListReports(
374
+ missionId: $missionId
375
+ type: $type
376
+ status: $status
377
+ pagination: $pagination
378
+ ) {
379
+ items { ${REPORT_FIELDS} }
380
+ ${PAGE_INFO}
381
+ }
382
+ }
383
+ `;
384
+ var CREATE_REPORT = `
385
+ mutation IntelwatchtowerCreateReport($input: IntCreateReportInput!) {
386
+ intCreateReport(input: $input) { ${REPORT_FIELDS} }
387
+ }
388
+ `;
389
+ var RELEASE_REPORT = `
390
+ mutation IntelwatchtowerReleaseReport($id: ID!) {
391
+ intReleaseReport(id: $id) { ${REPORT_FIELDS} }
392
+ }
393
+ `;
394
+ var HEALTH = `
395
+ query IntelwatchtowerHealth {
396
+ intHealth
397
+ }
398
+ `;
399
+ var ClassificationEnum = zod.z.enum(["CONFIDENTIAL", "SECRET", "TOP_SECRET", "UNCLASSIFIED"]).describe("Security classification of an intelligence object");
400
+ var ConfidenceEnum = zod.z.enum(["CONFIRMED", "HIGH", "LOW", "MODERATE"]).describe("Analyst confidence in an entity/indicator");
401
+ var PriorityEnum = zod.z.enum(["FLASH", "IMMEDIATE", "PRIORITY", "ROUTINE"]).describe("Precedence/priority of a case or requirement");
402
+ var AlertSeverityEnum = zod.z.enum(["CRITICAL", "HIGH", "INFO", "LOW", "MEDIUM"]).describe("Severity of a threat alert");
403
+ var AlertStatusEnum = zod.z.enum(["ESCALATED", "FALSE_POSITIVE", "OPEN", "RESOLVED", "SUPPRESSED", "TRIAGED"]).describe("Triage lifecycle status of a threat alert");
404
+ var CaseStatusEnum = zod.z.enum(["ACTIVE", "ARCHIVED", "CLOSED", "OPEN", "PENDING_REVIEW"]).describe("Lifecycle status of an investigation case");
405
+ var EntityTypeEnum = zod.z.enum([
406
+ "AIRCRAFT",
407
+ "EVENT",
408
+ "FACILITY",
409
+ "LOCATION",
410
+ "NETWORK_NODE",
411
+ "ORGANIZATION",
412
+ "PERSON",
413
+ "VEHICLE",
414
+ "VESSEL"
415
+ ]).describe("Type of a tracked entity");
416
+ var FeedStatusEnum = zod.z.enum(["CONNECTED", "DISCONNECTED", "ERROR", "STALE"]).describe("Connection status of a collection feed");
417
+ var IndicatorTypeEnum = zod.z.enum([
418
+ "BEHAVIOR",
419
+ "DOMAIN",
420
+ "EMAIL",
421
+ "FILE_HASH",
422
+ "GEO_COORDINATE",
423
+ "IP_ADDRESS",
424
+ "SIGNATURE",
425
+ "URL"
426
+ ]).describe("Type of an indicator of compromise / observable");
427
+ var MissionStatusEnum = zod.z.enum(["ABORTED", "ACTIVE", "COMPLETED", "PAUSED", "PLANNING", "READY"]).describe("Lifecycle status of a mission");
428
+ var ReportStatusEnum = zod.z.enum(["ARCHIVED", "DRAFT", "IN_REVIEW", "RECALLED", "RELEASED"]).describe("Lifecycle status of an intelligence report");
429
+ var ReportTypeEnum = zod.z.enum(["ASSESSMENT", "INTSUM", "SITREP", "SPOT_REPORT", "WARNING"]).describe("Product type of an intelligence report");
430
+ var RequirementStatusEnum = zod.z.enum(["APPROVED", "CANCELLED", "DRAFT", "SATISFIED", "SUBMITTED", "TASKED"]).describe("Lifecycle status of a collection requirement");
431
+ var SourceDisciplineEnum = zod.z.enum(["CYBER", "GEOINT", "HUMINT", "IMINT", "MASINT", "OSINT", "SIGINT"]).describe("Collection discipline of a source/sensor");
432
+ var SourceStatusEnum = zod.z.enum(["ACTIVE", "DEGRADED", "OFFLINE", "PROVISIONING", "RETIRED"]).describe("Operational status of a source/sensor");
433
+ var TaskStatusEnum = zod.z.enum(["CANCELLED", "COLLECTING", "COMPLETED", "DISPATCHED", "FAILED", "PENDING"]).describe("Lifecycle status of a collection (tasking) order");
434
+ var JsonObject = zod.z.record(zod.z.string(), zod.z.unknown());
435
+ var IsoDateTime = zod.z.string().describe('ISO-8601 timestamp (DateTime scalar), e.g. "2026-06-27T12:00:00.000Z"');
436
+ function buildPagination(limit, offset) {
437
+ const pagination = {};
438
+ if (limit !== void 0) pagination.limit = limit;
439
+ if (offset !== void 0) pagination.offset = offset;
440
+ return Object.keys(pagination).length > 0 ? pagination : void 0;
441
+ }
442
+
443
+ // src/modules/intelwatchtower/tools/sources.ts
444
+ function registerSourceTools(server, ctx, track) {
445
+ server.registerTool(
446
+ track(mcpToolName(ctx.productName, "sources_get")),
447
+ {
448
+ title: "Get Source",
449
+ description: "Fetch a single collection source/sensor by ID, including its feeds and tasking orders.",
450
+ inputSchema: { id: zod.z.string().describe("Source ID") }
451
+ },
452
+ async ({ id }) => {
453
+ try {
454
+ const data = await ctx.gql.workspace.request(GET_SOURCE, { id });
455
+ if (!data.intSource) return errorResult(`Source ${id} not found`);
456
+ return jsonResult(data.intSource);
457
+ } catch (error) {
458
+ ctx.logger.error("intelwatchtower sources_get failed", { error: String(error) });
459
+ return errorResult(
460
+ `Failed to get source: ${error instanceof Error ? error.message : String(error)}`
461
+ );
462
+ }
463
+ }
464
+ );
465
+ server.registerTool(
466
+ track(mcpToolName(ctx.productName, "sources_list")),
467
+ {
468
+ title: "List Sources",
469
+ description: "List collection sources/sensors in the bound workspace, optionally filtered by discipline and/or status, with pagination.",
470
+ inputSchema: {
471
+ discipline: SourceDisciplineEnum.optional().describe("Filter by collection discipline"),
472
+ status: SourceStatusEnum.optional().describe("Filter by operational status"),
473
+ limit: zod.z.number().int().optional().describe("Page size (default 50)"),
474
+ offset: zod.z.number().int().optional().describe("Pagination offset (default 0)")
475
+ }
476
+ },
477
+ async ({ discipline, status, limit, offset }) => {
478
+ try {
479
+ const data = await ctx.gql.workspace.request(LIST_SOURCES, {
480
+ discipline,
481
+ status,
482
+ pagination: buildPagination(limit, offset)
483
+ });
484
+ return jsonResult(data.intListSources);
485
+ } catch (error) {
486
+ ctx.logger.error("intelwatchtower sources_list failed", { error: String(error) });
487
+ return errorResult(
488
+ `Failed to list sources: ${error instanceof Error ? error.message : String(error)}`
489
+ );
490
+ }
491
+ }
492
+ );
493
+ server.registerTool(
494
+ track(mcpToolName(ctx.productName, "sources_create")),
495
+ {
496
+ title: "Create Source",
497
+ description: "Register a new collection source/sensor. `discipline` is required; `reliability` is an analyst-assigned score.",
498
+ inputSchema: {
499
+ name: zod.z.string().min(1).describe("Source display name"),
500
+ discipline: SourceDisciplineEnum.describe("Collection discipline (HUMINT, SIGINT, ...)"),
501
+ codename: zod.z.string().optional().describe("Operational codename"),
502
+ description: zod.z.string().optional().describe("Source description"),
503
+ classification: ClassificationEnum.optional().describe(
504
+ "Security classification (default UNCLASSIFIED)"
505
+ ),
506
+ region: zod.z.string().optional().describe("Geographic region of operation"),
507
+ reliability: zod.z.number().int().optional().describe("Reliability score (analyst-assigned)"),
508
+ operatorId: zod.z.string().optional().describe("User ID of the controlling operator"),
509
+ status: SourceStatusEnum.optional().describe("Initial status (default PROVISIONING)"),
510
+ tags: zod.z.array(zod.z.string()).optional().describe("Discovery/triage tags")
511
+ }
512
+ },
513
+ async ({
514
+ name,
515
+ discipline,
516
+ codename,
517
+ description,
518
+ classification,
519
+ region,
520
+ reliability,
521
+ operatorId,
522
+ status,
523
+ tags
524
+ }) => {
525
+ try {
526
+ const input = { name, discipline };
527
+ if (codename !== void 0) input.codename = codename;
528
+ if (description !== void 0) input.description = description;
529
+ if (classification !== void 0) input.classification = classification;
530
+ if (region !== void 0) input.region = region;
531
+ if (reliability !== void 0) input.reliability = reliability;
532
+ if (operatorId !== void 0) input.operatorId = operatorId;
533
+ if (status !== void 0) input.status = status;
534
+ if (tags !== void 0) input.tags = tags;
535
+ const data = await ctx.gql.workspace.request(CREATE_SOURCE, { input });
536
+ return jsonResult(data.intCreateSource);
537
+ } catch (error) {
538
+ ctx.logger.error("intelwatchtower sources_create failed", { error: String(error) });
539
+ return errorResult(
540
+ `Failed to create source: ${error instanceof Error ? error.message : String(error)}`
541
+ );
542
+ }
543
+ }
544
+ );
545
+ server.registerTool(
546
+ track(mcpToolName(ctx.productName, "sources_update")),
547
+ {
548
+ title: "Update Source",
549
+ description: "Update a collection source. At least one mutable field must be provided. Use `status` to activate/degrade/take a source offline.",
550
+ inputSchema: {
551
+ id: zod.z.string().describe("Source ID"),
552
+ name: zod.z.string().optional().describe("Updated display name"),
553
+ codename: zod.z.string().optional().describe("Updated codename"),
554
+ description: zod.z.string().optional().describe("Updated description"),
555
+ discipline: SourceDisciplineEnum.optional().describe("Updated discipline"),
556
+ classification: ClassificationEnum.optional().describe("Updated classification"),
557
+ region: zod.z.string().optional().describe("Updated region"),
558
+ reliability: zod.z.number().int().optional().describe("Updated reliability score"),
559
+ operatorId: zod.z.string().optional().describe("Updated operator user ID"),
560
+ status: SourceStatusEnum.optional().describe("Updated operational status"),
561
+ tags: zod.z.array(zod.z.string()).optional().describe("Updated tags")
562
+ }
563
+ },
564
+ async ({
565
+ id,
566
+ name,
567
+ codename,
568
+ description,
569
+ discipline,
570
+ classification,
571
+ region,
572
+ reliability,
573
+ operatorId,
574
+ status,
575
+ tags
576
+ }) => {
577
+ try {
578
+ const input = {};
579
+ if (name !== void 0) input.name = name;
580
+ if (codename !== void 0) input.codename = codename;
581
+ if (description !== void 0) input.description = description;
582
+ if (discipline !== void 0) input.discipline = discipline;
583
+ if (classification !== void 0) input.classification = classification;
584
+ if (region !== void 0) input.region = region;
585
+ if (reliability !== void 0) input.reliability = reliability;
586
+ if (operatorId !== void 0) input.operatorId = operatorId;
587
+ if (status !== void 0) input.status = status;
588
+ if (tags !== void 0) input.tags = tags;
589
+ if (Object.keys(input).length === 0) {
590
+ return errorResult("No updates specified \u2014 provide at least one mutable source field");
591
+ }
592
+ const data = await ctx.gql.workspace.request(UPDATE_SOURCE, { id, input });
593
+ return jsonResult(data.intUpdateSource);
594
+ } catch (error) {
595
+ ctx.logger.error("intelwatchtower sources_update failed", { error: String(error) });
596
+ return errorResult(
597
+ `Failed to update source: ${error instanceof Error ? error.message : String(error)}`
598
+ );
599
+ }
600
+ }
601
+ );
602
+ server.registerTool(
603
+ track(mcpToolName(ctx.productName, "sources_retire")),
604
+ {
605
+ title: "Retire Source",
606
+ description: "Retire (decommission) a collection source/sensor.",
607
+ inputSchema: { id: zod.z.string().describe("Source ID") }
608
+ },
609
+ async ({ id }) => {
610
+ try {
611
+ const data = await ctx.gql.workspace.request(
612
+ RETIRE_SOURCE,
613
+ { id }
614
+ );
615
+ return jsonResult({ ok: data.intRetireSource, id });
616
+ } catch (error) {
617
+ ctx.logger.error("intelwatchtower sources_retire failed", { error: String(error) });
618
+ return errorResult(
619
+ `Failed to retire source: ${error instanceof Error ? error.message : String(error)}`
620
+ );
621
+ }
622
+ }
623
+ );
624
+ }
625
+ function registerFeedTools(server, ctx, track) {
626
+ server.registerTool(
627
+ track(mcpToolName(ctx.productName, "feeds_create")),
628
+ {
629
+ title: "Create Feed",
630
+ description: "Attach a new ingest feed to a collection source. `sourceId` is required; `endpoint`/`format` describe the upstream connection.",
631
+ inputSchema: {
632
+ sourceId: zod.z.string().min(1).describe("Owning source ID"),
633
+ name: zod.z.string().min(1).describe("Feed display name"),
634
+ endpoint: zod.z.string().optional().describe("Upstream endpoint URL/URI"),
635
+ format: zod.z.string().optional().describe('Wire format, e.g. "stix", "json", "csv"'),
636
+ status: FeedStatusEnum.optional().describe(
637
+ "Initial connection status (default DISCONNECTED)"
638
+ )
639
+ }
640
+ },
641
+ async ({ sourceId, name, endpoint, format, status }) => {
642
+ try {
643
+ const input = { sourceId, name };
644
+ if (endpoint !== void 0) input.endpoint = endpoint;
645
+ if (format !== void 0) input.format = format;
646
+ if (status !== void 0) input.status = status;
647
+ const data = await ctx.gql.workspace.request(CREATE_FEED, { input });
648
+ return jsonResult(data.intCreateFeed);
649
+ } catch (error) {
650
+ ctx.logger.error("intelwatchtower feeds_create failed", { error: String(error) });
651
+ return errorResult(
652
+ `Failed to create feed: ${error instanceof Error ? error.message : String(error)}`
653
+ );
654
+ }
655
+ }
656
+ );
657
+ }
658
+ function registerRequirementTools(server, ctx, track) {
659
+ server.registerTool(
660
+ track(mcpToolName(ctx.productName, "requirements_list")),
661
+ {
662
+ title: "List Collection Requirements",
663
+ description: "List collection requirements (intelligence-gap statements), optionally filtered by mission and/or status. Each includes its tasking orders.",
664
+ inputSchema: {
665
+ missionId: zod.z.string().optional().describe("Filter by owning mission ID"),
666
+ status: RequirementStatusEnum.optional().describe("Filter by requirement status")
667
+ }
668
+ },
669
+ async ({ missionId, status }) => {
670
+ try {
671
+ const data = await ctx.gql.workspace.request(LIST_REQUIREMENTS, { missionId, status });
672
+ return jsonResult(data.intListRequirements);
673
+ } catch (error) {
674
+ ctx.logger.error("intelwatchtower requirements_list failed", { error: String(error) });
675
+ return errorResult(
676
+ `Failed to list requirements: ${error instanceof Error ? error.message : String(error)}`
677
+ );
678
+ }
679
+ }
680
+ );
681
+ server.registerTool(
682
+ track(mcpToolName(ctx.productName, "requirements_create")),
683
+ {
684
+ title: "Create Collection Requirement",
685
+ description: "Raise a new collection requirement (an intelligence gap to be satisfied through tasking).",
686
+ inputSchema: {
687
+ title: zod.z.string().min(1).describe("Requirement title"),
688
+ description: zod.z.string().optional().describe("Detailed requirement description"),
689
+ classification: ClassificationEnum.optional().describe(
690
+ "Security classification (default UNCLASSIFIED)"
691
+ ),
692
+ priority: PriorityEnum.optional().describe("Precedence (default ROUTINE)"),
693
+ missionId: zod.z.string().optional().describe("Owning mission ID"),
694
+ requestedById: zod.z.string().optional().describe("User ID of the requester"),
695
+ dueDate: IsoDateTime.optional().describe("Due date (ISO-8601)"),
696
+ tags: zod.z.array(zod.z.string()).optional().describe("Discovery/triage tags")
697
+ }
698
+ },
699
+ async ({
700
+ title,
701
+ description,
702
+ classification,
703
+ priority,
704
+ missionId,
705
+ requestedById,
706
+ dueDate,
707
+ tags
708
+ }) => {
709
+ try {
710
+ const input = { title };
711
+ if (description !== void 0) input.description = description;
712
+ if (classification !== void 0) input.classification = classification;
713
+ if (priority !== void 0) input.priority = priority;
714
+ if (missionId !== void 0) input.missionId = missionId;
715
+ if (requestedById !== void 0) input.requestedById = requestedById;
716
+ if (dueDate !== void 0) input.dueDate = dueDate;
717
+ if (tags !== void 0) input.tags = tags;
718
+ const data = await ctx.gql.workspace.request(CREATE_REQUIREMENT, { input });
719
+ return jsonResult(data.intCreateRequirement);
720
+ } catch (error) {
721
+ ctx.logger.error("intelwatchtower requirements_create failed", { error: String(error) });
722
+ return errorResult(
723
+ `Failed to create requirement: ${error instanceof Error ? error.message : String(error)}`
724
+ );
725
+ }
726
+ }
727
+ );
728
+ }
729
+ function registerTaskTools(server, ctx, track) {
730
+ server.registerTool(
731
+ track(mcpToolName(ctx.productName, "tasks_list")),
732
+ {
733
+ title: "List Tasking Orders",
734
+ description: "List collection tasking orders, optionally filtered by requirement, source, and/or status, with pagination.",
735
+ inputSchema: {
736
+ requirementId: zod.z.string().optional().describe("Filter by parent requirement ID"),
737
+ sourceId: zod.z.string().optional().describe("Filter by tasked source ID"),
738
+ status: TaskStatusEnum.optional().describe("Filter by task status"),
739
+ limit: zod.z.number().int().optional().describe("Page size (default 50)"),
740
+ offset: zod.z.number().int().optional().describe("Pagination offset (default 0)")
741
+ }
742
+ },
743
+ async ({ requirementId, sourceId, status, limit, offset }) => {
744
+ try {
745
+ const data = await ctx.gql.workspace.request(LIST_TASKS, {
746
+ requirementId,
747
+ sourceId,
748
+ status,
749
+ pagination: buildPagination(limit, offset)
750
+ });
751
+ return jsonResult(data.intListTasks);
752
+ } catch (error) {
753
+ ctx.logger.error("intelwatchtower tasks_list failed", { error: String(error) });
754
+ return errorResult(
755
+ `Failed to list tasks: ${error instanceof Error ? error.message : String(error)}`
756
+ );
757
+ }
758
+ }
759
+ );
760
+ server.registerTool(
761
+ track(mcpToolName(ctx.productName, "tasks_create")),
762
+ {
763
+ title: "Create Tasking Order",
764
+ description: "Dispatch a collection tasking order to a source. `sourceId` is required; optionally bind it to a requirement and set a collection window.",
765
+ inputSchema: {
766
+ sourceId: zod.z.string().min(1).describe("Source to task"),
767
+ requirementId: zod.z.string().optional().describe("Parent requirement ID"),
768
+ instructions: zod.z.string().optional().describe("Collection instructions"),
769
+ startAt: IsoDateTime.optional().describe("Collection-window start (ISO-8601)"),
770
+ endAt: IsoDateTime.optional().describe("Collection-window end (ISO-8601)")
771
+ }
772
+ },
773
+ async ({ sourceId, requirementId, instructions, startAt, endAt }) => {
774
+ try {
775
+ const input = { sourceId };
776
+ if (requirementId !== void 0) input.requirementId = requirementId;
777
+ if (instructions !== void 0) input.instructions = instructions;
778
+ if (startAt !== void 0) input.startAt = startAt;
779
+ if (endAt !== void 0) input.endAt = endAt;
780
+ const data = await ctx.gql.workspace.request(CREATE_TASK, { input });
781
+ return jsonResult(data.intCreateTask);
782
+ } catch (error) {
783
+ ctx.logger.error("intelwatchtower tasks_create failed", { error: String(error) });
784
+ return errorResult(
785
+ `Failed to create task: ${error instanceof Error ? error.message : String(error)}`
786
+ );
787
+ }
788
+ }
789
+ );
790
+ server.registerTool(
791
+ track(mcpToolName(ctx.productName, "tasks_transition")),
792
+ {
793
+ title: "Transition Tasking Order",
794
+ description: "Advance a tasking order through its lifecycle (validated transitions: PENDING \u2192 DISPATCHED \u2192 COLLECTING \u2192 COMPLETED, or CANCELLED/FAILED).",
795
+ inputSchema: {
796
+ id: zod.z.string().describe("Task ID"),
797
+ status: TaskStatusEnum.describe("New task status")
798
+ }
799
+ },
800
+ async ({ id, status }) => {
801
+ try {
802
+ const data = await ctx.gql.workspace.request(TRANSITION_TASK, { id, status });
803
+ return jsonResult(data.intTransitionTask);
804
+ } catch (error) {
805
+ ctx.logger.error("intelwatchtower tasks_transition failed", { error: String(error) });
806
+ return errorResult(
807
+ `Failed to transition task: ${error instanceof Error ? error.message : String(error)}`
808
+ );
809
+ }
810
+ }
811
+ );
812
+ }
813
+ function registerObservationTools(server, ctx, track) {
814
+ server.registerTool(
815
+ track(mcpToolName(ctx.productName, "observations_list")),
816
+ {
817
+ title: "List Observations",
818
+ description: "List raw observations (collected reporting), optionally filtered by entity, source, and/or task, with pagination.",
819
+ inputSchema: {
820
+ entityId: zod.z.string().optional().describe("Filter by associated entity ID"),
821
+ sourceId: zod.z.string().optional().describe("Filter by reporting source ID"),
822
+ taskId: zod.z.string().optional().describe("Filter by originating task ID"),
823
+ limit: zod.z.number().int().optional().describe("Page size (default 50)"),
824
+ offset: zod.z.number().int().optional().describe("Pagination offset (default 0)")
825
+ }
826
+ },
827
+ async ({ entityId, sourceId, taskId, limit, offset }) => {
828
+ try {
829
+ const data = await ctx.gql.workspace.request(LIST_OBSERVATIONS, {
830
+ entityId,
831
+ sourceId,
832
+ taskId,
833
+ pagination: buildPagination(limit, offset)
834
+ });
835
+ return jsonResult(data.intListObservations);
836
+ } catch (error) {
837
+ ctx.logger.error("intelwatchtower observations_list failed", { error: String(error) });
838
+ return errorResult(
839
+ `Failed to list observations: ${error instanceof Error ? error.message : String(error)}`
840
+ );
841
+ }
842
+ }
843
+ );
844
+ server.registerTool(
845
+ track(mcpToolName(ctx.productName, "observations_record")),
846
+ {
847
+ title: "Record Observation",
848
+ description: "Record a raw observation from a source. `sourceId`, `summary`, and `observedAt` are required; optionally geo-locate it and attach a structured payload.",
849
+ inputSchema: {
850
+ sourceId: zod.z.string().min(1).describe("Reporting source ID"),
851
+ summary: zod.z.string().min(1).describe("Human-readable observation summary"),
852
+ observedAt: IsoDateTime.describe("When the observation occurred (ISO-8601)"),
853
+ classification: ClassificationEnum.optional().describe(
854
+ "Security classification (default UNCLASSIFIED)"
855
+ ),
856
+ entityId: zod.z.string().optional().describe("Associated tracked entity ID"),
857
+ taskId: zod.z.string().optional().describe("Originating tasking order ID"),
858
+ latitude: zod.z.number().optional().describe("Observation latitude"),
859
+ longitude: zod.z.number().optional().describe("Observation longitude"),
860
+ payload: JsonObject.optional().describe("Structured observation payload JSON")
861
+ }
862
+ },
863
+ async ({
864
+ sourceId,
865
+ summary,
866
+ observedAt,
867
+ classification,
868
+ entityId,
869
+ taskId,
870
+ latitude,
871
+ longitude,
872
+ payload
873
+ }) => {
874
+ try {
875
+ const input = { sourceId, summary, observedAt };
876
+ if (classification !== void 0) input.classification = classification;
877
+ if (entityId !== void 0) input.entityId = entityId;
878
+ if (taskId !== void 0) input.taskId = taskId;
879
+ if (latitude !== void 0) input.latitude = latitude;
880
+ if (longitude !== void 0) input.longitude = longitude;
881
+ if (payload !== void 0) input.payload = payload;
882
+ const data = await ctx.gql.workspace.request(RECORD_OBSERVATION, { input });
883
+ return jsonResult(data.intRecordObservation);
884
+ } catch (error) {
885
+ ctx.logger.error("intelwatchtower observations_record failed", { error: String(error) });
886
+ return errorResult(
887
+ `Failed to record observation: ${error instanceof Error ? error.message : String(error)}`
888
+ );
889
+ }
890
+ }
891
+ );
892
+ }
893
+ function registerMissionTools(server, ctx, track) {
894
+ server.registerTool(
895
+ track(mcpToolName(ctx.productName, "missions_get")),
896
+ {
897
+ title: "Get Mission",
898
+ description: "Fetch a single mission by ID, including its cases and reports.",
899
+ inputSchema: { id: zod.z.string().describe("Mission ID") }
900
+ },
901
+ async ({ id }) => {
902
+ try {
903
+ const data = await ctx.gql.workspace.request(GET_MISSION, { id });
904
+ if (!data.intMission) return errorResult(`Mission ${id} not found`);
905
+ return jsonResult(data.intMission);
906
+ } catch (error) {
907
+ ctx.logger.error("intelwatchtower missions_get failed", { error: String(error) });
908
+ return errorResult(
909
+ `Failed to get mission: ${error instanceof Error ? error.message : String(error)}`
910
+ );
911
+ }
912
+ }
913
+ );
914
+ server.registerTool(
915
+ track(mcpToolName(ctx.productName, "missions_list")),
916
+ {
917
+ title: "List Missions",
918
+ description: "List missions in the bound workspace, optionally filtered by status.",
919
+ inputSchema: {
920
+ status: MissionStatusEnum.optional().describe("Filter by mission status")
921
+ }
922
+ },
923
+ async ({ status }) => {
924
+ try {
925
+ const data = await ctx.gql.workspace.request(LIST_MISSIONS, { status });
926
+ return jsonResult(data.intListMissions);
927
+ } catch (error) {
928
+ ctx.logger.error("intelwatchtower missions_list failed", { error: String(error) });
929
+ return errorResult(
930
+ `Failed to list missions: ${error instanceof Error ? error.message : String(error)}`
931
+ );
932
+ }
933
+ }
934
+ );
935
+ server.registerTool(
936
+ track(mcpToolName(ctx.productName, "missions_create")),
937
+ {
938
+ title: "Create Mission",
939
+ description: "Stand up a new mission. `name` is required.",
940
+ inputSchema: {
941
+ name: zod.z.string().min(1).describe("Mission name"),
942
+ codename: zod.z.string().optional().describe("Operational codename"),
943
+ objective: zod.z.string().optional().describe("Mission objective statement"),
944
+ classification: ClassificationEnum.optional().describe(
945
+ "Security classification (default UNCLASSIFIED)"
946
+ ),
947
+ commanderId: zod.z.string().optional().describe("User ID of the mission commander"),
948
+ startAt: IsoDateTime.optional().describe("Planned start (ISO-8601)"),
949
+ endAt: IsoDateTime.optional().describe("Planned end (ISO-8601)"),
950
+ tags: zod.z.array(zod.z.string()).optional().describe("Discovery/triage tags")
951
+ }
952
+ },
953
+ async ({ name, codename, objective, classification, commanderId, startAt, endAt, tags }) => {
954
+ try {
955
+ const input = { name };
956
+ if (codename !== void 0) input.codename = codename;
957
+ if (objective !== void 0) input.objective = objective;
958
+ if (classification !== void 0) input.classification = classification;
959
+ if (commanderId !== void 0) input.commanderId = commanderId;
960
+ if (startAt !== void 0) input.startAt = startAt;
961
+ if (endAt !== void 0) input.endAt = endAt;
962
+ if (tags !== void 0) input.tags = tags;
963
+ const data = await ctx.gql.workspace.request(CREATE_MISSION, { input });
964
+ return jsonResult(data.intCreateMission);
965
+ } catch (error) {
966
+ ctx.logger.error("intelwatchtower missions_create failed", { error: String(error) });
967
+ return errorResult(
968
+ `Failed to create mission: ${error instanceof Error ? error.message : String(error)}`
969
+ );
970
+ }
971
+ }
972
+ );
973
+ server.registerTool(
974
+ track(mcpToolName(ctx.productName, "missions_transition")),
975
+ {
976
+ title: "Transition Mission",
977
+ description: "Advance a mission through its lifecycle (PLANNING \u2192 READY \u2192 ACTIVE \u2192 PAUSED/COMPLETED/ABORTED).",
978
+ inputSchema: {
979
+ id: zod.z.string().describe("Mission ID"),
980
+ status: MissionStatusEnum.describe("New mission status")
981
+ }
982
+ },
983
+ async ({ id, status }) => {
984
+ try {
985
+ const data = await ctx.gql.workspace.request(TRANSITION_MISSION, { id, status });
986
+ return jsonResult(data.intTransitionMission);
987
+ } catch (error) {
988
+ ctx.logger.error("intelwatchtower missions_transition failed", { error: String(error) });
989
+ return errorResult(
990
+ `Failed to transition mission: ${error instanceof Error ? error.message : String(error)}`
991
+ );
992
+ }
993
+ }
994
+ );
995
+ }
996
+ function registerEntityTools(server, ctx, track) {
997
+ server.registerTool(
998
+ track(mcpToolName(ctx.productName, "entities_get")),
999
+ {
1000
+ title: "Get Entity",
1001
+ description: "Fetch a single tracked entity by ID, including its indicators and threat alerts.",
1002
+ inputSchema: { id: zod.z.string().describe("Entity ID") }
1003
+ },
1004
+ async ({ id }) => {
1005
+ try {
1006
+ const data = await ctx.gql.workspace.request(GET_ENTITY, { id });
1007
+ if (!data.intEntity) return errorResult(`Entity ${id} not found`);
1008
+ return jsonResult(data.intEntity);
1009
+ } catch (error) {
1010
+ ctx.logger.error("intelwatchtower entities_get failed", { error: String(error) });
1011
+ return errorResult(
1012
+ `Failed to get entity: ${error instanceof Error ? error.message : String(error)}`
1013
+ );
1014
+ }
1015
+ }
1016
+ );
1017
+ server.registerTool(
1018
+ track(mcpToolName(ctx.productName, "entities_list")),
1019
+ {
1020
+ title: "List Entities",
1021
+ description: "List tracked entities in the bound workspace, optionally filtered by type and/or confidence, with pagination.",
1022
+ inputSchema: {
1023
+ type: EntityTypeEnum.optional().describe("Filter by entity type"),
1024
+ confidence: ConfidenceEnum.optional().describe("Filter by analyst confidence"),
1025
+ limit: zod.z.number().int().optional().describe("Page size (default 50)"),
1026
+ offset: zod.z.number().int().optional().describe("Pagination offset (default 0)")
1027
+ }
1028
+ },
1029
+ async ({ type, confidence, limit, offset }) => {
1030
+ try {
1031
+ const data = await ctx.gql.workspace.request(LIST_ENTITIES, {
1032
+ type,
1033
+ confidence,
1034
+ pagination: buildPagination(limit, offset)
1035
+ });
1036
+ return jsonResult(data.intListEntities);
1037
+ } catch (error) {
1038
+ ctx.logger.error("intelwatchtower entities_list failed", { error: String(error) });
1039
+ return errorResult(
1040
+ `Failed to list entities: ${error instanceof Error ? error.message : String(error)}`
1041
+ );
1042
+ }
1043
+ }
1044
+ );
1045
+ server.registerTool(
1046
+ track(mcpToolName(ctx.productName, "entities_create")),
1047
+ {
1048
+ title: "Create Entity",
1049
+ description: "Register a new tracked entity (person, organization, vessel, facility, ...). `name` and `type` are required.",
1050
+ inputSchema: {
1051
+ name: zod.z.string().min(1).describe("Entity display name"),
1052
+ type: EntityTypeEnum.describe("Entity type"),
1053
+ classification: ClassificationEnum.optional().describe(
1054
+ "Security classification (default UNCLASSIFIED)"
1055
+ ),
1056
+ confidence: ConfidenceEnum.optional().describe("Analyst confidence (default LOW)"),
1057
+ description: zod.z.string().optional().describe("Entity description"),
1058
+ aliases: zod.z.array(zod.z.string()).optional().describe("Known aliases"),
1059
+ threatScore: zod.z.number().int().optional().describe("Threat score"),
1060
+ latitude: zod.z.number().optional().describe("Last-known latitude"),
1061
+ longitude: zod.z.number().optional().describe("Last-known longitude"),
1062
+ attributes: JsonObject.optional().describe("Arbitrary structured attributes JSON"),
1063
+ tags: zod.z.array(zod.z.string()).optional().describe("Discovery/triage tags")
1064
+ }
1065
+ },
1066
+ async ({
1067
+ name,
1068
+ type,
1069
+ classification,
1070
+ confidence,
1071
+ description,
1072
+ aliases,
1073
+ threatScore,
1074
+ latitude,
1075
+ longitude,
1076
+ attributes,
1077
+ tags
1078
+ }) => {
1079
+ try {
1080
+ const input = { name, type };
1081
+ if (classification !== void 0) input.classification = classification;
1082
+ if (confidence !== void 0) input.confidence = confidence;
1083
+ if (description !== void 0) input.description = description;
1084
+ if (aliases !== void 0) input.aliases = aliases;
1085
+ if (threatScore !== void 0) input.threatScore = threatScore;
1086
+ if (latitude !== void 0) input.latitude = latitude;
1087
+ if (longitude !== void 0) input.longitude = longitude;
1088
+ if (attributes !== void 0) input.attributes = attributes;
1089
+ if (tags !== void 0) input.tags = tags;
1090
+ const data = await ctx.gql.workspace.request(CREATE_ENTITY, { input });
1091
+ return jsonResult(data.intCreateEntity);
1092
+ } catch (error) {
1093
+ ctx.logger.error("intelwatchtower entities_create failed", { error: String(error) });
1094
+ return errorResult(
1095
+ `Failed to create entity: ${error instanceof Error ? error.message : String(error)}`
1096
+ );
1097
+ }
1098
+ }
1099
+ );
1100
+ server.registerTool(
1101
+ track(mcpToolName(ctx.productName, "entities_update")),
1102
+ {
1103
+ title: "Update Entity",
1104
+ description: "Update a tracked entity. At least one mutable field must be provided.",
1105
+ inputSchema: {
1106
+ id: zod.z.string().describe("Entity ID"),
1107
+ name: zod.z.string().optional().describe("Updated display name"),
1108
+ classification: ClassificationEnum.optional().describe("Updated classification"),
1109
+ confidence: ConfidenceEnum.optional().describe("Updated confidence"),
1110
+ description: zod.z.string().optional().describe("Updated description"),
1111
+ aliases: zod.z.array(zod.z.string()).optional().describe("Updated aliases"),
1112
+ threatScore: zod.z.number().int().optional().describe("Updated threat score"),
1113
+ latitude: zod.z.number().optional().describe("Updated latitude"),
1114
+ longitude: zod.z.number().optional().describe("Updated longitude"),
1115
+ attributes: JsonObject.optional().describe("Updated attributes JSON"),
1116
+ tags: zod.z.array(zod.z.string()).optional().describe("Updated tags")
1117
+ }
1118
+ },
1119
+ async ({
1120
+ id,
1121
+ name,
1122
+ classification,
1123
+ confidence,
1124
+ description,
1125
+ aliases,
1126
+ threatScore,
1127
+ latitude,
1128
+ longitude,
1129
+ attributes,
1130
+ tags
1131
+ }) => {
1132
+ try {
1133
+ const input = {};
1134
+ if (name !== void 0) input.name = name;
1135
+ if (classification !== void 0) input.classification = classification;
1136
+ if (confidence !== void 0) input.confidence = confidence;
1137
+ if (description !== void 0) input.description = description;
1138
+ if (aliases !== void 0) input.aliases = aliases;
1139
+ if (threatScore !== void 0) input.threatScore = threatScore;
1140
+ if (latitude !== void 0) input.latitude = latitude;
1141
+ if (longitude !== void 0) input.longitude = longitude;
1142
+ if (attributes !== void 0) input.attributes = attributes;
1143
+ if (tags !== void 0) input.tags = tags;
1144
+ if (Object.keys(input).length === 0) {
1145
+ return errorResult("No updates specified \u2014 provide at least one mutable entity field");
1146
+ }
1147
+ const data = await ctx.gql.workspace.request(UPDATE_ENTITY, { id, input });
1148
+ return jsonResult(data.intUpdateEntity);
1149
+ } catch (error) {
1150
+ ctx.logger.error("intelwatchtower entities_update failed", { error: String(error) });
1151
+ return errorResult(
1152
+ `Failed to update entity: ${error instanceof Error ? error.message : String(error)}`
1153
+ );
1154
+ }
1155
+ }
1156
+ );
1157
+ }
1158
+ function registerIndicatorTools(server, ctx, track) {
1159
+ server.registerTool(
1160
+ track(mcpToolName(ctx.productName, "indicators_list")),
1161
+ {
1162
+ title: "List Indicators",
1163
+ description: "List indicators (observables), optionally filtered by entity, type, and/or active state.",
1164
+ inputSchema: {
1165
+ entityId: zod.z.string().optional().describe("Filter by associated entity ID"),
1166
+ type: IndicatorTypeEnum.optional().describe("Filter by indicator type"),
1167
+ isActive: zod.z.boolean().optional().describe("Filter by active state")
1168
+ }
1169
+ },
1170
+ async ({ entityId, type, isActive }) => {
1171
+ try {
1172
+ const data = await ctx.gql.workspace.request(LIST_INDICATORS, { entityId, type, isActive });
1173
+ return jsonResult(data.intListIndicators);
1174
+ } catch (error) {
1175
+ ctx.logger.error("intelwatchtower indicators_list failed", { error: String(error) });
1176
+ return errorResult(
1177
+ `Failed to list indicators: ${error instanceof Error ? error.message : String(error)}`
1178
+ );
1179
+ }
1180
+ }
1181
+ );
1182
+ server.registerTool(
1183
+ track(mcpToolName(ctx.productName, "indicators_create")),
1184
+ {
1185
+ title: "Create Indicator",
1186
+ description: "Register a new indicator (observable). `type` and `value` are required; optionally bind it to an entity and a validity window.",
1187
+ inputSchema: {
1188
+ type: IndicatorTypeEnum.describe("Indicator type (IP_ADDRESS, DOMAIN, FILE_HASH, ...)"),
1189
+ value: zod.z.string().min(1).describe("Indicator value"),
1190
+ classification: ClassificationEnum.optional().describe(
1191
+ "Security classification (default UNCLASSIFIED)"
1192
+ ),
1193
+ confidence: ConfidenceEnum.optional().describe("Analyst confidence (default LOW)"),
1194
+ description: zod.z.string().optional().describe("Indicator description"),
1195
+ entityId: zod.z.string().optional().describe("Associated entity ID"),
1196
+ validFrom: IsoDateTime.optional().describe("Validity-window start (ISO-8601)"),
1197
+ validUntil: IsoDateTime.optional().describe("Validity-window end (ISO-8601)")
1198
+ }
1199
+ },
1200
+ async ({
1201
+ type,
1202
+ value,
1203
+ classification,
1204
+ confidence,
1205
+ description,
1206
+ entityId,
1207
+ validFrom,
1208
+ validUntil
1209
+ }) => {
1210
+ try {
1211
+ const input = { type, value };
1212
+ if (classification !== void 0) input.classification = classification;
1213
+ if (confidence !== void 0) input.confidence = confidence;
1214
+ if (description !== void 0) input.description = description;
1215
+ if (entityId !== void 0) input.entityId = entityId;
1216
+ if (validFrom !== void 0) input.validFrom = validFrom;
1217
+ if (validUntil !== void 0) input.validUntil = validUntil;
1218
+ const data = await ctx.gql.workspace.request(CREATE_INDICATOR, { input });
1219
+ return jsonResult(data.intCreateIndicator);
1220
+ } catch (error) {
1221
+ ctx.logger.error("intelwatchtower indicators_create failed", { error: String(error) });
1222
+ return errorResult(
1223
+ `Failed to create indicator: ${error instanceof Error ? error.message : String(error)}`
1224
+ );
1225
+ }
1226
+ }
1227
+ );
1228
+ server.registerTool(
1229
+ track(mcpToolName(ctx.productName, "indicators_deactivate")),
1230
+ {
1231
+ title: "Deactivate Indicator",
1232
+ description: "Deactivate (expire) an indicator so it no longer matches new reporting.",
1233
+ inputSchema: { id: zod.z.string().describe("Indicator ID") }
1234
+ },
1235
+ async ({ id }) => {
1236
+ try {
1237
+ const data = await ctx.gql.workspace.request(DEACTIVATE_INDICATOR, { id });
1238
+ return jsonResult(data.intDeactivateIndicator);
1239
+ } catch (error) {
1240
+ ctx.logger.error("intelwatchtower indicators_deactivate failed", { error: String(error) });
1241
+ return errorResult(
1242
+ `Failed to deactivate indicator: ${error instanceof Error ? error.message : String(error)}`
1243
+ );
1244
+ }
1245
+ }
1246
+ );
1247
+ }
1248
+ function registerAlertTools(server, ctx, track) {
1249
+ server.registerTool(
1250
+ track(mcpToolName(ctx.productName, "alerts_list")),
1251
+ {
1252
+ title: "List Alerts",
1253
+ description: "List threat alerts, optionally filtered by entity, severity, and/or status, with pagination.",
1254
+ inputSchema: {
1255
+ entityId: zod.z.string().optional().describe("Filter by associated entity ID"),
1256
+ severity: AlertSeverityEnum.optional().describe("Filter by severity"),
1257
+ status: AlertStatusEnum.optional().describe("Filter by triage status"),
1258
+ limit: zod.z.number().int().optional().describe("Page size (default 50)"),
1259
+ offset: zod.z.number().int().optional().describe("Pagination offset (default 0)")
1260
+ }
1261
+ },
1262
+ async ({ entityId, severity, status, limit, offset }) => {
1263
+ try {
1264
+ const data = await ctx.gql.workspace.request(LIST_ALERTS, {
1265
+ entityId,
1266
+ severity,
1267
+ status,
1268
+ pagination: buildPagination(limit, offset)
1269
+ });
1270
+ return jsonResult(data.intListAlerts);
1271
+ } catch (error) {
1272
+ ctx.logger.error("intelwatchtower alerts_list failed", { error: String(error) });
1273
+ return errorResult(
1274
+ `Failed to list alerts: ${error instanceof Error ? error.message : String(error)}`
1275
+ );
1276
+ }
1277
+ }
1278
+ );
1279
+ server.registerTool(
1280
+ track(mcpToolName(ctx.productName, "alerts_raise")),
1281
+ {
1282
+ title: "Raise Alert",
1283
+ description: "Raise a new threat alert. `title` is required; optionally bind it to an entity, indicator, and/or mission and set severity.",
1284
+ inputSchema: {
1285
+ title: zod.z.string().min(1).describe("Alert title"),
1286
+ description: zod.z.string().optional().describe("Alert description"),
1287
+ severity: AlertSeverityEnum.optional().describe("Severity (default MEDIUM)"),
1288
+ classification: ClassificationEnum.optional().describe(
1289
+ "Security classification (default UNCLASSIFIED)"
1290
+ ),
1291
+ entityId: zod.z.string().optional().describe("Associated entity ID"),
1292
+ indicatorId: zod.z.string().optional().describe("Triggering indicator ID"),
1293
+ missionId: zod.z.string().optional().describe("Associated mission ID"),
1294
+ assignedToId: zod.z.string().optional().describe("User ID to assign the alert to")
1295
+ }
1296
+ },
1297
+ async ({
1298
+ title,
1299
+ description,
1300
+ severity,
1301
+ classification,
1302
+ entityId,
1303
+ indicatorId,
1304
+ missionId,
1305
+ assignedToId
1306
+ }) => {
1307
+ try {
1308
+ const input = { title };
1309
+ if (description !== void 0) input.description = description;
1310
+ if (severity !== void 0) input.severity = severity;
1311
+ if (classification !== void 0) input.classification = classification;
1312
+ if (entityId !== void 0) input.entityId = entityId;
1313
+ if (indicatorId !== void 0) input.indicatorId = indicatorId;
1314
+ if (missionId !== void 0) input.missionId = missionId;
1315
+ if (assignedToId !== void 0) input.assignedToId = assignedToId;
1316
+ const data = await ctx.gql.workspace.request(RAISE_ALERT, { input });
1317
+ return jsonResult(data.intRaiseAlert);
1318
+ } catch (error) {
1319
+ ctx.logger.error("intelwatchtower alerts_raise failed", { error: String(error) });
1320
+ return errorResult(
1321
+ `Failed to raise alert: ${error instanceof Error ? error.message : String(error)}`
1322
+ );
1323
+ }
1324
+ }
1325
+ );
1326
+ server.registerTool(
1327
+ track(mcpToolName(ctx.productName, "alerts_transition")),
1328
+ {
1329
+ title: "Transition Alert",
1330
+ description: "Triage an alert through its lifecycle (validated transitions: OPEN \u2192 TRIAGED \u2192 ESCALATED/RESOLVED/FALSE_POSITIVE/SUPPRESSED), optionally recording triage notes.",
1331
+ inputSchema: {
1332
+ id: zod.z.string().describe("Alert ID"),
1333
+ status: AlertStatusEnum.describe("New alert status"),
1334
+ triageNotes: zod.z.string().optional().describe("Triage notes to record on the transition")
1335
+ }
1336
+ },
1337
+ async ({ id, status, triageNotes }) => {
1338
+ try {
1339
+ const data = await ctx.gql.workspace.request(TRANSITION_ALERT, { id, status, triageNotes });
1340
+ return jsonResult(data.intTransitionAlert);
1341
+ } catch (error) {
1342
+ ctx.logger.error("intelwatchtower alerts_transition failed", { error: String(error) });
1343
+ return errorResult(
1344
+ `Failed to transition alert: ${error instanceof Error ? error.message : String(error)}`
1345
+ );
1346
+ }
1347
+ }
1348
+ );
1349
+ }
1350
+ function registerCaseTools(server, ctx, track) {
1351
+ server.registerTool(
1352
+ track(mcpToolName(ctx.productName, "cases_get")),
1353
+ {
1354
+ title: "Get Case",
1355
+ description: "Fetch a single investigation case by ID, including its alerts and case entries.",
1356
+ inputSchema: { id: zod.z.string().describe("Case ID") }
1357
+ },
1358
+ async ({ id }) => {
1359
+ try {
1360
+ const data = await ctx.gql.workspace.request(GET_CASE, { id });
1361
+ if (!data.intCase) return errorResult(`Case ${id} not found`);
1362
+ return jsonResult(data.intCase);
1363
+ } catch (error) {
1364
+ ctx.logger.error("intelwatchtower cases_get failed", { error: String(error) });
1365
+ return errorResult(
1366
+ `Failed to get case: ${error instanceof Error ? error.message : String(error)}`
1367
+ );
1368
+ }
1369
+ }
1370
+ );
1371
+ server.registerTool(
1372
+ track(mcpToolName(ctx.productName, "cases_list")),
1373
+ {
1374
+ title: "List Cases",
1375
+ description: "List investigation cases, optionally filtered by mission and/or status, with pagination.",
1376
+ inputSchema: {
1377
+ missionId: zod.z.string().optional().describe("Filter by owning mission ID"),
1378
+ status: CaseStatusEnum.optional().describe("Filter by case status"),
1379
+ limit: zod.z.number().int().optional().describe("Page size (default 50)"),
1380
+ offset: zod.z.number().int().optional().describe("Pagination offset (default 0)")
1381
+ }
1382
+ },
1383
+ async ({ missionId, status, limit, offset }) => {
1384
+ try {
1385
+ const data = await ctx.gql.workspace.request(LIST_CASES, {
1386
+ missionId,
1387
+ status,
1388
+ pagination: buildPagination(limit, offset)
1389
+ });
1390
+ return jsonResult(data.intListCases);
1391
+ } catch (error) {
1392
+ ctx.logger.error("intelwatchtower cases_list failed", { error: String(error) });
1393
+ return errorResult(
1394
+ `Failed to list cases: ${error instanceof Error ? error.message : String(error)}`
1395
+ );
1396
+ }
1397
+ }
1398
+ );
1399
+ server.registerTool(
1400
+ track(mcpToolName(ctx.productName, "cases_create")),
1401
+ {
1402
+ title: "Create Case",
1403
+ description: "Open a new investigation case. `title` is required.",
1404
+ inputSchema: {
1405
+ title: zod.z.string().min(1).describe("Case title"),
1406
+ summary: zod.z.string().optional().describe("Case summary"),
1407
+ reference: zod.z.string().optional().describe("External reference number"),
1408
+ classification: ClassificationEnum.optional().describe(
1409
+ "Security classification (default UNCLASSIFIED)"
1410
+ ),
1411
+ priority: PriorityEnum.optional().describe("Precedence (default ROUTINE)"),
1412
+ missionId: zod.z.string().optional().describe("Owning mission ID"),
1413
+ leadAnalystId: zod.z.string().optional().describe("User ID of the lead analyst"),
1414
+ tags: zod.z.array(zod.z.string()).optional().describe("Discovery/triage tags")
1415
+ }
1416
+ },
1417
+ async ({
1418
+ title,
1419
+ summary,
1420
+ reference,
1421
+ classification,
1422
+ priority,
1423
+ missionId,
1424
+ leadAnalystId,
1425
+ tags
1426
+ }) => {
1427
+ try {
1428
+ const input = { title };
1429
+ if (summary !== void 0) input.summary = summary;
1430
+ if (reference !== void 0) input.reference = reference;
1431
+ if (classification !== void 0) input.classification = classification;
1432
+ if (priority !== void 0) input.priority = priority;
1433
+ if (missionId !== void 0) input.missionId = missionId;
1434
+ if (leadAnalystId !== void 0) input.leadAnalystId = leadAnalystId;
1435
+ if (tags !== void 0) input.tags = tags;
1436
+ const data = await ctx.gql.workspace.request(CREATE_CASE, { input });
1437
+ return jsonResult(data.intCreateCase);
1438
+ } catch (error) {
1439
+ ctx.logger.error("intelwatchtower cases_create failed", { error: String(error) });
1440
+ return errorResult(
1441
+ `Failed to create case: ${error instanceof Error ? error.message : String(error)}`
1442
+ );
1443
+ }
1444
+ }
1445
+ );
1446
+ server.registerTool(
1447
+ track(mcpToolName(ctx.productName, "cases_add_entry")),
1448
+ {
1449
+ title: "Add Case Entry",
1450
+ description: "Append an entry (note, finding, or evidence reference) to a case. `kind` and `body` are required; attach evidence via `fileId` (wspace-files-svc File).",
1451
+ inputSchema: {
1452
+ caseId: zod.z.string().min(1).describe("Case ID"),
1453
+ kind: zod.z.string().min(1).describe('Entry kind, e.g. "note", "finding", "evidence"'),
1454
+ body: zod.z.string().min(1).describe("Entry body text"),
1455
+ fileId: zod.z.string().optional().describe("Evidence attachment File ID (wspace-files-svc)")
1456
+ }
1457
+ },
1458
+ async ({ caseId, kind, body, fileId }) => {
1459
+ try {
1460
+ const input = { caseId, kind, body };
1461
+ if (fileId !== void 0) input.fileId = fileId;
1462
+ const data = await ctx.gql.workspace.request(ADD_CASE_ENTRY, { input });
1463
+ return jsonResult(data.intAddCaseEntry);
1464
+ } catch (error) {
1465
+ ctx.logger.error("intelwatchtower cases_add_entry failed", { error: String(error) });
1466
+ return errorResult(
1467
+ `Failed to add case entry: ${error instanceof Error ? error.message : String(error)}`
1468
+ );
1469
+ }
1470
+ }
1471
+ );
1472
+ server.registerTool(
1473
+ track(mcpToolName(ctx.productName, "cases_close")),
1474
+ {
1475
+ title: "Close Case",
1476
+ description: "Close an investigation case.",
1477
+ inputSchema: { id: zod.z.string().describe("Case ID") }
1478
+ },
1479
+ async ({ id }) => {
1480
+ try {
1481
+ const data = await ctx.gql.workspace.request(CLOSE_CASE, { id });
1482
+ return jsonResult(data.intCloseCase);
1483
+ } catch (error) {
1484
+ ctx.logger.error("intelwatchtower cases_close failed", { error: String(error) });
1485
+ return errorResult(
1486
+ `Failed to close case: ${error instanceof Error ? error.message : String(error)}`
1487
+ );
1488
+ }
1489
+ }
1490
+ );
1491
+ }
1492
+ function registerReportTools(server, ctx, track) {
1493
+ server.registerTool(
1494
+ track(mcpToolName(ctx.productName, "reports_list")),
1495
+ {
1496
+ title: "List Reports",
1497
+ description: "List intelligence reports, optionally filtered by mission, type, and/or status, with pagination.",
1498
+ inputSchema: {
1499
+ missionId: zod.z.string().optional().describe("Filter by owning mission ID"),
1500
+ type: ReportTypeEnum.optional().describe("Filter by report product type"),
1501
+ status: ReportStatusEnum.optional().describe("Filter by report status"),
1502
+ limit: zod.z.number().int().optional().describe("Page size (default 50)"),
1503
+ offset: zod.z.number().int().optional().describe("Pagination offset (default 0)")
1504
+ }
1505
+ },
1506
+ async ({ missionId, type, status, limit, offset }) => {
1507
+ try {
1508
+ const data = await ctx.gql.workspace.request(LIST_REPORTS, {
1509
+ missionId,
1510
+ type,
1511
+ status,
1512
+ pagination: buildPagination(limit, offset)
1513
+ });
1514
+ return jsonResult(data.intListReports);
1515
+ } catch (error) {
1516
+ ctx.logger.error("intelwatchtower reports_list failed", { error: String(error) });
1517
+ return errorResult(
1518
+ `Failed to list reports: ${error instanceof Error ? error.message : String(error)}`
1519
+ );
1520
+ }
1521
+ }
1522
+ );
1523
+ server.registerTool(
1524
+ track(mcpToolName(ctx.productName, "reports_create")),
1525
+ {
1526
+ title: "Create Report",
1527
+ description: "Draft a new intelligence report (SITREP, INTSUM, ASSESSMENT, ...). `title` is required; reference the rendered product via `fileId` (wspace-files-svc File).",
1528
+ inputSchema: {
1529
+ title: zod.z.string().min(1).describe("Report title"),
1530
+ type: ReportTypeEnum.optional().describe("Report product type (default SITREP)"),
1531
+ summary: zod.z.string().optional().describe("Report summary / BLUF"),
1532
+ body: zod.z.string().optional().describe("Report body text"),
1533
+ classification: ClassificationEnum.optional().describe(
1534
+ "Security classification (default UNCLASSIFIED)"
1535
+ ),
1536
+ authorId: zod.z.string().optional().describe("User ID of the report author"),
1537
+ caseId: zod.z.string().optional().describe("Associated case ID"),
1538
+ missionId: zod.z.string().optional().describe("Associated mission ID"),
1539
+ fileId: zod.z.string().optional().describe("Rendered-product File ID (wspace-files-svc)"),
1540
+ tags: zod.z.array(zod.z.string()).optional().describe("Discovery/triage tags")
1541
+ }
1542
+ },
1543
+ async ({
1544
+ title,
1545
+ type,
1546
+ summary,
1547
+ body,
1548
+ classification,
1549
+ authorId,
1550
+ caseId,
1551
+ missionId,
1552
+ fileId,
1553
+ tags
1554
+ }) => {
1555
+ try {
1556
+ const input = { title };
1557
+ if (type !== void 0) input.type = type;
1558
+ if (summary !== void 0) input.summary = summary;
1559
+ if (body !== void 0) input.body = body;
1560
+ if (classification !== void 0) input.classification = classification;
1561
+ if (authorId !== void 0) input.authorId = authorId;
1562
+ if (caseId !== void 0) input.caseId = caseId;
1563
+ if (missionId !== void 0) input.missionId = missionId;
1564
+ if (fileId !== void 0) input.fileId = fileId;
1565
+ if (tags !== void 0) input.tags = tags;
1566
+ const data = await ctx.gql.workspace.request(CREATE_REPORT, { input });
1567
+ return jsonResult(data.intCreateReport);
1568
+ } catch (error) {
1569
+ ctx.logger.error("intelwatchtower reports_create failed", { error: String(error) });
1570
+ return errorResult(
1571
+ `Failed to create report: ${error instanceof Error ? error.message : String(error)}`
1572
+ );
1573
+ }
1574
+ }
1575
+ );
1576
+ server.registerTool(
1577
+ track(mcpToolName(ctx.productName, "reports_release")),
1578
+ {
1579
+ title: "Release Report",
1580
+ description: "Release (publish/disseminate) an intelligence report.",
1581
+ inputSchema: { id: zod.z.string().describe("Report ID") }
1582
+ },
1583
+ async ({ id }) => {
1584
+ try {
1585
+ const data = await ctx.gql.workspace.request(RELEASE_REPORT, { id });
1586
+ return jsonResult(data.intReleaseReport);
1587
+ } catch (error) {
1588
+ ctx.logger.error("intelwatchtower reports_release failed", { error: String(error) });
1589
+ return errorResult(
1590
+ `Failed to release report: ${error instanceof Error ? error.message : String(error)}`
1591
+ );
1592
+ }
1593
+ }
1594
+ );
1595
+ }
1596
+
1597
+ // src/modules/intelwatchtower/tools/health.ts
1598
+ function registerHealthTools(server, ctx, track) {
1599
+ server.registerTool(
1600
+ track(mcpToolName(ctx.productName, "health")),
1601
+ {
1602
+ title: "IntelWatchtower Health Check",
1603
+ description: "Public liveness/identity probe for the IntelWatchtower subgraph (intHealth). Requires no authentication.",
1604
+ inputSchema: {}
1605
+ },
1606
+ async () => {
1607
+ try {
1608
+ const data = await ctx.gql.workspace.request(HEALTH, {});
1609
+ return jsonResult({ ok: true, status: data.intHealth });
1610
+ } catch (error) {
1611
+ ctx.logger.error("intelwatchtower health failed", { error: String(error) });
1612
+ return errorResult(
1613
+ `IntelWatchtower health check failed: ${error instanceof Error ? error.message : String(error)}`
1614
+ );
1615
+ }
1616
+ }
1617
+ );
1618
+ }
1619
+
1620
+ // src/modules/intelwatchtower/resources.ts
1621
+ function registerIntelwatchtowerResources(server, ctx, track) {
1622
+ const schemaUri = track(mcpResourceUri(ctx.productName, "schema"));
1623
+ const sourcesUri = track(mcpResourceUri(ctx.productName, "sources"));
1624
+ const missionsUri = track(mcpResourceUri(ctx.productName, "missions"));
1625
+ const alertsUri = track(mcpResourceUri(ctx.productName, "alerts"));
1626
+ server.registerResource(
1627
+ "intelwatchtower-schema",
1628
+ schemaUri,
1629
+ {
1630
+ title: "IntelWatchtower Domain Schema",
1631
+ description: "Overview of the IntelWatchtower military & intelligence domain \u2014 entities, enums, and the per-entity tool surface.",
1632
+ mimeType: "text/plain"
1633
+ },
1634
+ async () => {
1635
+ ctx.logger.debug(`Resource ${schemaUri} requested`);
1636
+ const schema = `# IntelWatchtower Domain (Overview)
1637
+
1638
+ Unified military & intelligence platform: multi-source collection + all-source
1639
+ fusion powering a real-time common operating picture.
1640
+
1641
+ ## Collection domain
1642
+ - IntSource \u2014 a collection source/sensor (has feeds + tasking orders)
1643
+ - IntFeed \u2014 an ingest feed attached to a source
1644
+ - IntCollectionRequirement \u2014 an intelligence gap to be satisfied (has tasks)
1645
+ - IntCollectionTask \u2014 a tasking order dispatched to a source
1646
+ - IntObservation \u2014 raw collected reporting
1647
+
1648
+ ## Fusion domain
1649
+ - IntMission \u2014 an operation (has cases + reports)
1650
+ - IntEntity \u2014 a tracked entity (has indicators + alerts)
1651
+ - IntIndicator \u2014 an observable / indicator of interest
1652
+ - IntAlert \u2014 a threat alert (triage lifecycle)
1653
+ - IntCase (+IntCaseEntry) \u2014 an investigation case + entries
1654
+ - IntReport \u2014 an intelligence report
1655
+
1656
+ ## Key enums
1657
+ - IntClassification: UNCLASSIFIED, CONFIDENTIAL, SECRET, TOP_SECRET
1658
+ - IntConfidence: LOW, MODERATE, HIGH, CONFIRMED
1659
+ - IntPriority: ROUTINE, PRIORITY, IMMEDIATE, FLASH
1660
+ - IntSourceDiscipline: HUMINT, SIGINT, GEOINT, IMINT, MASINT, OSINT, CYBER
1661
+ - IntSourceStatus: PROVISIONING, ACTIVE, DEGRADED, OFFLINE, RETIRED
1662
+ - IntTaskStatus: PENDING, DISPATCHED, COLLECTING, COMPLETED, CANCELLED, FAILED
1663
+ - IntEntityType: PERSON, ORGANIZATION, LOCATION, FACILITY, VESSEL, AIRCRAFT, VEHICLE, NETWORK_NODE, EVENT
1664
+ - IntIndicatorType: IP_ADDRESS, DOMAIN, URL, EMAIL, FILE_HASH, SIGNATURE, BEHAVIOR, GEO_COORDINATE
1665
+ - IntAlertSeverity: INFO, LOW, MEDIUM, HIGH, CRITICAL
1666
+ - IntAlertStatus: OPEN, TRIAGED, ESCALATED, RESOLVED, FALSE_POSITIVE, SUPPRESSED
1667
+ - IntMissionStatus: PLANNING, READY, ACTIVE, PAUSED, COMPLETED, ABORTED
1668
+ - IntCaseStatus: OPEN, ACTIVE, PENDING_REVIEW, CLOSED, ARCHIVED
1669
+ - IntReportType: SITREP, INTSUM, SPOT_REPORT, ASSESSMENT, WARNING
1670
+ - IntReportStatus: DRAFT, IN_REVIEW, RELEASED, RECALLED, ARCHIVED
1671
+ - IntRequirementStatus: DRAFT, SUBMITTED, APPROVED, TASKED, SATISFIED, CANCELLED
1672
+
1673
+ ## Tool groups
1674
+ sources, feeds, requirements, tasks, observations (collection);
1675
+ missions, entities, indicators, alerts, cases, reports (fusion); plus a public health probe.
1676
+ All run against the WORKSPACE gateway (workspace-scoped) except the public health probe.
1677
+ `;
1678
+ return {
1679
+ contents: [{ uri: schemaUri, text: schema, mimeType: "text/plain" }]
1680
+ };
1681
+ }
1682
+ );
1683
+ server.registerResource(
1684
+ "intelwatchtower-sources",
1685
+ sourcesUri,
1686
+ {
1687
+ title: "IntelWatchtower Source Registry",
1688
+ description: "The first 50 collection sources/sensors in the bound workspace.",
1689
+ mimeType: "application/json"
1690
+ },
1691
+ async () => {
1692
+ ctx.logger.debug(`Resource ${sourcesUri} requested`);
1693
+ try {
1694
+ const data = await ctx.gql.workspace.request(LIST_SOURCES, {
1695
+ pagination: { limit: 50, offset: 0 }
1696
+ });
1697
+ return {
1698
+ contents: [
1699
+ {
1700
+ uri: sourcesUri,
1701
+ text: JSON.stringify(data.intListSources, null, 2),
1702
+ mimeType: "application/json"
1703
+ }
1704
+ ]
1705
+ };
1706
+ } catch (error) {
1707
+ return {
1708
+ contents: [
1709
+ {
1710
+ uri: sourcesUri,
1711
+ text: JSON.stringify({
1712
+ error: error instanceof Error ? error.message : String(error)
1713
+ }),
1714
+ mimeType: "application/json"
1715
+ }
1716
+ ]
1717
+ };
1718
+ }
1719
+ }
1720
+ );
1721
+ server.registerResource(
1722
+ "intelwatchtower-missions",
1723
+ missionsUri,
1724
+ {
1725
+ title: "IntelWatchtower Mission Roster",
1726
+ description: "All missions in the bound workspace.",
1727
+ mimeType: "application/json"
1728
+ },
1729
+ async () => {
1730
+ ctx.logger.debug(`Resource ${missionsUri} requested`);
1731
+ try {
1732
+ const data = await ctx.gql.workspace.request(
1733
+ LIST_MISSIONS,
1734
+ {}
1735
+ );
1736
+ return {
1737
+ contents: [
1738
+ {
1739
+ uri: missionsUri,
1740
+ text: JSON.stringify(data.intListMissions, null, 2),
1741
+ mimeType: "application/json"
1742
+ }
1743
+ ]
1744
+ };
1745
+ } catch (error) {
1746
+ return {
1747
+ contents: [
1748
+ {
1749
+ uri: missionsUri,
1750
+ text: JSON.stringify({
1751
+ error: error instanceof Error ? error.message : String(error)
1752
+ }),
1753
+ mimeType: "application/json"
1754
+ }
1755
+ ]
1756
+ };
1757
+ }
1758
+ }
1759
+ );
1760
+ server.registerResource(
1761
+ "intelwatchtower-alerts",
1762
+ alertsUri,
1763
+ {
1764
+ title: "IntelWatchtower Open Alerts",
1765
+ description: "The first 50 OPEN threat alerts in the bound workspace.",
1766
+ mimeType: "application/json"
1767
+ },
1768
+ async () => {
1769
+ ctx.logger.debug(`Resource ${alertsUri} requested`);
1770
+ try {
1771
+ const data = await ctx.gql.workspace.request(LIST_ALERTS, {
1772
+ status: "OPEN",
1773
+ pagination: { limit: 50, offset: 0 }
1774
+ });
1775
+ return {
1776
+ contents: [
1777
+ {
1778
+ uri: alertsUri,
1779
+ text: JSON.stringify(data.intListAlerts, null, 2),
1780
+ mimeType: "application/json"
1781
+ }
1782
+ ]
1783
+ };
1784
+ } catch (error) {
1785
+ return {
1786
+ contents: [
1787
+ {
1788
+ uri: alertsUri,
1789
+ text: JSON.stringify({
1790
+ error: error instanceof Error ? error.message : String(error)
1791
+ }),
1792
+ mimeType: "application/json"
1793
+ }
1794
+ ]
1795
+ };
1796
+ }
1797
+ }
1798
+ );
1799
+ }
1800
+ function registerIntelwatchtowerPrompts(server, ctx, track) {
1801
+ const p = ctx.productName;
1802
+ const collectionName = track(mcpPromptName(p, "collection-setup"));
1803
+ const triageName = track(mcpPromptName(p, "fusion-triage"));
1804
+ server.registerPrompt(
1805
+ collectionName,
1806
+ {
1807
+ title: "Collection Setup",
1808
+ description: "Guide for standing up a collection pipeline end to end: register a source, raise a requirement, dispatch a tasking order, and record the resulting observation.",
1809
+ argsSchema: {
1810
+ discipline: zod.z.string().optional().describe("Collection discipline (HUMINT, SIGINT, ...)"),
1811
+ missionId: zod.z.string().optional().describe("Mission to bind the requirement to")
1812
+ }
1813
+ },
1814
+ ({ discipline, missionId }) => {
1815
+ ctx.logger.debug(`Prompt ${collectionName} called`, { discipline, missionId });
1816
+ const disciplineNote = discipline ? `Use discipline ${discipline}.` : "Help the user pick an IntSourceDiscipline.";
1817
+ const missionNote = missionId ? `Bind the requirement to mission "${missionId}".` : `Optionally create or pick a mission first with ${p}_missions_create / ${p}_missions_list.`;
1818
+ return {
1819
+ messages: [
1820
+ {
1821
+ role: "user",
1822
+ content: {
1823
+ type: "text",
1824
+ text: `Help me stand up an IntelWatchtower collection pipeline.
1825
+
1826
+ 1. **Register Source**: Use ${p}_sources_create. ${disciplineNote} Set a name, classification, region, and reliability.
1827
+ 2. **(Optional) Attach Feed**: Use ${p}_feeds_create to wire an ingest feed (endpoint + format) to the source.
1828
+ 3. **Raise Requirement**: Use ${p}_requirements_create. ${missionNote} Set a title, priority, and dueDate.
1829
+ 4. **Dispatch Tasking**: Use ${p}_tasks_create with the source and requirement IDs and a collection window.
1830
+ 5. **Advance Tasking**: Use ${p}_tasks_transition to move the task PENDING \u2192 DISPATCHED \u2192 COLLECTING \u2192 COMPLETED.
1831
+ 6. **Record Observation**: Use ${p}_observations_record with the source/task IDs, a summary, and observedAt.
1832
+
1833
+ Show results at each step and confirm before dispatching tasking.`
1834
+ }
1835
+ }
1836
+ ]
1837
+ };
1838
+ }
1839
+ );
1840
+ server.registerPrompt(
1841
+ triageName,
1842
+ {
1843
+ title: "Fusion & Alert Triage",
1844
+ description: "All-source fusion workflow: review tracked entities and indicators, triage open threat alerts, open an investigation case, and disseminate a report.",
1845
+ argsSchema: {
1846
+ entityId: zod.z.string().optional().describe("Entity to focus the triage on")
1847
+ }
1848
+ },
1849
+ ({ entityId }) => {
1850
+ ctx.logger.debug(`Prompt ${triageName} called`, { entityId });
1851
+ const entityNote = entityId ? `Focus on entity "${entityId}" (use ${p}_entities_get for its indicators + alerts).` : `First list entities with ${p}_entities_list and pick one to focus on.`;
1852
+ return {
1853
+ messages: [
1854
+ {
1855
+ role: "user",
1856
+ content: {
1857
+ type: "text",
1858
+ text: `Run IntelWatchtower all-source fusion + alert triage. ${entityNote}
1859
+
1860
+ 1. **Entities & Indicators**: Use ${p}_entities_list and ${p}_indicators_list to review tracked entities and their observables.
1861
+ 2. **Open Alerts**: Use ${p}_alerts_list filtered by status=OPEN (and severity) to find what needs triage.
1862
+ 3. **Triage**: For each alert use ${p}_alerts_transition (OPEN \u2192 TRIAGED \u2192 ESCALATED/RESOLVED/FALSE_POSITIVE), recording triageNotes.
1863
+ 4. **Open a Case**: For escalations, use ${p}_cases_create, then ${p}_cases_add_entry to log findings/evidence.
1864
+ 5. **Report**: Use ${p}_reports_create to draft an INTSUM/ASSESSMENT, then ${p}_reports_release to disseminate.
1865
+
1866
+ Summarize what needs attention after each step.`
1867
+ }
1868
+ }
1869
+ ]
1870
+ };
1871
+ }
1872
+ );
1873
+ }
1874
+
1875
+ // src/modules/intelwatchtower/index.ts
1876
+ var intelwatchtowerModule = {
1877
+ id: "intelwatchtower",
1878
+ version: "0.0.1",
1879
+ displayName: "IntelWatchtower",
1880
+ dependsOn: ["auth"],
1881
+ capabilities: { tools: {}, resources: {}, prompts: {} },
1882
+ register(server, ctx) {
1883
+ const tools = [];
1884
+ const resources = [];
1885
+ const prompts = [];
1886
+ const trackTool = (n) => {
1887
+ tools.push(n);
1888
+ return n;
1889
+ };
1890
+ const trackResource = (uri) => {
1891
+ resources.push(uri);
1892
+ return uri;
1893
+ };
1894
+ const trackPrompt = (n) => {
1895
+ prompts.push(n);
1896
+ return n;
1897
+ };
1898
+ registerSourceTools(server, ctx, trackTool);
1899
+ registerFeedTools(server, ctx, trackTool);
1900
+ registerRequirementTools(server, ctx, trackTool);
1901
+ registerTaskTools(server, ctx, trackTool);
1902
+ registerObservationTools(server, ctx, trackTool);
1903
+ registerMissionTools(server, ctx, trackTool);
1904
+ registerEntityTools(server, ctx, trackTool);
1905
+ registerIndicatorTools(server, ctx, trackTool);
1906
+ registerAlertTools(server, ctx, trackTool);
1907
+ registerCaseTools(server, ctx, trackTool);
1908
+ registerReportTools(server, ctx, trackTool);
1909
+ registerHealthTools(server, ctx, trackTool);
1910
+ registerIntelwatchtowerResources(server, ctx, trackResource);
1911
+ registerIntelwatchtowerPrompts(server, ctx, trackPrompt);
1912
+ return { tools, resources, prompts };
1913
+ }
1914
+ };
1915
+ var intelwatchtower_default = intelwatchtowerModule;
1916
+
1917
+ module.exports = intelwatchtower_default;
1918
+ //# sourceMappingURL=index.cjs.map
1919
+ //# sourceMappingURL=index.cjs.map