Skip to main content
Glama

search_by_tag

Search for notes containing a specific tag in Obsidian vaults, with options to preview content and limit results.

Instructions

Find all notes that contain a specific tag

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tagYesTag to search for (with or without # prefix)
includeContentNoIf true, include first 200 characters of note content as a preview
maxResultsNoMaximum number of results

Implementation Reference

  • The handler function that implements the logic for 'search_by_tag', including searching for tags in note content and returning the matching results.
    async ({ tag, includeContent, maxResults }) => {
      try {
        const searchTag = tag.replace(/^#/, "").toLowerCase();
        const notes = await listNotes(vaultPath);
        const matchingNotes: { path: string; preview?: string }[] = [];
    
        for (const notePath of notes) {
          if (matchingNotes.length >= maxResults) break;
    
          let content: string;
          try {
            content = await readNote(vaultPath, notePath);
          } catch (err) {
            console.error(`Failed to read note for tag search: ${notePath}`, err);
            continue;
          }
    
          const tags = extractTags(content);
          const hasMatch = tags.some((t) => {
            const normalized = t.toLowerCase();
            return normalized === searchTag || normalized.startsWith(`${searchTag}/`);
          });
    
          if (hasMatch) {
            const entry: { path: string; preview?: string } = { path: notePath };
            if (includeContent) {
              entry.preview = content.slice(0, 200).trim();
            }
            matchingNotes.push(entry);
          }
        }
    
        if (matchingNotes.length === 0) {
          return {
            content: [
              { type: "text" as const, text: `No notes found with tag #${searchTag}` },
            ],
          };
        }
    
        const lines: string[] = [];
        lines.push(`Found ${matchingNotes.length} ${matchingNotes.length === 1 ? "note" : "notes"} with tag #${searchTag}`);
        lines.push("");
    
        for (const note of matchingNotes) {
          lines.push(`- ${note.path}`);
          if (note.preview) {
            lines.push(`  ${note.preview}`);
            lines.push("");
          }
        }
    
        return {
          content: [{ type: "text" as const, text: lines.join("\n") }],
        };
      } catch (err) {
        console.error("Error in search_by_tag:", err);
        return errorResult(`Error searching by tag: ${err instanceof Error ? err.message : String(err)}`);
      }
    },
  • The schema definition (inputSchema) for the 'search_by_tag' tool.
    {
      description: "Find all notes that contain a specific tag",
      inputSchema: {
        tag: z.string().describe("Tag to search for (with or without # prefix)"),
        includeContent: z
          .boolean()
          .optional()
          .default(false)
          .describe("If true, include first 200 characters of note content as a preview"),
        maxResults: z.number().optional().default(100).describe("Maximum number of results"),
      },
    },
  • The registration call for the 'search_by_tag' tool within the McpServer instance.
    server.registerTool(
      "search_by_tag",
      {
        description: "Find all notes that contain a specific tag",
        inputSchema: {
          tag: z.string().describe("Tag to search for (with or without # prefix)"),
          includeContent: z
            .boolean()
            .optional()
            .default(false)
            .describe("If true, include first 200 characters of note content as a preview"),
          maxResults: z.number().optional().default(100).describe("Maximum number of results"),
        },
      },
      async ({ tag, includeContent, maxResults }) => {
        try {
          const searchTag = tag.replace(/^#/, "").toLowerCase();
          const notes = await listNotes(vaultPath);
          const matchingNotes: { path: string; preview?: string }[] = [];
    
          for (const notePath of notes) {
            if (matchingNotes.length >= maxResults) break;
    
            let content: string;
            try {
              content = await readNote(vaultPath, notePath);
            } catch (err) {
              console.error(`Failed to read note for tag search: ${notePath}`, err);
              continue;
            }
    
            const tags = extractTags(content);
            const hasMatch = tags.some((t) => {
              const normalized = t.toLowerCase();
              return normalized === searchTag || normalized.startsWith(`${searchTag}/`);
            });
    
            if (hasMatch) {
              const entry: { path: string; preview?: string } = { path: notePath };
              if (includeContent) {
                entry.preview = content.slice(0, 200).trim();
              }
              matchingNotes.push(entry);
            }
          }
    
          if (matchingNotes.length === 0) {
            return {
              content: [
                { type: "text" as const, text: `No notes found with tag #${searchTag}` },
              ],
            };
          }
    
          const lines: string[] = [];
          lines.push(`Found ${matchingNotes.length} ${matchingNotes.length === 1 ? "note" : "notes"} with tag #${searchTag}`);
          lines.push("");
    
          for (const note of matchingNotes) {
            lines.push(`- ${note.path}`);
            if (note.preview) {
              lines.push(`  ${note.preview}`);
              lines.push("");
            }
          }
    
          return {
            content: [{ type: "text" as const, text: lines.join("\n") }],
          };
        } catch (err) {
          console.error("Error in search_by_tag:", err);
          return errorResult(`Error searching by tag: ${err instanceof Error ? err.message : String(err)}`);
        }
      },
    );

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/rps321321/obsidian-mcp-pro'

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