@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
|
@@ -1,49 +1,64 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
boardIdParam,
|
|
4
|
+
resourceIdParam,
|
|
5
|
+
paginationParams,
|
|
6
|
+
buildQueryParams,
|
|
7
|
+
formatResult,
|
|
8
|
+
handleToolError,
|
|
9
|
+
RegisterToolsFn,
|
|
10
|
+
} from './shared.js';
|
|
3
11
|
|
|
4
12
|
export const registerMeetingTools: RegisterToolsFn = (server, client) => {
|
|
5
13
|
server.tool(
|
|
6
14
|
'list_board_meetings',
|
|
7
|
-
'Lists meetings for a board. Supports filtering by status and date range, and sorting by start time.',
|
|
15
|
+
'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.',
|
|
8
16
|
{
|
|
9
17
|
boardId: boardIdParam,
|
|
10
18
|
...paginationParams,
|
|
11
|
-
sort: z
|
|
19
|
+
sort: z
|
|
20
|
+
.enum(['updatedAt', 'startTime'])
|
|
21
|
+
.optional()
|
|
22
|
+
.describe('Sort field (default: startTime)'),
|
|
12
23
|
status: z.string().optional().describe('Filter by meeting status'),
|
|
13
|
-
startAfter: z
|
|
14
|
-
|
|
24
|
+
startAfter: z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('ISO-8601 date — only meetings starting after this'),
|
|
28
|
+
startBefore: z
|
|
29
|
+
.string()
|
|
30
|
+
.optional()
|
|
31
|
+
.describe('ISO-8601 date — only meetings starting before this'),
|
|
15
32
|
},
|
|
16
33
|
async ({ boardId, ...rest }) => {
|
|
17
34
|
try {
|
|
18
35
|
const params = buildQueryParams(rest, ['status', 'startAfter', 'startBefore']);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
);
|
|
23
|
-
return formatResult({ data: result.data, meta: result.meta });
|
|
36
|
+
params.include = 'users';
|
|
37
|
+
const result = await client.getCollection(`/api/boards/${boardId}/meetings`, params);
|
|
38
|
+
return formatResult({ data: result.data, meta: result.meta, users: result.users });
|
|
24
39
|
} catch (error) {
|
|
25
40
|
return handleToolError(error);
|
|
26
41
|
}
|
|
27
|
-
}
|
|
42
|
+
}
|
|
28
43
|
);
|
|
29
44
|
|
|
30
45
|
server.tool(
|
|
31
46
|
'get_meeting',
|
|
32
|
-
'Returns details for a specific meeting including title, status, location, and scheduled time.',
|
|
47
|
+
'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.',
|
|
33
48
|
{
|
|
34
49
|
boardId: boardIdParam,
|
|
35
50
|
meetingId: resourceIdParam.describe('The meeting ID'),
|
|
36
51
|
},
|
|
37
52
|
async ({ boardId, meetingId }) => {
|
|
38
53
|
try {
|
|
39
|
-
const result = await client.get(
|
|
40
|
-
|
|
41
|
-
);
|
|
42
|
-
return formatResult({ data: result.data });
|
|
54
|
+
const result = await client.get(`/api/boards/${boardId}/meetings/${meetingId}`, {
|
|
55
|
+
include: 'users',
|
|
56
|
+
});
|
|
57
|
+
return formatResult({ data: result.data, users: result.users });
|
|
43
58
|
} catch (error) {
|
|
44
59
|
return handleToolError(error);
|
|
45
60
|
}
|
|
46
|
-
}
|
|
61
|
+
}
|
|
47
62
|
);
|
|
48
63
|
|
|
49
64
|
server.tool(
|
|
@@ -52,14 +67,25 @@ export const registerMeetingTools: RegisterToolsFn = (server, client) => {
|
|
|
52
67
|
{
|
|
53
68
|
boardId: boardIdParam,
|
|
54
69
|
title: z.string().describe('Meeting title (max 200 characters)'),
|
|
55
|
-
status: z
|
|
70
|
+
status: z
|
|
71
|
+
.string()
|
|
72
|
+
.describe('Meeting status: draft, planned, scheduled, completed, or finalized'),
|
|
56
73
|
locationType: z.string().describe('Location type: physical, virtual, or hybrid'),
|
|
57
74
|
startTime: z.string().describe('Meeting start time as ISO-8601 date string'),
|
|
58
75
|
endTime: z.string().describe('Meeting end time as ISO-8601 date string'),
|
|
59
76
|
location: z.string().optional().describe('Physical location (max 255 characters)'),
|
|
60
77
|
virtualMeetingUrl: z.string().optional().describe('Virtual meeting URL (max 255 characters)'),
|
|
61
78
|
},
|
|
62
|
-
async ({
|
|
79
|
+
async ({
|
|
80
|
+
boardId,
|
|
81
|
+
title,
|
|
82
|
+
status,
|
|
83
|
+
locationType,
|
|
84
|
+
startTime,
|
|
85
|
+
endTime,
|
|
86
|
+
location,
|
|
87
|
+
virtualMeetingUrl,
|
|
88
|
+
}) => {
|
|
63
89
|
try {
|
|
64
90
|
const body: Record<string, string> = {
|
|
65
91
|
title,
|
|
@@ -71,15 +97,12 @@ export const registerMeetingTools: RegisterToolsFn = (server, client) => {
|
|
|
71
97
|
if (location !== undefined) body.location = location;
|
|
72
98
|
if (virtualMeetingUrl !== undefined) body.virtualMeetingUrl = virtualMeetingUrl;
|
|
73
99
|
|
|
74
|
-
const result = await client.post(
|
|
75
|
-
`/api/boards/${boardId}/meetings`,
|
|
76
|
-
body,
|
|
77
|
-
);
|
|
100
|
+
const result = await client.post(`/api/boards/${boardId}/meetings`, body);
|
|
78
101
|
return formatResult({ data: result.data });
|
|
79
102
|
} catch (error) {
|
|
80
103
|
return handleToolError(error);
|
|
81
104
|
}
|
|
82
|
-
}
|
|
105
|
+
}
|
|
83
106
|
);
|
|
84
107
|
|
|
85
108
|
server.tool(
|
|
@@ -89,14 +112,27 @@ export const registerMeetingTools: RegisterToolsFn = (server, client) => {
|
|
|
89
112
|
boardId: boardIdParam,
|
|
90
113
|
meetingId: resourceIdParam.describe('The meeting ID'),
|
|
91
114
|
title: z.string().optional().describe('Meeting title (max 200 characters)'),
|
|
92
|
-
status: z
|
|
115
|
+
status: z
|
|
116
|
+
.string()
|
|
117
|
+
.optional()
|
|
118
|
+
.describe('Meeting status: draft, planned, scheduled, completed, or finalized'),
|
|
93
119
|
locationType: z.string().optional().describe('Location type: physical, virtual, or hybrid'),
|
|
94
120
|
location: z.string().optional().describe('Physical location (max 255 characters)'),
|
|
95
121
|
virtualMeetingUrl: z.string().optional().describe('Virtual meeting URL (max 255 characters)'),
|
|
96
122
|
startTime: z.string().optional().describe('Meeting start time as ISO-8601 date string'),
|
|
97
123
|
endTime: z.string().optional().describe('Meeting end time as ISO-8601 date string'),
|
|
98
124
|
},
|
|
99
|
-
async ({
|
|
125
|
+
async ({
|
|
126
|
+
boardId,
|
|
127
|
+
meetingId,
|
|
128
|
+
title,
|
|
129
|
+
status,
|
|
130
|
+
locationType,
|
|
131
|
+
location,
|
|
132
|
+
virtualMeetingUrl,
|
|
133
|
+
startTime,
|
|
134
|
+
endTime,
|
|
135
|
+
}) => {
|
|
100
136
|
try {
|
|
101
137
|
const body: Record<string, string> = {};
|
|
102
138
|
if (title !== undefined) body.title = title;
|
|
@@ -107,15 +143,12 @@ export const registerMeetingTools: RegisterToolsFn = (server, client) => {
|
|
|
107
143
|
if (startTime !== undefined) body.startTime = startTime;
|
|
108
144
|
if (endTime !== undefined) body.endTime = endTime;
|
|
109
145
|
|
|
110
|
-
const result = await client.patch(
|
|
111
|
-
`/api/boards/${boardId}/meetings/${meetingId}`,
|
|
112
|
-
body,
|
|
113
|
-
);
|
|
146
|
+
const result = await client.patch(`/api/boards/${boardId}/meetings/${meetingId}`, body);
|
|
114
147
|
return formatResult({ data: result.data });
|
|
115
148
|
} catch (error) {
|
|
116
149
|
return handleToolError(error);
|
|
117
150
|
}
|
|
118
|
-
}
|
|
151
|
+
}
|
|
119
152
|
);
|
|
120
153
|
|
|
121
154
|
server.tool(
|
|
@@ -127,14 +160,12 @@ export const registerMeetingTools: RegisterToolsFn = (server, client) => {
|
|
|
127
160
|
},
|
|
128
161
|
async ({ boardId, meetingId }) => {
|
|
129
162
|
try {
|
|
130
|
-
const result = await client.delete(
|
|
131
|
-
`/api/meetings/${boardId}/${meetingId}/`,
|
|
132
|
-
);
|
|
163
|
+
const result = await client.delete(`/api/meetings/${boardId}/${meetingId}/`);
|
|
133
164
|
return formatResult({ data: result.data });
|
|
134
165
|
} catch (error) {
|
|
135
166
|
return handleToolError(error);
|
|
136
167
|
}
|
|
137
|
-
}
|
|
168
|
+
}
|
|
138
169
|
);
|
|
139
170
|
|
|
140
171
|
server.tool(
|
|
@@ -143,18 +174,19 @@ export const registerMeetingTools: RegisterToolsFn = (server, client) => {
|
|
|
143
174
|
{
|
|
144
175
|
boardId: boardIdParam,
|
|
145
176
|
meetingId: resourceIdParam.describe('The meeting ID'),
|
|
146
|
-
meetingStatus: z
|
|
177
|
+
meetingStatus: z
|
|
178
|
+
.string()
|
|
179
|
+
.describe('New meeting status: draft, planned, scheduled, completed, or finalized'),
|
|
147
180
|
},
|
|
148
181
|
async ({ boardId, meetingId, meetingStatus }) => {
|
|
149
182
|
try {
|
|
150
|
-
const result = await client.put(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
);
|
|
183
|
+
const result = await client.put(`/api/meetings/${boardId}/${meetingId}/status`, {
|
|
184
|
+
meetingStatus,
|
|
185
|
+
});
|
|
154
186
|
return formatResult({ data: result.data });
|
|
155
187
|
} catch (error) {
|
|
156
188
|
return handleToolError(error);
|
|
157
189
|
}
|
|
158
|
-
}
|
|
190
|
+
}
|
|
159
191
|
);
|
|
160
192
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { boardIdParam, formatResult, handleToolError, RegisterToolsFn } from './shared.js';
|
|
3
|
+
|
|
4
|
+
export const registerPersonaDossierTools: RegisterToolsFn = (server, client) => {
|
|
5
|
+
server.tool(
|
|
6
|
+
'get_persona_dossier',
|
|
7
|
+
'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 — designed to help you assist the persona in filling their board section.',
|
|
8
|
+
{
|
|
9
|
+
boardId: boardIdParam,
|
|
10
|
+
functionSlug: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe(
|
|
13
|
+
'The function slug: finance, sales, hr, r-and-d, product, legal, operations',
|
|
14
|
+
),
|
|
15
|
+
},
|
|
16
|
+
async ({ boardId, functionSlug }) => {
|
|
17
|
+
try {
|
|
18
|
+
const response = await client.get(
|
|
19
|
+
`/api/boards/${boardId}/dossiers/${functionSlug}`,
|
|
20
|
+
);
|
|
21
|
+
return formatResult({ data: response.data });
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return handleToolError(error);
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
};
|
|
@@ -1,47 +1,72 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
boardIdParam,
|
|
4
|
+
resourceIdParam,
|
|
5
|
+
paginationParams,
|
|
6
|
+
buildQueryParams,
|
|
7
|
+
formatResult,
|
|
8
|
+
handleToolError,
|
|
9
|
+
RegisterToolsFn,
|
|
10
|
+
} from './shared.js';
|
|
3
11
|
|
|
4
12
|
export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
5
13
|
server.tool(
|
|
6
14
|
'list_board_reports',
|
|
7
|
-
'Lists reports for a board. Supports filtering by status.',
|
|
15
|
+
'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).',
|
|
8
16
|
{
|
|
9
17
|
boardId: boardIdParam,
|
|
10
18
|
...paginationParams,
|
|
11
|
-
status: z
|
|
19
|
+
status: z
|
|
20
|
+
.enum(['draft', 'publishedForReview', 'finalized', 'archived', 'ongoing'])
|
|
21
|
+
.optional()
|
|
12
22
|
.describe('Filter by report status'),
|
|
13
23
|
},
|
|
14
24
|
async ({ boardId, ...rest }) => {
|
|
15
25
|
try {
|
|
16
26
|
const params = buildQueryParams(rest, ['status']);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
);
|
|
21
|
-
return formatResult({ data: result.data, meta: result.meta });
|
|
27
|
+
params.include = 'users';
|
|
28
|
+
const result = await client.getCollection(`/api/boards/${boardId}/reports`, params);
|
|
29
|
+
return formatResult({ data: result.data, meta: result.meta, users: result.users });
|
|
22
30
|
} catch (error) {
|
|
23
31
|
return handleToolError(error);
|
|
24
32
|
}
|
|
25
|
-
}
|
|
33
|
+
}
|
|
26
34
|
);
|
|
27
35
|
|
|
28
36
|
server.tool(
|
|
29
37
|
'get_report',
|
|
30
|
-
'Returns details for a specific board report including title, status, and publication date.',
|
|
38
|
+
'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.',
|
|
31
39
|
{
|
|
32
40
|
boardId: boardIdParam,
|
|
33
41
|
reportId: resourceIdParam.describe('The report ID'),
|
|
34
42
|
},
|
|
35
43
|
async ({ boardId, reportId }) => {
|
|
36
44
|
try {
|
|
37
|
-
const result = await client.get(
|
|
38
|
-
|
|
39
|
-
);
|
|
40
|
-
return formatResult({ data: result.data });
|
|
45
|
+
const result = await client.get(`/api/boards/${boardId}/reports/${reportId}`, {
|
|
46
|
+
include: 'users',
|
|
47
|
+
});
|
|
48
|
+
return formatResult({ data: result.data, users: result.users });
|
|
41
49
|
} catch (error) {
|
|
42
50
|
return handleToolError(error);
|
|
43
51
|
}
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
server.tool(
|
|
56
|
+
'get_report_full',
|
|
57
|
+
'Returns the ENTIRE board pack in one call: report metadata plus every dashboard’s latest normalized KPI content (all types — cash, sales, customers, pipeline, fundraising, HR, product, and custom narrative) and deterministic data-quality flags. Prefer this over fetching dashboards one by one — it avoids a slow multi-call fan-out.',
|
|
58
|
+
{
|
|
59
|
+
boardId: boardIdParam,
|
|
60
|
+
reportId: resourceIdParam.describe('The report ID'),
|
|
44
61
|
},
|
|
62
|
+
async ({ boardId, reportId }) => {
|
|
63
|
+
try {
|
|
64
|
+
const result = await client.get(`/api/boards/${boardId}/reports/${reportId}/full`);
|
|
65
|
+
return formatResult({ data: result.data });
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return handleToolError(error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
45
70
|
);
|
|
46
71
|
|
|
47
72
|
server.tool(
|
|
@@ -67,7 +92,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
67
92
|
} catch (error) {
|
|
68
93
|
return handleToolError(error);
|
|
69
94
|
}
|
|
70
|
-
}
|
|
95
|
+
}
|
|
71
96
|
);
|
|
72
97
|
|
|
73
98
|
server.tool(
|
|
@@ -83,7 +108,16 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
83
108
|
periodStart: z.string().optional().describe('Period start date (YYYY-MM-DD)'),
|
|
84
109
|
periodEnd: z.string().optional().describe('Period end date (YYYY-MM-DD)'),
|
|
85
110
|
},
|
|
86
|
-
async ({
|
|
111
|
+
async ({
|
|
112
|
+
boardId,
|
|
113
|
+
reportId,
|
|
114
|
+
name,
|
|
115
|
+
description,
|
|
116
|
+
status,
|
|
117
|
+
meetingIds,
|
|
118
|
+
periodStart,
|
|
119
|
+
periodEnd,
|
|
120
|
+
}) => {
|
|
87
121
|
try {
|
|
88
122
|
const body: Record<string, unknown> = {};
|
|
89
123
|
if (name !== undefined) body.name = name;
|
|
@@ -97,7 +131,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
97
131
|
} catch (error) {
|
|
98
132
|
return handleToolError(error);
|
|
99
133
|
}
|
|
100
|
-
}
|
|
134
|
+
}
|
|
101
135
|
);
|
|
102
136
|
|
|
103
137
|
server.tool(
|
|
@@ -115,7 +149,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
115
149
|
} catch (error) {
|
|
116
150
|
return handleToolError(error);
|
|
117
151
|
}
|
|
118
|
-
}
|
|
152
|
+
}
|
|
119
153
|
);
|
|
120
154
|
|
|
121
155
|
server.tool(
|
|
@@ -142,7 +176,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
142
176
|
} catch (error) {
|
|
143
177
|
return handleToolError(error);
|
|
144
178
|
}
|
|
145
|
-
}
|
|
179
|
+
}
|
|
146
180
|
);
|
|
147
181
|
|
|
148
182
|
server.tool(
|
|
@@ -163,7 +197,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
163
197
|
} catch (error) {
|
|
164
198
|
return handleToolError(error);
|
|
165
199
|
}
|
|
166
|
-
}
|
|
200
|
+
}
|
|
167
201
|
);
|
|
168
202
|
|
|
169
203
|
server.tool(
|
|
@@ -173,7 +207,9 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
173
207
|
boardId: boardIdParam,
|
|
174
208
|
reportId: resourceIdParam.describe('The report ID'),
|
|
175
209
|
dashboardId: resourceIdParam.describe('The dashboard ID'),
|
|
176
|
-
content: z
|
|
210
|
+
content: z
|
|
211
|
+
.record(z.string(), z.unknown())
|
|
212
|
+
.describe('Dashboard content object (must include _type field)'),
|
|
177
213
|
notes: z.array(z.string()).optional().describe('Version notes'),
|
|
178
214
|
},
|
|
179
215
|
async ({ boardId, reportId, dashboardId, content, notes }) => {
|
|
@@ -182,13 +218,13 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
182
218
|
if (notes !== undefined) body.notes = notes;
|
|
183
219
|
const result = await client.post(
|
|
184
220
|
`/api/reports/${boardId}/${reportId}/dashboards/${dashboardId}/versions`,
|
|
185
|
-
body
|
|
221
|
+
body
|
|
186
222
|
);
|
|
187
223
|
return formatResult({ data: result.data });
|
|
188
224
|
} catch (error) {
|
|
189
225
|
return handleToolError(error);
|
|
190
226
|
}
|
|
191
|
-
}
|
|
227
|
+
}
|
|
192
228
|
);
|
|
193
229
|
|
|
194
230
|
server.tool(
|
|
@@ -204,13 +240,13 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
204
240
|
try {
|
|
205
241
|
const result = await client.put(
|
|
206
242
|
`/api/reports/${boardId}/${reportId}/dashboards/${dashboardId}/review-status`,
|
|
207
|
-
{ newStatus }
|
|
243
|
+
{ newStatus }
|
|
208
244
|
);
|
|
209
245
|
return formatResult({ data: result.data });
|
|
210
246
|
} catch (error) {
|
|
211
247
|
return handleToolError(error);
|
|
212
248
|
}
|
|
213
|
-
}
|
|
249
|
+
}
|
|
214
250
|
);
|
|
215
251
|
|
|
216
252
|
server.tool(
|
|
@@ -228,13 +264,13 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
228
264
|
if (chatType !== undefined) params.chatType = chatType;
|
|
229
265
|
const result = await client.get(
|
|
230
266
|
`/api/reports/${boardId}/${reportId}/dashboards/${dashboardId}/chat`,
|
|
231
|
-
params
|
|
267
|
+
params
|
|
232
268
|
);
|
|
233
269
|
return formatResult({ data: result.data });
|
|
234
270
|
} catch (error) {
|
|
235
271
|
return handleToolError(error);
|
|
236
272
|
}
|
|
237
|
-
}
|
|
273
|
+
}
|
|
238
274
|
);
|
|
239
275
|
|
|
240
276
|
server.tool(
|
|
@@ -245,7 +281,9 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
245
281
|
reportId: resourceIdParam.describe('The report ID'),
|
|
246
282
|
dashboardId: resourceIdParam.describe('The dashboard ID'),
|
|
247
283
|
message: z.string().describe('Comment text (1-5000 characters)'),
|
|
248
|
-
chatType: z
|
|
284
|
+
chatType: z
|
|
285
|
+
.enum(['internal', 'boardFeedback'])
|
|
286
|
+
.describe('Chat type: internal or boardFeedback'),
|
|
249
287
|
recipientId: z.string().optional().describe('Recipient user ID (for directed feedback)'),
|
|
250
288
|
},
|
|
251
289
|
async ({ boardId, reportId, dashboardId, message, chatType, recipientId }) => {
|
|
@@ -254,13 +292,13 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
254
292
|
if (recipientId !== undefined) body.recipientId = recipientId;
|
|
255
293
|
const result = await client.post(
|
|
256
294
|
`/api/reports/${boardId}/${reportId}/dashboards/${dashboardId}/chat`,
|
|
257
|
-
body
|
|
295
|
+
body
|
|
258
296
|
);
|
|
259
297
|
return formatResult({ data: result.data });
|
|
260
298
|
} catch (error) {
|
|
261
299
|
return handleToolError(error);
|
|
262
300
|
}
|
|
263
|
-
}
|
|
301
|
+
}
|
|
264
302
|
);
|
|
265
303
|
|
|
266
304
|
server.tool(
|
|
@@ -277,13 +315,13 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
277
315
|
if (recipientId !== undefined) params.recipientId = recipientId;
|
|
278
316
|
const result = await client.get(
|
|
279
317
|
`/api/reports/${boardId}/${reportId}/board-feedback`,
|
|
280
|
-
params
|
|
318
|
+
params
|
|
281
319
|
);
|
|
282
320
|
return formatResult({ data: result.data });
|
|
283
321
|
} catch (error) {
|
|
284
322
|
return handleToolError(error);
|
|
285
323
|
}
|
|
286
|
-
}
|
|
324
|
+
}
|
|
287
325
|
);
|
|
288
326
|
|
|
289
327
|
server.tool(
|
|
@@ -297,15 +335,15 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
297
335
|
},
|
|
298
336
|
async ({ boardId, reportId, message, recipientId }) => {
|
|
299
337
|
try {
|
|
300
|
-
const result = await client.post(
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
);
|
|
338
|
+
const result = await client.post(`/api/reports/${boardId}/${reportId}/board-feedback`, {
|
|
339
|
+
message,
|
|
340
|
+
recipientId,
|
|
341
|
+
});
|
|
304
342
|
return formatResult({ data: result.data });
|
|
305
343
|
} catch (error) {
|
|
306
344
|
return handleToolError(error);
|
|
307
345
|
}
|
|
308
|
-
}
|
|
346
|
+
}
|
|
309
347
|
);
|
|
310
348
|
|
|
311
349
|
server.tool(
|
|
@@ -325,7 +363,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
325
363
|
} catch (error) {
|
|
326
364
|
return handleToolError(error);
|
|
327
365
|
}
|
|
328
|
-
}
|
|
366
|
+
}
|
|
329
367
|
);
|
|
330
368
|
|
|
331
369
|
server.tool(
|
|
@@ -342,7 +380,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
342
380
|
} catch (error) {
|
|
343
381
|
return handleToolError(error);
|
|
344
382
|
}
|
|
345
|
-
}
|
|
383
|
+
}
|
|
346
384
|
);
|
|
347
385
|
|
|
348
386
|
server.tool(
|
|
@@ -360,7 +398,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
360
398
|
} catch (error) {
|
|
361
399
|
return handleToolError(error);
|
|
362
400
|
}
|
|
363
|
-
}
|
|
401
|
+
}
|
|
364
402
|
);
|
|
365
403
|
|
|
366
404
|
server.tool(
|
|
@@ -368,7 +406,10 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
368
406
|
'Gets historical KPI data for a board. Supports filtering by period type, date range, and number of periods.',
|
|
369
407
|
{
|
|
370
408
|
boardId: boardIdParam,
|
|
371
|
-
periodType: z
|
|
409
|
+
periodType: z
|
|
410
|
+
.enum(['monthly', 'quarterly', 'yearly'])
|
|
411
|
+
.optional()
|
|
412
|
+
.describe('Period type (default: monthly)'),
|
|
372
413
|
periods: z.number().int().min(1).max(48).optional().describe('Number of periods (1-48)'),
|
|
373
414
|
startDate: z.string().optional().describe('Start date (ISO 8601)'),
|
|
374
415
|
endDate: z.string().optional().describe('End date (ISO 8601)'),
|
|
@@ -387,7 +428,7 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
387
428
|
} catch (error) {
|
|
388
429
|
return handleToolError(error);
|
|
389
430
|
}
|
|
390
|
-
}
|
|
431
|
+
}
|
|
391
432
|
);
|
|
392
433
|
|
|
393
434
|
server.tool(
|
|
@@ -409,6 +450,6 @@ export const registerReportTools: RegisterToolsFn = (server, client) => {
|
|
|
409
450
|
} catch (error) {
|
|
410
451
|
return handleToolError(error);
|
|
411
452
|
}
|
|
412
|
-
}
|
|
453
|
+
}
|
|
413
454
|
);
|
|
414
455
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
paginationParams,
|
|
4
|
+
buildQueryParams,
|
|
5
|
+
formatResult,
|
|
6
|
+
handleToolError,
|
|
7
|
+
RegisterToolsFn,
|
|
8
|
+
} from './shared.js';
|
|
9
|
+
|
|
10
|
+
export const registerRogueKpiTools: RegisterToolsFn = (server, client) => {
|
|
11
|
+
server.tool(
|
|
12
|
+
'browse_rogue_kpis',
|
|
13
|
+
'Browse the Rogue KPI catalog — 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.',
|
|
14
|
+
{
|
|
15
|
+
domain: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe(
|
|
19
|
+
'Filter by KPI domain: finance, sales, hr, product, customers, fundraising, operations'
|
|
20
|
+
),
|
|
21
|
+
maturity: z.string().optional().describe('Filter by maturity: draft, emerging, general'),
|
|
22
|
+
suggestedForStages: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('Filter by company stage: preSeed, seed, seriesA, seriesB, seriesC, public'),
|
|
26
|
+
search: z.string().optional().describe('Free-text search on KPI label and description'),
|
|
27
|
+
...paginationParams,
|
|
28
|
+
},
|
|
29
|
+
async ({ domain, maturity, suggestedForStages, search, limit, cursor, sort, order }) => {
|
|
30
|
+
try {
|
|
31
|
+
const params = buildQueryParams(
|
|
32
|
+
{ domain, maturity, suggestedForStages, search, limit, cursor, sort, order },
|
|
33
|
+
['domain', 'maturity', 'suggestedForStages', 'search']
|
|
34
|
+
);
|
|
35
|
+
const response = await client.getCollection('/api/rogue-kpis', params);
|
|
36
|
+
return formatResult({ data: response.data, meta: response.meta });
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return handleToolError(error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
server.tool(
|
|
44
|
+
'get_rogue_kpi',
|
|
45
|
+
'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.',
|
|
46
|
+
{
|
|
47
|
+
rogueId: z
|
|
48
|
+
.string()
|
|
49
|
+
.describe('The canonical Rogue KPI ID (e.g., "finance.arr", "hr.headcount")'),
|
|
50
|
+
},
|
|
51
|
+
async ({ rogueId }) => {
|
|
52
|
+
try {
|
|
53
|
+
const response = await client.get(`/api/rogue-kpis/${rogueId}`);
|
|
54
|
+
return formatResult({ data: response.data });
|
|
55
|
+
} catch (error) {
|
|
56
|
+
return handleToolError(error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
};
|
package/src/tools/user.tools.ts
CHANGED
|
@@ -7,12 +7,14 @@ export const registerUserTools: RegisterToolsFn = (server, client) => {
|
|
|
7
7
|
{},
|
|
8
8
|
async () => {
|
|
9
9
|
try {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
// Legacy non-enveloped route: returns { boardMemberships, boardInvites,
|
|
11
|
+
// personalGoogleConnection } with no `data` wrapper.
|
|
12
|
+
const data = await client.getRaw('/api/user/allboards');
|
|
13
|
+
return formatResult({ data });
|
|
12
14
|
} catch (error) {
|
|
13
15
|
return handleToolError(error);
|
|
14
16
|
}
|
|
15
|
-
}
|
|
17
|
+
}
|
|
16
18
|
);
|
|
17
19
|
|
|
18
20
|
server.tool(
|
|
@@ -21,11 +23,12 @@ export const registerUserTools: RegisterToolsFn = (server, client) => {
|
|
|
21
23
|
{},
|
|
22
24
|
async () => {
|
|
23
25
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
// Legacy non-enveloped route: returns { unassignedStorageUsed, lastCalculated }.
|
|
27
|
+
const data = await client.getRaw('/api/user/storage');
|
|
28
|
+
return formatResult({ data });
|
|
26
29
|
} catch (error) {
|
|
27
30
|
return handleToolError(error);
|
|
28
31
|
}
|
|
29
|
-
}
|
|
32
|
+
}
|
|
30
33
|
);
|
|
31
34
|
};
|