@imboard.ai/mcp-server 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -88
- package/dist/index.cjs +350 -73
- package/package.json +20 -19
- package/src/api-client/imboardApiClient.ts +61 -14
- package/src/server.ts +9 -1
- package/src/tools/dashboards.tools.ts +21 -9
- package/src/tools/documents.tools.ts +24 -15
- package/src/tools/kg-advisory.tools.ts +110 -0
- package/src/tools/knowledge-graph.tools.ts +82 -0
- package/src/tools/meetings.tools.ts +73 -41
- package/src/tools/persona-dossiers.tools.ts +27 -0
- package/src/tools/reports.tools.ts +84 -43
- package/src/tools/rogue-kpis.tools.ts +60 -0
- package/src/tools/user.tools.ts +9 -6
package/dist/index.cjs
CHANGED
|
@@ -139,7 +139,7 @@ var ImboardApiNetworkError = class extends Error {
|
|
|
139
139
|
};
|
|
140
140
|
|
|
141
141
|
// src/api-client/imboardApiClient.ts
|
|
142
|
-
var DEFAULT_TIMEOUT_MS =
|
|
142
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
143
143
|
var MAX_RETRIES = 2;
|
|
144
144
|
var RETRY_BASE_MS = 500;
|
|
145
145
|
var ImboardApiClient = class {
|
|
@@ -157,6 +157,16 @@ var ImboardApiClient = class {
|
|
|
157
157
|
async getCollection(path, params) {
|
|
158
158
|
return this.requestCollection("GET", path, params);
|
|
159
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* GET a legacy non-enveloped endpoint and return the parsed body as-is,
|
|
162
|
+
* with no `{ data }` unwrapping. `get()` now also tolerates bare bodies, so
|
|
163
|
+
* this is mostly for callers that want the raw shape without the
|
|
164
|
+
* `{ data, users, requestId }` wrapper. Still goes through timeout + GET-retry.
|
|
165
|
+
*/
|
|
166
|
+
async getRaw(path, params) {
|
|
167
|
+
const response = await this.executeWithRetry("GET", path, void 0, params);
|
|
168
|
+
return await response.json();
|
|
169
|
+
}
|
|
160
170
|
async post(path, body) {
|
|
161
171
|
return this.request("POST", path, body);
|
|
162
172
|
}
|
|
@@ -173,17 +183,19 @@ var ImboardApiClient = class {
|
|
|
173
183
|
const response = await this.executeWithRetry(method, path, body, params);
|
|
174
184
|
const requestId = response.headers.get("x-request-id");
|
|
175
185
|
const json = await response.json();
|
|
176
|
-
if (
|
|
186
|
+
if (json === null || typeof json !== "object") {
|
|
177
187
|
throw new ImboardApiError({
|
|
178
188
|
code: "INTERNAL_ERROR",
|
|
179
|
-
message:
|
|
189
|
+
message: "Response body is not a JSON object",
|
|
180
190
|
status: response.status,
|
|
181
191
|
requestId,
|
|
182
192
|
details: null
|
|
183
193
|
});
|
|
184
194
|
}
|
|
195
|
+
const hasEnvelope = "data" in json;
|
|
185
196
|
return {
|
|
186
|
-
data: json.data,
|
|
197
|
+
data: hasEnvelope ? json.data : json,
|
|
198
|
+
users: "users" in json ? json.users : void 0,
|
|
187
199
|
requestId
|
|
188
200
|
};
|
|
189
201
|
}
|
|
@@ -203,6 +215,7 @@ var ImboardApiClient = class {
|
|
|
203
215
|
return {
|
|
204
216
|
data: json.data,
|
|
205
217
|
meta: json.meta,
|
|
218
|
+
users: "users" in json ? json.users : void 0,
|
|
206
219
|
requestId
|
|
207
220
|
};
|
|
208
221
|
}
|
|
@@ -214,7 +227,9 @@ var ImboardApiClient = class {
|
|
|
214
227
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
215
228
|
if (attempt > 0) {
|
|
216
229
|
const delayMs = RETRY_BASE_MS * Math.pow(2, attempt - 1);
|
|
217
|
-
logger.info(`Retrying ${method} ${path} (attempt ${attempt + 1}/${maxAttempts})`, {
|
|
230
|
+
logger.info(`Retrying ${method} ${path} (attempt ${attempt + 1}/${maxAttempts})`, {
|
|
231
|
+
delayMs
|
|
232
|
+
});
|
|
218
233
|
await sleep(delayMs);
|
|
219
234
|
}
|
|
220
235
|
try {
|
|
@@ -232,7 +247,9 @@ var ImboardApiClient = class {
|
|
|
232
247
|
details: errorBody?.details ?? null
|
|
233
248
|
});
|
|
234
249
|
if (isIdempotent && response.status >= 500 && attempt < maxAttempts - 1) {
|
|
235
|
-
logger.warn(`Server error ${response.status} on ${method} ${path}, will retry`, {
|
|
250
|
+
logger.warn(`Server error ${response.status} on ${method} ${path}, will retry`, {
|
|
251
|
+
requestId
|
|
252
|
+
});
|
|
236
253
|
lastError = apiError;
|
|
237
254
|
continue;
|
|
238
255
|
}
|
|
@@ -259,8 +276,8 @@ var ImboardApiClient = class {
|
|
|
259
276
|
const controller = new AbortController();
|
|
260
277
|
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
261
278
|
const headers = {
|
|
262
|
-
|
|
263
|
-
|
|
279
|
+
Authorization: `Bearer ${this.token}`,
|
|
280
|
+
Accept: "application/json"
|
|
264
281
|
};
|
|
265
282
|
if (body !== void 0) {
|
|
266
283
|
headers["Content-Type"] = "application/json";
|
|
@@ -594,7 +611,7 @@ var import_zod3 = require("zod");
|
|
|
594
611
|
var registerMeetingTools = (server, client) => {
|
|
595
612
|
server.tool(
|
|
596
613
|
"list_board_meetings",
|
|
597
|
-
"Lists meetings for a board. Supports filtering by status and date range, and sorting by start time.",
|
|
614
|
+
"Lists meetings for a board. Supports filtering by status and date range, and sorting by start time. Includes a top-level `users` map resolving any userId references in the response (e.g. createdByUserId) to name + positions.",
|
|
598
615
|
{
|
|
599
616
|
boardId: boardIdParam,
|
|
600
617
|
...paginationParams,
|
|
@@ -606,11 +623,9 @@ var registerMeetingTools = (server, client) => {
|
|
|
606
623
|
async ({ boardId, ...rest }) => {
|
|
607
624
|
try {
|
|
608
625
|
const params = buildQueryParams(rest, ["status", "startAfter", "startBefore"]);
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
);
|
|
613
|
-
return formatResult({ data: result.data, meta: result.meta });
|
|
626
|
+
params.include = "users";
|
|
627
|
+
const result = await client.getCollection(`/api/boards/${boardId}/meetings`, params);
|
|
628
|
+
return formatResult({ data: result.data, meta: result.meta, users: result.users });
|
|
614
629
|
} catch (error) {
|
|
615
630
|
return handleToolError(error);
|
|
616
631
|
}
|
|
@@ -618,17 +633,17 @@ var registerMeetingTools = (server, client) => {
|
|
|
618
633
|
);
|
|
619
634
|
server.tool(
|
|
620
635
|
"get_meeting",
|
|
621
|
-
"Returns details for a specific meeting including title, status, location, and scheduled time.",
|
|
636
|
+
"Returns details for a specific meeting including title, status, location, and scheduled time. Includes a top-level `users` map resolving any userId references in the response.",
|
|
622
637
|
{
|
|
623
638
|
boardId: boardIdParam,
|
|
624
639
|
meetingId: resourceIdParam.describe("The meeting ID")
|
|
625
640
|
},
|
|
626
641
|
async ({ boardId, meetingId }) => {
|
|
627
642
|
try {
|
|
628
|
-
const result = await client.get(
|
|
629
|
-
|
|
630
|
-
);
|
|
631
|
-
return formatResult({ data: result.data });
|
|
643
|
+
const result = await client.get(`/api/boards/${boardId}/meetings/${meetingId}`, {
|
|
644
|
+
include: "users"
|
|
645
|
+
});
|
|
646
|
+
return formatResult({ data: result.data, users: result.users });
|
|
632
647
|
} catch (error) {
|
|
633
648
|
return handleToolError(error);
|
|
634
649
|
}
|
|
@@ -647,7 +662,16 @@ var registerMeetingTools = (server, client) => {
|
|
|
647
662
|
location: import_zod3.z.string().optional().describe("Physical location (max 255 characters)"),
|
|
648
663
|
virtualMeetingUrl: import_zod3.z.string().optional().describe("Virtual meeting URL (max 255 characters)")
|
|
649
664
|
},
|
|
650
|
-
async ({
|
|
665
|
+
async ({
|
|
666
|
+
boardId,
|
|
667
|
+
title,
|
|
668
|
+
status,
|
|
669
|
+
locationType,
|
|
670
|
+
startTime,
|
|
671
|
+
endTime,
|
|
672
|
+
location,
|
|
673
|
+
virtualMeetingUrl
|
|
674
|
+
}) => {
|
|
651
675
|
try {
|
|
652
676
|
const body = {
|
|
653
677
|
title,
|
|
@@ -658,10 +682,7 @@ var registerMeetingTools = (server, client) => {
|
|
|
658
682
|
};
|
|
659
683
|
if (location !== void 0) body.location = location;
|
|
660
684
|
if (virtualMeetingUrl !== void 0) body.virtualMeetingUrl = virtualMeetingUrl;
|
|
661
|
-
const result = await client.post(
|
|
662
|
-
`/api/boards/${boardId}/meetings`,
|
|
663
|
-
body
|
|
664
|
-
);
|
|
685
|
+
const result = await client.post(`/api/boards/${boardId}/meetings`, body);
|
|
665
686
|
return formatResult({ data: result.data });
|
|
666
687
|
} catch (error) {
|
|
667
688
|
return handleToolError(error);
|
|
@@ -682,7 +703,17 @@ var registerMeetingTools = (server, client) => {
|
|
|
682
703
|
startTime: import_zod3.z.string().optional().describe("Meeting start time as ISO-8601 date string"),
|
|
683
704
|
endTime: import_zod3.z.string().optional().describe("Meeting end time as ISO-8601 date string")
|
|
684
705
|
},
|
|
685
|
-
async ({
|
|
706
|
+
async ({
|
|
707
|
+
boardId,
|
|
708
|
+
meetingId,
|
|
709
|
+
title,
|
|
710
|
+
status,
|
|
711
|
+
locationType,
|
|
712
|
+
location,
|
|
713
|
+
virtualMeetingUrl,
|
|
714
|
+
startTime,
|
|
715
|
+
endTime
|
|
716
|
+
}) => {
|
|
686
717
|
try {
|
|
687
718
|
const body = {};
|
|
688
719
|
if (title !== void 0) body.title = title;
|
|
@@ -692,10 +723,7 @@ var registerMeetingTools = (server, client) => {
|
|
|
692
723
|
if (virtualMeetingUrl !== void 0) body.virtualMeetingUrl = virtualMeetingUrl;
|
|
693
724
|
if (startTime !== void 0) body.startTime = startTime;
|
|
694
725
|
if (endTime !== void 0) body.endTime = endTime;
|
|
695
|
-
const result = await client.patch(
|
|
696
|
-
`/api/boards/${boardId}/meetings/${meetingId}`,
|
|
697
|
-
body
|
|
698
|
-
);
|
|
726
|
+
const result = await client.patch(`/api/boards/${boardId}/meetings/${meetingId}`, body);
|
|
699
727
|
return formatResult({ data: result.data });
|
|
700
728
|
} catch (error) {
|
|
701
729
|
return handleToolError(error);
|
|
@@ -711,9 +739,7 @@ var registerMeetingTools = (server, client) => {
|
|
|
711
739
|
},
|
|
712
740
|
async ({ boardId, meetingId }) => {
|
|
713
741
|
try {
|
|
714
|
-
const result = await client.delete(
|
|
715
|
-
`/api/meetings/${boardId}/${meetingId}/`
|
|
716
|
-
);
|
|
742
|
+
const result = await client.delete(`/api/meetings/${boardId}/${meetingId}/`);
|
|
717
743
|
return formatResult({ data: result.data });
|
|
718
744
|
} catch (error) {
|
|
719
745
|
return handleToolError(error);
|
|
@@ -730,10 +756,9 @@ var registerMeetingTools = (server, client) => {
|
|
|
730
756
|
},
|
|
731
757
|
async ({ boardId, meetingId, meetingStatus }) => {
|
|
732
758
|
try {
|
|
733
|
-
const result = await client.put(
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
);
|
|
759
|
+
const result = await client.put(`/api/meetings/${boardId}/${meetingId}/status`, {
|
|
760
|
+
meetingStatus
|
|
761
|
+
});
|
|
737
762
|
return formatResult({ data: result.data });
|
|
738
763
|
} catch (error) {
|
|
739
764
|
return handleToolError(error);
|
|
@@ -747,7 +772,7 @@ var import_zod4 = require("zod");
|
|
|
747
772
|
var registerDocumentTools = (server, client) => {
|
|
748
773
|
server.tool(
|
|
749
774
|
"list_board_documents",
|
|
750
|
-
"Lists document metadata for a board. Supports filtering by meeting or document type. Does not provide file download in V1.",
|
|
775
|
+
"Lists document metadata for a board. Supports filtering by meeting or document type. Does not provide file download in V1. Includes a top-level `users` map resolving any userId references in the response (e.g. createdByUserId).",
|
|
751
776
|
{
|
|
752
777
|
boardId: boardIdParam,
|
|
753
778
|
...paginationParams,
|
|
@@ -757,11 +782,9 @@ var registerDocumentTools = (server, client) => {
|
|
|
757
782
|
async ({ boardId, ...rest }) => {
|
|
758
783
|
try {
|
|
759
784
|
const params = buildQueryParams(rest, ["meetingId", "documentType"]);
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
);
|
|
764
|
-
return formatResult({ data: result.data, meta: result.meta });
|
|
785
|
+
params.include = "users";
|
|
786
|
+
const result = await client.getCollection(`/api/boards/${boardId}/documents`, params);
|
|
787
|
+
return formatResult({ data: result.data, meta: result.meta, users: result.users });
|
|
765
788
|
} catch (error) {
|
|
766
789
|
return handleToolError(error);
|
|
767
790
|
}
|
|
@@ -769,17 +792,17 @@ var registerDocumentTools = (server, client) => {
|
|
|
769
792
|
);
|
|
770
793
|
server.tool(
|
|
771
794
|
"get_document",
|
|
772
|
-
"Returns metadata for a specific document including title, type, and associated meeting. Does not provide file download in V1.",
|
|
795
|
+
"Returns metadata for a specific document including title, type, and associated meeting. Does not provide file download in V1. Includes a top-level `users` map resolving any userId references in the response.",
|
|
773
796
|
{
|
|
774
797
|
boardId: boardIdParam,
|
|
775
798
|
documentId: resourceIdParam.describe("The document ID")
|
|
776
799
|
},
|
|
777
800
|
async ({ boardId, documentId }) => {
|
|
778
801
|
try {
|
|
779
|
-
const result = await client.get(
|
|
780
|
-
|
|
781
|
-
);
|
|
782
|
-
return formatResult({ data: result.data });
|
|
802
|
+
const result = await client.get(`/api/boards/${boardId}/documents/${documentId}`, {
|
|
803
|
+
include: "users"
|
|
804
|
+
});
|
|
805
|
+
return formatResult({ data: result.data, users: result.users });
|
|
783
806
|
} catch (error) {
|
|
784
807
|
return handleToolError(error);
|
|
785
808
|
}
|
|
@@ -898,7 +921,7 @@ var import_zod6 = require("zod");
|
|
|
898
921
|
var registerReportTools = (server, client) => {
|
|
899
922
|
server.tool(
|
|
900
923
|
"list_board_reports",
|
|
901
|
-
"Lists reports for a board. Supports filtering by status.",
|
|
924
|
+
"Lists reports for a board. Supports filtering by status. Includes a top-level `users` map resolving any userId references in the response (e.g. createdByUserId).",
|
|
902
925
|
{
|
|
903
926
|
boardId: boardIdParam,
|
|
904
927
|
...paginationParams,
|
|
@@ -907,11 +930,9 @@ var registerReportTools = (server, client) => {
|
|
|
907
930
|
async ({ boardId, ...rest }) => {
|
|
908
931
|
try {
|
|
909
932
|
const params = buildQueryParams(rest, ["status"]);
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
);
|
|
914
|
-
return formatResult({ data: result.data, meta: result.meta });
|
|
933
|
+
params.include = "users";
|
|
934
|
+
const result = await client.getCollection(`/api/boards/${boardId}/reports`, params);
|
|
935
|
+
return formatResult({ data: result.data, meta: result.meta, users: result.users });
|
|
915
936
|
} catch (error) {
|
|
916
937
|
return handleToolError(error);
|
|
917
938
|
}
|
|
@@ -919,16 +940,32 @@ var registerReportTools = (server, client) => {
|
|
|
919
940
|
);
|
|
920
941
|
server.tool(
|
|
921
942
|
"get_report",
|
|
922
|
-
"Returns details for a specific board report including title, status, and publication date.",
|
|
943
|
+
"Returns details for a specific board report including title, status, and publication date. Includes a top-level `users` map resolving any userId references in the response.",
|
|
923
944
|
{
|
|
924
945
|
boardId: boardIdParam,
|
|
925
946
|
reportId: resourceIdParam.describe("The report ID")
|
|
926
947
|
},
|
|
927
948
|
async ({ boardId, reportId }) => {
|
|
928
949
|
try {
|
|
929
|
-
const result = await client.get(
|
|
930
|
-
|
|
931
|
-
);
|
|
950
|
+
const result = await client.get(`/api/boards/${boardId}/reports/${reportId}`, {
|
|
951
|
+
include: "users"
|
|
952
|
+
});
|
|
953
|
+
return formatResult({ data: result.data, users: result.users });
|
|
954
|
+
} catch (error) {
|
|
955
|
+
return handleToolError(error);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
);
|
|
959
|
+
server.tool(
|
|
960
|
+
"get_report_full",
|
|
961
|
+
"Returns the ENTIRE board pack in one call: report metadata plus every dashboard\u2019s latest normalized KPI content (all types \u2014 cash, sales, customers, pipeline, fundraising, HR, product, and custom narrative) and deterministic data-quality flags. Prefer this over fetching dashboards one by one \u2014 it avoids a slow multi-call fan-out.",
|
|
962
|
+
{
|
|
963
|
+
boardId: boardIdParam,
|
|
964
|
+
reportId: resourceIdParam.describe("The report ID")
|
|
965
|
+
},
|
|
966
|
+
async ({ boardId, reportId }) => {
|
|
967
|
+
try {
|
|
968
|
+
const result = await client.get(`/api/boards/${boardId}/reports/${reportId}/full`);
|
|
932
969
|
return formatResult({ data: result.data });
|
|
933
970
|
} catch (error) {
|
|
934
971
|
return handleToolError(error);
|
|
@@ -973,7 +1010,16 @@ var registerReportTools = (server, client) => {
|
|
|
973
1010
|
periodStart: import_zod6.z.string().optional().describe("Period start date (YYYY-MM-DD)"),
|
|
974
1011
|
periodEnd: import_zod6.z.string().optional().describe("Period end date (YYYY-MM-DD)")
|
|
975
1012
|
},
|
|
976
|
-
async ({
|
|
1013
|
+
async ({
|
|
1014
|
+
boardId,
|
|
1015
|
+
reportId,
|
|
1016
|
+
name,
|
|
1017
|
+
description,
|
|
1018
|
+
status,
|
|
1019
|
+
meetingIds,
|
|
1020
|
+
periodStart,
|
|
1021
|
+
periodEnd
|
|
1022
|
+
}) => {
|
|
977
1023
|
try {
|
|
978
1024
|
const body = {};
|
|
979
1025
|
if (name !== void 0) body.name = name;
|
|
@@ -1178,10 +1224,10 @@ var registerReportTools = (server, client) => {
|
|
|
1178
1224
|
},
|
|
1179
1225
|
async ({ boardId, reportId, message, recipientId }) => {
|
|
1180
1226
|
try {
|
|
1181
|
-
const result = await client.post(
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
);
|
|
1227
|
+
const result = await client.post(`/api/reports/${boardId}/${reportId}/board-feedback`, {
|
|
1228
|
+
message,
|
|
1229
|
+
recipientId
|
|
1230
|
+
});
|
|
1185
1231
|
return formatResult({ data: result.data });
|
|
1186
1232
|
} catch (error) {
|
|
1187
1233
|
return handleToolError(error);
|
|
@@ -1293,20 +1339,23 @@ var registerReportTools = (server, client) => {
|
|
|
1293
1339
|
var registerDashboardTools = (server, client) => {
|
|
1294
1340
|
server.tool(
|
|
1295
1341
|
"list_report_dashboards",
|
|
1296
|
-
"Lists dashboards under a specific report. Dashboards are nested under reports in imboard's domain model.",
|
|
1342
|
+
"Lists dashboards under a specific report. Dashboards are nested under reports in imboard's domain model. Includes a top-level `users` map resolving any userId references in the response (e.g. createdByUserId).",
|
|
1297
1343
|
{
|
|
1298
1344
|
boardId: boardIdParam,
|
|
1299
|
-
reportId: resourceIdParam.describe(
|
|
1345
|
+
reportId: resourceIdParam.describe(
|
|
1346
|
+
"The report ID (required \u2014 dashboards are nested under reports)"
|
|
1347
|
+
),
|
|
1300
1348
|
...paginationParams
|
|
1301
1349
|
},
|
|
1302
1350
|
async ({ boardId, reportId, ...rest }) => {
|
|
1303
1351
|
try {
|
|
1304
1352
|
const params = buildQueryParams(rest, []);
|
|
1353
|
+
params.include = "users";
|
|
1305
1354
|
const result = await client.getCollection(
|
|
1306
1355
|
`/api/boards/${boardId}/reports/${reportId}/dashboards`,
|
|
1307
1356
|
params
|
|
1308
1357
|
);
|
|
1309
|
-
return formatResult({ data: result.data, meta: result.meta });
|
|
1358
|
+
return formatResult({ data: result.data, meta: result.meta, users: result.users });
|
|
1310
1359
|
} catch (error) {
|
|
1311
1360
|
return handleToolError(error);
|
|
1312
1361
|
}
|
|
@@ -1314,7 +1363,7 @@ var registerDashboardTools = (server, client) => {
|
|
|
1314
1363
|
);
|
|
1315
1364
|
server.tool(
|
|
1316
1365
|
"get_dashboard",
|
|
1317
|
-
"Returns details for a specific dashboard including type, title, and associated report.",
|
|
1366
|
+
"Returns details for a specific dashboard including type, title, and associated report. Includes a top-level `users` map resolving any userId references in the response.",
|
|
1318
1367
|
{
|
|
1319
1368
|
boardId: boardIdParam,
|
|
1320
1369
|
reportId: resourceIdParam.describe("The report ID"),
|
|
@@ -1323,9 +1372,10 @@ var registerDashboardTools = (server, client) => {
|
|
|
1323
1372
|
async ({ boardId, reportId, dashboardId }) => {
|
|
1324
1373
|
try {
|
|
1325
1374
|
const result = await client.get(
|
|
1326
|
-
`/api/boards/${boardId}/reports/${reportId}/dashboards/${dashboardId}
|
|
1375
|
+
`/api/boards/${boardId}/reports/${reportId}/dashboards/${dashboardId}`,
|
|
1376
|
+
{ include: "users" }
|
|
1327
1377
|
);
|
|
1328
|
-
return formatResult({ data: result.data });
|
|
1378
|
+
return formatResult({ data: result.data, users: result.users });
|
|
1329
1379
|
} catch (error) {
|
|
1330
1380
|
return handleToolError(error);
|
|
1331
1381
|
}
|
|
@@ -1621,8 +1671,8 @@ var registerUserTools = (server, client) => {
|
|
|
1621
1671
|
{},
|
|
1622
1672
|
async () => {
|
|
1623
1673
|
try {
|
|
1624
|
-
const
|
|
1625
|
-
return formatResult({ data
|
|
1674
|
+
const data = await client.getRaw("/api/user/allboards");
|
|
1675
|
+
return formatResult({ data });
|
|
1626
1676
|
} catch (error) {
|
|
1627
1677
|
return handleToolError(error);
|
|
1628
1678
|
}
|
|
@@ -1634,8 +1684,8 @@ var registerUserTools = (server, client) => {
|
|
|
1634
1684
|
{},
|
|
1635
1685
|
async () => {
|
|
1636
1686
|
try {
|
|
1637
|
-
const
|
|
1638
|
-
return formatResult({ data
|
|
1687
|
+
const data = await client.getRaw("/api/user/storage");
|
|
1688
|
+
return formatResult({ data });
|
|
1639
1689
|
} catch (error) {
|
|
1640
1690
|
return handleToolError(error);
|
|
1641
1691
|
}
|
|
@@ -1731,6 +1781,229 @@ var registerSupportingTools = (server, client) => {
|
|
|
1731
1781
|
);
|
|
1732
1782
|
};
|
|
1733
1783
|
|
|
1784
|
+
// src/tools/rogue-kpis.tools.ts
|
|
1785
|
+
var import_zod11 = require("zod");
|
|
1786
|
+
var registerRogueKpiTools = (server, client) => {
|
|
1787
|
+
server.tool(
|
|
1788
|
+
"browse_rogue_kpis",
|
|
1789
|
+
"Browse the Rogue KPI catalog \u2014 the master list of standardized KPIs that boards can adopt. Filter by domain (finance, sales, hr, product, customers, fundraising, operations), maturity level (draft, emerging, general), company stage, or free-text search.",
|
|
1790
|
+
{
|
|
1791
|
+
domain: import_zod11.z.string().optional().describe(
|
|
1792
|
+
"Filter by KPI domain: finance, sales, hr, product, customers, fundraising, operations"
|
|
1793
|
+
),
|
|
1794
|
+
maturity: import_zod11.z.string().optional().describe("Filter by maturity: draft, emerging, general"),
|
|
1795
|
+
suggestedForStages: import_zod11.z.string().optional().describe("Filter by company stage: preSeed, seed, seriesA, seriesB, seriesC, public"),
|
|
1796
|
+
search: import_zod11.z.string().optional().describe("Free-text search on KPI label and description"),
|
|
1797
|
+
...paginationParams
|
|
1798
|
+
},
|
|
1799
|
+
async ({ domain, maturity, suggestedForStages, search, limit, cursor, sort, order }) => {
|
|
1800
|
+
try {
|
|
1801
|
+
const params = buildQueryParams(
|
|
1802
|
+
{ domain, maturity, suggestedForStages, search, limit, cursor, sort, order },
|
|
1803
|
+
["domain", "maturity", "suggestedForStages", "search"]
|
|
1804
|
+
);
|
|
1805
|
+
const response = await client.getCollection("/api/rogue-kpis", params);
|
|
1806
|
+
return formatResult({ data: response.data, meta: response.meta });
|
|
1807
|
+
} catch (error) {
|
|
1808
|
+
return handleToolError(error);
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
);
|
|
1812
|
+
server.tool(
|
|
1813
|
+
"get_rogue_kpi",
|
|
1814
|
+
'Get a single Rogue KPI by its canonical rogueId (e.g., "finance.arr", "sales.pipeline_value"). Returns full details including description, field type, suggested stages, owning functions, and the required `definitionSource` attribution. When `definitionSource.tier === "published"`, the response carries an `attributionNotice` string that consumers must surface in any UI/output that renders the KPI definition. When `calculationPolicy` is present (added in ontology v1.1.0), an agent asked to COMPUTE the KPI from messy company data MUST surface `calculationPolicy.commonMiscomputations` to the user before running the calculation, apply `inclusionRules`/`exclusionRules` as boundary conditions on the source data, and run `validationChecks` against the result before returning it.',
|
|
1815
|
+
{
|
|
1816
|
+
rogueId: import_zod11.z.string().describe('The canonical Rogue KPI ID (e.g., "finance.arr", "hr.headcount")')
|
|
1817
|
+
},
|
|
1818
|
+
async ({ rogueId }) => {
|
|
1819
|
+
try {
|
|
1820
|
+
const response = await client.get(`/api/rogue-kpis/${rogueId}`);
|
|
1821
|
+
return formatResult({ data: response.data });
|
|
1822
|
+
} catch (error) {
|
|
1823
|
+
return handleToolError(error);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
);
|
|
1827
|
+
};
|
|
1828
|
+
|
|
1829
|
+
// src/tools/persona-dossiers.tools.ts
|
|
1830
|
+
var import_zod12 = require("zod");
|
|
1831
|
+
var registerPersonaDossierTools = (server, client) => {
|
|
1832
|
+
server.tool(
|
|
1833
|
+
"get_persona_dossier",
|
|
1834
|
+
"Get a per-persona dossier for a board function (e.g., finance, sales, hr, r-and-d, product). Returns a markdown guide with section overview, field-by-field guidance, data acquisition hints, and common pitfalls \u2014 designed to help you assist the persona in filling their board section.",
|
|
1835
|
+
{
|
|
1836
|
+
boardId: boardIdParam,
|
|
1837
|
+
functionSlug: import_zod12.z.string().describe(
|
|
1838
|
+
"The function slug: finance, sales, hr, r-and-d, product, legal, operations"
|
|
1839
|
+
)
|
|
1840
|
+
},
|
|
1841
|
+
async ({ boardId, functionSlug }) => {
|
|
1842
|
+
try {
|
|
1843
|
+
const response = await client.get(
|
|
1844
|
+
`/api/boards/${boardId}/dossiers/${functionSlug}`
|
|
1845
|
+
);
|
|
1846
|
+
return formatResult({ data: response.data });
|
|
1847
|
+
} catch (error) {
|
|
1848
|
+
return handleToolError(error);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
);
|
|
1852
|
+
};
|
|
1853
|
+
|
|
1854
|
+
// src/tools/knowledge-graph.tools.ts
|
|
1855
|
+
var import_zod13 = require("zod");
|
|
1856
|
+
var registerKnowledgeGraphTools = (server, client) => {
|
|
1857
|
+
server.tool(
|
|
1858
|
+
"get_board_prep_brief",
|
|
1859
|
+
"Get a full board preparation brief from the knowledge graph: open contradictions, unanswered director questions, approved decisions pending follow-up, governance coverage gaps, dropped topics, director question patterns, and narrative drift. Requires board admin or internal management role.",
|
|
1860
|
+
{
|
|
1861
|
+
boardId: boardIdParam
|
|
1862
|
+
},
|
|
1863
|
+
async ({ boardId }) => {
|
|
1864
|
+
try {
|
|
1865
|
+
const response = await client.get(`/api/boards/${boardId}/kg/prep-brief`);
|
|
1866
|
+
return formatResult({ data: response.data });
|
|
1867
|
+
} catch (error) {
|
|
1868
|
+
return handleToolError(error);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
);
|
|
1872
|
+
server.tool(
|
|
1873
|
+
"get_knowledge_graph_summary",
|
|
1874
|
+
"Get knowledge graph index stats for a board: node counts by type, edge count, health metrics (open contradictions, open questions, stale commitments), governance coverage gaps, dropped topics, compiled summary, and recent ingestion history. Requires board admin or internal management role.",
|
|
1875
|
+
{
|
|
1876
|
+
boardId: boardIdParam
|
|
1877
|
+
},
|
|
1878
|
+
async ({ boardId }) => {
|
|
1879
|
+
try {
|
|
1880
|
+
const response = await client.get(`/api/boards/${boardId}/kg/summary`);
|
|
1881
|
+
return formatResult({ data: response.data });
|
|
1882
|
+
} catch (error) {
|
|
1883
|
+
return handleToolError(error);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
);
|
|
1887
|
+
server.tool(
|
|
1888
|
+
"get_open_items",
|
|
1889
|
+
'Get open items from the knowledge graph. Filter by type: "contradictions" (conflicting data across sources), "questions" (unanswered or deferred director questions), or "commitments" (approved/proposed decisions pending follow-up). Omit type to get all. Requires board admin or internal management role.',
|
|
1890
|
+
{
|
|
1891
|
+
boardId: boardIdParam,
|
|
1892
|
+
type: import_zod13.z.enum(["contradictions", "questions", "commitments"]).optional().describe(
|
|
1893
|
+
"Filter by item type: contradictions, questions, or commitments. Omit to get all types."
|
|
1894
|
+
)
|
|
1895
|
+
},
|
|
1896
|
+
async ({ boardId, type }) => {
|
|
1897
|
+
try {
|
|
1898
|
+
const params = {};
|
|
1899
|
+
if (type) params.type = type;
|
|
1900
|
+
const response = await client.get(`/api/boards/${boardId}/kg/open-items`, params);
|
|
1901
|
+
return formatResult({ data: response.data });
|
|
1902
|
+
} catch (error) {
|
|
1903
|
+
return handleToolError(error);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
);
|
|
1907
|
+
server.tool(
|
|
1908
|
+
"query_knowledge_graph",
|
|
1909
|
+
"Ask a natural language question against the board knowledge graph. The system retrieves relevant graph data (contradictions, decisions, questions, topics, themes, KPI mentions) and synthesizes an answer using an LLM. Requires board admin or internal management role.",
|
|
1910
|
+
{
|
|
1911
|
+
boardId: boardIdParam,
|
|
1912
|
+
question: import_zod13.z.string().max(2e3).describe(
|
|
1913
|
+
"The natural language question to ask about the board knowledge graph (max 2000 chars)"
|
|
1914
|
+
)
|
|
1915
|
+
},
|
|
1916
|
+
async ({ boardId, question }) => {
|
|
1917
|
+
try {
|
|
1918
|
+
const response = await client.post(`/api/boards/${boardId}/kg/query`, { question });
|
|
1919
|
+
return formatResult({ data: response.data });
|
|
1920
|
+
} catch (error) {
|
|
1921
|
+
return handleToolError(error);
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
);
|
|
1925
|
+
};
|
|
1926
|
+
|
|
1927
|
+
// src/tools/kg-advisory.tools.ts
|
|
1928
|
+
var import_zod14 = require("zod");
|
|
1929
|
+
var ruleTypeEnum = import_zod14.z.enum([
|
|
1930
|
+
"stale_commitment",
|
|
1931
|
+
"dropped_topic",
|
|
1932
|
+
"governance_coverage_gap",
|
|
1933
|
+
"narrative_drift",
|
|
1934
|
+
"unanswered_director_question",
|
|
1935
|
+
"orphan_decision",
|
|
1936
|
+
"textual_contradiction"
|
|
1937
|
+
]);
|
|
1938
|
+
var statusEnum = import_zod14.z.enum(["open", "dismissed", "resolved", "snoozed"]);
|
|
1939
|
+
var registerKgAdvisoryTools = (server, client) => {
|
|
1940
|
+
server.tool(
|
|
1941
|
+
"get_governance_advisories",
|
|
1942
|
+
"List KG governance advisories for a board. Returns all statuses by default (consumer groups by status). Filter via status, ruleType, or limit. Includes a top-level `users` map resolving any userId references in the response (owner, raisedBy, dismissedBy).",
|
|
1943
|
+
{
|
|
1944
|
+
boardId: boardIdParam,
|
|
1945
|
+
status: statusEnum.optional().describe("Filter to a single status. Default: all statuses returned."),
|
|
1946
|
+
ruleType: ruleTypeEnum.optional().describe("Filter to a single rule type."),
|
|
1947
|
+
limit: import_zod14.z.number().int().min(1).max(200).optional().describe("Max advisories to return (default 100).")
|
|
1948
|
+
},
|
|
1949
|
+
async ({ boardId, status, ruleType, limit }) => {
|
|
1950
|
+
try {
|
|
1951
|
+
const params = { include: "users" };
|
|
1952
|
+
if (status) params.status = status;
|
|
1953
|
+
if (ruleType) params.ruleType = ruleType;
|
|
1954
|
+
if (limit !== void 0) params.limit = String(limit);
|
|
1955
|
+
const response = await client.get(
|
|
1956
|
+
`/api/boards/${boardId}/knowledge-graph/governance-advisory`,
|
|
1957
|
+
params
|
|
1958
|
+
);
|
|
1959
|
+
return formatResult(response.data);
|
|
1960
|
+
} catch (error) {
|
|
1961
|
+
return handleToolError(error);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
);
|
|
1965
|
+
server.tool(
|
|
1966
|
+
"get_governance_advisory_runs",
|
|
1967
|
+
"List recent KG governance advisory review runs for a board (paginated, newest first). Audit/retro surface \u2014 see when runs fired, who triggered them, and finding counts per rule.",
|
|
1968
|
+
{
|
|
1969
|
+
boardId: boardIdParam,
|
|
1970
|
+
limit: import_zod14.z.number().int().min(1).max(100).optional().describe("Max runs to return (default 10).")
|
|
1971
|
+
},
|
|
1972
|
+
async ({ boardId, limit }) => {
|
|
1973
|
+
try {
|
|
1974
|
+
const params = {};
|
|
1975
|
+
if (limit !== void 0) params.limit = String(limit);
|
|
1976
|
+
const response = await client.get(
|
|
1977
|
+
`/api/boards/${boardId}/knowledge-graph/governance-advisory/runs`,
|
|
1978
|
+
params
|
|
1979
|
+
);
|
|
1980
|
+
return formatResult(response.data);
|
|
1981
|
+
} catch (error) {
|
|
1982
|
+
return handleToolError(error);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
);
|
|
1986
|
+
server.tool(
|
|
1987
|
+
"run_governance_advisory_review",
|
|
1988
|
+
"Trigger a KG governance advisory review pass for a board. Returns the review ID. A 60s soft check returns the in-flight review if one already started in the last minute.",
|
|
1989
|
+
{
|
|
1990
|
+
boardId: boardIdParam,
|
|
1991
|
+
reason: import_zod14.z.string().optional().describe("Free-text reason for triggering this run.")
|
|
1992
|
+
},
|
|
1993
|
+
async ({ boardId, reason }) => {
|
|
1994
|
+
try {
|
|
1995
|
+
const response = await client.post(
|
|
1996
|
+
`/api/boards/${boardId}/knowledge-graph/governance-advisory/run`,
|
|
1997
|
+
{ reason, source: "mcp_tool" }
|
|
1998
|
+
);
|
|
1999
|
+
return formatResult(response.data);
|
|
2000
|
+
} catch (error) {
|
|
2001
|
+
return handleToolError(error);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
);
|
|
2005
|
+
};
|
|
2006
|
+
|
|
1734
2007
|
// src/resources/docs.resources.ts
|
|
1735
2008
|
var DOCS_BASE_URL = "https://docs.imboard.ai";
|
|
1736
2009
|
var STATIC_RESOURCES = [
|
|
@@ -1813,7 +2086,7 @@ function registerDocsResources(server) {
|
|
|
1813
2086
|
|
|
1814
2087
|
// src/server.ts
|
|
1815
2088
|
var SERVER_NAME = "imboard-mcp-server";
|
|
1816
|
-
var SERVER_VERSION = "0.1.
|
|
2089
|
+
var SERVER_VERSION = "0.1.3";
|
|
1817
2090
|
function createServer(config) {
|
|
1818
2091
|
logger.info(`Creating ${SERVER_NAME} v${SERVER_VERSION}`);
|
|
1819
2092
|
const server = new import_mcp.McpServer({
|
|
@@ -1835,6 +2108,10 @@ function createServer(config) {
|
|
|
1835
2108
|
registerActionItemTools(server, api);
|
|
1836
2109
|
registerUserTools(server, api);
|
|
1837
2110
|
registerSupportingTools(server, api);
|
|
2111
|
+
registerRogueKpiTools(server, api);
|
|
2112
|
+
registerPersonaDossierTools(server, api);
|
|
2113
|
+
registerKnowledgeGraphTools(server, api);
|
|
2114
|
+
registerKgAdvisoryTools(server, api);
|
|
1838
2115
|
registerDocsResources(server);
|
|
1839
2116
|
logger.info("All tools and resources registered");
|
|
1840
2117
|
return server;
|