Summary
get_vault_file currently accepts only { filename, format } and always returns the full file contents. The underlying obsidian-local-rest-api plugin already supports several partial-read modes on GET /vault/{filename} that are not exposed through the MCP layer. Surfacing them would avoid loading large files into LLM context when only a heading, block, or the frontmatter is needed.
Motivation
Using obsidian-mcp-tools with LLM agents (Claude Code, Claude Desktop, Cowork) on a moderately-sized vault (~2k notes, some >30 KB), the full-content read is often disproportionate to the task. Typical cases where we only need a fragment:
- Classify or validate a single frontmatter field (is
status still open?) — currently forces loading the entire note.
- Follow a wiki-link to a specific heading and read just that section.
- Build an outline/TOC of a long note before deciding what to read in full.
On large pilot notes (deployment docs, aggregated bug registries, long reference sheets), a full read can push the context window past useful limits and has occasionally caused truncation / timeout. The workaround today is search_vault_simple with a short contextLength, which is cheap but imprecise when the needle string is not unique.
Existing upstream support
The Local REST API already documents these capabilities on GET /vault/{filename} (OpenAPI spec):
Target-Type: heading + Target: <path> + Target-Delimiter: :: → section under a heading
Target-Type: block + Target: <block-id> → referenced block
Target-Type: frontmatter + Target: <field> → a single frontmatter field value
Accept: application/vnd.olrapi.note+json → structured NoteJson (parsed frontmatter + stat + tags + content)
Accept: application/vnd.olrapi.document-map+json → outline only (headings, blocks, frontmatter fields), no body
None of these are reachable from the MCP schema today.
Proposal — two viable shapes
Option A — new dedicated verb (simpler mental model):
get_vault_file_partial({
filename: string,
mode: "frontmatter" | "heading" | "block" | "document-map",
target?: string // field name, heading path, or block id
targetDelimiter?: string // default "::"
})
Option B — extend the existing get_vault_file (smaller surface, more overloaded):
get_vault_file({
filename: string,
format?: "markdown" | "json" | "note+json" | "document-map+json",
targetType?: "heading" | "block" | "frontmatter",
target?: string,
targetDelimiter?: string
})
Either shape maps trivially onto the existing Local REST API headers — no backend work required, purely a wrapper extension.
I mildly prefer Option A because it disambiguates behaviour at the tool-schema level (LLMs decide which tool to call before filling in parameters; mixing "give me the whole file" and "give me one heading" behind the same verb makes routing harder).
Related
A separate validation bug (format: "json" rejecting array-valued frontmatter) is tracked in its own issue — see #81. The two are independent but often surface together because "read just the frontmatter" is the most common partial-read case.
Environment
obsidian-mcp-tools 0.2.27
obsidian-local-rest-api 3.6.1
- Obsidian 1.7.x on macOS
- Consumed via Claude Code / Cowork
Summary
get_vault_filecurrently accepts only{ filename, format }and always returns the full file contents. The underlyingobsidian-local-rest-apiplugin already supports several partial-read modes onGET /vault/{filename}that are not exposed through the MCP layer. Surfacing them would avoid loading large files into LLM context when only a heading, block, or the frontmatter is needed.Motivation
Using
obsidian-mcp-toolswith LLM agents (Claude Code, Claude Desktop, Cowork) on a moderately-sized vault (~2k notes, some >30 KB), the full-content read is often disproportionate to the task. Typical cases where we only need a fragment:statusstillopen?) — currently forces loading the entire note.On large pilot notes (deployment docs, aggregated bug registries, long reference sheets), a full read can push the context window past useful limits and has occasionally caused truncation / timeout. The workaround today is
search_vault_simplewith a shortcontextLength, which is cheap but imprecise when the needle string is not unique.Existing upstream support
The Local REST API already documents these capabilities on
GET /vault/{filename}(OpenAPI spec):Target-Type: heading+Target: <path>+Target-Delimiter: ::→ section under a headingTarget-Type: block+Target: <block-id>→ referenced blockTarget-Type: frontmatter+Target: <field>→ a single frontmatter field valueAccept: application/vnd.olrapi.note+json→ structuredNoteJson(parsed frontmatter + stat + tags + content)Accept: application/vnd.olrapi.document-map+json→ outline only (headings, blocks, frontmatter fields), no bodyNone of these are reachable from the MCP schema today.
Proposal — two viable shapes
Option A — new dedicated verb (simpler mental model):
Option B — extend the existing
get_vault_file(smaller surface, more overloaded):Either shape maps trivially onto the existing Local REST API headers — no backend work required, purely a wrapper extension.
I mildly prefer Option A because it disambiguates behaviour at the tool-schema level (LLMs decide which tool to call before filling in parameters; mixing "give me the whole file" and "give me one heading" behind the same verb makes routing harder).
Related
A separate validation bug (
format: "json"rejecting array-valued frontmatter) is tracked in its own issue — see #81. The two are independent but often surface together because "read just the frontmatter" is the most common partial-read case.Environment
obsidian-mcp-tools0.2.27obsidian-local-rest-api3.6.1