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 分