Evc Team Relay Mcp

io.github.entire-vc由 GitHub 帳號 entire-vc 發布v1.0.10更新於 Nov 1, 2026

MCP server for AI agent read/write access to Obsidian vaults via EVC Team Relay.

概覽

AI 產生的概覽

讓 AI 助理透過 EVC Team Relay 伺服器讀寫 Obsidian 筆記庫中的共享資料夾:列出共享、搜尋、讀取檔案,並新增或覆寫檔案。

可以做什麼
  • 驗證身分並回報目前使用的驗證模式,接著找出可存取的共享
  • 列出共享資料夾中的檔案,並依路徑或名稱搜尋
  • 依路徑讀取單一檔案的完整內容
  • 在共享資料夾中新增或覆寫檔案(僅限 agent key 模式),變更會同步到訂閱者的筆記庫
  • 文件讀寫與單檔刪除工具雖已列出,但後端沒有對應路由,呼叫必定報錯
適用情境
當你的筆記存放在透過自架或託管的 EVC Team Relay 同步的 Obsidian 筆記庫中,並希望助理在其中搜尋、閱讀、新增或更新筆記時使用。適合已在運作 Team Relay 的團隊,而非單獨使用 Obsidian 的個人。
執行需求
本機需 Python 3.10+ 及 uv 或 pip(PyPI 套件,可用 uvx 執行),也可用 Docker/HTTP 部署。需要一個運作中的 Team Relay 執行個體及其控制面帳號。必須設定 RELAY_CP_URL;驗證使用 RELAY_AGENT_KEY 或 RELAY_AGENT_KEYS,或使用 RELAY_EMAIL 搭配 RELAY_PASSWORD。需能連線至控制面網路。
安裝前請注意
需要密鑰:RELAY_AGENT_KEY、RELAY_AGENT_KEYS 或 RELAY_PASSWORD,可存取共享筆記庫內容。upsert_file 會寫入並覆寫檔案,變更會同步進他人的筆記庫,誤操作會擴散。電子郵件密碼模式依設計僅供讀取。選用的 HTTP 傳輸本身沒有驗證機制,綁定到 localhost 以外會讓所有工具呼叫暴露,建議改用 SSH 通道或反向代理。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Evc Team Relay Mcp,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

EVC Team Relay - MCP Server

[PyPI] [Docker Hub] [License: MIT] [MCP] [Smithery] [Install via Spark]

Give your AI agent read/write access to your Obsidian vault.

Your agent reads your notes, creates new ones, and stays in sync — all through the Team Relay API.

Works with Claude Code, Codex CLI, OpenCode, and any MCP-compatible client.

[evc-team-relay-mcp MCP server]

Quick Start

1. Install

Option A — from PyPI (recommended):

No installation needed — uvx downloads and runs automatically. Skip to step 2.

Option B — from source:

bash
git clone https://github.com/entire-vc/evc-team-relay-mcp.gitcd evc-team-relay-mcpuv sync   # or: pip install .

2. Configure your AI tool

Add the MCP server to your tool's config. Choose one authentication method:

Agent key (recommended) — create a key in the Obsidian plugin → Team Relay settings → Agent Keys. Supports read and write: list_files, read_file, tr_search, and upsert_file all work with a single key. Quickstart →

Email + password — use a dedicated agent account on your Relay instance.

Claude Code — agent key

Add to .mcp.json in your project root or ~/.claude/.mcp.json:

json
{  "mcpServers": {    "evc-relay": {      "command": "uvx",      "args": ["evc-team-relay-mcp"],      "env": {        "RELAY_CP_URL": "https://cp.yourdomain.com",        "RELAY_AGENT_KEY": "tr_agent_your_key_here"      }    }  }}
Claude Code — email/password
json
{  "mcpServers": {    "evc-relay": {      "command": "uvx",      "args": ["evc-team-relay-mcp"],      "env": {        "RELAY_CP_URL": "https://cp.yourdomain.com",        "RELAY_EMAIL": "[email protected]",        "RELAY_PASSWORD": "your-password"      }    }  }}
Codex CLI

Add to your codex.json:

json
{  "mcp_servers": {    "evc-relay": {      "type": "stdio",      "command": "uvx",      "args": ["evc-team-relay-mcp"],      "env": {        "RELAY_CP_URL": "https://cp.yourdomain.com",        "RELAY_AGENT_KEY": "tr_agent_your_key_here"      }    }  }}
OpenCode

Add to opencode.json:

json
{  "mcpServers": {    "evc-relay": {      "command": "uvx",      "args": ["evc-team-relay-mcp"],      "env": {        "RELAY_CP_URL": "https://cp.yourdomain.com",        "RELAY_AGENT_KEY": "tr_agent_your_key_here"      }    }  }}
From source (all tools)

If you installed from source instead of PyPI, replace "command": "uvx" / "args": ["evc-team-relay-mcp"] with:

json
"command": "uv","args": ["run", "--directory", "/path/to/evc-team-relay-mcp", "relay_mcp.py"]

Environment variables:

VariableRequiredDescription
RELAY_CP_URLYesControl plane base URL
RELAY_AGENT_KEYOne ofAgent key from plugin settings — read + write (recommended)
RELAY_EMAILOne ofAccount email (email/password mode)
RELAY_PASSWORDOne ofAccount password (email/password mode)

Ready-to-copy config templates are also in config/.

3. Use it

Your AI agent now has these tools:

ToolDescription
authenticateAuthenticate with credentials (auto-managed)
list_sharesList accessible shares (filter by kind, ownership)
list_filesList files in a folder share
read_fileRead a file by path from a folder share
read_documentNot implemented — no backend route in any auth mode, always raises
upsert_fileCreate or update a file by path — agent-key mode only; raises in email/password (JWT) mode
write_documentNot implemented — no backend route in any auth mode, always raises
delete_fileNot implemented — no backend route in any auth mode, always raises

Typical workflow: list_shares -> list_files -> read_file / upsert_file

Authentication is automatic — the server logs in and refreshes tokens internally.

Tool availability matrix

Not every tool works in every auth mode, and one group doesn't work in either mode — these are two unrelated facts, so don't conflate them:

GroupToolsStatus
Agent key, folder shareslist_files, read_file, upsert_fileWorking — the only write path in this MCP server
JWT (email/password)list_files, tr_search, read_fileWorking, read-only by design
No backend route in either moderead_document, write_document, delete_fileAlways raise ValueError — not an auth restriction
  • Write access requires an agent key: upsert_file is the only write tool with a working backend route, and it only writes when an agent key (RELAY_AGENT_KEY / RELAY_AGENT_KEYS) is configured. JWT mode calling upsert_file raises a clear ValueError naming agent-key mode as the fix, instead of a confusing 404.
  • read_document, write_document, and delete_file are a separate, independent gap — the control plane has no backend route for them at all, in agent-key mode either. Switching to an agent key will not make them work: doc-share live content is CRDT/WebSocket-only (no REST bridge), and per-file delete has no DELETE route server-side yet. If routes for these are ever added, they'd still follow the agent-key-only write policy above — JWT would stay read-only.

Remote Deployment (HTTP Transport)

For shared or server-side deployments, run as an HTTP server:

bash
# Directuv run relay_mcp.py --transport http --port 8888
# Docker (pulls from Docker Hub automatically)RELAY_CP_URL=https://cp.yourdomain.com \[email protected] \RELAY_PASSWORD=your-password \docker compose up -d
# Or pull explicitlydocker pull deadalusevc/evc-team-relay-mcp:latest

By default the server binds to 127.0.0.1 (localhost-only) — the endpoint is not reachable over the network even if the host has a public IP. This matches the common case of a single MCP client on the same machine as the server.

Then configure your MCP client to connect via HTTP:

json
{  "mcpServers": {    "evc-relay": {      "type": "streamable-http",      "url": "http://127.0.0.1:8888/mcp"    }  }}

Remote access via SSH tunnel (recommended)

If your MCP client runs on a different machine than the server, tunnel to the localhost-bound port instead of exposing it publicly:

bash
# From the client machine, forward local 8888 to the server's localhost:8888ssh -N -L 8888:127.0.0.1:8888 user@your-server

Then point the client config at http://127.0.0.1:8888/mcp as above — traffic goes through the SSH tunnel, and the server's bind address never needs to change.

Public / reverse-proxy binding (opt-in)

If you genuinely need the server to accept connections from other hosts directly (e.g. it sits behind a reverse proxy that terminates TLS and handles auth), pass --host explicitly:

bash
uv run relay_mcp.py --transport http --port 8888 --host 0.0.0.0

Only do this behind a reverse proxy or firewall — the MCP HTTP endpoint itself has no built-in authentication, so binding it to 0.0.0.0 on an open network exposes every relay tool call to anyone who can reach the port.


Security

The MCP server provides significant security advantages over shell-based integrations:

  • No shell execution — all operations are Python function calls via JSON-RPC, eliminating command injection risks
  • No CLI arguments — credentials and tokens are never passed as process arguments (invisible in ps output)
  • Automatic token management — the server handles login, JWT refresh, and token lifecycle internally; the agent never touches raw tokens
  • Typed inputs — all parameters are validated against JSON Schema before execution
  • Single persistent process — no per-call shell spawning, no environment leakage between invocations

Note: If you're using the OpenClaw skill (bash scripts), consider migrating to this MCP server for a more secure and maintainable integration.


How It Works

┌─────────────┐      MCP        ┌──────────────┐     REST API     ┌──────────────┐     Yjs CRDT      ┌──────────────┐│  AI Agent   │ ◄────────────► │  MCP Server  │ ◄─────────────► │  Team Relay  │ ◄──────────────► │   Obsidian   ││ (any tool)  │  stdio / HTTP  │ (this repo)  │    read/write   │   Server     │    real-time     │    Client    │└─────────────┘                └──────────────┘                 └──────────────┘      sync         └──────────────┘

The MCP server wraps Team Relay's REST API into standard MCP tools. Team Relay stores documents as Yjs CRDTs and syncs them to Obsidian clients in real-time. Changes made by the agent appear in Obsidian instantly — and vice versa.


Prerequisites

  • Python 3.10+ with uv (recommended) or pip
  • A running EVC Team Relay instance (self-hosted or hosted)
  • A user account on the Relay control plane

Part of the Entire VC Toolbox

ProductWhat it doesLink
Team RelaySelf-hosted collaboration serverrepo
Team Relay SyncObsidian plugin for Team Relayinstall / repo
Relay MCPMCP server for AI agentsthis repo
OpenClaw SkillOpenClaw agent skill (bash)repo
Local SyncVault <-> AI dev tools syncrepo
Spark MCPMCP server for AI workflow catalogrepo

Community

Find us in other directories

[MCP Badge] [Glama] [Smithery]

License

MIT

來源:README.md,提交 26747aa

工具

9

authenticate

Check 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_shares

List 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.

輸入參數kindowned_only

list_files

List 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.

輸入參數share_id必填

read_file

Read 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).

輸入參數share_id必填file_path必填

read_document

Reserved 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".

輸入參數keydoc_idshare_id必填

upsert_file

Create 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].

輸入參數content必填share_id必填file_path必填

write_document

Reserved 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".

輸入參數keydoc_id必填content必填share_id必填

delete_file

Reserved 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").

輸入參數share_id必填file_path必填

版本歷史

3
  1. v1.0.10最新Nov 1, 2026
  2. v1.0.9Sep 23, 2026
  3. v1.0.3Sep 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分