@mentagen/mcp 0.1.0
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 +100 -0
- package/dist/client/helene.js +178 -0
- package/dist/client/types.js +27 -0
- package/dist/index.js +26 -0
- package/dist/tools/batch-update.js +118 -0
- package/dist/tools/boards.js +50 -0
- package/dist/tools/check-collision.js +55 -0
- package/dist/tools/colors.js +35 -0
- package/dist/tools/create-board.js +50 -0
- package/dist/tools/create-edge.js +61 -0
- package/dist/tools/create-graph.js +174 -0
- package/dist/tools/create.js +152 -0
- package/dist/tools/delete-edge.js +36 -0
- package/dist/tools/delete.js +36 -0
- package/dist/tools/extract-board-content.js +207 -0
- package/dist/tools/find-position.js +117 -0
- package/dist/tools/grid-calc.js +205 -0
- package/dist/tools/index.js +940 -0
- package/dist/tools/link.js +22 -0
- package/dist/tools/list-edges.js +58 -0
- package/dist/tools/list-nodes.js +96 -0
- package/dist/tools/list-positions.js +64 -0
- package/dist/tools/node-types.js +65 -0
- package/dist/tools/patch-content.js +143 -0
- package/dist/tools/read.js +41 -0
- package/dist/tools/search-board.js +99 -0
- package/dist/tools/search-boards.js +50 -0
- package/dist/tools/search.js +89 -0
- package/dist/tools/size-calc.js +108 -0
- package/dist/tools/update-board.js +64 -0
- package/dist/tools/update-edge.js +63 -0
- package/dist/tools/update.js +157 -0
- package/dist/utils/collision.js +177 -0
- package/dist/utils/config.js +16 -0
- package/dist/utils/ejson.js +30 -0
- package/dist/utils/errors.js +16 -0
- package/dist/utils/formatting.js +15 -0
- package/dist/utils/urls.js +18 -0
- package/package.json +49 -0
|
@@ -0,0 +1,940 @@
|
|
|
1
|
+
// The SDK requires these Zod schemas for request handler registration.
|
|
2
|
+
// Using raw objects like { method: 'tools/list' } causes "Schema is missing
|
|
3
|
+
// a method literal" errors because the SDK validates against ZodLiteral types.
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { batchUpdateSchema, handleBatchUpdate } from './batch-update.js';
|
|
6
|
+
import { boardsSchema, handleBoards } from './boards.js';
|
|
7
|
+
import { checkCollisionSchema, handleCheckCollision, } from './check-collision.js';
|
|
8
|
+
import { colorsSchema, handleColors } from './colors.js';
|
|
9
|
+
import { createSchema, handleCreate } from './create.js';
|
|
10
|
+
import { createBoardSchema, handleCreateBoard } from './create-board.js';
|
|
11
|
+
import { createEdgeSchema, handleCreateEdge } from './create-edge.js';
|
|
12
|
+
import { createGraphSchema, handleCreateGraph } from './create-graph.js';
|
|
13
|
+
import { deleteSchema, handleDelete } from './delete.js';
|
|
14
|
+
import { deleteEdgeSchema, handleDeleteEdge } from './delete-edge.js';
|
|
15
|
+
import { extractBoardContentSchema, handleExtractBoardContent, } from './extract-board-content.js';
|
|
16
|
+
import { findPositionSchema, handleFindPosition } from './find-position.js';
|
|
17
|
+
import { gridCalcSchema, handleGridCalc } from './grid-calc.js';
|
|
18
|
+
import { handleLink, linkSchema } from './link.js';
|
|
19
|
+
import { handleListEdges, listEdgesSchema } from './list-edges.js';
|
|
20
|
+
import { handleListNodes, listNodesSchema } from './list-nodes.js';
|
|
21
|
+
import { handleListPositions, listPositionsSchema } from './list-positions.js';
|
|
22
|
+
import { handleNodeTypes, nodeTypesSchema } from './node-types.js';
|
|
23
|
+
import { handlePatchContent, patchContentSchema } from './patch-content.js';
|
|
24
|
+
import { handleRead, readSchema } from './read.js';
|
|
25
|
+
import { handleSearch, searchSchema } from './search.js';
|
|
26
|
+
import { handleSearchBoard, searchBoardSchema } from './search-board.js';
|
|
27
|
+
import { handleSearchBoards, searchBoardsSchema } from './search-boards.js';
|
|
28
|
+
import { handleSizeCalc, sizeCalcSchema } from './size-calc.js';
|
|
29
|
+
import { handleUpdate, updateSchema } from './update.js';
|
|
30
|
+
import { handleUpdateBoard, updateBoardSchema } from './update-board.js';
|
|
31
|
+
import { handleUpdateEdge, updateEdgeSchema } from './update-edge.js';
|
|
32
|
+
export function registerTools(server, client, config) {
|
|
33
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
34
|
+
tools: [
|
|
35
|
+
// Board tools
|
|
36
|
+
{
|
|
37
|
+
name: 'mentagen_list_boards',
|
|
38
|
+
description: 'List all boards you have access to in Mentagen. Returns board IDs, names, node counts, and direct links.',
|
|
39
|
+
inputSchema: {
|
|
40
|
+
type: 'object',
|
|
41
|
+
properties: {},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'mentagen_search_boards',
|
|
46
|
+
description: 'Search for boards by name. Returns matching boards with their ID, name, node count, last updated date, and direct links.',
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
query: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
description: 'Search query to filter boards by name',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
required: ['query'],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'mentagen_create_board',
|
|
60
|
+
description: 'Create a new board in Mentagen.',
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: {
|
|
64
|
+
name: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
description: 'The name for the new board',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
required: ['name'],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'mentagen_update_board',
|
|
74
|
+
description: 'Update a board name in Mentagen.',
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
boardId: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
description: 'The board ID to update',
|
|
81
|
+
},
|
|
82
|
+
name: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'New name for the board',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
required: ['boardId', 'name'],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
// Node tools
|
|
91
|
+
{
|
|
92
|
+
name: 'mentagen_list_nodes',
|
|
93
|
+
description: 'List all nodes in a board. Returns node ID, name, type, truncated content, and direct links. Use mentagen_read_node to get full content of a specific node.',
|
|
94
|
+
inputSchema: {
|
|
95
|
+
type: 'object',
|
|
96
|
+
properties: {
|
|
97
|
+
boardId: {
|
|
98
|
+
type: 'string',
|
|
99
|
+
description: 'The board ID to list nodes from',
|
|
100
|
+
},
|
|
101
|
+
limit: {
|
|
102
|
+
type: 'number',
|
|
103
|
+
description: 'Maximum number of nodes to return (default: 1000, max: 1000)',
|
|
104
|
+
default: 100,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
required: ['boardId'],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: 'mentagen_list_positions',
|
|
112
|
+
description: 'List node positions in a board. Returns minimal data (id, name, x, y, width, height) optimized for layout operations. Use this instead of list_nodes when you only need positioning info.',
|
|
113
|
+
inputSchema: {
|
|
114
|
+
type: 'object',
|
|
115
|
+
properties: {
|
|
116
|
+
boardId: {
|
|
117
|
+
type: 'string',
|
|
118
|
+
description: 'The board ID to list node positions from',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
required: ['boardId'],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'mentagen_extract_board_content',
|
|
126
|
+
description: 'Extract all textual content from a board as a single markdown document. ' +
|
|
127
|
+
'Each node is annotated with its ID, name, type, and link for easy reference. ' +
|
|
128
|
+
'Handles code nodes (code field) and text/markdown nodes (content field) automatically. ' +
|
|
129
|
+
'Use this to get a comprehensive view of all knowledge in a board.',
|
|
130
|
+
inputSchema: {
|
|
131
|
+
type: 'object',
|
|
132
|
+
properties: {
|
|
133
|
+
boardId: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
description: 'The board ID to extract content from',
|
|
136
|
+
},
|
|
137
|
+
includeEmpty: {
|
|
138
|
+
type: 'boolean',
|
|
139
|
+
description: 'Include nodes with no content (default: false)',
|
|
140
|
+
default: false,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
required: ['boardId'],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'mentagen_search_nodes',
|
|
148
|
+
description: 'Search for nodes across ALL your boards using semantic search. Returns matching nodes with truncated content previews and direct links. Use mentagen_search_board to search within a specific board, or mentagen_read_node with the node ID to retrieve full content.',
|
|
149
|
+
inputSchema: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
query: {
|
|
153
|
+
type: 'string',
|
|
154
|
+
description: 'The search query - can be a question or keywords',
|
|
155
|
+
},
|
|
156
|
+
board: {
|
|
157
|
+
type: 'string',
|
|
158
|
+
description: 'Optional board ID to limit search scope',
|
|
159
|
+
},
|
|
160
|
+
limit: {
|
|
161
|
+
type: 'number',
|
|
162
|
+
description: 'Maximum number of results (default: 10)',
|
|
163
|
+
default: 10,
|
|
164
|
+
},
|
|
165
|
+
semanticRatio: {
|
|
166
|
+
type: 'number',
|
|
167
|
+
description: 'Balance between semantic (1.0) and keyword (0.0) search',
|
|
168
|
+
default: 0.5,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
required: ['query'],
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'mentagen_search_board',
|
|
176
|
+
description: 'Search for nodes within a SPECIFIC board using semantic search. Use this when you know which board to search in. Returns matching nodes with truncated content previews and direct links. Use mentagen_read_node with the node ID to retrieve full content.',
|
|
177
|
+
inputSchema: {
|
|
178
|
+
type: 'object',
|
|
179
|
+
properties: {
|
|
180
|
+
boardId: {
|
|
181
|
+
type: 'string',
|
|
182
|
+
description: 'The board ID to search within (required)',
|
|
183
|
+
},
|
|
184
|
+
query: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
description: 'The search query - can be a question or keywords',
|
|
187
|
+
},
|
|
188
|
+
limit: {
|
|
189
|
+
type: 'number',
|
|
190
|
+
description: 'Maximum number of results (default: 10)',
|
|
191
|
+
default: 10,
|
|
192
|
+
},
|
|
193
|
+
semanticRatio: {
|
|
194
|
+
type: 'number',
|
|
195
|
+
description: 'Balance between semantic (1.0) and keyword (0.0) search',
|
|
196
|
+
default: 0.5,
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
required: ['boardId', 'query'],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'mentagen_read_node',
|
|
204
|
+
description: 'Read a single node by ID. Returns the full node content without truncation, unlike search results. Includes a direct link to the node.',
|
|
205
|
+
inputSchema: {
|
|
206
|
+
type: 'object',
|
|
207
|
+
properties: {
|
|
208
|
+
boardId: {
|
|
209
|
+
type: 'string',
|
|
210
|
+
description: 'The board ID containing the node',
|
|
211
|
+
},
|
|
212
|
+
nodeId: {
|
|
213
|
+
type: 'string',
|
|
214
|
+
description: 'The node ID to read',
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
required: ['boardId', 'nodeId'],
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: 'mentagen_create_node',
|
|
222
|
+
description: 'Create a new node on a Mentagen board. IMPORTANT: Do NOT provide width/height - let auto-sizing calculate dimensions from the name. Only provide explicit dimensions if the user specifically requests a custom size. Content does not affect size (it scrolls inside the node).',
|
|
223
|
+
inputSchema: {
|
|
224
|
+
type: 'object',
|
|
225
|
+
properties: {
|
|
226
|
+
boardId: {
|
|
227
|
+
type: 'string',
|
|
228
|
+
description: 'The board ID to create the node on',
|
|
229
|
+
},
|
|
230
|
+
name: {
|
|
231
|
+
type: 'string',
|
|
232
|
+
description: 'The node title/name (used for auto-sizing). For code nodes, use a filename with extension (e.g., "utils.ts", "app.py") for syntax highlighting.',
|
|
233
|
+
},
|
|
234
|
+
content: {
|
|
235
|
+
type: 'string',
|
|
236
|
+
description: 'Content for the node (scrollable, does NOT affect size)',
|
|
237
|
+
},
|
|
238
|
+
type: {
|
|
239
|
+
type: 'string',
|
|
240
|
+
enum: ['text', 'markdown', 'code', 'url'],
|
|
241
|
+
description: 'Node type: text (default), markdown, code, or url. Code nodes get syntax highlighting based on the file extension in the name.',
|
|
242
|
+
},
|
|
243
|
+
color: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
description: 'Optional color override. If not specified, uses default for type (markdown=cyan, code=indigo)',
|
|
246
|
+
},
|
|
247
|
+
x: {
|
|
248
|
+
type: 'number',
|
|
249
|
+
description: 'X position (snapped to 16px grid, default: 96)',
|
|
250
|
+
},
|
|
251
|
+
y: {
|
|
252
|
+
type: 'number',
|
|
253
|
+
description: 'Y position (snapped to 16px grid, default: 96)',
|
|
254
|
+
},
|
|
255
|
+
width: {
|
|
256
|
+
type: 'number',
|
|
257
|
+
description: 'DO NOT USE unless user requests specific size. Auto-calculated from name.',
|
|
258
|
+
},
|
|
259
|
+
height: {
|
|
260
|
+
type: 'number',
|
|
261
|
+
description: 'DO NOT USE unless user requests specific size. Auto-calculated from name.',
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
required: ['boardId', 'name'],
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: 'mentagen_update_node',
|
|
269
|
+
description: 'Update an existing node in Mentagen. When name changes, size auto-adjusts unless explicit width/height provided. Returns the final position and size.',
|
|
270
|
+
inputSchema: {
|
|
271
|
+
type: 'object',
|
|
272
|
+
properties: {
|
|
273
|
+
boardId: {
|
|
274
|
+
type: 'string',
|
|
275
|
+
description: 'The board ID containing the node',
|
|
276
|
+
},
|
|
277
|
+
nodeId: {
|
|
278
|
+
type: 'string',
|
|
279
|
+
description: 'The node ID to update',
|
|
280
|
+
},
|
|
281
|
+
name: {
|
|
282
|
+
type: 'string',
|
|
283
|
+
description: 'New name for the node',
|
|
284
|
+
},
|
|
285
|
+
content: {
|
|
286
|
+
type: 'string',
|
|
287
|
+
description: 'New content for the node',
|
|
288
|
+
},
|
|
289
|
+
color: {
|
|
290
|
+
type: 'string',
|
|
291
|
+
description: 'Node color name (use mentagen_colors to see available colors)',
|
|
292
|
+
},
|
|
293
|
+
x: {
|
|
294
|
+
type: 'number',
|
|
295
|
+
description: 'X position on the board canvas (multiple of 16)',
|
|
296
|
+
},
|
|
297
|
+
y: {
|
|
298
|
+
type: 'number',
|
|
299
|
+
description: 'Y position on the board canvas (multiple of 16)',
|
|
300
|
+
},
|
|
301
|
+
width: {
|
|
302
|
+
type: 'number',
|
|
303
|
+
description: 'Node width in pixels (multiple of 16)',
|
|
304
|
+
},
|
|
305
|
+
height: {
|
|
306
|
+
type: 'number',
|
|
307
|
+
description: 'Node height in pixels (multiple of 16)',
|
|
308
|
+
},
|
|
309
|
+
autoSize: {
|
|
310
|
+
type: 'boolean',
|
|
311
|
+
description: 'Auto-resize when name changes (default: true). Set false to keep current size.',
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
required: ['boardId', 'nodeId'],
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: 'mentagen_delete_node',
|
|
319
|
+
description: 'Delete a node from a Mentagen board. This is a soft delete and can be undone in the app.',
|
|
320
|
+
inputSchema: {
|
|
321
|
+
type: 'object',
|
|
322
|
+
properties: {
|
|
323
|
+
boardId: {
|
|
324
|
+
type: 'string',
|
|
325
|
+
description: 'The board ID containing the node',
|
|
326
|
+
},
|
|
327
|
+
nodeId: {
|
|
328
|
+
type: 'string',
|
|
329
|
+
description: 'The node ID to delete',
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
required: ['boardId', 'nodeId'],
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
name: 'mentagen_batch_update',
|
|
337
|
+
description: 'Update multiple nodes and/or edges in a single call. More efficient than individual updates for bulk operations like repositioning or restyling.',
|
|
338
|
+
inputSchema: {
|
|
339
|
+
type: 'object',
|
|
340
|
+
properties: {
|
|
341
|
+
boardId: {
|
|
342
|
+
type: 'string',
|
|
343
|
+
description: 'The board ID containing the items to update',
|
|
344
|
+
},
|
|
345
|
+
nodes: {
|
|
346
|
+
type: 'array',
|
|
347
|
+
description: 'Array of node updates',
|
|
348
|
+
items: {
|
|
349
|
+
type: 'object',
|
|
350
|
+
properties: {
|
|
351
|
+
nodeId: { type: 'string', description: 'The node ID' },
|
|
352
|
+
name: { type: 'string', description: 'New name' },
|
|
353
|
+
content: { type: 'string', description: 'New content' },
|
|
354
|
+
color: { type: 'string', description: 'Node color' },
|
|
355
|
+
x: { type: 'number', description: 'X position' },
|
|
356
|
+
y: { type: 'number', description: 'Y position' },
|
|
357
|
+
width: { type: 'number', description: 'Width' },
|
|
358
|
+
height: { type: 'number', description: 'Height' },
|
|
359
|
+
},
|
|
360
|
+
required: ['nodeId'],
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
edges: {
|
|
364
|
+
type: 'array',
|
|
365
|
+
description: 'Array of edge updates',
|
|
366
|
+
items: {
|
|
367
|
+
type: 'object',
|
|
368
|
+
properties: {
|
|
369
|
+
edgeId: { type: 'string', description: 'The edge ID' },
|
|
370
|
+
direction: {
|
|
371
|
+
type: 'string',
|
|
372
|
+
enum: ['none', 'source', 'target'],
|
|
373
|
+
description: 'Arrow direction',
|
|
374
|
+
},
|
|
375
|
+
label: { type: 'string', description: 'Edge label' },
|
|
376
|
+
},
|
|
377
|
+
required: ['edgeId'],
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
required: ['boardId'],
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: 'mentagen_patch_content',
|
|
386
|
+
description: 'Apply targeted patches to node content without sending the full text. ' +
|
|
387
|
+
'Use this instead of mentagen_update_node for efficient edits that save tokens. ' +
|
|
388
|
+
'Automatically uses the correct field (content for markdown/text, code for code nodes). ' +
|
|
389
|
+
'Operations: replace (find unique string and replace), prepend (add to start), append (add to end).',
|
|
390
|
+
inputSchema: {
|
|
391
|
+
type: 'object',
|
|
392
|
+
properties: {
|
|
393
|
+
boardId: {
|
|
394
|
+
type: 'string',
|
|
395
|
+
description: 'The board ID containing the node',
|
|
396
|
+
},
|
|
397
|
+
nodeId: {
|
|
398
|
+
type: 'string',
|
|
399
|
+
description: 'The node ID to patch',
|
|
400
|
+
},
|
|
401
|
+
operations: {
|
|
402
|
+
type: 'array',
|
|
403
|
+
description: 'Array of patch operations to apply sequentially',
|
|
404
|
+
items: {
|
|
405
|
+
oneOf: [
|
|
406
|
+
{
|
|
407
|
+
type: 'object',
|
|
408
|
+
description: 'Replace a unique string with new text',
|
|
409
|
+
properties: {
|
|
410
|
+
type: { const: 'replace' },
|
|
411
|
+
oldString: {
|
|
412
|
+
type: 'string',
|
|
413
|
+
description: 'Text to find (must be unique unless replaceAll is true). Include surrounding context if needed.',
|
|
414
|
+
},
|
|
415
|
+
newString: {
|
|
416
|
+
type: 'string',
|
|
417
|
+
description: 'Replacement text',
|
|
418
|
+
},
|
|
419
|
+
replaceAll: {
|
|
420
|
+
type: 'boolean',
|
|
421
|
+
description: 'Replace all occurrences instead of requiring uniqueness (default: false)',
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
required: ['type', 'oldString', 'newString'],
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
type: 'object',
|
|
428
|
+
description: 'Add content at the beginning',
|
|
429
|
+
properties: {
|
|
430
|
+
type: { const: 'prepend' },
|
|
431
|
+
content: {
|
|
432
|
+
type: 'string',
|
|
433
|
+
description: 'Content to add at the start',
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
required: ['type', 'content'],
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
type: 'object',
|
|
440
|
+
description: 'Add content at the end',
|
|
441
|
+
properties: {
|
|
442
|
+
type: { const: 'append' },
|
|
443
|
+
content: {
|
|
444
|
+
type: 'string',
|
|
445
|
+
description: 'Content to add at the end',
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
required: ['type', 'content'],
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
required: ['boardId', 'nodeId', 'operations'],
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
name: 'mentagen_create_graph',
|
|
459
|
+
description: 'Create multiple nodes with edges in a single call. IMPORTANT: Do NOT provide width/height for nodes - let auto-sizing calculate dimensions from names. Only provide explicit dimensions if the user specifically requests custom sizes.',
|
|
460
|
+
inputSchema: {
|
|
461
|
+
type: 'object',
|
|
462
|
+
properties: {
|
|
463
|
+
boardId: {
|
|
464
|
+
type: 'string',
|
|
465
|
+
description: 'The board ID to create the graph on',
|
|
466
|
+
},
|
|
467
|
+
nodes: {
|
|
468
|
+
type: 'array',
|
|
469
|
+
description: 'Array of nodes to create',
|
|
470
|
+
items: {
|
|
471
|
+
type: 'object',
|
|
472
|
+
properties: {
|
|
473
|
+
tempId: {
|
|
474
|
+
type: 'string',
|
|
475
|
+
description: 'Temporary ID for referencing in edges',
|
|
476
|
+
},
|
|
477
|
+
name: {
|
|
478
|
+
type: 'string',
|
|
479
|
+
description: 'Node title/name (used for auto-sizing). For code nodes, use a filename with extension for syntax highlighting.',
|
|
480
|
+
},
|
|
481
|
+
content: {
|
|
482
|
+
type: 'string',
|
|
483
|
+
description: 'Node content (scrollable, does NOT affect size)',
|
|
484
|
+
},
|
|
485
|
+
type: {
|
|
486
|
+
type: 'string',
|
|
487
|
+
enum: ['text', 'markdown', 'code', 'url'],
|
|
488
|
+
description: 'Node type (default: text). Code nodes get syntax highlighting based on file extension in name.',
|
|
489
|
+
},
|
|
490
|
+
color: { type: 'string', description: 'Node color' },
|
|
491
|
+
x: { type: 'number', description: 'X position' },
|
|
492
|
+
y: { type: 'number', description: 'Y position' },
|
|
493
|
+
width: {
|
|
494
|
+
type: 'number',
|
|
495
|
+
description: 'DO NOT USE - auto-calculated from name',
|
|
496
|
+
},
|
|
497
|
+
height: {
|
|
498
|
+
type: 'number',
|
|
499
|
+
description: 'DO NOT USE - auto-calculated from name',
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
required: ['tempId', 'name'],
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
edges: {
|
|
506
|
+
type: 'array',
|
|
507
|
+
description: 'Array of edges connecting nodes by tempId',
|
|
508
|
+
items: {
|
|
509
|
+
type: 'object',
|
|
510
|
+
properties: {
|
|
511
|
+
source: {
|
|
512
|
+
type: 'string',
|
|
513
|
+
description: 'Source node tempId',
|
|
514
|
+
},
|
|
515
|
+
target: {
|
|
516
|
+
type: 'string',
|
|
517
|
+
description: 'Target node tempId',
|
|
518
|
+
},
|
|
519
|
+
direction: {
|
|
520
|
+
type: 'string',
|
|
521
|
+
enum: ['none', 'source', 'target'],
|
|
522
|
+
description: 'Arrow direction',
|
|
523
|
+
},
|
|
524
|
+
label: { type: 'string', description: 'Edge label' },
|
|
525
|
+
},
|
|
526
|
+
required: ['source', 'target'],
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
},
|
|
530
|
+
required: ['boardId', 'nodes'],
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
// Edge tools
|
|
534
|
+
{
|
|
535
|
+
name: 'mentagen_list_edges',
|
|
536
|
+
description: 'List all edges (connections) in a board. Returns edge ID, source node, target node, direction, and label.',
|
|
537
|
+
inputSchema: {
|
|
538
|
+
type: 'object',
|
|
539
|
+
properties: {
|
|
540
|
+
boardId: {
|
|
541
|
+
type: 'string',
|
|
542
|
+
description: 'The board ID to list edges from',
|
|
543
|
+
},
|
|
544
|
+
limit: {
|
|
545
|
+
type: 'number',
|
|
546
|
+
description: 'Maximum number of edges to return (default: 1000, max: 1000)',
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
required: ['boardId'],
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
name: 'mentagen_create_edge',
|
|
554
|
+
description: 'Create an edge (connection) between two nodes. IMPORTANT: Connected nodes should have at least 96px gap between them for visual clarity.',
|
|
555
|
+
inputSchema: {
|
|
556
|
+
type: 'object',
|
|
557
|
+
properties: {
|
|
558
|
+
boardId: {
|
|
559
|
+
type: 'string',
|
|
560
|
+
description: 'The board ID where the edge will be created',
|
|
561
|
+
},
|
|
562
|
+
source: {
|
|
563
|
+
type: 'string',
|
|
564
|
+
description: 'The source node ID',
|
|
565
|
+
},
|
|
566
|
+
target: {
|
|
567
|
+
type: 'string',
|
|
568
|
+
description: 'The target node ID',
|
|
569
|
+
},
|
|
570
|
+
direction: {
|
|
571
|
+
type: 'string',
|
|
572
|
+
enum: ['none', 'source', 'target'],
|
|
573
|
+
description: 'Arrow direction: "none" (no arrow, default), "source" (arrow points to source), "target" (arrow points to target)',
|
|
574
|
+
},
|
|
575
|
+
},
|
|
576
|
+
required: ['boardId', 'source', 'target'],
|
|
577
|
+
},
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
name: 'mentagen_update_edge',
|
|
581
|
+
description: 'Update an edge direction or label. Direction controls arrow display: "none" (no arrow), "source" (arrow points to source), "target" (arrow points to target).',
|
|
582
|
+
inputSchema: {
|
|
583
|
+
type: 'object',
|
|
584
|
+
properties: {
|
|
585
|
+
boardId: {
|
|
586
|
+
type: 'string',
|
|
587
|
+
description: 'The board ID containing the edge',
|
|
588
|
+
},
|
|
589
|
+
edgeId: {
|
|
590
|
+
type: 'string',
|
|
591
|
+
description: 'The edge ID to update',
|
|
592
|
+
},
|
|
593
|
+
direction: {
|
|
594
|
+
type: 'string',
|
|
595
|
+
enum: ['none', 'source', 'target'],
|
|
596
|
+
description: 'Edge direction: none (no arrow), source (arrow to source), target (arrow to target)',
|
|
597
|
+
},
|
|
598
|
+
label: {
|
|
599
|
+
type: 'string',
|
|
600
|
+
description: 'Optional label text for the edge',
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
required: ['boardId', 'edgeId'],
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
name: 'mentagen_delete_edge',
|
|
608
|
+
description: 'Delete an edge from a Mentagen board. This is a soft delete and can be undone in the app.',
|
|
609
|
+
inputSchema: {
|
|
610
|
+
type: 'object',
|
|
611
|
+
properties: {
|
|
612
|
+
boardId: {
|
|
613
|
+
type: 'string',
|
|
614
|
+
description: 'The board ID containing the edge',
|
|
615
|
+
},
|
|
616
|
+
edgeId: {
|
|
617
|
+
type: 'string',
|
|
618
|
+
description: 'The edge ID to delete',
|
|
619
|
+
},
|
|
620
|
+
},
|
|
621
|
+
required: ['boardId', 'edgeId'],
|
|
622
|
+
},
|
|
623
|
+
},
|
|
624
|
+
// Utility tools
|
|
625
|
+
{
|
|
626
|
+
name: 'mentagen_link',
|
|
627
|
+
description: 'Generate a URL link to a Mentagen board or a specific node. Use this to create shareable links.',
|
|
628
|
+
inputSchema: {
|
|
629
|
+
type: 'object',
|
|
630
|
+
properties: {
|
|
631
|
+
boardId: {
|
|
632
|
+
type: 'string',
|
|
633
|
+
description: 'The board ID',
|
|
634
|
+
},
|
|
635
|
+
nodeId: {
|
|
636
|
+
type: 'string',
|
|
637
|
+
description: 'Optional node ID to link directly to a specific node',
|
|
638
|
+
},
|
|
639
|
+
},
|
|
640
|
+
required: ['boardId'],
|
|
641
|
+
},
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
name: 'mentagen_colors',
|
|
645
|
+
description: 'Get the list of available colors for nodes. Returns color names and their RGB values.',
|
|
646
|
+
inputSchema: {
|
|
647
|
+
type: 'object',
|
|
648
|
+
properties: {},
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
name: 'mentagen_node_types',
|
|
653
|
+
description: 'Get the list of supported node types with descriptions and usage guidance. Use this to understand what types of nodes can be created.',
|
|
654
|
+
inputSchema: {
|
|
655
|
+
type: 'object',
|
|
656
|
+
properties: {},
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
name: 'mentagen_grid_calc',
|
|
661
|
+
description: 'Math helper for calculating node positions on the 16px grid. Use gap=96+ for connected nodes, gap=16 for unrelated nodes. Operations: "snap" rounds to 16px, "next_x"/"next_y" calculate position after a node, "grid_units" converts units to pixels.',
|
|
662
|
+
inputSchema: {
|
|
663
|
+
type: 'object',
|
|
664
|
+
properties: {
|
|
665
|
+
operation: {
|
|
666
|
+
type: 'string',
|
|
667
|
+
enum: ['snap', 'next_x', 'next_y', 'grid_units'],
|
|
668
|
+
description: 'The calculation operation to perform',
|
|
669
|
+
},
|
|
670
|
+
value: {
|
|
671
|
+
type: 'number',
|
|
672
|
+
description: 'Value to snap to the grid (for snap operation)',
|
|
673
|
+
},
|
|
674
|
+
position: {
|
|
675
|
+
type: 'number',
|
|
676
|
+
description: 'Current x or y position (for next_x/next_y operations)',
|
|
677
|
+
},
|
|
678
|
+
size: {
|
|
679
|
+
type: 'number',
|
|
680
|
+
description: 'Width or height of the current node (for next_x/next_y)',
|
|
681
|
+
},
|
|
682
|
+
gap: {
|
|
683
|
+
type: 'number',
|
|
684
|
+
description: 'Gap in pixels. Use 96+ for connected nodes, 16 for unrelated (default: 16)',
|
|
685
|
+
},
|
|
686
|
+
units: {
|
|
687
|
+
type: 'number',
|
|
688
|
+
description: 'Number of grid units to convert to pixels (for grid_units)',
|
|
689
|
+
},
|
|
690
|
+
boardId: {
|
|
691
|
+
type: 'string',
|
|
692
|
+
description: 'Optional: Board ID for collision checking (requires nodeWidth and nodeHeight)',
|
|
693
|
+
},
|
|
694
|
+
nodeWidth: {
|
|
695
|
+
type: 'number',
|
|
696
|
+
description: 'Width of node being placed (required with boardId)',
|
|
697
|
+
},
|
|
698
|
+
nodeHeight: {
|
|
699
|
+
type: 'number',
|
|
700
|
+
description: 'Height of node being placed (required with boardId)',
|
|
701
|
+
},
|
|
702
|
+
nodeY: {
|
|
703
|
+
type: 'number',
|
|
704
|
+
description: 'Y position of node (for next_x collision check)',
|
|
705
|
+
},
|
|
706
|
+
nodeX: {
|
|
707
|
+
type: 'number',
|
|
708
|
+
description: 'X position of node (for next_y collision check)',
|
|
709
|
+
},
|
|
710
|
+
excludeNodeId: {
|
|
711
|
+
type: 'string',
|
|
712
|
+
description: 'Node ID to exclude from collision check',
|
|
713
|
+
},
|
|
714
|
+
},
|
|
715
|
+
required: ['operation'],
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
name: 'mentagen_check_collision',
|
|
720
|
+
description: 'Check if a rectangle would collide with existing nodes on a board. Use this to validate positions before creating or moving nodes.',
|
|
721
|
+
inputSchema: {
|
|
722
|
+
type: 'object',
|
|
723
|
+
properties: {
|
|
724
|
+
boardId: {
|
|
725
|
+
type: 'string',
|
|
726
|
+
description: 'The board ID to check against',
|
|
727
|
+
},
|
|
728
|
+
x: {
|
|
729
|
+
type: 'number',
|
|
730
|
+
description: 'Left position of the rectangle',
|
|
731
|
+
},
|
|
732
|
+
y: {
|
|
733
|
+
type: 'number',
|
|
734
|
+
description: 'Top position of the rectangle',
|
|
735
|
+
},
|
|
736
|
+
width: {
|
|
737
|
+
type: 'number',
|
|
738
|
+
description: 'Width of the rectangle',
|
|
739
|
+
},
|
|
740
|
+
height: {
|
|
741
|
+
type: 'number',
|
|
742
|
+
description: 'Height of the rectangle',
|
|
743
|
+
},
|
|
744
|
+
excludeNodeId: {
|
|
745
|
+
type: 'string',
|
|
746
|
+
description: 'Optional node ID to exclude from check (for move operations)',
|
|
747
|
+
},
|
|
748
|
+
},
|
|
749
|
+
required: ['boardId', 'x', 'y', 'width', 'height'],
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
name: 'mentagen_find_position',
|
|
754
|
+
description: 'Find a valid non-colliding position for a new node. IMPORTANT: Use gap=96 or more when nodes will be connected by edges, otherwise gap=16 is fine for unrelated nodes.',
|
|
755
|
+
inputSchema: {
|
|
756
|
+
type: 'object',
|
|
757
|
+
properties: {
|
|
758
|
+
boardId: {
|
|
759
|
+
type: 'string',
|
|
760
|
+
description: 'The board ID to search',
|
|
761
|
+
},
|
|
762
|
+
width: {
|
|
763
|
+
type: 'number',
|
|
764
|
+
description: 'Width of the node to place',
|
|
765
|
+
},
|
|
766
|
+
height: {
|
|
767
|
+
type: 'number',
|
|
768
|
+
description: 'Height of the node to place',
|
|
769
|
+
},
|
|
770
|
+
anchorNodeId: {
|
|
771
|
+
type: 'string',
|
|
772
|
+
description: 'Optional node ID to place relative to',
|
|
773
|
+
},
|
|
774
|
+
direction: {
|
|
775
|
+
type: 'string',
|
|
776
|
+
enum: ['right', 'below', 'left', 'above'],
|
|
777
|
+
description: 'Search direction from anchor or start (default: right)',
|
|
778
|
+
},
|
|
779
|
+
gap: {
|
|
780
|
+
type: 'number',
|
|
781
|
+
description: 'Gap between nodes in pixels. Use 96+ for connected nodes (edges), 16 for unrelated nodes',
|
|
782
|
+
},
|
|
783
|
+
startX: {
|
|
784
|
+
type: 'number',
|
|
785
|
+
description: 'Explicit start X (ignored if anchorNodeId provided)',
|
|
786
|
+
},
|
|
787
|
+
startY: {
|
|
788
|
+
type: 'number',
|
|
789
|
+
description: 'Explicit start Y (ignored if anchorNodeId provided)',
|
|
790
|
+
},
|
|
791
|
+
},
|
|
792
|
+
required: ['boardId', 'width', 'height'],
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
name: 'mentagen_size_calc',
|
|
797
|
+
description: 'Calculate recommended node dimensions based on name and type. Returns width and height values (multiples of 16) sized to fit the title. Content is intentionally ignored — nodes are sized for their title with content scrollable inside.',
|
|
798
|
+
inputSchema: {
|
|
799
|
+
type: 'object',
|
|
800
|
+
properties: {
|
|
801
|
+
name: {
|
|
802
|
+
type: 'string',
|
|
803
|
+
description: 'The node name/title to measure',
|
|
804
|
+
},
|
|
805
|
+
type: {
|
|
806
|
+
type: 'string',
|
|
807
|
+
description: 'Node type (text, markdown, code, url) - affects icon space',
|
|
808
|
+
},
|
|
809
|
+
},
|
|
810
|
+
required: ['name'],
|
|
811
|
+
},
|
|
812
|
+
},
|
|
813
|
+
],
|
|
814
|
+
}));
|
|
815
|
+
const toolHandlers = {
|
|
816
|
+
// Board handlers
|
|
817
|
+
mentagen_list_boards: async (args) => {
|
|
818
|
+
const params = boardsSchema.parse(args);
|
|
819
|
+
return handleBoards(client, params, config.mentagenUrl);
|
|
820
|
+
},
|
|
821
|
+
mentagen_search_boards: async (args) => {
|
|
822
|
+
const params = searchBoardsSchema.parse(args);
|
|
823
|
+
return handleSearchBoards(client, params, config.mentagenUrl);
|
|
824
|
+
},
|
|
825
|
+
mentagen_create_board: async (args) => {
|
|
826
|
+
const params = createBoardSchema.parse(args);
|
|
827
|
+
return handleCreateBoard(client, params, config.mentagenUrl);
|
|
828
|
+
},
|
|
829
|
+
mentagen_update_board: async (args) => {
|
|
830
|
+
const params = updateBoardSchema.parse(args);
|
|
831
|
+
return handleUpdateBoard(client, params, config.mentagenUrl);
|
|
832
|
+
},
|
|
833
|
+
// Node handlers
|
|
834
|
+
mentagen_list_nodes: async (args) => {
|
|
835
|
+
const params = listNodesSchema.parse(args);
|
|
836
|
+
return handleListNodes(client, params, config.mentagenUrl);
|
|
837
|
+
},
|
|
838
|
+
mentagen_list_positions: async (args) => {
|
|
839
|
+
const params = listPositionsSchema.parse(args);
|
|
840
|
+
return handleListPositions(client, params);
|
|
841
|
+
},
|
|
842
|
+
mentagen_extract_board_content: async (args) => {
|
|
843
|
+
const params = extractBoardContentSchema.parse(args);
|
|
844
|
+
return handleExtractBoardContent(client, params, config.mentagenUrl);
|
|
845
|
+
},
|
|
846
|
+
mentagen_search_nodes: async (args) => {
|
|
847
|
+
const params = searchSchema.parse(args);
|
|
848
|
+
return handleSearch(client, params, config.mentagenUrl);
|
|
849
|
+
},
|
|
850
|
+
mentagen_search_board: async (args) => {
|
|
851
|
+
const params = searchBoardSchema.parse(args);
|
|
852
|
+
return handleSearchBoard(client, params, config.mentagenUrl);
|
|
853
|
+
},
|
|
854
|
+
mentagen_read_node: async (args) => {
|
|
855
|
+
const params = readSchema.parse(args);
|
|
856
|
+
return handleRead(client, params, config.mentagenUrl);
|
|
857
|
+
},
|
|
858
|
+
mentagen_create_node: async (args) => {
|
|
859
|
+
const params = createSchema.parse(args);
|
|
860
|
+
return handleCreate(client, params, config.mentagenUrl);
|
|
861
|
+
},
|
|
862
|
+
mentagen_update_node: async (args) => {
|
|
863
|
+
const params = updateSchema.parse(args);
|
|
864
|
+
return handleUpdate(client, params);
|
|
865
|
+
},
|
|
866
|
+
mentagen_delete_node: async (args) => {
|
|
867
|
+
const params = deleteSchema.parse(args);
|
|
868
|
+
return handleDelete(client, params);
|
|
869
|
+
},
|
|
870
|
+
mentagen_batch_update: async (args) => {
|
|
871
|
+
const params = batchUpdateSchema.parse(args);
|
|
872
|
+
return handleBatchUpdate(client, params);
|
|
873
|
+
},
|
|
874
|
+
mentagen_patch_content: async (args) => {
|
|
875
|
+
const params = patchContentSchema.parse(args);
|
|
876
|
+
return handlePatchContent(client, params);
|
|
877
|
+
},
|
|
878
|
+
mentagen_create_graph: async (args) => {
|
|
879
|
+
const params = createGraphSchema.parse(args);
|
|
880
|
+
return handleCreateGraph(client, params);
|
|
881
|
+
},
|
|
882
|
+
// Edge handlers
|
|
883
|
+
mentagen_list_edges: async (args) => {
|
|
884
|
+
const params = listEdgesSchema.parse(args);
|
|
885
|
+
return handleListEdges(client, params);
|
|
886
|
+
},
|
|
887
|
+
mentagen_create_edge: async (args) => {
|
|
888
|
+
const params = createEdgeSchema.parse(args);
|
|
889
|
+
return handleCreateEdge(client, params);
|
|
890
|
+
},
|
|
891
|
+
mentagen_update_edge: async (args) => {
|
|
892
|
+
const params = updateEdgeSchema.parse(args);
|
|
893
|
+
return handleUpdateEdge(client, params);
|
|
894
|
+
},
|
|
895
|
+
mentagen_delete_edge: async (args) => {
|
|
896
|
+
const params = deleteEdgeSchema.parse(args);
|
|
897
|
+
return handleDeleteEdge(client, params);
|
|
898
|
+
},
|
|
899
|
+
// Utility handlers
|
|
900
|
+
mentagen_link: async (args) => {
|
|
901
|
+
const params = linkSchema.parse(args);
|
|
902
|
+
return handleLink(params, config);
|
|
903
|
+
},
|
|
904
|
+
mentagen_colors: async (args) => {
|
|
905
|
+
colorsSchema.parse(args);
|
|
906
|
+
return handleColors();
|
|
907
|
+
},
|
|
908
|
+
mentagen_node_types: async (args) => {
|
|
909
|
+
nodeTypesSchema.parse(args);
|
|
910
|
+
return handleNodeTypes();
|
|
911
|
+
},
|
|
912
|
+
mentagen_grid_calc: async (args) => {
|
|
913
|
+
const params = gridCalcSchema.parse(args);
|
|
914
|
+
return handleGridCalc(params, client);
|
|
915
|
+
},
|
|
916
|
+
mentagen_check_collision: async (args) => {
|
|
917
|
+
const params = checkCollisionSchema.parse(args);
|
|
918
|
+
return handleCheckCollision(client, params);
|
|
919
|
+
},
|
|
920
|
+
mentagen_find_position: async (args) => {
|
|
921
|
+
const params = findPositionSchema.parse(args);
|
|
922
|
+
return handleFindPosition(client, params);
|
|
923
|
+
},
|
|
924
|
+
mentagen_size_calc: async (args) => {
|
|
925
|
+
const params = sizeCalcSchema.parse(args);
|
|
926
|
+
return handleSizeCalc(params);
|
|
927
|
+
},
|
|
928
|
+
};
|
|
929
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
930
|
+
const { name, arguments: args } = request.params;
|
|
931
|
+
const handler = toolHandlers[name];
|
|
932
|
+
if (!handler) {
|
|
933
|
+
return {
|
|
934
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
|
|
935
|
+
isError: true,
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
return handler(args);
|
|
939
|
+
});
|
|
940
|
+
}
|