Evc Team Relay Mcp

io.github.entire-vcPublished by GitHub account entire-vcv1.0.10Updated Nov 1, 2026

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

Overview

AI-generated overview

Gives an AI assistant read and write access to Obsidian vaults shared through an EVC Team Relay server, via folder-share listing, search, reading and file…

What you can do
  • Authenticate and report the active auth mode, then discover accessible shares
  • List files in a shared folder and search them by path or name
  • Read a single file's full content by path
  • Create or overwrite a file in a shared folder (agent-key mode only), which syncs into subscribers' vaults
  • Document read/write and per-file delete tools exist but always raise, since the backend has no route for them
When to use it
Use it when your notes live in Obsidian vaults synced through a self-hosted or hosted EVC Team Relay instance and you want an assistant to search, read, and add or update notes there. It suits teams that already run Team Relay rather than standalone Obsidian users.
Requirements
A local Python 3.10+ runtime with uv or pip (PyPI package, run via uvx), or a Docker/HTTP deployment. A running Team Relay instance and a user account on its control plane. RELAY_CP_URL is required; authentication uses either RELAY_AGENT_KEY or RELAY_AGENT_KEYS, or RELAY_EMAIL with RELAY_PASSWORD. Network access to the control plane.
Before you install
Requires secrets: RELAY_AGENT_KEY, RELAY_AGENT_KEYS or RELAY_PASSWORD, which grant access to shared vault content. upsert_file writes and overwrites files that sync into other people's vaults, so mistakes propagate. Email/password mode is read-only by design. The optional HTTP transport has no built-in authentication; binding it beyond localhost exposes every tool call, so use an SSH tunnel or a reverse proxy.

Installation

In SourceWeft

  1. Open Evc Team Relay Mcp in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

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

Source: README.md at commit 26747aa

Tools

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.

Takes no parameters.

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.

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

Parametersshare_idrequired

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

Parametersshare_idrequiredfile_pathrequired

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

Parameterskeydoc_idshare_idrequired

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

Parameterscontentrequiredshare_idrequiredfile_pathrequired

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

Parameterskeydoc_idrequiredcontentrequiredshare_idrequired

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

Parametersshare_idrequiredfile_pathrequired

Version history

3
  1. v1.0.10LatestNov 1, 2026
  2. v1.0.9Sep 23, 2026
  3. v1.0.3Sep 16, 2026

Score

90% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts