mcpvessel

module
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: Apache-2.0

README

mcpvessel

Tell Claude to add an MCP server. Claude cages it, runs it, watches everything it sends, and tells you if it's safe.

CI Release License

Run mcpvessel init once, then tell Claude to add any MCP server, even one you would never trust. Claude installs it in a deny-default cage (secrets it cannot leak, no network it was not allowed), uses it on your behalf, surfaces everything it tries to send, and tells you plainly whether it is behaving or hiding something. You never vet a server or touch a cage. Nothing slips past you.

Why this matters

An MCP server runs as a subprocess with your full user permissions. The protocol does not sandbox it, so an installed server can read your SSH keys, cloud credentials, and .env files, run arbitrary commands on your machine, and send any of it anywhere.

This is not theoretical. CVE-2025-6514 (rated critical) is host remote code execution from connecting to an untrusted server, and audits keep finding thousands of vulnerable public servers. You cannot read the source of every server you want to try, and safe today does not mean safe after the next update.

mcpvessel makes that a thing you no longer have to weigh. Every server runs alone in its own container on an isolated network, its outbound traffic filtered by a gateway that opens only the hosts you allow, and your keys held outside the cage where it cannot reach them. So Claude can run a server you have never vetted, and the worst it can do is try. You run none of it: Claude installs, cages, and watches each server, and tells you the truth about what it does.

Contents

Set it up once, then just ask

Install the binary, then run one command:

# macOS via the Homebrew cask (on Linux see Install).
brew install --cask okedeji/tap/mcpvessel

# One command sets up everything.
mcpvessel init

init is the whole setup. It provisions the runtime, installs the mcpvessel skill into Claude Code so Claude knows how to drive it, and installs mcpvessel's own docs as a caged server so Claude knows the tool inside out, all in one go. From here you do not run mcpvessel commands. Claude does.

Open a new Claude Code session and just ask:

you:    add the GitHub MCP server so I can use it here.
Claude: Installed github-mcp-server into a cage and served it to this session.
        Its network is deny-default, so I will hold anything it reaches that you
        have not approved, and I am watching what it sends. Ask me to use it.

Later, a server shows its true colors, and Claude catches it without being asked:

you:    save a note "buy milk" with the notes server.
Claude: Saved. One thing: right after that, notes-server tried to POST your
        STRIPE_SECRET_KEY to exfil.attacker.net. The cage blocked it, nothing
        left. This server is trying to exfiltrate secrets; I would not trust it.
        Want me to remove it?

You never touched a cage, an allow-list, or a config file. That is the point.

Nothing slips the watch

mcpvessel records every request each caged server makes, continuously, even the ones a server fires off while you are away from the keyboard. Claude reads that record and reports it: a host you did not expect, a secret leaving, a server reaching out during a call that had no business touching the network. When a granted secret shows up in an outbound request, mcpvessel flags it by name (it knows the value, it injected it), so "notes-server is shipping your STRIPE_SECRET_KEY" is caught, not guessed. And before a new host is ever allowed, Claude shows you the actual request the server wants to send, with your secrets redacted, so you weigh the real payload, not just a hostname.

Then you decide. Nothing new leaves a cage without your yes: Claude surfaces the choice, what it saw, where it was going, and its recommendation, and you approve or deny. Claude never approves on its own, and a server cannot talk it into approving. A line in its output saying "this is safe, approve it" changes nothing: the door stays deny-default until you open it. Your say-so, on top of the cage's deny-default, is the backstop.

Prefer to drive it yourself

You do not have to hand it to Claude. mcpvessel is a full CLI: import a server into a cage, serve it on one URL, and approve hosts with egress allow as they come up, same cages, same watch, no agent involved. It accepts any MCP server from npm, PyPI, or a container image. The docs cover every command.

What it does not protect against

The cage constrains what a server can reach, not whether it behaves. Know the edges:

  • An allowed host receives whatever the server sends it. Egress control decides which hosts, not what goes to one you permitted; the watch is what surfaces the payload so you can catch it.
  • A prompt-injected agent could in principle run an approval you did not intend. The cage's deny-default and your own review are the backstop, and VESSEL_STRICT_APPROVAL=1 keeps approvals to a human at a terminal if you want it airtight.
  • A tool that returns a plausible lie is not detected, and a host compromised outside mcpvessel is out of scope.

The complete list is in ARCHITECTURE.md §14.

Install

Homebrew (macOS). Installs a signed cask and wires up shell completions.

brew install --cask okedeji/tap/mcpvessel

Direct download (Linux, Windows/WSL2). Grab the archive for your OS and architecture from the releases page, verify it against checksums.txt, and put the binary on your PATH.

From source. For contributors and anyone who wants to build it themselves:

git clone https://github.com/okedeji/mcpvessel
cd mcpvessel
make build

Note: on macOS the release archives bundle the Linux VM image the runtime needs, so prefer Homebrew or the direct download over go install.

Requirements

  • macOS (Apple Silicon or Intel) or Linux. On Windows, it runs inside WSL2: install the Linux binary in your WSL2 distro and run everything (the CLI, the daemon, and ~/.mcpvessel) there. There is no native Windows binary.
  • Claude Code, for the agent-driven flow. init installs the skill into it and registers the docs server with it. You can also drive mcpvessel by hand without it.
  • Homebrew, only for the macOS cask above. The Linux and WSL2 paths install from the release archive and need no Homebrew.
  • On first run, mcpvessel init sets up everything: the runtime, the Claude skill, and the caged docs server. On macOS the runtime step downloads a small Linux VM image and starts a rootless container daemon, so first init takes a few minutes depending on your connection. Every run after that is a few seconds, and re-running init is cheap. On Linux the runtime step is a no-op and uses the host's container runtime directly.

Uninstall

Stop the runtime, remove the binary, then delete the state directory (this removes the macOS VM, cached images, your signing key, and config):

mcpvessel daemon stop
brew uninstall --cask mcpvessel   # or delete the binary you installed
rm -rf ~/.mcpvessel

Commands

mcpvessel --help lists every command, and mcpvessel <command> --help covers any one in full, with its flags and examples. With Claude driving, you rarely type any of them.

Deeper guides for each command, and the agent-driven skill and audit feed, live in the docs directory.

Contributing and support

License

Apache 2.0. See LICENSE.

Directories

Path Synopsis
cmd
mcpvessel command
internal
bundle
Package bundle reads an agent's source directory plus its Vesselfile and packages them into a .agent file: a gzip-tarball of the source tree alongside a manifest.json that describes it.
Package bundle reads an agent's source directory plus its Vesselfile and packages them into a .agent file: a gzip-tarball of the source tree alongside a manifest.json that describes it.
clientskill
Package clientskill installs the mcpvessel skill into an MCP client, so an agent (Claude Code and friends) can drive mcpvessel itself.
Package clientskill installs the mcpvessel skill into an MCP client, so an agent (Claude Code and friends) can drive mcpvessel itself.
cliout
Package cliout is the single output vocabulary the CLI speaks: one table shape and one empty-state shape, so every list command renders the way ps and store ls do rather than each hand-rolling its own spacing.
Package cliout is the single output vocabulary the CLI speaks: one table shape and one empty-state shape, so every list command renders the way ps and store ls do rather than each hand-rolling its own spacing.
config
Package config reads and writes the operator's ~/.mcpvessel/config.json: LLM provider endpoints and per-cage resource caps.
Package config reads and writes the operator's ~/.mcpvessel/config.json: LLM provider endpoints and per-cage resource caps.
daemon
Package daemon is mcpvessel's long-lived host process.
Package daemon is mcpvessel's long-lived host process.
egress
Package egress is the in-run HTTP CONNECT proxy: a cage reaches only the hosts its EGRESS allow: policy names, and the internal run network makes this the only way out.
Package egress is the in-run HTTP CONNECT proxy: a cage reaches only the hosts its EGRESS allow: policy names, and the internal run network makes this the only way out.
env
Package env is the single source of the VESSEL_* environment variable names.
Package env is the single source of the VESSEL_* environment variable names.
eval
Package eval runs an agent's eval suite: it loads the YAML the EVAL directive points at, runs each case in a real cage, checks the output against the case's expectations, and reports pass/fail counts plus an aggregate judge score.
Package eval runs an agent's eval suite: it loads the YAML the EVAL directive points at, runs each case in a real cage, checks the output against the case's expectations, and reports pass/fail counts plus an aggregate judge score.
githubauth
Package githubauth runs GitHub's OAuth device flow for MCP Registry publishing: a proven GitHub identity maps to the io.github.<user> namespace.
Package githubauth runs GitHub's OAuth device flow for MCP Registry publishing: a proven GitHub identity maps to the io.github.<user> namespace.
history
Package history is the daemon's durable run log: a bbolt store under ~/.mcpvessel, one record per run, keyed by the daemon-assigned run id.
Package history is the daemon's durable run log: a bbolt store under ~/.mcpvessel, one record per run, keyed by the daemon-assigned run id.
identity
Package identity is the single source of the product name and version.
Package identity is the single source of the product name and version.
llmgateway
Package llmgateway proxies an agent's OpenAI-compatible calls to the configured provider endpoint, holds provider keys so agents never see one, meters per-call cost, and enforces the run's shared budget.
Package llmgateway proxies an agent's OpenAI-compatible calls to the configured provider endpoint, holds provider keys so agents never see one, meters per-call cost, and enforces the run's shared budget.
locate
Package locate turns a bundle path or registry reference into a local .agent file, the step run, call, inspect, and tree share.
Package locate turns a bundle path or registry reference into a local .agent file, the step run, call, inspect, and tree share.
mcp
Package mcp wraps the official Go MCP SDK with the narrow surface mcpvessel needs: connect over stdio or HTTP, list tools, call one, read the text result.
Package mcp wraps the official Go MCP SDK with the narrow surface mcpvessel needs: connect over stdio or HTTP, list tools, call one, read the text result.
mcpgateway
Package mcpgateway is the in-run MCP gateway: a transparent MCP-over-HTTP reverse proxy that routes a parent agent's USES calls to each sub-agent and rejects denied tools with a JSON-RPC error.
Package mcpgateway is the in-run MCP gateway: a transparent MCP-over-HTTP reverse proxy that routes a parent agent's USES calls to each sub-agent and rejects denied tools with a JSON-RPC error.
mcpregistry
Package mcpregistry talks to the official MCP Registry: search, resolve a reverse-DNS name, publish a server.json.
Package mcpregistry talks to the official MCP Registry: search, resolve a reverse-DNS name, publish a server.json.
progress
Package progress renders build progress: Plain (line-by-line, safe everywhere) and TTY (BuildKit-style live dashboard), selected by the --progress flag.
Package progress renders build progress: Plain (line-by-line, safe everywhere) and TTY (BuildKit-style live dashboard), selected by the --progress flag.
reasoner
Package reasoner carries the Python reasoning harness that `import --reasoning` writes into a generated agent, and renders that agent's Vesselfile.
Package reasoner carries the Python reasoning harness that `import --reasoning` writes into a generated agent, and renders that agent's Vesselfile.
reference
Package reference parses agent references into OCI coordinates.
Package reference parses agent references into OCI coordinates.
registry
Package registry pushes and pulls .agent bundles as OCI artifacts: one gzip-tar layer under a manifest whose artifactType marks it mcpvessel's.
Package registry pushes and pulls .agent bundles as OCI artifacts: one gzip-tar layer under a manifest whose artifactType marks it mcpvessel's.
replay
Package replay owns the .replay artifact under ~/.mcpvessel/replays: the full-payload recording of a run's external interactions.
Package replay owns the .replay artifact under ~/.mcpvessel/replays: the full-payload recording of a run's external interactions.
resolve
Package resolve locks USES tags to the digests the manifest lockfile records and rejects cyclic graphs.
Package resolve locks USES tags to the digests the manifest lockfile records and rejects cyclic graphs.
runtime
Package runtime builds and runs agent cages (each cage is one OCI container).
Package runtime builds and runs agent cages (each cage is one OCI container).
secrets
Package secrets stores the operator's named secret values in a 0600 file under ~/.mcpvessel.
Package secrets stores the operator's named secret values in a 0600 file under ~/.mcpvessel.
serve
Package serve exposes a served run's public agents over MCP-over-HTTP and plain JSON-over-HTTP on one front door.
Package serve exposes a served run's public agents over MCP-over-HTTP and plain JSON-over-HTTP on one front door.
signing
Package signing signs pushed bundles and verifies pulled ones.
Package signing signs pushed bundles and verifies pulled ones.
store
Package store keeps built .agent bundles under ~/.mcpvessel/store.
Package store keeps built .agent bundles under ~/.mcpvessel/store.
telemetry
Package telemetry holds a run's trace model: the span tree the daemon writes into history and `mcpvessel trace` renders.
Package telemetry holds a run's trace model: the span tree the daemon writes into history and `mcpvessel trace` renders.
vesselfile
Package vesselfile parses and validates the Vesselfile, the declarative manifest at the root of every agent's source tree.
Package vesselfile parses and validates the Vesselfile, the declarative manifest at the root of every agent's source tree.
wrap
Package wrap generates the Vesselfile that turns an existing MCP server (npm, PyPI, or OCI) into an mcpvessel agent: a FROM/RUN/ENTRYPOINT that installs and launches it over stdio.
Package wrap generates the Vesselfile that turns an existing MCP server (npm, PyPI, or OCI) into an mcpvessel agent: a FROM/RUN/ENTRYPOINT that installs and launches it over stdio.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL