A side-by-side look at the MCP Obsidian and Evc Team Relay MCP MCP servers: transport, auth, tools, quality signals, and the config to install either one in Claude, Cursor, Windsurf or VS Code.
Verdict: choose MCP Obsidian for knowledge & memory work as a local process; choose Evc Team Relay MCP for knowledge & memory as a local process. You can also run both side by side in one mcpServers block.
read_note, write_note, patch_note.RELAY_CP_URL, RELAY_AGENT_KEY, RELAY_EMAIL, RELAY_PASSWORD.authenticate, list_shares, list_files.Rows where the two servers differ are marked.
| Spec | ||
|---|---|---|
| Category | Knowledge & Memory | Knowledge & Memory |
| Quality signal | 73/100 · Great | 61/100 · Good |
| Install command | Confirmed | Confirmed |
| Transport | Local subprocess (stdio) | Local subprocess (stdio) |
| Auth | No auth required | other |
| Pricing | Free | Free |
| Required env vars | None listed | RELAY_CP_URLRELAY_AGENT_KEYRELAY_EMAILRELAY_PASSWORD |
| Verified owner | Community listing | Community listing |
| GitHub stars | 1,684 | 3 |
| Directory activity | 5 views 0 installs 0 upvotes | 4 views 0 installs 0 upvotes |
| Tools | 18 | 9 |
| Full listing | View MCP Obsidian | View Evc Team Relay MCP |
read_noteRead a note from the Obsidian vaultwrite_noteWrite a note to the Obsidian vaultpatch_noteEfficiently update part of a note by replacing a specific string. This is more efficient than rewriting the entire note for small changes.list_directoryList files and directories in the vault (includes non-note filenames, while read/write tools remain note-only)delete_noteDelete a note from the Obsidian vault (requires confirmation). Supports permanent delete, vault trash, or system trash.search_notesSearch for notes in the vault by content or frontmattermove_noteMove or rename a note in the vaultmove_fileMove or rename any file in the vault (binary-safe, file-only, requires confirmation)read_multiple_notesRead multiple notes in a batch (max 10 files)update_frontmatterUpdate frontmatter of a note without changing contentget_notes_infoGet metadata for notes without reading full contentget_frontmatterExtract frontmatter from a note without reading the contentauthenticateCheck which auth mode is active (agent key or email/password) and log in if needed.
Takes no arguments; call it first, once, before any other tool.
In agent-key mode (RELAY_AGENT_KEY or RELAY_AGENT_KEYS is set): no login
is needed — each request carries X-Agent-Key directly, this just reports
which mode is active.
In email/password mode: logs in with the RELAY_EMAIL and RELAY_PASSWORD
env vars. The resulting token is managed internally; subsequent tool
calls use it automatically — you never need to pass it yourself.
list_sharesList the shared folders and documents this key or account can access.
Only lists what auth mode/key was granted — it does not create or change
access. Example: `list_shares(kind="folder")`.
In multi-key mode (RELAY_AGENT_KEYS set): returns metadata for every share
that has a configured key, fetched via per-share agent-key auth.
RELAY_AGENT_KEYS is typically keyed by share UUID, but the bare
share-metadata endpoint (/v1/web/shares/{ref}) only resolves web slugs —
a UUID always 404s there. When that happens this falls back to the
UUID-addressable files-index endpoint, which proves the share is real
and reachable but can't report kind/path/visibility (reported as
kind="unknown", plus a file_count instead).
A per-share failure (bad key, wrong share, share genuinely gone) is
NEVER silently dropped — it lands in the response's `errors` field.
"Couldn't check this share" and "checked, it doesn't exist" must stay
distinguishable; collapsing both into an empty list is what let a
config/auth problem read as "you have no shares".
In single-key mode (RELAY_AGENT_KEY only): returns an empty list — the
single key is tied to one share but its identity is unknown; call list_files
or tr_search directly with the known share_id.
In email/password mode: returns all shares the user has access to.
Args:
kind: Filter by share type — "doc" or "folder". Empty for all.
owned_only: If true, only return shares owned by the user (email/password mode only).
Returns:
On full success: a bare JSON array of shares (id, kind, path,
visibility, user_role — or id/kind="unknown"/file_count for
UUID-resolved entries).
If any share failed to resolve: a JSON object
{"shares": [...], "errors": {share_ref: "reason"}} instead of a
silently-shortened array.
list_filesList every file in a shared folder with its metadata.
Read-only; does not download file contents (use read_file for that).
In agent-key mode (RELAY_AGENT_KEYS or RELAY_AGENT_KEY is set): uses the
agent-key endpoint; share_id may be a UUID or web slug.
In email/password mode: share_id must be a UUID.
Args:
share_id: UUID or web slug of the folder share, e.g.
"a1b2c3d4-..." or "research-vault".
Returns:
Object with share_id and files map (path -> metadata). The exact set
of metadata keys per file is server-controlled, hence the loose
dict[str, Any] shape rather than a strict per-field schema.
tr_searchFind files in a shared folder by a case-insensitive match on path or name.
Read-only; does not download file contents (use read_file for that).
Example: `tr_search(share_id="research-vault", query="roadmap")`.
In agent-key mode (RELAY_AGENT_KEY is set): share_id may be UUID or web slug.
In email/password mode: share_id must be a UUID.
Args:
share_id: UUID or web slug of the folder share.
query: Search string matched case-insensitively against file paths.
limit: Max results to return (default 20).
Returns:
JSON list of matching files:
[{"id": doc_id_or_null, "title": filename_without_ext, "path": full_path,
"relay_url": "relay://<slug>/<path>", "updated_at": null}]
read_fileRead one file from a shared folder by its path.
Read-only. Returns the full file content in one response — there is no
partial/range read.
In agent-key mode (RELAY_AGENT_KEY is set): fetches via the agent-key
download endpoint; share_id may be a UUID or web slug.
In email/password mode: fetches via the same CAS download endpoint used by
agent-key mode, over Bearer JWT instead of X-Agent-Key; share_id must be a UUID.
Args:
share_id: UUID or web slug of the folder share.
file_path: File path within the folder (e.g. "Marketing/plan.md").
Returns:
{"path", "content", "format"} on success, or {"error": ...} if the
file doesn't exist — two distinct shapes on the same 200-equivalent
outcome, hence dict[str, Any] rather than a strict per-field schema
(a stricter schema would reject the error shape as invalid output).
read_documentReserved for live document content; not yet available on the server, use read_file.
Always raises: the control-plane has no REST route for reading a
document's live content by ID for either DOC-kind shares or a
folder-share file's doc_id (that concept doesn't exist in the current
CAS-based folder sync model). This is a genuine backend gap, not an
agent-key-vs-JWT restriction. Use read_file for folder shares instead —
it works in both agent-key and JWT mode.
Args:
share_id: UUID of the share (for ACL check).
doc_id: Document UUID. Defaults to share_id for doc shares.
key: Yjs shared type key. Default "contents".
upsert_fileCreate or overwrite a file in a shared folder; it syncs into subscribers' vaults. Agent key only.
**Write access is agent-key-only by design** — this is the sanctioned,
permanent policy (not a temporary gap): agent-key mode is the only
authorized write path in this MCP server.
**Agent key mode** (RELAY_AGENT_KEY is set):
- share_id may be the share UUID or web slug (e.g. "research-vault")
- Folder shares use /sync-upload → file enters the CRDT sync store and
appears in subscribers' local Obsidian vaults on the next sync cycle
- Doc shares fall back to /upload (web-publish only)
- list_files, read_file, and tr_search also work with the same agent key
**Email/password (JWT) mode** — always raises; intentionally read-only.
There is no write route reachable by JWT for an arbitrary (non-web-
published) folder share, and even if one existed, JWT mode stays
read-only by policy. Use agent-key mode for writes.
Args:
share_id: Share UUID (email/password mode) or web slug (agent key mode).
file_path: File path within the share (e.g. "notes/todo.md").
content: Full text content to write.
Returns:
Object with path, size/operation, and optional public_url (agent-key
mode). The exact set of keys is server-controlled (plus the
"operation" key added here), hence dict[str, Any].
write_documentReserved for live document writes; not yet available on the server, use upsert_file.
Always raises: the control-plane has no REST route for writing a
document's live content by ID (doc-share content is CRDT/WebSocket-only).
This is a genuine backend gap in BOTH agent-key and JWT mode, not an
agent-key-vs-JWT restriction — but were a route ever added, per the
sanctioned write policy (agent-key writes only) JWT mode would still be
read-only.
Args:
share_id: UUID of the share (for ACL check).
doc_id: Document UUID.
content: Full text content to write (replaces entire document).
key: Yjs shared type key. Default "contents".
delete_fileReserved for per-file deletion; not yet available on the server.
Always raises: the control-plane has no DELETE route for an individual
folder-share file in ANY auth mode (agent-key or JWT) — this isn't a
JWT-vs-agent-key gap, per-file deletion simply isn't implemented
server-side yet. Note this is independent of the agent-key-only write
policy that governs upsert_file: even once/if a delete route lands, it
would follow that same policy (agent-key-only, JWT read-only).
Args:
share_id: UUID of the folder share.
file_path: File path within the folder (e.g. "old-note.md").
Paste either block (or both) into your client config, e.g. claude_desktop_config.json or ~/.cursor/mcp.json. We only show a config when the install command is confirmed.
{
"mcpServers": {
"bitbonsai-mcp-obsidian": {
"command": "npx",
"args": [
"-y",
"@bitbonsai/mcpvault@latest"
]
}
}
}
{
"mcpServers": {
"evc-team-relay-mcp": {
"command": "uvx",
"args": [
"evc-team-relay-mcp"
],
"env": {
"RELAY_CP_URL": "YOUR_RELAY_CP_URL_HERE",
"RELAY_AGENT_KEY": "YOUR_RELAY_AGENT_KEY_HERE",
"RELAY_EMAIL": "YOUR_RELAY_EMAIL_HERE",
"RELAY_PASSWORD": "YOUR_RELAY_PASSWORD_HERE"
}
}
}
}