Fenced Obsidian Sync
БесплатноНе проверенA deny-by-default MCP server for Obsidian vaults where operators declare exact capabilities (list, read, create, etc.) scoped by path globs; everything not perm
Описание
A deny-by-default MCP server for Obsidian vaults where operators declare exact capabilities (list, read, create, etc.) scoped by path globs; everything not permitted is impossible by construction as disallowed tools are never registered.
README
A deny-by-default, finely fenced MCP server
over an Obsidian vault. The operator declares exactly which capabilities (list,
read, create, …) an agent gets, each scoped by path globs — and everything
else is impossible by construction, not merely guarded.
Other Obsidian MCP servers hand an agent broad read/write/search/delete. Here
the fence is the product: you can run it so an agent may only create notes
under Inbox/, or only see note titles, or touch nothing at all — and prove
the rest is impossible because the tools are never registered.
Full design brief: docs/SPEC.md. The "Core principles (security invariants)" there are requirements, and each is backed by a test.
Install
pip install -e ".[http,dev]" # http extra for remote serving; dev for tests
Requires Python ≥ 3.10.
Run
fenced-obsidian-sync-mcp --config examples/create-only.yaml
# or
python -m fenced_obsidian_sync_mcp --config examples/create-only.yaml
By default this speaks stdio (for a local MCP client). Set
transport.type: http for remote serving (see below).
The three canonical postures
Each is a complete, runnable config (full files in examples/).
1. Deny-all — a dark vault
The server runs but exposes no tools at all.
mode: local
vault: /path/to/your/vault
capabilities: {}
2. Create-only — file, never read
The agent can drop new notes into Inbox/ and do nothing else. No
read/list/update/delete tool is registered. Collisions never overwrite.
mode: local
vault: /path/to/your/vault
collision: suffix # fail | suffix
capabilities:
create:
enabled: true
allow: ["Inbox/**"]
3. Titles-only — see names, not bodies
The agent learns which notes exist (to suggest links) but no registered tool
can open their contents. read and read_metadata are absent.
mode: local
vault: /path/to/your/vault
capabilities:
list:
enabled: true
allow: ["**/*.md"]
deny: ["Private/**", "Journal/**"]
Capabilities
Every capability is off by default and independently path-scoped. Enabling one registers exactly one tool; disabling it means the tool is absent from the MCP tool list.
| Capability | Tool | Exposes | Opens file contents? |
|---|---|---|---|
list |
list_notes |
enumerate paths / filenames | no — readdir only |
read_metadata |
read_metadata |
frontmatter, tags, stat | frontmatter only |
read |
read_note |
full note contents | yes |
search |
search_notes |
content search (implies read) |
yes |
create |
create_note |
new files only, never overwrite | no |
update |
update_note |
modify / append existing files | n/a |
delete |
delete_note |
remove files | n/a |
move |
move_note |
rename / relocate, never overwrite | n/a |
search implies read: enabling search without read is a config error,
because returning snippets while read is off would be a content oracle.
Glob semantics
Globs use wcmatch with GLOBSTAR,
evaluated against vault-relative POSIX paths:
**spans directories (**/*.mdmatches at any depth);*matches within a single segment.- Case-sensitive.
- Dotfiles are not matched unless a pattern names the leading dot, so
.obsidian/stays out of**/*.md. denyalways beatsallowon every capability.
Modes
mode: local— pointvaultat a directory you already keep current (Syncthing, iCloud, git, or nothing). No sync subprocess, noobsidian-headlessdependency. Works anywhere, including a phone via Termux.mode: sync—vaultis your remote Obsidian Sync vault name andvault_diris the local directory the officialobsidian-headlessclient (ob sync --continuous) mirrors into. The server supervises that process.
The fence is identical in both modes; only how the directory stays current differs.
⚠️ Sync-mode write warning: in
syncmode,update/delete/movepropagate to every device on your Obsidian Sync. Create-only is the conflict-free default; enable writes deliberately.
Transports
- stdio (default) — for a local MCP client.
- HTTP (
transport.type: http) — streamable-http behind a bearer token (required) and TLS. Terminate TLS in-process (transport.tls.certfile/keyfile) or at a reverse proxy such as Caddy. Full OAuth is a future extension; bearer + TLS is the supported remote posture today.
transport:
type: http
host: 0.0.0.0
port: 8080
auth: { bearer_token: "a-long-random-secret" }
tls: { certfile: /etc/ssl/certs/server.crt, keyfile: /etc/ssl/private/server.key }
Audit log
Optional structured JSONL of every allowed and denied call (capability, path, decision, and — for denials — an internal reason never shown to the client):
audit:
enabled: true
path: /var/log/fenced-obsidian-sync-mcp/audit.jsonl # omit -> stderr
Deploy with Docker (mode: sync)
The repo ships a Dockerfile, docker-compose.yml, and Makefile for running
mode: sync behind a reverse proxy (e.g. the central Caddy on a Hetzner box).
The image bundles both the Python server and the official obsidian-headless
(ob) client; TLS is terminated at the proxy, so the container speaks plain
HTTP on 0.0.0.0:4012 and the bearer token comes from $FOSM_BEARER_TOKEN.
# 1. one-time obsidian-headless auth (persists in named volumes)
make ob-login # interactive: email, password, MFA
make ob-setup VAULT="My Vault" # links the remote vault into /vault
# 2. config + secret
cp examples/config.docker-sync.yaml config.yaml # edit vault name + globs
cp .env.example .env && echo "FOSM_BEARER_TOKEN=$(openssl rand -hex 32)" > .env
# 3. run
make deploy # docker compose up -d --build
bearer_token_env: FOSM_BEARER_TOKEN in the config sources the token from the
container environment, keeping the secret out of the config file and git. Point
your reverse proxy at 172.18.0.1:4012 (the Docker bridge gateway) and, because
MCP streamable-http uses SSE, disable proxy buffering — in Caddy:
reverse_proxy 172.18.0.1:4012 { flush_interval -1 }.
Security invariants
These are guaranteed and tested (tests/):
- Deny by default — a disabled capability's tool is not registered.
- Capabilities are independent — knowing a note exists (
list) is separate from its metadata (read_metadata) is separate from its body (read). - Path confinement —
.., absolute paths, escaping symlinks, and percent-/double-encoded separators are all rejected. - No silent overwrite —
createusesO_EXCL; collisionsfailorsuffix. - Glob-scoped, deny-wins —
denyalways beatsallow. - No existence oracle — denied paths return a uniform
not permitted. - Auditable — optional structured log; a small, readable codebase.
Development
pip install -e ".[http,dev]"
pytest # full invariant + acceptance suite
ruff check .
License
MIT
Установить Fenced Obsidian Sync в Claude Desktop, Claude Code, Cursor
unyly install fenced-obsidian-sync-mcpСтавит в Claude Desktop, Claude Code, Cursor и VS Code — сам разбирается с npx, uvx и сборкой из исходников.
Впервые? Поставь CLI: curl -fsSL https://unyly.org/install | sh
Или настроить вручную
Выполни в терминале:
claude mcp add fenced-obsidian-sync-mcp -- uvx --from git+https://github.com/mmsge/fenced-obsidian-sync-mcp fenced-obsidian-sync-mcpFAQ
Fenced Obsidian Sync MCP бесплатный?
Да, Fenced Obsidian Sync MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Fenced Obsidian Sync?
Нет, Fenced Obsidian Sync работает без API-ключей и переменных окружения.
Fenced Obsidian Sync — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Fenced Obsidian Sync в Claude Desktop, Claude Code или Cursor?
Открой Fenced Obsidian Sync на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Fenced Obsidian Sync with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
