Skip to main content
Glama
camiloluvino

Roam Research MCP Server

by camiloluvino

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

TableJSON Schema
NameRequiredDescriptionDefault
todosYesList of todo items to add

Implementation Reference

  • 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 };
    }
  • 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'],
      },
    },
  • 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) }],
      };
    }
  • Wrapper handler in ToolHandlers class that delegates to TodoOperations.addTodos.
    async addTodos(todos: string[]) {
      return this.todoOps.addTodos(todos);
    }
  • 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);

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/camiloluvino/roamMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server