self-hosted mcp server · v0.4.8

Raven

66 tools. One server. Two transports.

Point any MCP client at one process you host yourself. raven-mcp speaks stdio for local clients and JSON-RPC over HTTP for remote ones, with workspace confinement and keyed auth on both.

MCP 2025-03-26 Python 3.11+ MIT License no telemetry

raven-mcp — stdio
Which transport carried the frames below
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"any-mcp-client","version":"*"}}}
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{}},"serverInfo":{"name":"raven-mcp","version":"0.4.8"}}}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
{"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"read"},{"name":"write"},{"name":"edit"},{"name":"verify"},{"name":"glob"},{"name":"grep"},{"name":"bash"},"… 59 more"]}}
66 tools registered · workspace confined

Replayed from a live raven-mcp process by scripts/record_site_frames.py — no frame here is typed by hand.

install
git clone https://github.com/ssrjkk/raven
cd raven
pip install .
client config
{
  "mcpServers": {
    "raven": {
      "command": "raven-mcp",
      "args": ["--workspace", "/path/to/project"]
    }
  }
}

Python 3.11+ · installs raven-mcp and ravencode-mcp · the full install guide

Counted from the tree

The repository, measured

Five numbers the test suite recomputes on every commit. They are written into site/stats.js by the recorder rather than typed into the page, so a count that drifts from the code fails CI instead of shipping a wrong claim.

Registered tools
66
what tools/list returns
Channel adapters
15
one channel.py each
Console screens
38
routes the SPA registers
Optional groups
32
declared in pyproject.toml
Commands installed
5
console entry points

The registry by category

    Why Raven

    Built for control

    Your code, your keys, your infrastructure. No Raven-run service in the middle, no telemetry by default, no vendor lock-in.

    Self-hosted

    One Python process on your own server. Nothing of yours runs on anyone else's hardware: the calls it makes go to the LLM provider, the messengers and the tools you configure, and every one of those destinations is listed in the egress map.

    nothing between you and the model

    66 tools

    Files, shell, git, web search, code analysis, testing, memory, routines, monitors — all over MCP.

    one registry, every surface

    Two transports

    stdio for local clients that spawn the server as a subprocess, JSON-RPC over HTTP for remote access.

    identical frames on both

    Workspace confinement

    Every file operation is bounded to your project. Symlinks resolved, escape attempts blocked.

    refused, never silently rewritten

    Keyed auth

    HTTP transport requires a secret token. Fail-closed: unconfigured means rejected, not accepted.

    Bearer or X-Raven-Key

    MIT licensed

    Use it, modify it, distribute it. No copyleft, no strings attached. The server is Python you can read end to end, and every page here is built from the same tree the package ships — the tool list, the recorded frames and the five counts above all come out of the repository they describe.

    source, tests and documentation in one repository

    Request path

    One frame, end to end

    What happens between a client pressing Enter and the tool's own text landing back in the reply — four stages, each quoted from the code that runs it.

    The client writes one frame

    A single JSON object, newline-terminated. Nothing about it is specific to Raven: this is the tools/call shape the MCP specification defines, which is why any client can send it.

    {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"read","arguments":{"path":"README.md","max_chars":100}}}

    The transport carries it

    On stdio the frame goes down the pipe the client opened. On HTTP the same bytes become the body of POST /mcp/rpc, and the call is refused before anything is parsed unless an Authorization: Bearer or X-Raven-Key header checks out.

    POST /mcp/rpc HTTP/1.1
    Authorization: Bearer <token>
    Content-Type: application/json

    Policy gets the veto

    Before execution the name and its arguments pass through the ruleset the agent path obeys as well. A denied call comes back as an error, not as an empty result that reads like success.

    {"jsonrpc":"2.0","error":{"code":-32601,"message":"Unauthorized"}}
    'process.run' is denied by policy - 'process.run' is in TOOLS_DENY

    The tool answers

    The reply is the server's own answer to the frame in stage 01, recorded from the process instead of written for the page — including the truncation marker the read tool emits when a file is longer than the budget it was given.

    {"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"<div align=\"center\"> … (truncated, 8720 total chars)"}]}}

    Run it

    One registry, three ways in

    The same tools are reachable as an MCP server, as a terminal coding agent with its own session store, and behind a gateway that holds the channel adapters.

    MCP server

    Stdio for a client that spawns the process, JSON-RPC over HTTP for one that reaches it across a network.

    stdio
    raven-mcp --workspace <dir>
    ravencode-mcp --workspace <dir>

    serverInfo.name · raven-mcp / ravencode

    Coding agent

    RavenCode runs the registry in an agent loop, keeps sessions on disk, exports them with credentials stripped and answers as an OpenAI-compatible endpoint.

    cli
    ravencode tui <dir>
    ravencode serve --port 8080
    ravencode session export <id>

    sessions under the data dir · basic auth on serve

    Gateway

    One process holds the registry, the DM policy and the messengers, so a chat message reaches the same tools a client frame does.

    cli
    raven start
    raven start --daemon
    ravenflow

    15 channel adapters · DM policy pairing|open|closed