Search Notes By Tag
tags.searchSearch the entire vault for notes containing a given tag, from frontmatter or inline #tag. Returns file path and distinguishes frontmatter from inline locations. Read-only. For a single note, use tags.analyze instead.
Instructions
Find every note in the vault that contains a given tag, either in frontmatter tags or as an inline #tag in the body. Leading # on the query is stripped. For each hit, the result carries {file, absolutePath, tagLocations: {frontmatter, inline}} so callers can distinguish where the tag came from. Read-only. For analyzing tags of ONE specific note (not a vault-wide search), use tags.analyze instead.
Operates on the session-active vault (see vault.current — selectable via vault.select) unless an explicit vaultPath argument is passed, which always wins.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tag | Yes | Tag to find. Leading `#` is stripped. | |
| vaultPath | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tag | Yes | The normalized tag that was searched (leading `#` stripped). | |
| total | Yes | ||
| items | Yes |
Implementation Reference
- src/domain/tags.ts:90-122 (handler)The core domain function that walks all markdown files in the vault, searches for the given tag in frontmatter and inline content, and returns matching notes with location details.
export async function searchByTag( context: DomainContext, args: { tag: string; vaultPath?: string }, ) { const vaultRoot = requireVaultPath(context, args.vaultPath); const searchTag = args.tag.replace(/^#/, ""); const items: Array<{ file: string; absolutePath: string; tagLocations: { frontmatter: boolean; inline: boolean }; }> = []; for (const absolutePath of await walkMarkdownFiles(vaultRoot)) { const content = await readUtf8(absolutePath); const tags = extractAllTags(content); const frontmatter = tags.frontmatterTags.includes(searchTag); const inline = tags.inlineTags.includes(searchTag); if (!frontmatter && !inline) { continue; } items.push({ file: toVaultRelativePath(vaultRoot, absolutePath), absolutePath, tagLocations: { frontmatter, inline }, }); } return { tag: searchTag, items, total: items.length, }; } - src/schema/tags.ts:30-37 (schema)Zod schema defining the input arguments for tags.search: requires a tag string, optionally accepts vaultPath.
export const tagsSearchArgsSchema = z .object({ tag: tagSchema.describe("Tag to find. Leading `#` is stripped."), vaultPath: z.string().optional(), }) .strict() .describe("Arguments for `tags.search`."); export type TagsSearchArgs = z.input<typeof tagsSearchArgsSchema>; - src/schema/tags.ts:75-96 (schema)Zod schema defining the output shape: normalized tag, total count, and array of items with file paths and tag location booleans.
export const tagsSearchOutputSchema = z .object({ tag: z.string().describe("The normalized tag that was searched (leading `#` stripped)."), total: z.number().int().nonnegative(), items: z.array( z .object({ file: z.string(), absolutePath: z.string(), tagLocations: z.object({ frontmatter: z .boolean() .describe("True if the tag appears in the note's frontmatter `tags` list."), inline: z .boolean() .describe("True if the tag appears as an inline `#tag` in the body."), }), }) .passthrough(), ), }) .passthrough(); - src/server/tools/tags.ts:61-73 (registration)Tool registration in the tagTools array: defines the tool name, description, input/output schemas, and the handler that delegates to searchByTag.
{ name: "tags.search", title: "Search Notes By Tag", description: "Find every note in the vault that contains a given tag, either in frontmatter `tags` or as an inline `#tag` in the body. Leading `#` on the query is stripped. For each hit, the result carries `{file, absolutePath, tagLocations: {frontmatter, inline}}` so callers can distinguish where the tag came from. Read-only. For analyzing tags of ONE specific note (not a vault-wide search), use `tags.analyze` instead.", inputSchema: tagsSearchArgsSchema, outputSchema: tagsSearchOutputSchema, annotations: READ_ONLY, handler: async (context, rawArgs) => { const args = tagsSearchArgsSchema.parse(rawArgs) as TagsSearchArgs; return searchByTag(context, args); }, },