@mentagen/mcp 0.2.0 → 0.3.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.
@@ -1,10 +1,14 @@
1
1
  import { z } from 'zod';
2
2
  import { formatError } from '../utils/errors.js';
3
- import { generateId } from './create.js';
3
+ import { applyExtension, generateId } from './create.js';
4
4
  import { calculateNodeSize } from './size-calc.js';
5
5
  const nodeInputSchema = z.object({
6
6
  tempId: z.string().describe('Temporary ID for referencing in edges'),
7
7
  name: z.string().describe('The node title/name'),
8
+ extension: z
9
+ .string()
10
+ .optional()
11
+ .describe('File extension to append to name (e.g., ".ts", ".py"). Only applies to code nodes. Defaults to .js.'),
8
12
  content: z.string().optional().describe('Node content'),
9
13
  type: z
10
14
  .enum(['text', 'markdown', 'code', 'url'])
@@ -43,8 +47,9 @@ const DEFAULT_NODE_COLORS = {
43
47
  async function createNode(client, boardId, nodeInput, idMap) {
44
48
  const realId = generateId();
45
49
  const type = nodeInput.type ?? 'text';
50
+ const finalName = applyExtension(nodeInput.name, type, nodeInput.extension);
46
51
  const color = nodeInput.color ?? DEFAULT_NODE_COLORS[type];
47
- const autoSize = calculateNodeSize(nodeInput.name, type);
52
+ const autoSize = calculateNodeSize(finalName, type);
48
53
  const x = nodeInput.x ?? 100;
49
54
  const y = nodeInput.y ?? 100;
50
55
  const width = nodeInput.width ?? autoSize.width;
@@ -57,7 +62,7 @@ async function createNode(client, boardId, nodeInput, idMap) {
57
62
  _id: realId,
58
63
  boardId,
59
64
  node: {
60
- name: nodeInput.name,
65
+ name: finalName,
61
66
  ...(isCodeNode ? { code: nodeContent } : { content: nodeContent }),
62
67
  type,
63
68
  color,
@@ -27,9 +27,27 @@ const DEFAULT_NODE_COLORS = {
27
27
  excalidraw: 'teal',
28
28
  teleprompter: 'rose',
29
29
  };
30
+ const DEFAULT_CODE_EXTENSION = '.js';
31
+ /**
32
+ * Append extension to name for code nodes only.
33
+ * Defaults to .js if no extension provided.
34
+ * Avoids double extensions if name already ends with the extension.
35
+ */
36
+ export function applyExtension(name, type, extension) {
37
+ if (type !== 'code')
38
+ return name;
39
+ const ext = extension ?? DEFAULT_CODE_EXTENSION;
40
+ if (name.endsWith(ext))
41
+ return name;
42
+ return `${name}${ext}`;
43
+ }
30
44
  export const createSchema = z.object({
31
45
  boardId: z.string().describe('The board ID to create the node on'),
32
46
  name: z.string().describe('The node title/name'),
47
+ extension: z
48
+ .string()
49
+ .optional()
50
+ .describe('File extension to append to name (e.g., ".ts", ".py"). Only applies to code nodes. Defaults to .js.'),
33
51
  content: z
34
52
  .string()
35
53
  .optional()
@@ -77,6 +95,7 @@ export function generateId() {
77
95
  }
78
96
  /**
79
97
  * Build node fields object with content mapped to the correct field based on type.
98
+ * Expects params.name to already have extension applied.
80
99
  */
81
100
  function buildNodeFields(params, color, position) {
82
101
  const nodeFields = {
@@ -105,15 +124,16 @@ function buildNodeFields(params, color, position) {
105
124
  export async function handleCreate(client, params, mentagenUrl) {
106
125
  try {
107
126
  const _id = generateId();
127
+ const finalName = applyExtension(params.name, params.type, params.extension);
108
128
  const color = params.color || DEFAULT_NODE_COLORS[params.type];
109
- const autoSize = calculateNodeSize(params.name, params.type);
129
+ const autoSize = calculateNodeSize(finalName, params.type);
110
130
  const position = {
111
131
  x: snapToGrid(params.x ?? 96),
112
132
  y: snapToGrid(params.y ?? 96),
113
133
  width: snapToGrid(params.width ?? autoSize.width),
114
134
  height: snapToGrid(params.height ?? autoSize.height),
115
135
  };
116
- const nodeFields = buildNodeFields(params, color, position);
136
+ const nodeFields = buildNodeFields({ ...params, name: finalName }, color, position);
117
137
  const node = await client.addNode({
118
138
  _id,
119
139
  boardId: params.boardId,
@@ -231,7 +231,11 @@ export function registerTools(server, client, config) {
231
231
  },
232
232
  name: {
233
233
  type: 'string',
234
- 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.',
234
+ description: 'The node title/name (used for auto-sizing). Extension is appended automatically via the extension parameter.',
235
+ },
236
+ extension: {
237
+ type: 'string',
238
+ description: 'File extension to append to name (e.g., ".ts", ".py"). Only applies to code nodes. Defaults to .js.',
235
239
  },
236
240
  content: {
237
241
  type: 'string',
@@ -240,7 +244,7 @@ export function registerTools(server, client, config) {
240
244
  type: {
241
245
  type: 'string',
242
246
  enum: ['text', 'markdown', 'code', 'url'],
243
- description: 'Node type: text (default), markdown, code, or url. Code nodes get syntax highlighting based on the file extension in the name.',
247
+ description: 'Node type: text (default), markdown, code, or url.',
244
248
  },
245
249
  color: {
246
250
  type: 'string',
@@ -478,7 +482,11 @@ export function registerTools(server, client, config) {
478
482
  },
479
483
  name: {
480
484
  type: 'string',
481
- description: 'Node title/name (used for auto-sizing). For code nodes, use a filename with extension for syntax highlighting.',
485
+ description: 'Node title/name (used for auto-sizing). Extension is appended automatically via the extension parameter.',
486
+ },
487
+ extension: {
488
+ type: 'string',
489
+ description: 'File extension to append to name (e.g., ".ts", ".py"). Only applies to code nodes. Defaults to .js.',
482
490
  },
483
491
  content: {
484
492
  type: 'string',
@@ -487,7 +495,7 @@ export function registerTools(server, client, config) {
487
495
  type: {
488
496
  type: 'string',
489
497
  enum: ['text', 'markdown', 'code', 'url'],
490
- description: 'Node type (default: text). Code nodes get syntax highlighting based on file extension in name.',
498
+ description: 'Node type (default: text).',
491
499
  },
492
500
  color: { type: 'string', description: 'Node color' },
493
501
  x: { type: 'number', description: 'X position' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentagen/mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for Mentagen knowledge base integration with Cursor",
5
5
  "type": "module",
6
6
  "bin": "dist/index.js",