# io.github.stonematt/mcp-obsidian-cli (npm · mcp-obsidian-cli)

Save chat notes from Claude Desktop to your vault — MCP on Obsidian CLI. Keep what matters.

- Trust score: 80/100 (high trust)
- Change this week: +29
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- npm · `mcp-obsidian-cli`: 80/100 (this document), [markdown](https://verifymcp.io/servers/stonematt-mcp-obsidian-cli/mcp-obsidian-cli.md), [page](https://verifymcp.io/servers/stonematt-mcp-obsidian-cli/mcp-obsidian-cli)

## Channel facts

- Registry: `npm`
- Package: `mcp-obsidian-cli`
- Version: `2.0.4`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Supply Chain Security**: 87/100
  - No malware found by supply-chain analysis.
  - Only part of the dependency tree could be resolved (97 of 101), so this covers what we could see, not the whole tree.
  - No install/post-install scripts declared.
  - Only part of the dependency tree could be resolved (97 of 101), so this covers what we could see, not the whole tree.
- **Provenance & Transparency**: 97/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to stonematt/mcp-obsidian-cli).
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 23 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 79/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 4139 tokens (~159/item across 26 items; 23 tools + 3 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 23/100
  - Stability observed for 7 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add stonematt-mcp-obsidian-cli -- npx -y mcp-obsidian-cli
```

### Codex

```bash
codex mcp add stonematt-mcp-obsidian-cli -- npx -y mcp-obsidian-cli
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "stonematt-mcp-obsidian-cli": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "mcp-obsidian-cli"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add stonematt-mcp-obsidian-cli --command npx --arg -y --arg mcp-obsidian-cli
```

### Hermes

```yaml
mcp_servers:
  stonematt-mcp-obsidian-cli:
    command: "npx"
    args: ["-y", "mcp-obsidian-cli"]
```

### Other

```json
{
  "mcpServers": {
    "stonematt-mcp-obsidian-cli": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-obsidian-cli"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-03 (score 80, +1)

No change was recorded against any check on this day. Stability & Change Management went from 20 to 23. That category is still filling its 30-day observation window: 6 days of observed history at the previous scan, 7 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-08-02 (score 79, +43)

- [security improvement] Provenance: unverified → pass
- [security improvement] Known CVEs: unverified → partial
- [security improvement] Install scripts: unverified → pass
- [security improvement] Malware scan: unverified → pass
- [security] Stability: Stability not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet.
- [security] The attested source repository moved: stonematt/mcp-obsidian-cli
- [functional regression] Capabilities: pass → unverified
- [functional regression] Schema quality: 100 → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional improvement] Maintenance: unverified → pass
- [functional improvement] Dependency health: unverified → partial
- [functional improvement] License: unverified → pass
- [functional improvement] Stability: unverified → 0.20
- [functional] Licence: MIT

### 2026-07-31 (score 36, −57)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 93, +93)

- [security improvement] Malware scan: unverified → pass
- [security improvement] Install scripts: unverified → pass
- [security improvement] Provenance: unverified → pass
- [security improvement] Source repository: unverified → pass
- [security improvement] Known CVEs: unverified → partial
- [security] The attested source repository moved: stonematt/mcp-obsidian-cli
- [functional regression] Security disclosure: unverified → fail
- [functional improvement] Dependency health: unverified → partial
- [functional improvement] Schema quality: unverified → excellent
- [functional improvement] Tool coverage: unverified → 100
- [functional improvement] License: unverified → pass
- [functional improvement] Schema quality: unverified → 100
- [functional improvement] Maintenance: unverified → pass
- [functional] Licence: MIT

### 2026-07-29 (score 0, −26)

- [security regression] Provenance: pass → unverified
- [security regression] Malware scan: pass → unverified
- [functional regression] Dependency health: partial → unverified

### 2026-07-28 (score 26, −25)

- [functional regression] Tool coverage: 100 → unverified
- [functional regression] Security disclosure: fail → unverified
- [functional regression] Schema quality: 100 → unverified
- [functional improvement] Dependency health: unverified → partial

### 2026-07-27 (score 51)

First indexed and scored.

## MCP tools (23)

### `obsidian` (~340 tokens)

Run any Obsidian CLI command. Pass the full command string exactly as you
would on the terminal (minus the leading 'obsidian' binary name). Leading
\`vault=NAME` overrides the active vault and is cached for subsequent calls.

Intent -> verb cheatsheet. Use the canonical verb on the right; the convenience
tools (`obsidian_*`) wrap the same verbs with typed args.

PUT
  put new note from template     -> templater:create-from-template template=… file=…
  create plain note              -> create path=… content=…
  append to today's daily        -> daily:append content=…
GET
  read note                      -> read path=…   (or file=…)
  search content                 -> search:context query=… [path=… limit=…]
  list properties / read one     -> properties [file=…]  |  property:read name=… file=…
  list backlinks                 -> backlinks file=…
MOVE/RENAME
  move or rename note            -> move file=… to=…   (or path=…)
DELETE
  delete note                    -> delete path=…
DISCOVER
  list files                     -> files [folder=… ext=…]
  list tags with counts          -> tags counts [sort=name|count]
  list tasks                     -> tasks [daily todo done path=…]
  recently opened                -> recents
  CLI reference                  -> help [verb]

If you don't see the intent here, the CLI's `help` verb is the source of truth.

Input parameters:

- `command` (string, required): CLI command and arguments

### `obsidian_daily_read` (~37 tokens)

Read today's daily note contents.

Returns the full markdown content of today's daily note. Returns an error if no daily note exists for today.

### `obsidian_daily_path` (~47 tokens)

Get the file path of today's daily note.

Returns the vault-relative path (e.g. 'Daily/2026-04-03.md'). Useful for constructing paths for other tools.

### `obsidian_daily_append` (~90 tokens)

Append content to today's daily note.

Parameters:
  content (required) — markdown text to append at the end of today's daily note

Examples:
  obsidian_daily_append({ content: "- Meeting with team at 3pm" })
  obsidian_daily_append({ content: "> [!tip] Remember\n> Review PR before EOD" })

Input parameters:

- `content` (string, required): Content to append

### `obsidian_read` (~129 tokens)

Read a note by file name (wikilink-style) or exact path.

Parameters:
  file (optional) — note name using wikilink resolution (e.g. 'My Note')
  path (optional) — exact vault-relative path (e.g. 'folder/My Note.md')
  One of file or path is required.

Examples:
  obsidian_read({ file: "Meeting Notes" })
  obsidian_read({ path: "Projects/todo.md" })

Input parameters:

- `file` (string): File name (wikilink resolution)
- `path` (string): Exact file path

### `obsidian_search` (~128 tokens)

Full-text search across the vault with line context.

Parameters:
  query (required) — search terms, supports Obsidian query syntax
  path (optional) — restrict results to a folder path
  limit (optional) — max number of files to return

Examples:
  obsidian_search({ query: "meeting notes" })
  obsidian_search({ query: "project status", path: "Work/", limit: 5 })

Input parameters:

- `limit` (number): Max files to return
- `path` (string): Limit to folder
- `query` (string, required): Search query

### `obsidian_tags` (~94 tokens)

List tags in the vault with counts.

Returns structured JSON content (an array of { tag, count } objects) alongside the text form, so clients can consume it without re-parsing.

Parameters:
  sort (optional) — 'name' or 'count' (default: name)

Examples:
  obsidian_tags({})
  obsidian_tags({ sort: "count" })

Input parameters:

- `sort` (string): Sort order

### `obsidian_tasks` (~175 tokens)

List tasks from vault notes.

Returns structured JSON content (an array of task objects with status, text, file, and line) alongside the text form, so clients can consume it without re-parsing.

Parameters:
  daily (optional) — true to show only today's daily note tasks
  todo (optional) — true to show only incomplete tasks
  done (optional) — true to show only completed tasks
  path (optional) — filter by file path

Examples:
  obsidian_tasks({ daily: true })
  obsidian_tasks({ todo: true, path: "Projects/" })

Input parameters:

- `daily` (boolean): Show only daily note tasks
- `done` (boolean): Show completed tasks only
- `path` (string): Filter by file path
- `todo` (boolean): Show incomplete tasks only

### `obsidian_properties` (~145 tokens)

List or read frontmatter properties.

Parameters:
  file (optional) — note name for wikilink resolution
  path (optional) — exact file path
  name (optional) — specific property name to read (requires file or path)

Examples:
  obsidian_properties({}) — list all properties with counts
  obsidian_properties({ file: "My Note" }) — properties of a specific note
  obsidian_properties({ file: "My Note", name: "status" }) — read one property

Input parameters:

- `file` (string): File name
- `name` (string): Specific property name to read
- `path` (string): File path

### `obsidian_create` (~219 tokens)

Create a new PLAIN note (no Templater expansion).

This wraps the CLI's `create` verb. It does NOT expand Templater placeholders
like `<% tp.date.now() %>` — if your template contains placeholders, use
\`obsidian_create_from_template` instead, which routes to
\`templater:create-from-template`.

Parameters:
  name (optional) — file name for the new note
  path (optional) — vault-relative path
  content (optional) — initial markdown content (literal, no placeholder expansion)

Examples:
  obsidian_create({ name: "Meeting 2026-04-03", content: "# Meeting Notes\n\n- Attendees: ..." })
  obsidian_create({ path: "Projects/new-idea.md", content: "# New idea" })

Input parameters:

- `content` (string): Initial content (literal — Templater placeholders are NOT expanded; use obsidian_create_from_template for that)
- `name` (string): File name
- `path` (string): File path

### `obsidian_create_from_template` (~256 tokens)

Create a new note from a Templater template, expanding placeholders.

This wraps the CLI's `templater:create-from-template` verb. Use this whenever
the template contains Templater placeholders such as `<% tp.date.now() %>`,
\`<% tp.file.title %>`, or any other `<% ... %>` expression — those are
evaluated by Obsidian's Templater plugin and substituted into the output.
For plain notes with no placeholder expansion, use `obsidian_create`.

Parameters:
  template (required) — vault-relative path to the Templater template (e.g. "Templates/daily.md")
  file (required) — vault-relative output path for the new note (e.g. "Daily/2026-05-18.md")

Examples:
  obsidian_create_from_template({ template: "Templates/daily.md", file: "Daily/2026-05-18.md" })
  obsidian_create_from_template({ template: "Templates/project.md", file: "Projects/new-idea.md" })

Input parameters:

- `file` (string, required): Vault-relative output path for the new note
- `template` (string, required): Vault-relative path to the Templater template

### `obsidian_property_set` (~385 tokens)

Set a frontmatter property on a note.

Parameters:
  name (required) — property name
  value (required) — property value (see type for multi-valued props)
  type (optional) — property type: text (default) | list | number | checkbox | date | datetime
  file (optional) — note name (wikilink resolution)
  path (optional) — exact file path
  One of file or path is required.

Multi-valued properties (tags, aliases, Links, etc.):
  You MUST pass type="list" AND a JSON-array string as value. Without type="list" the value is written as a single scalar string — a comma-separated value is NOT split into YAML list items, and bracketed wikilinks are never split. Use a JSON array universally; it is unambiguous for both plain strings and wikilinks.

Examples:
  obsidian_property_set({ name: "status", value: "done", file: "My Task" })
  obsidian_property_set({ name: "tags", value: "[\"project\", \"active\"]", type: "list", path: "Work/todo.md" })
  obsidian_property_set({ name: "Links", value: "[\"[[plan]]\", \"[[baseline]]\"]", type: "list", file: "My Task" })

Input parameters:

- `file` (string): File name
- `name` (string, required): Property name
- `path` (string): File path
- `type` (string): Property type. Use "list" for multi-valued props (tags/aliases/Links) with a JSON-array value; omitting it writes a scalar string
- `value` (string, required): Property value. For type="list", pass a JSON-array string, e.g. '["a", "b"]'

### `obsidian_backlinks` (~91 tokens)

List backlinks to a note.

Parameters:
  file (optional) — note name (wikilink resolution)
  path (optional) — exact file path

Examples:
  obsidian_backlinks({ file: "Project Plan" })
  obsidian_backlinks({ path: "Ideas/brainstorm.md" })

Input parameters:

- `file` (string): File name
- `path` (string): File path

### `obsidian_files` (~96 tokens)

List files in the vault or a specific folder.

Parameters:
  folder (optional) — filter by folder path
  ext (optional) — filter by file extension (e.g. 'md', 'canvas')

Examples:
  obsidian_files({})
  obsidian_files({ folder: "Projects/", ext: "md" })

Input parameters:

- `ext` (string): Filter by extension
- `folder` (string): Filter by folder path

### `obsidian_move` (~213 tokens)

Move or rename a note, selecting it by file name or exact path.

Wraps the CLI's `move` Verb. Provide one of file or path to select the note, and `to` for the destination. Setting `to` to a new name in the same folder renames the note.

Parameters:
  file (optional) — note name using wikilink resolution (e.g. 'My Note')
  path (optional) — exact vault-relative path (e.g. 'folder/My Note.md')
  to (required) — destination folder or vault-relative path
  One of file or path is required.

Examples:
  obsidian_move({ file: "My Note", to: "Archive/" })
  obsidian_move({ path: "Inbox/idea.md", to: "Projects/idea.md" })

Input parameters:

- `file` (string): File name (wikilink resolution)
- `path` (string): Exact file path
- `to` (string, required): Destination folder or vault-relative path

### `obsidian_outline` (~252 tokens)

List the heading outline of a note, selecting it by file name or exact path.

Wraps the CLI's `outline` Verb. Provide one of file or path. Optional `format` controls the output shape; optional `total` returns just the heading count.

Parameters:
  file (optional) — note name using wikilink resolution (e.g. 'My Note')
  path (optional) — exact vault-relative path (e.g. 'folder/My Note.md')
  format (optional) — output format: 'tree' (default), 'md', or 'json'
  total (optional) — true to return the heading count instead of the outline
  One of file or path is required.

Examples:
  obsidian_outline({ file: "Meeting Notes" })
  obsidian_outline({ path: "Projects/plan.md", format: "json" })
  obsidian_outline({ file: "Long Doc", total: true })

Input parameters:

- `file` (string): File name (wikilink resolution)
- `format` (string): Output format (default: tree)
- `path` (string): Exact file path
- `total` (boolean): Return heading count instead of the outline

### `obsidian_command` (~181 tokens)

Execute an Obsidian command by its canonical command ID.

Wraps the CLI's `command` Verb. Triggers any core or plugin command exactly as the user would from the command palette — identified by its stable command ID (e.g. 'editor:toggle-bold', 'app:go-back', 'daily-notes').

Discovering IDs: run the generic `obsidian` tool with the `commands` verb to list every available command ID, or `commands filter=<prefix>` to narrow by prefix (e.g. 'commands filter=editor:').

Parameters:
  id (required) — the command ID to execute

Examples:
  obsidian_command({ id: "editor:toggle-bold" })
  obsidian_command({ id: "daily-notes" })

Input parameters:

- `id` (string, required): Obsidian command ID to execute

### `obsidian_history` (~184 tokens)

List the saved file-history versions of a note, selecting it by file name or exact path.

Wraps the CLI's `history` Verb. Returns the version history (snapshots/sync revisions) recorded for a single note — not a list of recently-modified notes. Provide one of file or path to select the note.

Parameters:
  file (optional) — note name using wikilink resolution (e.g. 'My Note')
  path (optional) — exact vault-relative path (e.g. 'folder/My Note.md')
  One of file or path is required.

Examples:
  obsidian_history({ file: "Project Plan" })
  obsidian_history({ path: "Daily/2026-05-20.md" })

Input parameters:

- `file` (string): File name (wikilink resolution)
- `path` (string): Exact file path

### `obsidian_template_read` (~209 tokens)

Read the content of a template by name from the vault's templates folder.

Wraps the CLI's `template:read` Verb. Returns the raw template text. Set `resolve` to expand the template's variables (e.g. Templater placeholders) instead of returning them literally; pass `title` to supply the title used during that variable resolution.

Parameters:
  name (required) — template name (as it appears in the templates folder)
  resolve (optional) — true to resolve/expand template variables
  title (optional) — title used for variable resolution (with resolve)

Examples:
  obsidian_template_read({ name: "daily" })
  obsidian_template_read({ name: "meeting", resolve: true, title: "Standup 2026-05-20" })

Input parameters:

- `name` (string, required): Template name
- `resolve` (boolean): Resolve/expand template variables
- `title` (string): Title for variable resolution (used with resolve)

### `obsidian_rename` (~218 tokens)

Rename a note, selecting it by file name or exact path.

Wraps the CLI's `rename` Verb. Provide one of file or path to select the note, and `name` for the new file name. Renaming changes only the name within the same folder; use obsidian_move to relocate a note to a different folder.

Parameters:
  file (optional) — note name using wikilink resolution (e.g. 'My Note')
  path (optional) — exact vault-relative path (e.g. 'folder/My Note.md')
  name (required) — the new file name
  One of file or path is required.

Examples:
  obsidian_rename({ file: "Draft", name: "Final" })
  obsidian_rename({ path: "Inbox/idea.md", name: "refined-idea.md" })

Input parameters:

- `file` (string): File name (wikilink resolution)
- `name` (string, required): New file name
- `path` (string): Exact file path

### `obsidian_delete` (~223 tokens)

Delete a note, selecting it by file name or exact path.

Wraps the CLI's `delete` Verb. DESTRUCTIVE: by default the note is moved to the system trash (recoverable). Pass `permanent: true` to skip the trash and delete irrecoverably — there is no undo for a permanent delete.

Parameters:
  file (optional) — note name using wikilink resolution (e.g. 'My Note')
  path (optional) — exact vault-relative path (e.g. 'folder/My Note.md')
  permanent (optional) — true to skip trash and delete permanently (irreversible)
  One of file or path is required.

Examples:
  obsidian_delete({ file: "Old Draft" }) — moves to trash
  obsidian_delete({ path: "Inbox/spam.md", permanent: true }) — irreversible

Input parameters:

- `file` (string): File name (wikilink resolution)
- `path` (string): Exact file path
- `permanent` (boolean): Skip trash and delete permanently (irreversible)

### `obsidian_recents` (~31 tokens)

List recently opened files.

Returns the most recently opened files in the vault, ordered by last access time.

### `obsidian_help` (~338 tokens)

Get Obsidian help: a live verb index from the CLI, or reference docs by slug.

Parameters:
  topic (optional) — a verb name (e.g. "read", "daily:append", "property:set") OR a reference-doc slug (cli, markdown, bases, canvas)

Behavior:
  \- No topic — returns the live, category-grouped verb index parsed from the CLI's `help` output (Read, Write, Edit, Discover, Tasks, Daily, Properties, Plugins, Dev, Eval).
  \- Verb name — returns that verb's description and flag list from the live manifest.
  \- Doc slug — returns the Kepano-derived reference prompt (markdown / bases / canvas / cli syntax).
  \- Collision rule: the four reserved doc slugs (cli, markdown, bases, canvas) always return their reference doc, even when a CLI verb shares the name (e.g. `bases`). The shadowed verb still appears in the no-arg verb index.

Examples:
  obsidian_help({}) — browse the verb catalog
  obsidian_help({ topic: "read" }) — live verb help for `read`
  obsidian_help({ topic: "markdown" }) — Obsidian-flavored markdown reference
  obsidian_help({ topic: "bases" }) — Bases YAML schema, filters, formulas
  obsidian_help({ topic: "canvas" }) — JSON Canvas reference
  obsidian_help({ topic: "cli" }) — CLI command syntax reference

Input parameters:

- `topic` (string): Verb name or reference-doc slug (cli, markdown, bases, canvas)

## Diagnostics

Captured diagnostic sections: Provenance, Dependencies. The full working is on the page: https://verifymcp.io/servers/stonematt-mcp-obsidian-cli/mcp-obsidian-cli#diagnostics

## Score history

- 2026-08-03: 80
- 2026-08-02: 79
- 2026-08-01: 36
- 2026-07-31: 36
- 2026-07-30: 93
- 2026-07-29: 0
- 2026-07-28: 26
- 2026-07-27: 51

## Links

- npm package: https://www.npmjs.com/package/mcp-obsidian-cli
- Socket report: https://socket.dev/npm/package/mcp-obsidian-cli
- Repository: https://github.com/stonematt/mcp-obsidian-cli
- Changelog RSS feed: https://verifymcp.io/servers/stonematt-mcp-obsidian-cli/mcp-obsidian-cli/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/stonematt-mcp-obsidian-cli/mcp-obsidian-cli/changelog.json
- HTML version of this page: https://verifymcp.io/servers/stonematt-mcp-obsidian-cli/mcp-obsidian-cli
