Wrap command-line tools in an MCP wrapper to separate secrets from the coding environment. Support introspection of tools and allow requests for additional cababilities.
  • Go 94.2%
  • Shell 3.6%
  • HTML 1.2%
  • CSS 0.7%
  • Scheme 0.3%
Find a file
pti 6b65a8bd74
Some checks failed
Publish documentation / publish (push) Failing after 4s
Lint / lint (push) Failing after 4s
add git execution hardening
2026-08-02 11:28:56 +02:00
.claude/agents docs(agents): fold Phase 1 retro into the workflow — fix rounds, seams, MR sizing 2026-07-30 20:06:21 +00:00
.devcontainer test harness pool concept in devcontainers 2026-07-30 11:21:40 +02:00
.forgejo/workflows fix(release): publish through Forgejo API 2026-07-24 10:50:29 +00:00
cmd style: 0o600 octal prefix; rename test to match yamledit.MapSet 2026-07-30 22:09:11 +00:00
design add git execution hardening 2026-08-02 11:28:56 +02:00
docs update git-hardeniing tips 2026-08-02 11:28:45 +02:00
examples/devcontainer docs(design): reorganize design/ into subsystem subdirs with index 2026-07-30 16:18:42 +02:00
features docs(design): reorganize design/ into subsystem subdirs with index 2026-07-30 16:18:42 +02:00
internal style: 0o600 octal prefix; rename test to match yamledit.MapSet 2026-07-30 22:09:11 +00:00
testdata Initial implementation of wraptool MCP server 2026-05-15 12:52:10 +02:00
.envrc build(guix): pin toolchain channels 2026-07-23 23:27:23 +00:00
.gitignore chore(agents): add implementor/reviewer subagent definitions 2026-07-30 09:37:13 +00:00
.gitlab-ci.yml ci(gitlab): make release upload loop idempotent 2026-07-24 13:49:10 +00:00
.golangci.yml docs(design): reorganize design/ into subsystem subdirs with index 2026-07-30 16:18:42 +02:00
channels.scm fix(guix): evaluate channels expression directly 2026-07-23 23:32:08 +00:00
CLAUDE.md fix(yamledit): address review nits — anchors, error prefixes, strictness 2026-07-30 21:37:15 +00:00
go.mod build(deps): add semver and flock for the harness pool 2026-07-30 12:04:29 +00:00
go.sum build(deps): add semver and flock for the harness pool 2026-07-30 12:04:29 +00:00
LICENSE Add GPLv3 license 2026-05-16 01:24:55 +02:00
main.go Initial implementation of wraptool MCP server 2026-05-15 12:52:10 +02:00
manifest.scm fix(release): preserve annotated tags in CI 2026-07-24 10:42:26 +00:00
README.md cmd: add server start, keep serve as a hidden alias 2026-07-24 12:56:41 +00:00
release-signing-key.asc feat(release): verify signed release tags 2026-07-24 10:21:23 +00:00
release-version fix(release): pin verified tag signer 2026-07-24 10:27:34 +00:00
test-container.sh Add Guix container integration test script 2026-05-16 01:22:32 +02:00
test-release-version.sh fix(release): pin verified tag signer 2026-07-24 10:27:34 +00:00

wraptool

An MCP server that places CLI tools and local stdio MCP servers behind a security policy, so AI coding assistants can use credentialed host capabilities without direct access to the underlying credentials.

Why

AI coding assistants need CLI tools to be productive, but giving them direct access exposes API keys, SSH keys, kubeconfigs, and service account credentials to the model context. The same risk runs through everyday development: a postinstall hook or a compromised transitive dependency executes with your full credentials the moment you build, test, or bump a package. wraptool treats everything running in your workspace — the assistant, its tool calls, and the build/test/dependency code they trigger — as untrusted, and bounds what it can reach:

  • Credentials stay isolated -- wraptool runs as a separate process with its own environment; secrets never enter the AI context.
  • Bounded blast radius -- inside wraptool up's throwaway container the assistant, your build scripts, and the dependencies they pull in all run with no host credentials. A hijacked agent or a poisoned dependency can't steal your credentials or exceed the whitelist: raw host secrets (SSH keys, gcloud, kubeconfig, push access) never leave the host, and privileged git/kubectl happen only through wraptool's whitelisted, constrained subcommands. A malicious payload still runs with the container's network and source tree, and can invoke the same approved tools the agent can — but policy, not the payload, bounds which operations reach the host.
  • Subcommand-level whitelisting -- allow git commit but deny git push --force, with flag-level granularity and value constraints.
  • MCP-server filtering -- spawn credentialed local stdio MCP servers and expose only explicitly allowed upstream tool names under a stable prefix.
  • Auto-discovery -- wraptool parses --help output to generate MCP tool schemas with real descriptions.
  • Structured denial workflow -- denied commands trigger a capability-request flow that an operator approves from the CLI, so escalation always requires a human.

Quick start

Install a precompiled Linux, macOS, or Windows binary by following the installation guide, or build it from source (on Guix: guix time-machine -C channels.scm -- shell -m manifest.scm -- go build -o wraptool .):

go build -o wraptool .

Create ~/.config/wraptool/config.yaml listing the tools to expose (allow/deny rules, auth token) — see Getting started for a full example. Then pick how your AI assistant reaches wraptool:

wraptool up          # or just `wraptool`, from any git repo

Brings up a credential-isolated container — a native Guix container built from your manifest.scm when Guix is available, otherwise a Dev Container — with your coding assistant inside it (installed once: a shared pool for Guix, the wraptool feature for Dev Containers) wired to the wraptool server on the host. Secrets never enter the container: git push, gcloud, and kubectl run on the host through MCP. The host gateway is auto-detected — no URL to set.

2. Scaffold a committed Dev Container

wraptool init devcontainer --harness claude --lang go,node

Writes .devcontainer/devcontainer.json — base image + language features + the wraptool feature (installs the harness, writes its MCP wiring, and shares your harness login/skills across projects). Commit it; teammates get the same isolated box on "Reopen in Container" or wraptool up.

3. Minimal — assistant on the host, no container

wraptool init --harness claude   # writes .mcp.json pointing at localhost
wraptool server start

The assistant runs on the same host as wraptool, so 127.0.0.1:8717 is reachable. From inside a container it is not — loopback is the container's own, not the host's; use option 1 or 2, which detect the host gateway for you.

Web UI

An optional operator-facing dashboard (bound to 127.0.0.1, not AI-facing) reviews capability requests and provides full rule CRUD — edit a tool's allow/deny rules in the browser and the running server hot-reloads the change. See docs/web-ui.qmd.

wraptool Web UI — the Rules view, with per-tool allow/deny rules and inline edit controls

Documentation

Full documentation lives in docs/, is rendered with Quarto, and is published at https://pti.pages.snamellit.com/wraptool/ from the Forgejo pages branch:

Page Source
Getting started docs/getting-started.qmd
Installation docs/installation.qmd
Configuration reference docs/configuration.qmd
CLI reference docs/cli-reference.qmd
MCP integration docs/mcp-integration.qmd
Architecture docs/architecture.qmd
Security model docs/security.qmd
Hot-reload & capability requests docs/hot-reload.qmd
Request-review Web UI docs/web-ui.qmd
Isolated environments docs/isolated-environments.md
Troubleshooting docs/troubleshooting.qmd
Contributing docs/contributing.qmd

Build the site locally

guix time-machine -C channels.scm -- shell -m manifest.scm -- quarto preview docs
guix time-machine -C channels.scm -- shell -m manifest.scm -- quarto render docs

The render writes docs/_site/, which is ignored and must not be committed to main. The deployment workflow publishes only that generated tree to the orphan pages branch.

License

GPLv3 -- see LICENSE.