Skip to main content
Glama
Obsidian MCP (pgvector + Ollama, self-hosted)

Obsidian MCP (pgvector + Ollama, self-hosted)

by maxkuminov

Semantic search

semantic_search
Read-onlyIdempotent

Find notes by meaning rather than exact wording using vector similarity over chunk embeddings. Use for conceptual or paraphrased queries when keyword matching would miss the point.

Instructions

Vector similarity search over the vault's chunk embeddings. Use this for conceptual or paraphrased queries — anywhere exact word matching would miss the point.

Exact identifiers, code symbols, titles or known phrases: keyword_search. Conceptual or paraphrased questions: semantic_search. Unsure which: hybrid_search.

Each result is one note (deduped) with its closest-matching chunk as a ~200-character preview. Call read_note on a result's path to get the full note content.

The header line carries a stale count and a truncated count, always — including when both are zero, so "nothing here is degraded" is distinguishable from a build that does not report it.

stale: true on a row means the note changed after it was embedded: it was matched and ranked against its previous content, and its preview is withheld rather than shown, because that excerpt is text the note no longer has. Its path, title and tags are current — the indexer refreshed them, which is how the staleness is known at all — so read_note on that path returns the true content and is the remedy. Stale notes are never filtered out: during an embedding outage that would empty the result set rather than degrade it.

embedding_truncated: true means the note is longer than the indexer's per-note chunk cap and only its head was embedded. A match against such a note is a match against its head; its tail is not reachable by semantic search at all, though keyword_search still covers the whole note.

Section locator. A fresh row names the section it matched on its result line: § "<heading path>" (#N) for a heading's section, or § (top of note) for text before the first heading. read_note(path, section="#N") reads exactly that section. The quoted path is note text; the (#N) after it is the server's. The locator is omitted on stale rows and on rows not yet re-embedded since heading-aware chunking. While any of your notes is not yet re-chunked, the line after the header reads index_transition: N notes not yet re-chunked; …: ranking across the two generations is approximate, so re-run once it is gone. Previews are one line.

The bound on the staleness signal, stated so it is not over-read: it reports what the index has committed. An edit that the indexer has not yet scanned is not marked, so a note edited in the last few minutes may come back unmarked with a superseded preview. The guarantee is "no result presents text the index knows to be superseded", not "no result is ever out of date".

rerank=true asks the deployment's reranker to reorder the candidates this call already fetched; it can add up to the configured timeout. Its rows are one-line quoted objects followed by server fields (with rerank_score when reranked). The header says reranked: true or reranked: false (<reason>), and an unreranked page keeps the unreranked order; reranked: false (not_configured) means this deployment has no reranker.

The header also carries confidence: ok or confidence: low (the closest match is under the deployment's threshold; ok when none is set).

Args: query: Natural language description of what you're looking for. limit: Maximum number of distinct notes to return (default 15). folder: Optional folder prefix (e.g. "Projects/"). tags: Optional list of tag names; only notes carrying ALL listed tags match (e.g. ["product"]). frontmatter: Optional dict of frontmatter key/value pairs; strict type matching — string "0" does not match integer 0 (e.g. {"status": "active"}). rerank: Reorder the fetched candidates with the deployment's reranker (default false).

Input Schema

NameRequiredDescriptionDefault
tagsNo
limitNo
queryYes
folderNo
rerankNo
frontmatterNo

Output Schema

NameRequiredDescriptionDefault
resultYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.10.0
    • addedInput schema / properties / rerank
      Added value: +{
      +  "default": false,
      +  "title": "Rerank",
      +  "type": "boolean"
      +}
  2. Changed1 schema field changedv0.8.2
    • addedInput schema / additionalProperties
      Added value: +false
  3. First observed

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already cover read-only/idempotent safety, yet the description adds substantial non-obvious behavior: stale rows are ranked on prior content with previews withheld but never filtered out, truncated embeddings make a note's tail unreachable by this tool, rerank can add up to a configured timeout and may return reranked: false with a reason, and confidence can be low. It even bounds its own staleness guarantee ('no result presents text the index knows to be superseded'), which prevents over-trust. No contradiction with annotations.

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

Conciseness4/5

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

Routing and purpose are front-loaded in the first three lines, and most detail is decision-relevant for interpreting results. It is nonetheless long for a search tool, and some framing is meta-commentary ('stated so it is not over-read', 'which is how the staleness is known at all') that could be trimmed without losing information.

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?

For a tool with staleness, truncation, section locators, reranking and confidence signals, the description covers every behavior an agent must interpret correctly, including how to recover full content via read_note. Return-value explanation is partly redundant with the output schema, but that redundancy is harmless rather than missing information.

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 description coverage is 0%, so the description carries the full burden and does: tags require ALL listed tags, frontmatter uses strict type matching ('string "0" does not match integer 0'), folder is a prefix, limit is distinct notes (default 15), rerank trades latency for order. These are semantics the bare schema cannot convey.

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?

Opens with a specific verb+resource: 'Vector similarity search over the vault's chunk embeddings.' It immediately distinguishes itself from keyword_search (exact identifiers) and hybrid_search (unsure which), so an agent can route without opening any 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?

Gives an explicit decision table: exact identifiers/code symbols/titles → keyword_search; conceptual or paraphrased → semantic_search; unsure → hybrid_search. It also states the remedy path (read_note on a result's path) and when to re-run (after index_transition clears).

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