roam_add_todo
Add todo items as individual blocks to today's daily page in Roam Research, creating actionable tasks with todo status for each item.
Instructions
Add a list of todo items as individual blocks to today's daily page in Roam. Each item becomes its own actionable block with todo status. NOTE on Roam-flavored markdown: For direct linking: use [[link]] syntax. For aliased linking, use alias syntax. Do not concatenate words in links/hashtags - correct: #[[multiple words]] #self-esteem (for typically hyphenated words). IMPORTANT: Before using this tool, ensure that you have loaded into context the 'Roam Markdown Cheatsheet' resource.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| todos | Yes | List of todo items to add |
Implementation Reference
- src/tools/operations/todos.ts:8-69 (handler)Core handler implementation for roam_add_todo: adds todo items as individual TODO blocks to today's daily page, creating the page if necessary.async addTodos(todos: string[]): Promise<{ success: boolean }> { if (!Array.isArray(todos) || todos.length === 0) { throw new McpError( ErrorCode.InvalidRequest, 'todos must be a non-empty array' ); } // Get today's date const today = new Date(); const dateStr = formatRoamDate(today); // Try to find today's page const findQuery = `[:find ?uid :in $ ?title :where [?e :node/title ?title] [?e :block/uid ?uid]]`; const findResults = await q(this.graph, findQuery, [dateStr]) as [string][]; let targetPageUid: string; if (findResults && findResults.length > 0) { targetPageUid = findResults[0][0]; } else { // Create today's page if it doesn't exist try { await createPage(this.graph, { action: 'create-page', page: { title: dateStr } }); // Get the new page's UID const results = await q(this.graph, findQuery, [dateStr]) as [string][]; if (!results || results.length === 0) { throw new Error('Could not find created today\'s page'); } targetPageUid = results[0][0]; } catch (error) { throw new Error('Failed to create today\'s page'); } } const todo_tag = "{{TODO}}"; const actions = todos.map((todo, index) => ({ action: 'create-block', location: { 'parent-uid': targetPageUid, order: index }, block: { string: `${todo_tag} ${todo}` } })); const result = await batchActions(this.graph, { action: 'batch-actions', actions }); if (!result) { throw new Error('Failed to create todo blocks'); } return { success: true }; }
- src/tools/schemas.ts:40-57 (schema)Input schema definition for the roam_add_todo tool, specifying an array of todo strings.[toolName(BASE_TOOL_NAMES.ADD_TODO)]: { name: toolName(BASE_TOOL_NAMES.ADD_TODO), description: 'Add a list of todo items as individual blocks to today\'s daily page in Roam. Each item becomes its own actionable block with todo status.\nNOTE on Roam-flavored markdown: For direct linking: use [[link]] syntax. For aliased linking, use [alias]([[link]]) syntax. Do not concatenate words in links/hashtags - correct: #[[multiple words]] #self-esteem (for typically hyphenated words).\nIMPORTANT: Before using this tool, ensure that you have loaded into context the \'Roam Markdown Cheatsheet\' resource.', inputSchema: { type: 'object', properties: { todos: { type: 'array', items: { type: 'string', description: 'Todo item text' }, description: 'List of todo items to add' } }, required: ['todos'], }, },
- src/server/roam-server.ts:189-195 (registration)Tool registration in the MCP server's callTool handler switch statement, dispatching to toolHandlers.addTodos.case BASE_TOOL_NAMES.ADD_TODO: { const { todos } = request.params.arguments as { todos: string[] }; const result = await this.toolHandlers.addTodos(todos); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; }
- src/tools/tool-handlers.ts:119-121 (handler)Wrapper handler in ToolHandlers class that delegates to TodoOperations.addTodos.async addTodos(todos: string[]) { return this.todoOps.addTodos(todos); }
- src/tools/tool-handlers.ts:21-32 (registration)Instantiation of TodoOperations instance in ToolHandlers constructor for use by addTodos wrapper.private todoOps: TodoOperations; private outlineOps: OutlineOperations; private batchOps: BatchOperations; private cachedCheatsheet: string | null = null; constructor(private graph: Graph) { this.pageOps = new PageOperations(graph); this.blockOps = new BlockOperations(graph); this.blockRetrievalOps = new BlockRetrievalOperations(graph); // Initialize new instance this.searchOps = new SearchOperations(graph); this.memoryOps = new MemoryOperations(graph); this.todoOps = new TodoOperations(graph);