vela-mcp
by mikesplore
README.md
# Vela MCP Server
MCP (Model Context Protocol) server that exposes [Vela RemotePC](https://github.com/mikesplore/vela) endpoints as tools, so AI clients (Claude Desktop, Cline, Cursor, Gemini, etc.) can control remote systems.
## Architecture
The server supports **two transport modes** that share the same 150+ tool definitions (`tools.py`):
### 1. STDIO (single-tenant, per-process)
Each process is bound to **one agent** via environment variables. Run multiple agents by defining multiple entries in `mcp_settings.json`, each with its own env block.
**MCP client config** (`cline_mcp_settings.json` or `claude_desktop_config.json`):
```json
{
"mcpServers": {
"vela-home": {
"command": "/path/to/.venv/bin/mcp",
"args": ["run", "vela_mcp/tools.py:mcp"],
"cwd": "/path/to/vela-mcp",
"env": {
"VELA_API_URL": "https://vela.mikesplore.tech",
"VELA_TOKEN": "<relay_secret>",
"AGENT_ID": "agt_123"
}
},
"vela-work": {
"command": "/path/to/.venv/bin/mcp",
"args": ["run", "vela_mcp/tools.py:mcp"],
"cwd": "/path/to/vela-mcp",
"env": {
"VELA_API_URL": "https://vela.mikesplore.tech",
"VELA_TOKEN": "<relay_secret>",
"AGENT_ID": "agt_456"
}
}
}
}
```
### 2. HTTP (multi-tenant, shared server)
A single server instance handles **any number of agents**. Create a scoped MCP connection with `vela --mcp`; it returns an opaque URL and a dedicated bearer credential:
```
MCP URL: https://mcp.mikesplore.tech/mcp/c_8f4a...
Authentication: Bearer <mcp-credential>
```
The MCP credential is stored as a hash and can expire or be revoked independently of the Vela relay secret. The gateway resolves the connection to its agent and uses the relay secret internally. Neither `agent_id` nor `relay_secret` is accepted in the MCP URL.
Claude connectors select OAuth during setup. The gateway provides OAuth discovery, dynamic client registration, PKCE authorization, short-lived bearer access tokens, and rotating refresh tokens. During authorization, enter the MCP credential printed once by `vela --mcp`; supported clients can then renew access without asking for that credential again.
### MCP tool safety
The gateway applies the same risk categories used by Vela’s assistant. Read-only tools execute immediately. Medium- and high-risk tools return a short-lived, single-use approval link and `request_id` instead of executing. Open the returned `approval_url`, approve once, then let the MCP client continue the exact pending request. The server claims and completes that request atomically, so duplicate continuations cannot execute the action twice. High-risk approvals also require the Vela `ASSISTANT_ACTION_PIN` when one was configured during connection creation.
Each MCP connection has a user-selected tool policy: `strict` (default) requires approval for medium/high-risk tools, `read_only` exposes only read-only tools, and `open` executes all exposed tools without MCP approval. Set `MCP_TOOL_POLICY` in the agent `.env`, or override one connection with `vela --mcp --mcp-policy read_only`.
Stdio mode also supports `strict` approvals. The first gated call starts a
loopback-only approval page on `127.0.0.1`, returns a one-time local link, and
waits for the client to continue the request. The server never opens the
browser automatically and the page is not reachable from the network. Set
`ASSISTANT_ACTION_PIN` in the MCP environment if high-risk local approvals
should require a PIN.
### How multi-tenancy works
- **vela-mcp** stores scoped MCP connection records. It extracts only an opaque connection ID and a dedicated MCP credential from each request, then resolves the agent server-side.
- **velavps** (the relay server) enforces isolation: `_verify_agent_access(agent_id, secret)` rejects requests where the secret doesn't match the agent's registered secret, or where the agent belongs to another user.
- **150+ tools** are untouched — they call `vela_client.get/post/…` which resolves to either the per-request or per-process client automatically.
## Quick Start
```bash
python -m vela_mcp.server
```
Server starts on `http://0.0.0.0:8002` with the MCP endpoint at `/mcp/{connection_id}`.
## Setup
1. Copy `.env.example` to `.env`
2. Set `VELA_API_URL` — your Vela relay VPS host (e.g. `https://vela.mikesplore.tech`)
3. For **stdio mode**: also set `VELA_TOKEN` (relay secret) and `AGENT_ID`
4. For **HTTP mode**: you only need `VELA_API_URL` and `PORT`; credentials come from the client
## Run Script
```bash
./run.sh # start the MCP server (HTTP/streamable transport)
./run.sh dev # start the MCP Inspector (dev/testing UI)
```
## Project Layout
```
vela_mcp/
__init__.py
config.py # Settings (VELA_API_URL, VELA_TOKEN, AGENT_ID, PORT)
client.py # RelayConnection, VelaClient, per-request contextvar proxy
server.py # FastAPI app with scoped middleware at /mcp/{connection_id}
tools.py # 150+ MCP tool definitions (unchanged)
```
## Development
```bash
.venv/bin/mcp dev vela_mcp/tools.py:mcp
```
## Requirements
- Python >= 3.10
- `mcp >= 1.0.0`
- `fastapi >= 0.110.0`
- `httpx >= 0.27.0`
- `pydantic-settings >= 2.0.0`
- `uvicorn >= 0.30.0`
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues