@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/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 = 3e4;
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 (!json || typeof json !== "object" || !("data" in json)) {
186
+ if (json === null || typeof json !== "object") {
177
187
  throw new ImboardApiError({
178
188
  code: "INTERNAL_ERROR",
179
- message: 'Response body missing "data" field',
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})`, { delayMs });
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`, { requestId });
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
- "Authorization": `Bearer ${this.token}`,
263
- "Accept": "application/json"
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
- const result = await client.getCollection(
610
- `/api/boards/${boardId}/meetings`,
611
- params
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
- `/api/boards/${boardId}/meetings/${meetingId}`
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 ({ boardId, title, status, locationType, startTime, endTime, location, virtualMeetingUrl }) => {
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 ({ boardId, meetingId, title, status, locationType, location, virtualMeetingUrl, startTime, endTime }) => {
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
- `/api/meetings/${boardId}/${meetingId}/status`,
735
- { meetingStatus }
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
- const result = await client.getCollection(
761
- `/api/boards/${boardId}/documents`,
762
- params
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
- `/api/boards/${boardId}/documents/${documentId}`
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
- const result = await client.getCollection(
911
- `/api/boards/${boardId}/reports`,
912
- params
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
- `/api/boards/${boardId}/reports/${reportId}`
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 ({ boardId, reportId, name, description, status, meetingIds, periodStart, periodEnd }) => {
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
- `/api/reports/${boardId}/${reportId}/board-feedback`,
1183
- { message, recipientId }
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("The report ID (required \u2014 dashboards are nested under reports)"),
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 response = await client.get("/api/user/allboards");
1625
- return formatResult({ data: response.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 response = await client.get("/api/user/storage");
1638
- return formatResult({ data: response.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.0";
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;