Skip to main content
Glama
camiloluvino

Roam Research MCP Server

by camiloluvino

roam_remember

Store memories and information in Roam Research by adding them to the daily page with tagging and categorization for organized knowledge retention.

Instructions

Add a memory or piece of information to remember, stored on the daily page with MEMORIES_TAG tag and optional categories. 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
memoryYesThe memory detail or information to remember
categoriesNoOptional categories to tag the memory with (will be converted to Roam tags)

Implementation Reference

  • Core handler implementation for the 'roam_remember' tool. Adds a memory block tagged with MEMORIES_TAG to today's daily page, creating the page if necessary, and optionally adds category tags.
    async remember(memory: string, categories?: string[]): Promise<{ success: boolean }> {
      // 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 pageUid: string;
      
      if (findResults && findResults.length > 0) {
        pageUid = 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 McpError(
              ErrorCode.InternalError,
              'Could not find created today\'s page'
            );
          }
          pageUid = results[0][0];
        } catch (error) {
          throw new McpError(
            ErrorCode.InternalError,
            'Failed to create today\'s page'
          );
        }
      }
    
      // Get memories tag from environment
      const memoriesTag = process.env.MEMORIES_TAG;
      if (!memoriesTag) {
        throw new McpError(
          ErrorCode.InternalError,
          'MEMORIES_TAG environment variable not set'
        );
      }
    
      // Format categories as Roam tags if provided
      const categoryTags = categories?.map(cat => {
        // Handle multi-word categories
        return cat.includes(' ') ? `#[[${cat}]]` : `#${cat}`;
      }).join(' ') || '';
    
      // Create block with memory, memories tag, and optional categories
      const blockContent = `${memoriesTag} ${memory} ${categoryTags}`.trim();
      
      const actions = [{
        action: 'create-block',
        location: {
          'parent-uid': pageUid,
          order: 'last'
        },
        block: {
          string: blockContent
        }
      }];
    
      try {
        const result = await batchActions(this.graph, {
          action: 'batch-actions',
          actions
        });
    
        if (!result) {
          throw new McpError(
            ErrorCode.InternalError,
            'Failed to create memory block via batch action'
          );
        }
      } catch (error) {
        throw new McpError(
          ErrorCode.InternalError,
          `Failed to create memory block: ${error instanceof Error ? error.message : String(error)}`
        );
      }
    
      return { success: true };
    }
  • Input schema definition for the 'roam_remember' tool, including parameters for memory text and optional categories.
    [toolName(BASE_TOOL_NAMES.REMEMBER)]: {
      name: toolName(BASE_TOOL_NAMES.REMEMBER),
      description: 'Add a memory or piece of information to remember, stored on the daily page with MEMORIES_TAG tag and optional categories. \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: {
          memory: {
            type: 'string',
            description: 'The memory detail or information to remember'
          },
          categories: {
            type: 'array',
            items: {
              type: 'string'
            },
            description: 'Optional categories to tag the memory with (will be converted to Roam tags)'
          }
        },
        required: ['memory']
      }
    },
  • Tool registration and dispatching logic in the MCP server. Maps 'roam_remember' calls to the toolHandlers.remember method.
    case BASE_TOOL_NAMES.REMEMBER: {
      const { memory, categories } = request.params.arguments as {
        memory: string;
        categories?: string[];
      };
      const result = await this.toolHandlers.remember(memory, categories);
      return {
        content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
      };
    }
  • Wrapper method in ToolHandlers class that delegates to MemoryOperations.remember.
    async remember(memory: string, categories?: string[]) {
      return this.memoryOps.remember(memory, categories);
  • BASE_TOOL_NAMES constant defining the base name 'roam_remember' used for handler mapping and schema key generation.
    REMEMBER: 'roam_remember',
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It adds valuable context beyond the input schema: it explains that memories are stored on the 'daily page' with a specific tag ('MEMORIES_TAG'), mentions optional categories are converted to Roam tags, and provides detailed formatting rules for Roam-flavored markdown (e.g., linking syntax, hashtag usage). However, it doesn't cover aspects like error handling, rate limits, or authentication needs, which could be relevant for a tool that modifies data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded: the first sentence clearly states the tool's purpose. Subsequent sentences provide necessary formatting guidelines and a prerequisite note. While the formatting details are somewhat lengthy, they are relevant for correct usage in the Roam context. There is minimal waste, though the structure could be slightly more streamlined (e.g., integrating the note more seamlessly).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the context: no annotations, no output schema, 2 parameters with full schema coverage, and moderate complexity (involving markdown formatting and tagging), the description is partially complete. It covers the core purpose, storage location, formatting rules, and a prerequisite, but lacks details on behavioral aspects like what happens on failure, whether the operation is idempotent, or example outputs. For a tool that adds data to a system, more behavioral transparency would improve completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters ('memory' and 'categories'). The description adds some semantic context: it clarifies that 'memory' is 'detail or information to remember' and that 'categories' are 'optional' and 'will be converted to Roam tags.' This provides marginal value over the schema but doesn't significantly enhance understanding of parameter usage or constraints. The baseline of 3 is appropriate given high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Add a memory or piece of information to remember, stored on the daily page with MEMORIES_TAG tag and optional categories.' It specifies the verb ('Add'), resource ('memory or piece of information'), and destination ('daily page with MEMORIES_TAG tag'). However, it doesn't explicitly differentiate from sibling tools like 'roam_recall' (which likely retrieves memories) or 'roam_create_page' (which creates pages rather than adding to daily pages).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides some usage context: it mentions storing on the 'daily page' and includes an 'IMPORTANT' note to load the 'Roam Markdown Cheatsheet' resource before use. However, it doesn't explicitly state when to use this tool versus alternatives (e.g., 'roam_create_page' for non-daily pages or 'roam_add_todo' for tasks). The guidance is implied rather than explicit, lacking clear exclusions or comparisons to siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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