Skip to main content
Glama
bazylhorsey
by bazylhorsey

search_notes

Find specific notes in your Obsidian vault using search queries, tag filters, and folder navigation to locate relevant information quickly.

Instructions

Search for notes in a vault

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
folderNoFilter by folder
limitNoMaximum number of results
queryYesSearch query
tagsNoFilter by tags
vaultYesVault name

Implementation Reference

  • Defines the SearchOptions interface for input parameters to the search_notes tool.
    export interface SearchOptions {
      query: string;
      tags?: string[];
      folder?: string;
      limit?: number;
      includeContent?: boolean;
    }
  • src/index.ts:78-92 (registration)
    Registers the search_notes tool in the MCP server's list tools handler with name, description, and input schema.
    {
      name: 'search_notes',
      description: 'Search for notes in a vault',
      inputSchema: {
        type: 'object',
        properties: {
          vault: { type: 'string', description: 'Vault name' },
          query: { type: 'string', description: 'Search query' },
          tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags' },
          folder: { type: 'string', description: 'Filter by folder' },
          limit: { type: 'number', description: 'Maximum number of results' },
        },
        required: ['vault', 'query'],
      },
    },
  • Top-level MCP tool handler for 'search_notes': validates vault, calls connector.searchNotes with parameters, returns JSON result.
    case 'search_notes': {
      const connector = this.connectors.get(args?.vault as string);
      if (!connector) {
        throw new Error(`Vault "${args?.vault}" not found`);
      }
      const result = await connector.searchNotes({
        query: args?.query as string,
        tags: args?.tags as string[] | undefined,
        folder: args?.folder as string | undefined,
        limit: args?.limit as number | undefined,
        includeContent: true,
      });
      return {
        content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
      };
    }
  • Core search logic for local vaults: retrieves all notes from cache, applies filters for folder/tags/query/content, limits results.
    async searchNotes(options: SearchOptions): Promise<VaultOperationResult<Note[]>> {
      try {
        const allNotes = await this.getAllNotes();
        if (!allNotes.success || !allNotes.data) {
          return allNotes;
        }
    
        let results = allNotes.data;
    
        // Filter by folder
        if (options.folder) {
          results = results.filter(note => note.path.startsWith(options.folder!));
        }
    
        // Filter by tags
        if (options.tags && options.tags.length > 0) {
          results = results.filter(note => {
            if (!note.tags) return false;
            return options.tags!.some(tag => note.tags!.includes(tag));
          });
        }
    
        // Search in title and content
        if (options.query) {
          const query = options.query.toLowerCase();
          results = results.filter(note => {
            const inTitle = note.title.toLowerCase().includes(query);
            const inContent = options.includeContent && note.content.toLowerCase().includes(query);
            return inTitle || inContent;
          });
        }
    
        // Apply limit
        if (options.limit && options.limit > 0) {
          results = results.slice(0, options.limit);
        }
    
        return { success: true, data: results };
      } catch (error) {
        return {
          success: false,
          error: `Failed to search notes: ${error instanceof Error ? error.message : String(error)}`
        };
      }
    }
  • Core search logic for remote vaults: attempts server-side search via POST /search, falls back to identical client-side filtering.
    async searchNotes(options: SearchOptions): Promise<VaultOperationResult<Note[]>> {
      try {
        // Try server-side search first
        try {
          const response = await this.client.post('/search', options);
          if (response.data.notes) {
            return { success: true, data: response.data.notes };
          }
        } catch {
          // Fall back to client-side search
        }
    
        // Client-side search fallback
        const allNotes = await this.getAllNotes();
        if (!allNotes.success || !allNotes.data) {
          return allNotes;
        }
    
        let results = allNotes.data;
    
        if (options.folder) {
          results = results.filter(note => note.path.startsWith(options.folder!));
        }
    
        if (options.tags && options.tags.length > 0) {
          results = results.filter(note => {
            if (!note.tags) return false;
            return options.tags!.some(tag => note.tags!.includes(tag));
          });
        }
    
        if (options.query) {
          const query = options.query.toLowerCase();
          results = results.filter(note => {
            const inTitle = note.title.toLowerCase().includes(query);
            const inContent = options.includeContent && note.content.toLowerCase().includes(query);
            return inTitle || inContent;
          });
        }
    
        if (options.limit && options.limit > 0) {
          results = results.slice(0, options.limit);
        }
    
        return { success: true, data: results };
      } catch (error) {
        return {
          success: false,
          error: `Failed to search notes: ${error instanceof Error ? error.message : String(error)}`
        };
      }
    }

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/bazylhorsey/obsidian-mcp-server'

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