obsidian-mcp
An MCP (Model Context Protocol) server for Obsidian vaults. Connects Claude (or any MCP client) directly to your vault — read, write, search, navigate links, and manage notes, canvases, and kanban boards.
Why obsidian-mcp?
The official Obsidian MCP plugin requires the Obsidian desktop app to be running and only works on the same machine. obsidian-mcp is a standalone server — no Obsidian app needed.
The intended setup is to host obsidian-mcp on a server or NAS where your vault is continuously synced (via Syncthing, git, rclone, or Obsidian Sync). Claude then connects to that server over the network, so:
- Always up to date — the server sees every change your Obsidian app writes, immediately
- Access from anywhere — connect from Claude Desktop, Claude Code, or any MCP client on any machine, without the vault being present locally
- Multiple clients — several Claude sessions can read the vault simultaneously; writes are serialized with per-file locking
- No app dependency — the server runs headless and starts automatically (systemd, Docker, etc.)
[Obsidian app] ──sync──► [vault on server] ◄──MCP── [Claude on any machine]
(phone/laptop) (NAS / VPS) (Claude Desktop / Code)
Features
- Read & Search — read notes, search full-text (exact/regex/fuzzy, optionally combined with a frontmatter filter or scoped to filenames), render embedded transclusions, inspect note outlines, list every file in the vault regardless of type
- Duplicate prevention —
find_similar_notes_toolranks notes by TF-IDF similarity so a new note doesn't duplicate an existing one under different wording - Schema linting —
lint_schema_toolvalidates frontmatter against the enums declared in your own_AI_INSTRUCTIONS.md, plus an optional cron-friendly health-check script - Write — create/overwrite notes (with automatic frontmatter preservation, dry-run previews, and unified diffs), patch sections or anchor-less body text, append content, update frontmatter (single or batch), manage tags, move notes with automatic wikilink rewriting
- Folders — list (optionally recursive with a full tree dump), create, delete, rename folders; renaming rewrites path-based wikilinks vault-wide
- Query & Graph — backlinks, broken links, orphan detection, BFS link graph, vault stats, task collection across vault
- Dataview-like queries — filter notes by tags, status, frontmatter fields (exact match or
$ne/$in/$nin/$existsoperators), or inline fields (key:: value) - Audit log — every write-tool call is recorded ({timestamp, tool, path, summary});
get_audit_log_toolqueries it (passpath=for one note's history) - Periodic Notes — read/preview daily, weekly, monthly, quarterly, yearly journal notes from templates
- Canvas (opt-in via
ENABLE_CANVAS) — read, create, and patch Obsidian Canvas (.canvas) files - Excalidraw (opt-in via
ENABLE_EXCALIDRAW) — read, create, and patch Obsidian Excalidraw (*.excalidraw.md) drawings - Kanban (opt-in via
ENABLE_KANBAN) — read, create, and manipulate Obsidian Kanban boards (columns and cards) - Bases (opt-in via
ENABLE_BASES) — read, create, and patch Obsidian Bases (.base) files — YAML-defined table/cards/list views over existing frontmatter properties - Attachments — list, read (text or base64), and add binary files
- Two auth variants — a static API key (Claude Code, Desktop, curl) and, optionally, GitHub OAuth (claude.ai Web/Mobile Custom Connector) — usable independently or at the same time
- Multi-vault (opt-in via
VAULTS_CONFIG) — serve several fully isolated vaults from one deployment, each identity (API key or GitHub login) mapped to only the vault(s) it may access - Templates — render Obsidian templates with built-in (
{{date}},{{title}}, …) and custom variables - MCP Resources — expose vault notes, stats, and tags as MCP resources for direct context injection
- MCP Prompts —
weekly_review,daily_notestarting points for common workflows
Installation
Via uvx (no clone needed):
VAULT_PATH=/your/vault uvx obsidian-remote-mcp
Via Docker (no Python needed):
docker compose up -d # see docker-compose.yml
From source:
git clone https://github.com/ykoellmann/obsidian-mcp.git
cd obsidian-mcp
uv sync
uv run obsidian-remote-mcp
Configuration
Copy .env.example to .env and set your vault path:
VAULT_PATH=/path/to/your/obsidian/vault
# Optional:
# READ_ONLY=true # safe default for network Compose deployments
# READ_PATHS=Notes/,Inbox/ # restrict all reads to specific rooted scopes
# WRITE_PATHS=Notes/,Inbox/ # restrict writes to specific folders
# DENY_READ_PATHS=.obsidian/,.trash/ # security boundary for all reads
# DENY_WRITE_PATHS=.obsidian/,.trash/,_AI_INSTRUCTIONS.md
# ALLOW_PERMANENT_DELETE=false
# REQUIRE_WRITE_PRECONDITIONS=true # require read revision before full overwrite
# INDEX_RECONCILE_INTERVAL=900 # full Markdown hash sweep every 15 minutes
# TRANSPORT=stdio # stdio (default), http (recommended for network use), or sse (legacy)
Slash-suffixed policy entries such as Notes/ cover that directory and its
descendants. An entry without a trailing slash grants or denies only the exact
path. For compatibility, native configuration still permits unrestricted
writes when both READ_ONLY=false and WRITE_PATHS is empty; choose that
combination explicitly, not as a network default. Use a case-sensitive
filesystem for authoritative path scopes.
Docker upgrade note: this Compose configuration now defaults
READ_ONLY=true, while a nativeConfiginvocation retains its historicalfalsedefault. Existing Docker deployments that intentionally write must explicitly setREAD_ONLY=false; pair it with a narrowWRITE_PATHSvalue. For a nested scope such asdeep/nested/, createdeep/beforehand. MCP may create the configurednested/scope and descendants, but never ancestors above the configured write boundary.
READ_PATHS is an optional allowlist using the same rooted exact/recursive
syntax. When set, direct reads, listings, search, index construction, and
resources are limited to those scopes; DENY_READ_PATHS still takes
precedence. Ancestor directories may be traversed only to reach an allowed
scope and do not expose sibling content.
EXCLUDE_PATHS uses those same rooted exact/recursive matching rules, but is
only a discovery filter—not an access-control boundary. For example,
private/ hides that root directory and its descendants, while it does not
hide Projects/private/.
Revision-aware note mutation tools must read the target to determine existence,
preserve frontmatter, calculate diffs, or derive an incremental edit. They
therefore reject paths covered by DENY_READ_PATHS even if WRITE_PATHS also
contains the path. Avoid overlapping those scopes for note workflows. The
storage policy can still support intentionally write-only capabilities that do
not inspect existing content, but write_note_tool is not one of them.
The best-effort JSONL audit log is application state, not vault content. It
defaults beneath LOCK_PATH for native runs and to /data/audit.jsonl in
Docker. AUDIT_LOG_PATH must remain outside VAULT_PATH; the final log file
is opened without following symlinks.
New files and directories use the normal 0666/0777 creation modes filtered
by the MCP process umask. Atomic overwrites preserve the existing file's
permission bits. In a shared sync deployment, run the MCP and sync daemon with
compatible UID/GID and umask settings so both can continue reading and updating
new notes; the home-server profile exposes these as PUID and PGID.
Direct note reads return an opaque sha256:... revision. Pass it as
expected_revision when replacing or appending to an existing note so an edit
landed by Obsidian Sync during the client's think time is reported as a conflict
instead of silently overwritten. Network Compose configurations enable strict
full-overwrite preconditions by default. Incremental patch/tag/frontmatter tools
always protect the exact version they read internally. This is optimistic
concurrency, not exactly-once execution: after a lost append response, re-read
and verify the result before retrying without the old revision.
Watcher events are debounced, and the index additionally hashes readable, indexable Markdown every 15 minutes by default to repair missed events. PDFs, images, other attachments, excluded paths, and Excalidraw files are not hashed. See the design note for the scope, measured cost, health fields, and remaining final-rename race.
Full list of variables — including API_KEY, PUBLIC_BASE_URL, and the
OAUTH_GITHUB_* variables for the optional second auth variant — is
documented with inline comments in .env.example; see Remote Setup
for the two auth variants in detail.
Optional plugin-format tools (Canvas / Excalidraw / Kanban / Bases)
# ENABLE_CANVAS=true # .canvas file tools
# ENABLE_EXCALIDRAW=true # *.excalidraw.md file tools
# ENABLE_KANBAN=true # Kanban board tools
# ENABLE_BASES=true # .base file tools (Obsidian core plugin, 1.9.0+)
# High-impact mutations are absent from the MCP tool list unless enabled.
# ENABLE_MOVE=true # move_note_tool
# ENABLE_FOLDER_RENAME=true # rename_folder_tool
# ENABLE_BULK_REPLACE=true # find_replace_in_vault_tool
# ENABLE_DELETE=true # delete_tool, restore_tool and list_trash_tool
Each defaults to false. A disabled group's tools aren't just refused at
call time — they're never registered, so they don't appear in the tool list
at all.
The high-impact mutation groups are similarly opt-in: set ENABLE_MOVE,
ENABLE_FOLDER_RENAME, ENABLE_BULK_REPLACE, or ENABLE_DELETE to register
the corresponding tools. Their underlying Python functions remain available
for local/unit-test use and future transactional implementations.
Usage with Claude Code
Add to your MCP config (e.g. ~/.claude/mcp.json):
{
"mcpServers": {
"obsidian": {
"command": "uv",
"args": ["--directory", "/path/to/obsidian-mcp", "run", "obsidian-remote-mcp"],
"env": {
"VAULT_PATH": "/path/to/your/obsidian/vault"
}
}
}
}
Usage with Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"obsidian": {
"command": "uv",
"args": ["--directory", "/path/to/obsidian-mcp", "run", "obsidian-remote-mcp"],
"env": {
"VAULT_PATH": "/path/to/your/obsidian/vault"
}
}
}
}
Docker
# 1. Copy and edit the environment variables
cp .env.example .env
# 2. Set HOST_VAULT_PATH and API_KEY in .env, then:
docker compose up -d
The docker-compose.yml pulls the pre-built image from GHCR — no cloning or building required. To build locally instead, swap image: for build: . in the compose file.
GitHub OAuth state is stored under /data/fastmcp by default, inside the
Compose mcp-data volume, so logins survive container restarts.
The image has a built-in HEALTHCHECK against GET /health (unauthenticated,
with no vault content or filesystem paths). It reports index readiness plus the
last reconciliation time, duration, and error, and is visible in
docker ps/docker compose ps. Only meaningful for TRANSPORT=http/sse; a
no-op for stdio.
Hardened home-server Compose profile
For a home server where Cloudflare Tunnel is the only network entry point,
use docker-compose.home-server.yml. It
builds the MCP image from the checked-out source, bind-mounts the complete
vault read-only, overlays only the two configured AI memory/output directories
read-write, sets matching WRITE_PATHS, runs as the configured non-root
UID/GID, and publishes no host port. The MCP service is only on an internal
network; cloudflared has that network plus a separate normal egress network
so it can reach Cloudflare without making MCP externally reachable.
Create the nested writable directories before starting it, set
HOST_VAULT_PATH, AI_MEMORY_PATH, AI_OUTPUT_PATH, PUID, PGID,
MCP_DATA_PATH, API_KEY, CLOUDFLARE_TUNNEL_TOKEN, and a digest-pinned
CLOUDFLARED_IMAGE (for example,
cloudflare/cloudflared@sha256:<digest>) in .env. Create the data directory
and make it owned by PUID:PGID; it stores /data/locks and application state.
Cloudflare Access Managed OAuth authenticates the edge, but it does not inject
this application's bearer API key. Clients must still send API_KEY to the
origin; trusted-proxy header injection is a future phase, not part of this
profile. Then run:
docker compose -f docker-compose.home-server.yml up -d
Folder/note trash and restore are intentionally unavailable in this nested-bind
profile: moving from a writable overlay into the read-only parent vault's
.trash would cross mounts. Keep ENABLE_DELETE=false (hard-coded here) and
do not enable folder restore in this topology.
The static Compose checks are covered by the test suite. A real deployment
test (Docker mount precedence, host UID/GID permissions, and the Cloudflare
Tunnel route) remains environment-specific and must be run on the target
server before relying on it. To update Cloudflared, choose a reviewed release,
resolve its immutable RepoDigest, update CLOUDFLARED_IMAGE, then recreate
the sidecar; rebuild the MCP service after source changes with
docker compose -f docker-compose.home-server.yml build --pull.
Health-Check Cron (Frontmatter Schema)
Separate from the /health liveness check above: scripts/health_check.py runs lint_schema_tool's logic directly (no MCP client needed) and, only if it finds notes whose frontmatter violates the enums declared in your _AI_INSTRUCTIONS.md, drops a report note into your vault's inbox folder. Silent when the vault is clean — no note, no noise.
# One-off / manual run:
VAULT_PATH=/path/to/vault HEALTH_CHECK_INBOX=00-Inbox python scripts/health_check.py
To run it weekly via cron against the running container:
# crontab -e (on the Docker host)
0 6 * * 1 docker exec obsidian-mcp-obsidian-mcp-1 \
env VAULT_PATH=/vault READ_ONLY=false WRITE_PATHS=00-Inbox/ \
HEALTH_CHECK_INBOX=00-Inbox python scripts/health_check.py
Swap the container name for whatever docker compose ps shows, and set both
HEALTH_CHECK_INBOX and WRITE_PATHS to your vault's actual inbox folder
(default Inbox). The command must have write access because it creates a
report when violations are found. With the home-server profile, choose an
inbox inside one of its writable nested mounts (for example AI-Output/).
Remote Setup (Recommended)
Run obsidian-mcp on a server and connect to it remotely. Network transports
(sse/streamable-http) need at least one of the two auth variants below —
API key and GitHub OAuth are independent and can be used at the same
time: keep the API key for Claude Code/Desktop/curl while adding OAuth only
for claude.ai, or use either one alone.
Security: Always put a TLS-terminating reverse proxy (e.g. Caddy) in front when exposing to the internet — required for GitHub OAuth callbacks in particular, since GitHub rejects plain
http://callback URLs except onlocalhost.API_KEY/OAuth are not needed for stdio transport (local use only).
Option A: API key (Claude Code, Claude Desktop, curl, mcp-remote)
1. Generate an API key:
openssl rand -hex 32
2. Configure the server (docker-compose.yml or .env):
VAULT_PATH=/data/vault
TRANSPORT=http
API_KEY=your-generated-key
(sse also works here, but see the note under Option B — http is the
more robust choice and works identically for this bearer-key setup.)
3. Start:
docker compose up -d # or: uv run obsidian-remote-mcp
4. Connect from your MCP client (anywhere on the network):
{
"mcpServers": {
"obsidian": {
"type": "http",
"url": "https://your-server/mcp",
"headers": {
"Authorization": "Bearer your-generated-key"
}
}
}
}
Option B: GitHub OAuth (claude.ai Web/Mobile Custom Connector)
claude.ai's "Custom Connector" UI only has fields for OAuth (Authorization URL, Token URL, Client ID/Secret) — no field for a bearer token or custom header. obsidian-mcp handles the whole OAuth protocol for you (discovery endpoints, PKCE, token exchange); you only ever hand claude.ai your server's URL.
1. Create a GitHub OAuth App: GitHub → Settings → Developer settings → OAuth Apps → New OAuth App.
- Homepage URL: your server's public URL (e.g.
https://obsidian.example.com) - Authorization callback URL: the same URL +
/auth/callback(e.g.https://obsidian.example.com/auth/callback)
Copy the generated Client ID and Client Secret.
2. Configure the server (docker-compose.yml or .env):
VAULT_PATH=/data/vault
TRANSPORT=http
PUBLIC_BASE_URL=https://obsidian.example.com # must match the GitHub callback host
OAUTH_GITHUB_CLIENT_ID=your-client-id
OAUTH_GITHUB_CLIENT_SECRET=your-client-secret
OAUTH_GITHUB_ALLOWED_LOGINS=your-github-username # comma-separated; required, no "allow anyone" fallback
OAUTH_GITHUB_ALLOWED_LOGINS is enforced at login: only the listed GitHub
accounts can authenticate, everyone else is rejected, even with a valid
GitHub account.
Use
TRANSPORT=http, notsse.ssecaused OAuth authorization errors with claude.ai specifically (token issued fine server-side, but claude.ai never followed up with a request) —httpfixed it.
3. Start:
docker compose up -d # or: uv run obsidian-remote-mcp
4. Connect from claude.ai: Settings → Connectors → Add Custom Connector,
and enter just the server URL (https://obsidian.example.com/mcp). claude.ai
discovers everything else (/.well-known/oauth-authorization-server, PKCE,
etc.) automatically and redirects you to GitHub to log in on first connect.
Persistence in Docker: OAuth client registrations and tokens are stored under FastMCP's own data directory, which is not inside the vault volume by default. Without a persistent mount there, every container restart logs claude.ai out and forces re-authentication. Set
FASTMCP_HOMEto a mounted path (seedocker-compose.yml) to avoid that.
Keep the vault synced on the server with Syncthing, git+cron, rclone, or Obsidian Sync. The file watcher picks up normal changes, while periodic Markdown reconciliation repairs missed watcher events.
Multi-Vault Setup
By default obsidian-mcp serves one vault (VAULT_PATH). If you need several
completely separate vaults from one deployment — e.g. a private vault and a
work vault, each only reachable by its own identity — set VAULTS_CONFIG to
the path of a JSON file instead. Vault path-policy settings (VAULT_PATH,
READ_PATHS, WRITE_PATHS, DENY_READ_PATHS, DENY_WRITE_PATHS, and
EXCLUDE_PATHS) and identity settings (API_KEY and
OAUTH_GITHUB_ALLOWED_LOGINS) then come from that file. See
vaults.json.example:
{
"vaults": {
"private": {"path": "/vaults/private", "exclude_paths": ["private/", ".obsidian/", ".trash/"]},
"monari": {"path": "/vaults/monari", "write_paths": ["02-Areas/monari/"]}
},
"identities": [
{"type": "api_key", "value": "sk-...", "vaults": ["private"]},
{"type": "github_login", "value": "your-github-username", "vaults": ["private", "monari"], "default": "private"}
]
}
Each vault entry can set read_paths, write_paths, deny_read_paths,
deny_write_paths, exclude_paths, and read_only independently. Path rules
are rooted: a trailing slash includes descendants, while a rule without one
matches only that exact path. exclude_paths controls discovery/indexing;
the read/write/deny fields are the access-control boundary.
VAULT_PATH= # unused — vaults.json defines paths instead
VAULTS_CONFIG=/data/vaults.json
TRANSPORT=http
Multi-vault mode requires an authenticated network transport (http, sse,
or streamable-http). It cannot be used with stdio, because stdio has no
authenticated request identity to map to a vault.
Each identities entry is either an API key (Authorization: Bearer <value>, same as Option A
above) or a GitHub login (same allowlist mechanism as
Option B — set
OAUTH_GITHUB_CLIENT_ID/SECRET/PUBLIC_BASE_URL as usual, just skip
OAUTH_GITHUB_ALLOWED_LOGINS since vaults.json replaces it). Both kinds
can be mixed and used at the same time, exactly like today. Whichever
identity a request authenticates as, every tool call is transparently
scoped to that identity's vault(s) — there is no way to reach a vault an
identity isn't listed for.
An identity with more than one entry in "vaults" can switch between them:
every tool accepts an optional vault=<name> argument for that one call. If
omitted, it uses the identity's configured "default"; an identity with
several vaults and no default must pass vault= explicitly.
list_vaults_tool() returns [{name, description, is_default}]
for whichever identity is calling, so an MCP client can discover what it's
allowed to pass — the built-in instructions tell Claude to call it first
and pass vault= when the conversation clearly points at a non-default
vault. There's no server-side memory of which vault was picked last; it's
re-selected on every call, same as any other argument.
/attachments/* (the direct binary upload/download route) is fully
multi-vault-aware: a plain Authorization: Bearer request resolves to that
identity's default vault, or pass ?vault=<name> in the URL to pick a
different one of its allowed vaults (same rule as the vault= tool
argument). create_attachment_token_tool's short-lived scoped tokens
(?exp=&sig=) work too, signed against the calling identity's own key and
bound to a specific vault — but only for api_key identities, since a
GitHub login has no static secret of its own to sign with; use a plain
Authorization: Bearer request for those instead.
Known limitation:
/healthdoesn't go through per-request auth/vault resolution — it always reports on the first vault listed invaults.json, regardless of which identity would be calling. It exposes no vault content either way (just process liveness), so this doesn't leak anything.
Vault Conventions (Customization)
Create _AI_INSTRUCTIONS.md in your vault root to teach the AI how your specific vault is organized:
## Structure
- `Notes/` — evergreen notes and concepts
- `Projects/` — active and archived projects (tag: #project/active, #project/done)
- `Journal/` — daily notes (YYYY-MM-DD.md)
## Frontmatter Schema
- status: active | done | inbox
- tags: nested with / (e.g. #concept/programming)
## Conventions
- Link by stem only, never by full path
- Every note needs a created: date in frontmatter
In single-vault mode, the server loads this file at startup and sends it to
the AI as system instructions. Without it, built-in generic Obsidian syntax
guidance is used. Multi-vault servers always use the generic startup
instructions because MCP server instructions are shared by every identity;
use get_vault_conventions_tool(vault=...) to load the selected vault's
conventions after authorization. The _AI_INSTRUCTIONS.md is the right place
for everything vault-specific — folder layout, tag schema, naming conventions,
and any workflow rules.
Tool Reference
| Category | Tools |
|---|---|
| Read | list_notes, read_note (mode: full/outline/rendered), search_notes |
| Write | write_note, patch_note, delete, restore, append_to_note, patch_frontmatter (one note or many), manage_tags, move_note, find_replace_in_vault |
| Folders | list_folder, create_folder, rename_folder, list_trash* (folders are deleted/restored by delete/restore) |
| Query | query_notes, get_backlinks, get_broken_links, get_orphans, get_link_graph, get_vault_stats, get_tasks, resolve_alias |
| Tags | list_all_tags (mode: flat/tree; notes for one tag: query_notes(tags=[...])) |
| Periodic | get_periodic_note |
| Canvas | list_canvases, read_canvas, write_canvas, patch_canvas |
| Excalidraw | list_excalidraw, read_excalidraw, write_excalidraw, patch_excalidraw |
| Kanban | read_kanban, create_kanban_board, add_kanban_card, move_kanban_card, delete_kanban_card |
| Bases | list_bases, read_base, write_base, patch_base |
| Attachments | list_attachments, read_attachment, add_attachment |
| Templates | list_templates, create_from_template |
* Delete, restore, and trash-listing tools are registered only when ENABLE_DELETE=true.
Canvas, Excalidraw, Kanban, and Bases are each opt-in (see Optional plugin-format tools above) — their tools only appear once the matching ENABLE_* flag is set.
Full parameter documentation is embedded in the server and shown automatically to connected AI clients.
Architecture
src/obsidian_mcp/
├── config.py # env-based config and read/write security boundaries
├── server.py # FastMCP entry point, tool and resource registrations
├── domain/
│ ├── models.py # Note dataclass (frontmatter, tags, wikilinks, tasks, …)
│ ├── parser.py # Markdown parser (YAML frontmatter, wikilinks, block refs, …)
│ └── index.py # VaultIndex — alias resolution, backlinks, tag tree, BFS
├── storage/
│ ├── filesystem.py # VaultStorage authorization and atomic writes
│ ├── locking.py # hashed locks outside the synced vault
│ └── watcher.py # watchdog-based vault change detection (polling fallback)
└── tools/
├── read.py # read_note, search_notes, render_note, get_note_outline
├── write.py # write_note, patch_note, move_note, manage_tags, …
├── query.py # graph tools, task aggregation, periodic notes, query_notes
├── folders.py # folder management
├── canvas.py # Obsidian Canvas (.canvas JSON) tools
├── excalidraw.py # Obsidian Excalidraw (*.excalidraw.md) tools
├── kanban.py # Obsidian Kanban plugin tools
├── bases.py # Obsidian Bases (.base YAML) tools
├── attachments.py # binary and text attachment handling
├── templates.py # template rendering with variable substitution
└── prompts.py # MCP Prompts (weekly_review, daily_note)
Development
uv run pytest -q # complete automated suite
uv run ruff check src/ tests/ scripts/run_local_smoke_test.py scripts/smoke_test_mcp.py
Local HTTP functional smoke test
The automated suite exercises most behavior in process. This command also starts the installed server entry point and connects a real authenticated MCP client over HTTP:
uv run python scripts/run_local_smoke_test.py
The runner chooses a free localhost port, creates a disposable vault and API
key, starts and health-checks the server, then invokes smoke_test_mcp.py. The
client lists tools, creates and reads a uniquely named note, overwrites it,
verifies the bytes on disk, and confirms that a write outside WRITE_PATHS is
rejected. The runner always stops the server and removes successful test data;
pass --keep to retain the disposable vault and server log for inspection.
Use smoke_test_mcp.py directly for an already-running local, containerized,
or remote server. It reads the bearer token from OBSIDIAN_MCP_API_KEY (or
prompts securely), so secrets do not need to appear in command history or
process arguments. Its denied-write probe is opt-in via --denied-note PATH;
only provide a path known to be outside that server's configured write scope.
License
MIT
Metadata
Release files for obsidian-remote-mcp 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| obsidian_remote_mcp-2.0.0.tar.gz | 250.9 kB | Without provenance | Details for obsidian_remote_mcp-2.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| obsidian_remote_mcp-2.0.0-py3-none-any.whl | Python 3 | none | any | Details for obsidian_remote_mcp-2.0.0-py3-none-any.whl |
Total release size: 361.1 kB
Release files / obsidian_remote_mcp-2.0.0.tar.gz
| Download URL | obsidian_remote_mcp-2.0.0.tar.gz |
|---|---|
| Size | 250.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3398f84006cc8c1bec8e0591ae0e06e974b338f1e30da53c1a3a05a42e6d670a
|
|
BLAKE2b-256 checksum How to use checksums |
7d270b8418739c7c3b98197fcb75cafe3c2a43395125ca2ca883286369ff4591
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / obsidian_remote_mcp-2.0.0-py3-none-any.whl
| Download URL | obsidian_remote_mcp-2.0.0-py3-none-any.whl |
|---|---|
| Size | 110.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5976a44c782fd122a954ce22758c25f90d7650e570a47b0b762d4fd5ca21bb24
|
|
BLAKE2b-256 checksum How to use checksums |
eba8e7b2bb24ea424b64c9f2309184bf86295d2793de8e5b85be9eadcbee6c70
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for obsidian-remote-mcp 2.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.