add_canvas_node
Add nodes to Obsidian canvases including files, text, links, or groups with specified position and dimensions to organize visual knowledge structures.
Instructions
Add a node to canvas (file, text, link, or group)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| canvasPath | Yes | Path to canvas file | |
| color | No | Node color (1-6) | |
| file | No | File path (for file nodes) | |
| height | Yes | Node height | |
| label | No | Label (for group nodes) | |
| nodeType | Yes | Type of node | |
| text | No | Text content (for text nodes) | |
| url | No | URL (for link nodes) | |
| vault | Yes | Vault name | |
| width | Yes | Node width | |
| x | Yes | X coordinate | |
| y | Yes | Y coordinate |
Implementation Reference
- src/index.ts:239-260 (registration)Registration of the 'add_canvas_node' tool in the ListTools handler, including full input schema definition.{ name: 'add_canvas_node', description: 'Add a node to canvas (file, text, link, or group)', inputSchema: { type: 'object', properties: { vault: { type: 'string', description: 'Vault name' }, canvasPath: { type: 'string', description: 'Path to canvas file' }, nodeType: { type: 'string', enum: ['file', 'text', 'link', 'group'], description: 'Type of node' }, x: { type: 'number', description: 'X coordinate' }, y: { type: 'number', description: 'Y coordinate' }, width: { type: 'number', description: 'Node width' }, height: { type: 'number', description: 'Node height' }, file: { type: 'string', description: 'File path (for file nodes)' }, text: { type: 'string', description: 'Text content (for text nodes)' }, url: { type: 'string', description: 'URL (for link nodes)' }, label: { type: 'string', description: 'Label (for group nodes)' }, color: { type: 'string', description: 'Node color (1-6)' }, }, required: ['vault', 'canvasPath', 'nodeType', 'x', 'y', 'width', 'height'], }, },
- src/index.ts:663-713 (handler)Handler for 'add_canvas_node' tool call in the main switch statement, dispatching to CanvasService based on nodeType.case 'add_canvas_node': { const connector = this.connectors.get(args?.vault as string); if (!connector || !connector.vaultPath) { throw new Error(`Vault "${args?.vault}" not found or not a local vault`); } const nodeType = args?.nodeType as string; const canvasPath = args?.canvasPath as string; const commonOpts = { x: args?.x as number, y: args?.y as number, width: args?.width as number, height: args?.height as number, color: args?.color as any, }; let result; switch (nodeType) { case 'file': result = await this.canvasService.addFileNode(connector.vaultPath, canvasPath, { ...commonOpts, file: args?.file as string, subpath: args?.subpath as string | undefined, }); break; case 'text': result = await this.canvasService.addTextNode(connector.vaultPath, canvasPath, { ...commonOpts, text: args?.text as string, }); break; case 'link': result = await this.canvasService.addLinkNode(connector.vaultPath, canvasPath, { ...commonOpts, url: args?.url as string, }); break; case 'group': result = await this.canvasService.addGroupNode(connector.vaultPath, canvasPath, { ...commonOpts, label: args?.label as string | undefined, }); break; default: throw new Error(`Unknown node type: ${nodeType}`); } return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; }
- Core implementation for adding file nodes to canvas (one of four node types). Reads canvas, adds node, writes back.async addFileNode( vaultPath: string, canvasPath: string, options: CreateFileNodeOptions ): Promise<VaultOperationResult<CanvasFileNode>> { const canvasResult = await this.readCanvas(vaultPath, canvasPath); if (!canvasResult.success || !canvasResult.data) { return { success: false, error: canvasResult.error }; } const node: CanvasFileNode = { id: options.id || this.generateId(), type: 'file', file: options.file, subpath: options.subpath, x: options.x, y: options.y, width: options.width, height: options.height, color: options.color }; canvasResult.data.nodes.push(node); const writeResult = await this.writeCanvas(vaultPath, canvasPath, canvasResult.data); if (!writeResult.success) { return { success: false, error: writeResult.error }; } return { success: true, data: node }; }
- Core implementation for adding text nodes to canvas.async addTextNode( vaultPath: string, canvasPath: string, options: CreateTextNodeOptions ): Promise<VaultOperationResult<CanvasTextNode>> { const canvasResult = await this.readCanvas(vaultPath, canvasPath); if (!canvasResult.success || !canvasResult.data) { return { success: false, error: canvasResult.error }; } const node: CanvasTextNode = { id: options.id || this.generateId(), type: 'text', text: options.text, x: options.x, y: options.y, width: options.width, height: options.height, color: options.color }; canvasResult.data.nodes.push(node); const writeResult = await this.writeCanvas(vaultPath, canvasPath, canvasResult.data); if (!writeResult.success) { return { success: false, error: writeResult.error }; } return { success: true, data: node }; }
- Core implementation for adding link nodes to canvas.async addLinkNode( vaultPath: string, canvasPath: string, options: CreateLinkNodeOptions ): Promise<VaultOperationResult<CanvasLinkNode>> { const canvasResult = await this.readCanvas(vaultPath, canvasPath); if (!canvasResult.success || !canvasResult.data) { return { success: false, error: canvasResult.error }; } const node: CanvasLinkNode = { id: options.id || this.generateId(), type: 'link', url: options.url, x: options.x, y: options.y, width: options.width, height: options.height, color: options.color }; canvasResult.data.nodes.push(node); const writeResult = await this.writeCanvas(vaultPath, canvasPath, canvasResult.data); if (!writeResult.success) { return { success: false, error: writeResult.error }; } return { success: true, data: node }; }