Skip to main content

agentvisor

CI

~/.ssh/agent for AI agents.

Everyone solves auth by controlling the server. Nobody solves auth for the client who doesn't own the server.

agentvisor fills that gap. It runs a local proxy that sits between your AI agent (Claude Code, Cursor, OpenCode) and the Remote MCP servers it talks to. Credentials live in an encrypted local vault. The proxy injects them on every request. Your agent never sees a raw token. Your config files never contain a secret.

pipx install agentvisor

agentvisor provider create                      # register GitHub (slug: github, url, auth type)
agentvisor creds login github                   # paste your PAT once
agentvisor mcp-config --proxy                   # writes Claude Code config + installs OS service

# Done. GitHub Remote MCP works in Claude Code.
# No token in your config. No manual restart. It just works.

What it does

Remote MCP servers require Bearer tokens. Today developers hardcode them in ~/.claude.json or .env files. Tokens expire silently. Configs get stale. Credentials end up in git history.

agentvisor intercepts the calls, injects the right credential from its vault, and handles token refresh automatically. The agent sees an authenticated HTTP call. The developer sees nothing — because there's nothing to manage.

Claude Code
    │ http://localhost:9090/github
    ▼
agentvisor proxy (127.0.0.1:9090)
    │ vault.get("github") → Authorization: Bearer <token>
    ▼
https://mcp.github.com   (authenticated)

How it works

Store

Providers and credentials are stored in ~/.agentvisor/store.db — a two-table SQLite database:

providers   (id PK, auth_type, url, client_id, client_secret_enc, created_at)
credentials (id PK, provider_id FK, account_id, auth_flow, is_default, login_creds_enc, created_at)
  UNIQUE(provider_id, account_id)

Tokens are stored as AES-256-GCM encrypted JSON blobs. The encryption key lives in the OS keychain (keyring library: macOS Keychain, SecretService on Linux). On headless Linux with no keyring daemon, the key falls back to ~/.agentvisor/vault.key (0600 permissions) with a one-time warning.

Multiple credentials per provider are supported. One credential per provider can be marked is_default. A specific account can be selected at request time via the X-Agentvisor-Account header (stripped before forwarding upstream).

Proxy

A starlette ASGI server on 127.0.0.1:9090. Path-based routing: every registered provider gets a path prefix. /github/* goes to the GitHub MCP URL, /context7/* to the Context7 MCP URL. On each request, the proxy:

  1. Looks up the provider in the store
  2. Selects the credential: X-Agentvisor-Account header if present, otherwise the default
  3. Injects Authorization: Bearer <token> into the outgoing request
  4. Streams the response back without buffering (SSE-safe)

A single httpx.AsyncClient is shared across all requests for connection pooling. One asyncio.Lock per service prevents double-refresh within the proxy process.

Auto-start

agentvisor mcp-config --proxy installs an OS-native login service:

  • macOS: ~/Library/LaunchAgents/com.agentvisor.proxy.plist + launchctl load
  • Linux: ~/.config/systemd/user/agentvisor-proxy.service + systemctl --user enable

The proxy starts at login and stays running. launchd/systemd handle restart-on-crash. You never have to think about it.

Port

Fixed at 9090. If occupied: ERR_PORT_IN_USE — resolve the conflict, then retry. No port fallback, no config drift.


Install

pipx install agentvisor

Requires Python 3.10+. macOS or Linux (Windows is not supported in v1).


CLI reference

Providers

agentvisor provider create           # register a new provider interactively (slug, auth type, URL)
agentvisor provider list             # show all providers + credential count
agentvisor provider get <id>         # show provider details (secrets redacted)
agentvisor provider update <id> \
  --url <url> \
  --auth-type api_key|oauth2 \
  --client-id <id> \
  --client-secret <secret>
agentvisor provider delete <id>      # delete provider and all its credentials (-y to skip confirm)

Auth types:

Type Behavior
api_key Static token. Authorization: Bearer <token>. Never refreshed.
oauth2 Short-lived OAuth token. Requires client_id and client_secret.

Credentials

agentvisor creds login <provider_id>          # store a new credential (prompts account ID + token)
                                              # --account <id>  skip account ID prompt
                                              # --default / --no-default  skip confirmation
agentvisor creds list [<provider_id>]         # list all credentials, optionally filtered by provider
agentvisor creds fetch <provider_id>          # print plaintext token to stdout
                                              # --account <id>  select specific account
agentvisor creds re-login <provider_id>       # overwrite token for an existing credential
                                              # --account <id>
agentvisor creds revoke <provider_id>         # delete credential locally
                                              # --account <id>  (default credential if omitted)
agentvisor creds remove <provider_id>         # alias for revoke
agentvisor creds default <provider_id> \
  --account <id>                              # set the default credential for a provider

Config generation

agentvisor mcp-config                # upsert managed mcpServers in ~/.claude.json
                                    # leaves user-added entries untouched
agentvisor mcp-config --proxy        # use localhost:9090/<name> URLs + install OS service
agentvisor mcp-config --unproxy      # remove proxy entries + stop + unload OS service
agentvisor mcp-config --dry-run      # preview what will be written (v1.5)
agentvisor mcp-config --stdout       # print JSON to stdout, write nothing
agentvisor mcp-config --out <path>   # write to specified path

Exit codes: 1 = ERR_REFRESH_FAILED:<service>, 2 = ERR_VAULT_LOCKED

Proxy lifecycle

agentvisor proxy-start               # start proxy in foreground (Ctrl-C to stop)
agentvisor proxy-start --background  # ephemeral background start
                                    # no-op if OS service is already running
                                    # no-op if proxy.pid exists and process is live
agentvisor proxy-stop                # SIGTERM to proxy.pid
agentvisor proxy-status              # process, HTTP health, per-route vault check

Uninstall

agentvisor uninstall                 # stop proxy + remove OS service + remove Claude config
                                    # + delete ~/.agentvisor/ (store, logs)
agentvisor uninstall --keep-vault    # same but keep ~/.agentvisor/ intact (store + credentials)

Proxy HTTP responses

Code Error Meaning
404 ERR_UNKNOWN_SERVICE Path prefix not in provider store
503 ERR_REFRESH_FAILED:<svc> OAuth refresh rejected by endpoint
503 ERR_TOKEN_REJECTED:<svc> Upstream 401 after refresh (or immediately for api_key)
503 ERR_NO_CREDENTIAL No credential for provider — run agentvisor creds login <id>
503 ERR_VAULT_LOCKED Vault could not be decrypted
503 ERR_UPSTREAM_UNREACHABLE Upstream MCP server unreachable
504 ERR_UPSTREAM_TIMEOUT Upstream timed out (default 30s)
429 (passed through) Rate limited; adds X-Agentvisor-Ratelimited: true header

Error bodies are JSON: {"error": "ERR_...", "message": "human-readable explanation"}.

Health

curl http://localhost:9090/health
# {"status": "ok", "uptime_s": 7234}

curl http://localhost:9090/__agentvisor__/status
# {"routes": [{"name": "github", "upstream": "mcp.github.com", "auth": "pat"}], "uptime_s": 7234, "last_crash": null}

Architecture

~/.agentvisor/
  store.db          two-table SQLite: providers + credentials (AES-256-GCM encrypted tokens)
  claude_managed_keys.json  tracks which mcpServers keys agentvisor owns
  proxy.pid         PID of background proxy process (if --background)
  proxy.log         crash log for background mode + launchd/systemd stderr

OS Keychain ──► vault_key (32-byte AES key, via keyring library)
Fallback (headless Linux): ~/.agentvisor/vault.key (0600)

┌──────────────────────────────────────────────────────────────┐
│ Developer machine                                             │
│                                                              │
│  agentvisor proxy (127.0.0.1:9090)                            │
│  starlette + httpx AsyncClient (shared, connection-pooled)   │
│                                                              │
│  GET /health              → 200 {"status": "ok"}             │
│  GET /__agentvisor__/status → 200 {providers, uptime, ...}    │
│  /github/*   → store.fetch("github")  → Bearer inject        │
│  /context7/* → store.fetch("context7") → Bearer inject       │
│  X-Agentvisor-Account: <id> selects a non-default credential  │
│                                                              │
│  asyncio.Lock per service (single-process refresh guard)     │
│  SSE: streams chunks via aiter_bytes(), never buffers        │
│                                                              │
│  Auto-start:                                                  │
│  macOS: ~/Library/LaunchAgents/com.agentvisor.proxy.plist     │
│  Linux: ~/.config/systemd/user/agentvisor-proxy.service       │
│                                                              │
└─────────────────────────┬────────────────────────────────────┘
                          │ HTTPS + Bearer token (injected)
                          ▼
              Remote MCP servers
              mcp.github.com, mcp.context7.com, ...

Claude Code config (~/.claude.json, written by mcp-config --proxy):
  {
    "mcpServers": {
      "github":   { "type": "http", "url": "http://localhost:9090/github" },
      "context7": { "type": "http", "url": "http://localhost:9090/context7" }
    }
  }

Dependencies

Library Purpose
keyring OS keychain (macOS Keychain, SecretService on Linux)
cryptography AES-256-GCM encryption (AESGCM primitive)
sqlite3 Vault storage (stdlib, no extra dep)
starlette ASGI proxy server
httpx Async HTTP client with streaming support
asyncclick Async CLI framework

Known limitations

  • Any local process can use the proxy. The OS user boundary is the security boundary. The proxy binds to 127.0.0.1 only. If you need per-agent authorization scoping, that's v2.
  • Cross-process refresh race. If agentvisor creds fetch <id> and the proxy both trigger an OAuth refresh simultaneously, you may get invalid_grant. v1 targets are static API keys so this doesn't apply. Fix in v2 via SQLite EXCLUSIVE transaction.
  • provider delete doesn't clean up OS service or Claude config. Re-run agentvisor mcp-config --proxy after removing a provider. Use mcp-config --unproxy to remove all proxy config.
  • Corporate proxy / custom CA. The launchd plist captures HTTP_PROXY, HTTPS_PROXY, SSL_CERT_FILE, and REQUESTS_CA_BUNDLE from your environment at install time. If those change, re-run agentvisor mcp-config --proxy.

Platform support

Platform Status
macOS (arm64, x86_64) v1
Linux v1
Windows Not supported

What's not in this tool

  • No cloud signup. Everything runs locally.
  • No agent identity verification. Any process on the machine can call the proxy.
  • No OpenAPI support. Remote MCP only in v1.
  • No team credential sharing. That's the v2 enterprise model.

Roadmap

v1 (current)

  • Encrypted local store (AES-256-GCM, OS keychain) — two-table SQLite: providers + credentials
  • Multi-account credentials per provider, selectable via X-Agentvisor-Account header
  • Local auth-injecting proxy (starlette + httpx, SSE streaming)
  • Path-based multi-provider routing on a single port (9090)
  • Auto-start via launchd (macOS) / systemd user service (Linux)
  • agentvisor provider + agentvisor creds CLI command groups
  • agentvisor mcp-config --proxy — installs OS service + writes Claude Code config
  • agentvisor mcp-config --unproxy — teardown proxy config + OS service
  • agentvisor uninstall [--keep-vault] — full teardown

v1.5

  • agentvisor mcp-config --dry-run — preview before committing
  • Multi-client support (Cursor, OpenCode)
  • Claude Desktop support

v2

  • OpenAPI spec-aware auth injection
  • Enterprise: managed vault, team credentials, audit logs, RBAC

Security model

The store encryption key is machine-local. If the OS keychain is wiped or you migrate to a new machine, credentials must be re-entered. There is no cross-machine sync in v1.

The proxy binds to 127.0.0.1 only. Any process running as your OS user can call it. The OS user boundary is the security boundary. This is the same model as ssh-agent.

Nonces for AES-256-GCM are generated fresh per encryption operation (os.urandom(12)). They are prepended to the ciphertext blob. Nonces are never reused.

Release files for agentvisor 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agentvisor 0.2.0
File Size Uploaded
agentvisor-0.2.0.tar.gz 60.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for agentvisor 0.2.0
File Interpreter ABI Platform
agentvisor-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 79.6 kB

Release files / agentvisor-0.2.0.tar.gz

Download URL agentvisor-0.2.0.tar.gz
Size 60.9 kB
Tags Source
SHA-256 checksum
How to use checksums
39f96f190152f738ad811fda4a36cea0536ac607cdf14cbcc46b2f474031e22c
BLAKE2b-256 checksum
How to use checksums
b0406cd154f99eb81c92118ab125a13b5c72baf684f7c6f43a702ff7a9a076e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 20, 2026.

Transparency log

Release files / agentvisor-0.2.0-py3-none-any.whl

Download URL agentvisor-0.2.0-py3-none-any.whl
Size 18.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
347e39d282d66c50647c927826f542869818f015ee1a7ae388ad9b3cb0555a67
BLAKE2b-256 checksum
How to use checksums
bdb3e52cda56847fb1dc44e0ffbcdcf6542501257369ee8268bfd4bb7e558b78
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 20, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page