checkbox-mcp-server 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +103 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,7 +34,11 @@ async function apiGet(path) {
|
|
|
34
34
|
method: 'GET',
|
|
35
35
|
headers: getHeaders(),
|
|
36
36
|
});
|
|
37
|
-
|
|
37
|
+
const json = await res.json().catch(() => null);
|
|
38
|
+
if (!res.ok) {
|
|
39
|
+
throw new Error(extractError(json) || `Request failed (${res.status})`);
|
|
40
|
+
}
|
|
41
|
+
return json;
|
|
38
42
|
}
|
|
39
43
|
async function apiPost(path, body) {
|
|
40
44
|
const res = await fetch(`${API_URL}${path}`, {
|
|
@@ -42,7 +46,28 @@ async function apiPost(path, body) {
|
|
|
42
46
|
headers: getHeaders(),
|
|
43
47
|
body: JSON.stringify(body),
|
|
44
48
|
});
|
|
45
|
-
|
|
49
|
+
const json = await res.json().catch(() => null);
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
const msg = extractError(json) || `Request failed (${res.status})`;
|
|
52
|
+
throw new Error(msg);
|
|
53
|
+
}
|
|
54
|
+
if (json && json.success === false) {
|
|
55
|
+
throw new Error(extractError(json) || 'Request failed');
|
|
56
|
+
}
|
|
57
|
+
return json;
|
|
58
|
+
}
|
|
59
|
+
function extractError(obj) {
|
|
60
|
+
if (!obj)
|
|
61
|
+
return '';
|
|
62
|
+
if (typeof obj === 'string')
|
|
63
|
+
return obj;
|
|
64
|
+
if (typeof obj.error === 'string')
|
|
65
|
+
return obj.error;
|
|
66
|
+
if (obj.error?.message)
|
|
67
|
+
return obj.error.message;
|
|
68
|
+
if (obj.message)
|
|
69
|
+
return obj.message;
|
|
70
|
+
return JSON.stringify(obj);
|
|
46
71
|
}
|
|
47
72
|
function resultText(data) {
|
|
48
73
|
return JSON.stringify(data, null, 2);
|
|
@@ -50,12 +75,17 @@ function resultText(data) {
|
|
|
50
75
|
// ── MCP Server ──────────────────────────────────────────────────────
|
|
51
76
|
const server = new McpServer({
|
|
52
77
|
name: 'checkbox',
|
|
53
|
-
version: '2.0.
|
|
78
|
+
version: '2.0.1',
|
|
54
79
|
});
|
|
55
80
|
// 1. List capabilities ───────────────────────────────────────────────
|
|
56
81
|
server.tool('list_capabilities', 'List all available Checkbox commands and queries with their descriptions, required roles, and domains. Call this first to understand what actions are available.', {}, async () => {
|
|
57
|
-
|
|
58
|
-
|
|
82
|
+
try {
|
|
83
|
+
const data = await apiGet('/api/v2/introspection/capabilities');
|
|
84
|
+
return { content: [{ type: 'text', text: resultText(data) }] };
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
88
|
+
}
|
|
59
89
|
});
|
|
60
90
|
// 2. Execute command ─────────────────────────────────────────────────
|
|
61
91
|
server.tool('execute_command', 'Execute a Checkbox capability command. Use list_capabilities to see available command types and get_schema to understand the payload shape for each entity type.', {
|
|
@@ -63,11 +93,16 @@ server.tool('execute_command', 'Execute a Checkbox capability command. Use list_
|
|
|
63
93
|
organization_id: z.string().optional().describe('Organization ID. Required for org-scoped commands; omit for authenticated-scope commands like create_organization.'),
|
|
64
94
|
payload: z.record(z.unknown()).describe('Command payload — structure depends on the command type. Use get_schema to discover the expected fields.'),
|
|
65
95
|
}, async ({ type, organization_id, payload }) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
96
|
+
try {
|
|
97
|
+
const body = { type, payload };
|
|
98
|
+
if (organization_id)
|
|
99
|
+
body.organization_id = organization_id;
|
|
100
|
+
const data = await apiPost('/api/v2/commands', body);
|
|
101
|
+
return { content: [{ type: 'text', text: resultText(data) }] };
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
105
|
+
}
|
|
71
106
|
});
|
|
72
107
|
// 3. Execute query ───────────────────────────────────────────────────
|
|
73
108
|
server.tool('execute_query', 'Execute a Checkbox capability query. Use list_capabilities to see available query types.', {
|
|
@@ -75,19 +110,29 @@ server.tool('execute_query', 'Execute a Checkbox capability query. Use list_capa
|
|
|
75
110
|
organization_id: z.string().describe('Organization ID'),
|
|
76
111
|
payload: z.record(z.unknown()).describe('Query payload — structure depends on the query type. Use get_schema to discover the expected fields.'),
|
|
77
112
|
}, async ({ type, organization_id, payload }) => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
113
|
+
try {
|
|
114
|
+
const data = await apiPost('/api/v2/query', {
|
|
115
|
+
type,
|
|
116
|
+
organization_id,
|
|
117
|
+
payload: { ...payload, organization_id },
|
|
118
|
+
});
|
|
119
|
+
return { content: [{ type: 'text', text: resultText(data) }] };
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
123
|
+
}
|
|
84
124
|
});
|
|
85
125
|
// 4. Get workspace graph ─────────────────────────────────────────────
|
|
86
126
|
server.tool('get_workspace', 'Get the full workspace graph — all entities (tasks, plans, goals, rules, requirements, tables, documents, etc.) and their relationships. Useful for understanding the structure of an organization before taking actions.', {
|
|
87
127
|
organization_id: z.string().describe('Organization ID'),
|
|
88
128
|
}, async ({ organization_id }) => {
|
|
89
|
-
|
|
90
|
-
|
|
129
|
+
try {
|
|
130
|
+
const data = await apiPost('/api/v2/introspection/workspace', { organization_id });
|
|
131
|
+
return { content: [{ type: 'text', text: resultText(data) }] };
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
135
|
+
}
|
|
91
136
|
});
|
|
92
137
|
// 5. Find entities ───────────────────────────────────────────────────
|
|
93
138
|
server.tool('find_entities', 'Search for entities in the workspace by type and/or text search. Returns matching entities with their IDs, names, and metadata.', {
|
|
@@ -96,13 +141,18 @@ server.tool('find_entities', 'Search for entities in the workspace by type and/o
|
|
|
96
141
|
search: z.string().optional().describe('Text search across entity names'),
|
|
97
142
|
limit: z.number().optional().describe('Max results to return (default varies by type)'),
|
|
98
143
|
}, async ({ organization_id, entity_type, search, limit }) => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
144
|
+
try {
|
|
145
|
+
const data = await apiPost('/api/v2/introspection/entities', {
|
|
146
|
+
organization_id,
|
|
147
|
+
entity_type,
|
|
148
|
+
search,
|
|
149
|
+
limit,
|
|
150
|
+
});
|
|
151
|
+
return { content: [{ type: 'text', text: resultText(data) }] };
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
155
|
+
}
|
|
106
156
|
});
|
|
107
157
|
// 6. Get schema ──────────────────────────────────────────────────────
|
|
108
158
|
server.tool('get_schema', 'Get the schema for entity types — describes fields, writable fields, and filterable fields. Use this to understand what parameters to pass when creating or updating entities.', {
|
|
@@ -110,27 +160,42 @@ server.tool('get_schema', 'Get the schema for entity types — describes fields,
|
|
|
110
160
|
entity_type: z.string().optional().describe('Specific entity type to get schema for (e.g. "task", "plan", "table")'),
|
|
111
161
|
entity_id: z.string().optional().describe('Specific entity ID to get schema for (useful for table records whose schema is defined per-table)'),
|
|
112
162
|
}, async ({ organization_id, entity_type, entity_id }) => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
163
|
+
try {
|
|
164
|
+
const data = await apiPost('/api/v2/introspection/schema', {
|
|
165
|
+
organization_id,
|
|
166
|
+
entity_type,
|
|
167
|
+
entity_id,
|
|
168
|
+
});
|
|
169
|
+
return { content: [{ type: 'text', text: resultText(data) }] };
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
173
|
+
}
|
|
119
174
|
});
|
|
120
175
|
// 7. Check permissions ───────────────────────────────────────────────
|
|
121
176
|
server.tool('check_permissions', 'Check which capabilities the current user has in an organization. Returns the user role and a list of all commands/queries with allowed/denied status.', {
|
|
122
177
|
organization_id: z.string().describe('Organization ID'),
|
|
123
178
|
}, async ({ organization_id }) => {
|
|
124
|
-
|
|
125
|
-
|
|
179
|
+
try {
|
|
180
|
+
const data = await apiPost('/api/v2/introspection/permissions', { organization_id });
|
|
181
|
+
return { content: [{ type: 'text', text: resultText(data) }] };
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
185
|
+
}
|
|
126
186
|
});
|
|
127
187
|
// 8. List my organizations ──────────────────────────────────────────
|
|
128
188
|
server.tool('list_my_organizations', 'List all organizations the authenticated user belongs to, with their role in each. Call this first to discover which organization_id to use for subsequent commands and queries.', {}, async () => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
189
|
+
try {
|
|
190
|
+
const data = await apiPost('/api/v2/query', {
|
|
191
|
+
type: 'list_my_organizations',
|
|
192
|
+
payload: {},
|
|
193
|
+
});
|
|
194
|
+
return { content: [{ type: 'text', text: resultText(data) }] };
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
return { content: [{ type: 'text', text: err.message }], isError: true };
|
|
198
|
+
}
|
|
134
199
|
});
|
|
135
200
|
// ── Start ───────────────────────────────────────────────────────────
|
|
136
201
|
async function main() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "checkbox-mcp-server",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "MCP server for the Checkbox capability API — lets AI assistants (Claude, Cursor, etc.) manage compliance plans, tasks, documents, and more through the Model Context Protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|