Skip to main content
Glama
aliasunder

Vault Cortex Obsidian MCP Server

Search Notes

vault_search
Read-onlyIdempotent

Hybrid search across all vault notes, ranked by combined keyword and semantic relevance using Reciprocal Rank Fusion (RRF) — combining FTS5 keyword matching with vector similarity.

Instructions

Hybrid search across all vault notes, ranked by combined keyword and semantic relevance using Reciprocal Rank Fusion (RRF) — combining FTS5 keyword matching with vector similarity. Results are refined by a cross-encoder reranker using position-aware score blending when available. Semantic matching finds notes even when exact keywords differ — "career aspirations" finds notes about "goals" and "targets". Falls back to keyword-only (FTS5 BM25) transparently while embeddings are being built. Combine a text query with structured filters to narrow results by metadata — the "narrow by metadata, search by text" pattern. Unquoted terms use implicit AND with porter stemming; wrap in double quotes for exact phrases; punctuated terms (vault-cortex, deploy/local) are matched as exact adjacent-word phrases automatically.

Filters — all conditions AND-combine with each other and the text query:

  • folder: a whole folder, subfolders included — "Projects" covers "Projects/Archive" but not "ProjectsOld/"; ignores ASCII letter case

  • tags: every listed frontmatter tag must match, in any letter case; "project" also matches "project/a"

  • properties: arbitrary frontmatter key-value pairs, supports string/number/boolean (e.g. { status: "active" }). Values compare by exact type — pass a number as a number, not "4". Exception: checkbox values are stored as 1 and 0, so pass true to match 1 and false to match 0. A list property matches when any element equals the value.

  • created / modified: bounds compare whole calendar days, server-local, so on matches anywhere within the day. Notes without a parseable created property never match a created filter

Example: vault_search({ query: "kubernetes networking", filters: { tags: ["reference"] } }) Example: vault_search({ query: "meeting notes", filters: { type: "meeting", folder: "Work" } }) Example: vault_search({ query: "decision", filters: { modified: { after: "2026-06-30" } } }) — matching notes touched in July or later Example: vault_search({ query: "how the server watches for file changes" }) — semantic: finds notes about chokidar and file watchers even without those exact terms

When to use: The primary discovery tool for content-based queries, optionally constrained by metadata. Semantic matching bridges vocabulary gaps — try natural-language queries, not just keywords. Prefer vault_search_by_tag for tag-only queries without text. Prefer vault_search_by_folder for browsing a folder. Prefer vault_search_by_property for metadata-only queries. Prefer vault_recent_notes for time-based browsing.

Errors:

  • No matches returns { results: [], total: 0 }, not an error

  • Malformed query syntax is sanitized automatically — the tool never throws a query syntax error

  • "invalid created.on date: …" (any created/modified bound) — the bound isn't in YYYY-MM-DD form; use that form

  • "… is not a calendar date" — the bound has the YYYY-MM-DD form but names a day that doesn't exist, such as 2026-02-30; pass a real date

  • tag must not be empty after its leading "#" — a tags entry is only "#"; pass the tag name

Returns: JSON with results array (path, title, snippet, score, tags, folder, type, kind, extension, created, modified, bytes), total (results returned, not all matches), search_mode ("hybrid" or "fts"), and reranked (boolean — true when cross-encoder reranking refined the ordering). search_mode indicates which ranking was used — "hybrid" when vector embeddings contributed, "fts" when only keyword matching was available. score reflects combined relevance (higher = more relevant). kind is "note" for markdown notes or "file" for non-markdown content (canvas, PDF, and text files — .txt, .csv, .json, .xml, .svg, .log, .yaml, .yml, .base); file results also carry extension (e.g. ".canvas", ".pdf", ".txt"). created is omitted when null. bytes is the on-disk file size. With include_leading_callout, each result also carries leading_callout ({ type, title, body }) when present.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNoMax results (default 20)
queryYesSearch query text
filtersNoOptional structured filters
snippet_tokensNoSnippet length in words (default 30)
include_leading_calloutNoIf true, include each result's leading callout. Off by default to keep results lean.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.54.13
    • changedInput schema / properties / filters / properties / tags / description
      Previous value: -"Require all listed tags (AND — every tag must be present)"New value: +"Tags, \"#\" optional (e.g. [\"reference\"])"
  2. Changed5 schema fields changedv0.54.9
    • changedInput schema / properties / filters / description
      Previous value: -"Optional structured filters — all conditions AND-combine with each other and with the text query"New value: +"Optional structured filters"
    • changedInput schema / properties / filters / properties / created / description
      Previous value: -"Created date bounds (YYYY-MM-DD) on the frontmatter \"created\" property — notes without a parseable value never match"New value: +"Created date bounds (YYYY-MM-DD) on the frontmatter \"created\" property"
    • changedInput schema / properties / include_leading_callout / description
      Previous value: -"If true, each result includes its leading_callout ({ type, title, body }) when present. Off by default to keep results lean."New value: +"If true, include each result's leading callout. Off by default to keep results lean."
    • changedInput schema / properties / query / description
      Previous value: -"Search query text — unquoted terms use implicit AND with stemming; wrap in double quotes for exact phrases"New value: +"Search query text"
    • changedInput schema / properties / snippet_tokens / description
      Previous value: -"Snippet length in tokens (default 30)"New value: +"Snippet length in words (default 30)"
  3. Changed1 schema field changedv0.54.7
    • changedInput schema / properties / filters / properties / folder / description
      Previous value: -"Restrict to a folder path prefix (e.g. \"Projects\")"New value: +"Restrict to a folder (e.g. \"Projects\")"
  4. Changed6 schema fields changedv0.50.0
    • removedInput schema / properties / filters / properties / include_leading_callout
      Removed value: -{
      -  "description": "If true, each result includes its leading_callout ({ type, title, body }) when present. Off by default to keep results lean.",
      -  "type": "boolean"
      -}
    • removedInput schema / properties / filters / properties / limit
      Removed value: -{
      -  "description": "Max results (default 20)",
      -  "type": "number"
      -}
    • removedInput schema / properties / filters / properties / snippet_tokens
      Removed value: -{
      -  "description": "Snippet length in tokens (default 30)",
      -  "type": "number"
      -}
    • addedInput schema / properties / include_leading_callout
      Added value: +{
      +  "default": false,
      +  "description": "If true, each result includes its leading_callout ({ type, title, body }) when present. Off by default to keep results lean.",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / limit
      Added value: +{
      +  "default": 20,
      +  "description": "Max results (default 20)",
      +  "maximum": 9007199254740991,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • addedInput schema / properties / snippet_tokens
      Added value: +{
      +  "default": 30,
      +  "description": "Snippet length in tokens (default 30)",
      +  "maximum": 9007199254740991,
      +  "minimum": 1,
      +  "type": "integer"
      +}
  5. Changed2 schema fields changedv0.27.2
    • addedInput schema / properties / filters / properties / created
      Added value: +{
      +  "description": "Created date bounds (YYYY-MM-DD) on the frontmatter \"created\" property — notes without a parseable value never match",
      +  "properties": {
      +    "after": {
      +      "description": "Exclusive lower bound (YYYY-MM-DD) — strictly later dates",
      +      "minLength": 1,
      +      "type": "string"
      +    },
      +    "before": {
      +      "description": "Exclusive upper bound (YYYY-MM-DD) — strictly earlier dates",
      +      "minLength": 1,
      +      "type": "string"
      +    },
      +    "on": {
      +      "description": "Exact date match (YYYY-MM-DD)",
      +      "minLength": 1,
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
    • addedInput schema / properties / filters / properties / modified
      Added value: +{
      +  "description": "Modified date bounds (YYYY-MM-DD) on filesystem modified time, server-local day boundaries",
      +  "properties": {
      +    "after": {
      +      "description": "Exclusive lower bound (YYYY-MM-DD) — strictly later dates",
      +      "minLength": 1,
      +      "type": "string"
      +    },
      +    "before": {
      +      "description": "Exclusive upper bound (YYYY-MM-DD) — strictly earlier dates",
      +      "minLength": 1,
      +      "type": "string"
      +    },
      +    "on": {
      +      "description": "Exact date match (YYYY-MM-DD)",
      +      "minLength": 1,
      +      "type": "string"
      +    }
      +  },
      +  "type": "object"
      +}
  6. Changed7 schema fields changedv0.22.1
    • addedInput schema / properties / filters / properties / folder / minLength
      Added value: +1
    • changedInput schema / properties / filters / properties / properties / additionalProperties / anyOf
      Previous value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "boolean"
      -  }
      -]New value: +[
      +  {
      +    "minLength": 1,
      +    "type": "string"
      +  },
      +  {
      +    "type": "number"
      +  },
      +  {
      +    "type": "boolean"
      +  }
      +]
    • addedInput schema / properties / filters / properties / properties / propertyNames / minLength
      Added value: +1
    • addedInput schema / properties / filters / properties / related / items / minLength
      Added value: +1
    • addedInput schema / properties / filters / properties / tags / items / minLength
      Added value: +1
    • addedInput schema / properties / filters / properties / type / minLength
      Added value: +1
    • addedInput schema / properties / query / minLength
      Added value: +1
  7. Changed7 schema fields changedv0.19.2
    • changedInput schema / properties / filters / description
      Previous value: -"Optional search filters"New value: +"Optional structured filters — all conditions AND-combine with each other and with the text query"
    • changedInput schema / properties / filters / properties / folder / description
      Previous value: -"Restrict to folder"New value: +"Restrict to a folder path prefix (e.g. \"Projects\")"
    • addedInput schema / properties / filters / properties / include_leading_callout
      Added value: +{
      +  "description": "If true, each result includes its leading_callout ({ type, title, body }) when present. Off by default to keep results lean.",
      +  "type": "boolean"
      +}
    • changedInput schema / properties / filters / properties / properties / description
      Previous value: -"Arbitrary property key-value filters"New value: +"Match arbitrary frontmatter properties by key-value (e.g. { status: \"active\", priority: 1 })"
    • changedInput schema / properties / filters / properties / tags / description
      Previous value: -"Require all listed tags"New value: +"Require all listed tags (AND — every tag must be present)"
    • changedInput schema / properties / filters / properties / type / description
      Previous value: -"Frontmatter type field value"New value: +"Match the frontmatter type field (exact match, e.g. \"person\", \"meeting\")"
    • changedInput schema / properties / query / description
      Previous value: -"Search query text"New value: +"Search query text — unquoted terms use implicit AND with stemming; wrap in double quotes for exact phrases"
  8. Added

TDQS

A5/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent/non-destructive, but the description goes well beyond: transparent fallback to keyword-only BM25 while embeddings build (surfaced via search_mode), automatic query sanitization, no-match returning an empty result set rather than an error, reranking behavior, and named error messages. This is rich operational context an agent cannot get from annotations.

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?

Front-loaded with the ranking model, then organized into clearly delineated Filters, Examples, When to use, Errors, and Returns sections. Although long, it is dense and every section maps to a real invocation concern; no filler sentences.

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

Completeness5/5

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

No output schema exists, so the description carries the return contract, and it does so thoroughly: results array fields (path, title, snippet, score, tags, folder, type, kind, extension, created, modified, bytes), total, search_mode, reranked, and the leading_callout opt-in. Combined with the error catalogue and nested-filter semantics, it is complete for a tool of this complexity.

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

Parameters5/5

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

Schema coverage is 100%, so baseline would be 3, but the description adds substantial semantics the schema lacks: folder matching includes subfolders but not similarly-prefixed siblings, tags are case-insensitive AND-combined with 'project' matching 'project/a', typed property comparison (numbers as numbers, checkbox true/false mapping to 1/0, list any-element match), and whole-day server-local date bounds with unparseable created never matching.

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?

States a specific verb and resource ('Hybrid search across all vault notes') and immediately names the ranking mechanism (RRF combining FTS5 with vector similarity). It also positions itself against siblings ('The primary discovery tool for content-based queries'), so an agent can distinguish it from the metadata-only and time-based search tools without opening a schema.

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?

Contains an explicit 'When to use' section and routes the agent to alternatives by condition: vault_search_by_tag for tag-only, vault_search_by_folder for browsing, vault_search_by_property for metadata-only, vault_recent_notes for time-based. Nothing is left to inference about which sibling to pick.

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