Skip to main content
Glama
camiloluvino

Roam Research MCP Server

by camiloluvino

roam_search_by_date

Find Roam Research blocks or pages created or modified within specific date ranges to locate historical content and track changes over time.

Instructions

Search for blocks or pages based on creation or modification dates. Not for daily pages with ordinal date titles.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
start_dateYesStart date in ISO format (YYYY-MM-DD)
end_dateNoOptional: End date in ISO format (YYYY-MM-DD)
typeYesWhether to search by creation date, modification date, or both
scopeYesWhether to search blocks, pages
include_contentNoWhether to include the content of matching blocks/pages

Implementation Reference

  • Core handler function that implements the 'roam_search_by_date' tool logic: converts date range to timestamps, fetches all blocks via text search with empty query, filters by date (using placeholder logic), maps and sorts results.
    async searchByDate(params: {
      start_date: string;
      end_date?: string;
      type: 'created' | 'modified' | 'both';
      scope: 'blocks' | 'pages' | 'both';
      include_content: boolean;
    }): Promise<{ 
      success: boolean; 
      matches: Array<{ 
        uid: string; 
        type: string; 
        time: number; 
        content?: string; 
        page_title?: string 
      }>; 
      message: string 
    }> {
      // Convert dates to timestamps
      const startTimestamp = new Date(`${params.start_date}T00:00:00`).getTime();
      const endTimestamp = params.end_date ? new Date(`${params.end_date}T23:59:59`).getTime() : undefined;
    
      // Use text search handler for content-based filtering
      const handler = new TextSearchHandlerImpl(this.graph, {
        text: '', // Empty text to match all blocks
      });
    
      const result = await handler.execute();
    
      // Filter results by date
      const matches = result.matches
        .filter(match => {
          const time = params.type === 'created' ? 
            new Date(match.content || '').getTime() : // Use content date for creation time
            Date.now(); // Use current time for modification time (simplified)
          
          return time >= startTimestamp && (!endTimestamp || time <= endTimestamp);
        })
        .map(match => ({
          uid: match.block_uid,
          type: 'block',
          time: params.type === 'created' ? 
            new Date(match.content || '').getTime() : 
            Date.now(),
          ...(params.include_content && { content: match.content }),
          page_title: match.page_title
        }));
    
      // Sort by time
      const sortedMatches = matches.sort((a, b) => b.time - a.time);
    
      return {
        success: true,
        matches: sortedMatches,
        message: `Found ${sortedMatches.length} matches for the given date range and criteria`
      };
    }
  • Delegating handler method in ToolHandlers class that forwards the tool call to SearchOperations.searchByDate.
    async searchByDate(params: {
      start_date: string;
      end_date?: string;
      type: 'created' | 'modified' | 'both';
      scope: 'blocks' | 'pages' | 'both';
      include_content: boolean;
    }) {
      return this.searchOps.searchByDate(params);
  • Input schema definition for the 'roam_search_by_date' tool, including parameters for date range, type, scope, and content inclusion.
    [toolName(BASE_TOOL_NAMES.SEARCH_BY_DATE)]: {
      name: toolName(BASE_TOOL_NAMES.SEARCH_BY_DATE),
      description: 'Search for blocks or pages based on creation or modification dates. Not for daily pages with ordinal date titles.',
      inputSchema: {
        type: 'object',
        properties: {
          start_date: {
            type: 'string',
            description: 'Start date in ISO format (YYYY-MM-DD)',
          },
          end_date: {
            type: 'string',
            description: 'Optional: End date in ISO format (YYYY-MM-DD)',
          },
          type: {
            type: 'string',
            enum: ['created', 'modified', 'both'],
            description: 'Whether to search by creation date, modification date, or both',
          },
          scope: {
            type: 'string',
            enum: ['blocks', 'pages', 'both'],
            description: 'Whether to search blocks, pages',
          },
          include_content: {
            type: 'boolean',
            description: 'Whether to include the content of matching blocks/pages',
            default: true,
          }
        },
        required: ['start_date', 'type', 'scope']
      }
    },
  • Tool registration in the MCP server request handler: switch case that handles calls to 'roam_search_by_date' by invoking ToolHandlers.searchByDate and returning JSON result.
    case BASE_TOOL_NAMES.SEARCH_BY_DATE: {
      const params = request.params.arguments as {
        start_date: string;
        end_date?: string;
        type: 'created' | 'modified' | 'both';
        scope: 'blocks' | 'pages' | 'both';
        include_content: boolean;
      };
      const result = await this.toolHandlers.searchByDate(params);
      return {
        content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
      };
    }
  • Registers all tools (including 'roam_search_by_date') for listing via MCP ListToolsRequest.
    mcpServer.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: Object.values(toolSchemas),
    }));
Behavior3/5

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

No annotations are provided, so the description carries the full burden. It discloses the search behavior and a key exclusion (not for daily pages), but lacks details on permissions, rate limits, pagination, or error handling. For a search tool with no annotations, this is a moderate gap, as it covers basic intent but not operational traits.

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

Conciseness5/5

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

The description is two sentences, front-loaded with the core purpose and followed by a critical exclusion. Every sentence earns its place by providing essential guidance without redundancy, making it highly efficient and well-structured.

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 no annotations and no output schema, the description is moderately complete. It covers the purpose and a key exclusion, but lacks details on return values, error cases, or behavioral constraints. For a search tool with 5 parameters and no structured output, it should do more to guide the agent on what to expect.

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 fully documents all parameters. The description adds no additional parameter semantics beyond implying date-based filtering, which is already covered in the schema. Baseline 3 is appropriate when the schema does the heavy lifting, with no extra value from the description.

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

Purpose5/5

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

The description clearly states the specific action ('Search for blocks or pages'), resource ('blocks or pages'), and distinguishing scope ('based on creation or modification dates'). It explicitly differentiates from sibling tools by stating 'Not for daily pages with ordinal date titles,' which distinguishes it from tools like roam_find_pages_modified_today that might handle daily pages differently.

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

Usage Guidelines5/5

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

The description provides explicit guidance on when not to use this tool ('Not for daily pages with ordinal date titles'), which helps the agent avoid misuse. It also implies usage context by specifying date-based search, distinguishing it from text-based (roam_search_by_text), tag-based (roam_search_for_tag), or status-based (roam_search_by_status) 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