Skip to content

Latest commit

Β 

History

20 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ™ octoport

See every MCP tool call your AI agents make β€” and exactly where they fail.

A local-first debugger, flight recorder, and control layer for MCP.

npx octoport up --open

Your agents call MCP tools all day. When something breaks β€” an expired OAuth token, a crashing server, a tool that silently changed its schema β€” you get a vague client error and zero visibility. octoport sits on the path of every MCP call and turns that darkness into a live, diagnosable record:

15:04:12  Claude Code β†’ github / create_pull_request    WRITE Β· MEDIUM            βœ“ 381ms
15:04:18  Claude Code β†’ supabase / execute_sql          DATABASE_WRITE Β· MEDIUM   βœ• 4.2s   AUTH Β· token_expired
15:04:30  Cursor      β†’ playwright / browser_click      UNKNOWN Β· LOW             ⚠ 12.7s
  • Live Activity β€” every call, live: client, identity, server, tool, latency, risk badge, and a canonical failure diagnosis. The home screen.
  • Failure diagnosis β€” every failed call is classified deterministically into a canonical taxonomy (AUTH Β· token_expired, NETWORK Β· dns, SERVER Β· circuit_open, …) instead of a raw stack trace.
  • Reliability β€” per server and per tool: success rate, p50/p95/p99, timeout and auth-failure counts, top failure categories, and deterministic anomaly alerts (consecutive failures, restart loops, latency spikes).
  • octoport doctor β€” "why won't this MCP setup work?" answered with evidence and a concrete fix, in the CLI and the dashboard (same engine).
  • Tool surface integrity β€” every server's tool catalog is snapshotted and diffed. A server that quietly grows delete_repository triggers a risk-classified warning you must Accept β€” or Block the tool for every client with one click.
  • Local-first privacy β€” everything stays on your machine in SQLite. Secret-looking argument keys are redacted before they ever hit disk, and metadata-only mode (logPayloads: false) never stores args/results at all. The dashboard always states which mode is active.

Quickstart β€” one command, then it's all web

npx octoport up --open

The dashboard walks you through the rest:

  1. We found your MCP servers β€” octoport scans your Claude Code / Claude Desktop / Cursor / Windsurf / VS Code configs (global and project-scoped).
  2. Connect your AI client β€” copy one snippet per client.
  3. Make a test call β€” and watch it appear in Live Activity, live.
  4. Optionally clean up the now-duplicate direct entries (per-file preview, timestamped backups, restorable from Settings).

From then on your clients talk to one endpoint, and octoport sees everything: add/edit/toggle servers centrally, and new servers propagate to every connected client live (tools/list_changed), no restarts.

Until the npm package is published, run from source: git clone https://github.com/nullarch/octoport && cd octoport && npm install && npm run build && node dist/cli.js up --open

Start at login:

octoport autostart          # launchd (macOS) / systemd --user (Linux) / schtasks (Windows)
octoport autostart --remove

Port 6286 is "OCTO" on a phone keypad. Change it with octoport up --port <n>.

When MCP breaks

$ octoport doctor

SERVER
  βœ• github: error β€” AUTH Β· token_expired
      The credential has expired β€” re-authenticate.
      raw: Error POSTing to endpoint (HTTP 401): Unauthorized
      fix: Reauthorize "github": revoke the stored grant (Servers β†’ github β†’ Grants)
           and authorize again, or refresh the credential in its headers/env.

Doctor checks the environment (Node, config permissions), your clients (detected configs, whether they point at the hub, whether a session ever connected), every server (status, classified failure, stderr tail, last successful call), and the gateway (tokens, privacy mode, policy, IdP reachability). --json for scripts; the dashboard's Doctor tab runs the same engine.

One endpoint for everything

Under the observability layer, octoport is a full MCP gateway β€” that's why it sees every call:

  • One endpoint β€” N clients Γ— M servers becomes 1 Γ— M.
  • Process supervision β€” stdio servers run as child processes with crash isolation, jittered backoff restart, start/call timeouts, a circuit breaker after 8 straight failures, and a per-server stderr ring buffer.
  • Hosted servers with OAuth β€” add a hosted MCP URL; if it wants OAuth the server card shows Authorize (PKCE, one-time state, dynamic client registration). Tokens live in your config dir, 0600.
  • Full catalog aggregation β€” tools, prompts (server__prompt), and resources (URIs pass through, reads routed to the owning server). The call log records all three kinds.
  • Server-initiated requests relayed β€” sampling/elicitation/roots answered by the client whose call is executing on that server.
  • Named access tokens β€” one per person or machine; revoking kills live sessions on the spot. Scopes: admin (dashboard) vs mcp (endpoint).
  • Local security by default β€” 127.0.0.1 binding, Host/Origin validation (DNS-rebinding protection), per-install bearer token. The MCP Inspector RCE (CVE-2025-49596) happened because a localhost tool skipped exactly these.
  • Blocked tools β€” a per-server denylist (globs) enforced at tools/list and on every call; the "Block" button on surface-change warnings writes it.

Remote access (optional, explicit)

octoport never exposes itself beyond loopback unless you say so, twice.

Recommended: Tailscale. Keep the default loopback bind, or bind the tailnet address; nothing touches the public internet:

octoport up --host 100.x.y.z --allow-host hub.tailnet-name.ts.net --behind-proxy

Reverse proxy (Caddy) with a real domain. octoport does not terminate TLS β€” your proxy does:

# Caddyfile
hub.example.com {
  reverse_proxy 127.0.0.1:6286
}
octoport up --allow-host hub.example.com --behind-proxy --public-url https://hub.example.com

--public-url makes snippets, the dashboard, and OAuth callbacks use the external address; the dashboard WebSocket switches to wss:// on HTTPS. GET /healthz answers without a token for proxy health checks. A non-loopback bind refuses to start without --allow-host and --behind-proxy; X-Forwarded-Host is deliberately ignored.

Small team setup: run octoport on a shared box behind Tailscale, one named token per teammate, and Live Activity becomes a team-level "which agent did what" record.

Organization mode (experimental)

Status: functional, not yet pilot-verified. The organization gateway is feature-complete for a first pilot and covered by the test suite (including user-boundary attack repros), but has not yet been run end-to-end against a real IdP and real MCP clients in production. Treat it as alpha. Personal mode is stable.

One MCP endpoint for every employee: IT registers servers once, employees add one URL and sign in with company SSO, access follows group profiles, per-user services are authorized individually, and every call is centrally audited under a verified identity.

Company SSO (generic OIDC).

// config.json
"oidc": {
  "issuer": "https://login.example.com/realms/acme",
  "audience": "octoport",                  // aud your IdP mints for this hub
  "groupsClaim": "groups",                 // default
  "adminGroups": ["platform-admins"]       // these groups may open the dashboard
}

Tokens validate against the IdP's JWKS (discovery, cache, rotation; RS256/384/ 512 + ES256/384; iss/aud/exp/nbf enforced). Unauthenticated requests get a WWW-Authenticate challenge pointing at /.well-known/oauth-protected-resource (RFC 9728). Add loginClientId for a browser Sign in with SSO flow (/login, Authorization Code + PKCE). Disable the account at the IdP and access dies β€” octoport has no user database of its own, on purpose.

Profiles (group-based access). Once any profile exists the MCP surface is default-deny. Enforced at tools/list and on every call; denials are logged. Settings has a policy simulator ("what would this identity see?").

"profiles": {
  "backend-engineer": {
    "groups": ["engineering"],
    "servers": ["github", "jira", "sentry"],
    "denyTools": ["kubernetes__delete_*"]  // globs on public names; deny wins
  },
  "ci": { "tokens": ["github-actions"], "servers": ["github"] }
}

Per-user OAuth downstream. "credentialMode": "per_user_oauth" gives every identity its own connection and OAuth grant β€” employee A's GitHub is never employee B's GitHub. Employees self-serve at /my; admins can revoke any grant (kills its live connection). Secrets can be references (file://…, vault://…) instead of literals.

Central audit. Every row records the verified subject, including policy denials. Admin actions get their own event trail (GET /api/events, Audit tab); GET /metrics serves Prometheus.

Deployment: Dockerfile + deploy/docker-compose.yml (+ a Keycloak demo); guides in docs/deploy.md and docs/idp.md; design in docs/threat-model.md.

Commands

Command What it does
octoport up [--open] [--port <n>] [--host <addr>] [--allow-host <h>] [--behind-proxy] [--public-url <url>] Start the hub
octoport doctor [server] [--json] Diagnose client/server/gateway problems, with fixes
octoport autostart [--remove] Start at login (launchd/systemd)
octoport import [--dry-run] CLI import (the wizard does this too)
octoport connect [client] Print connection snippets
octoport logs [--limit <n>] [--jsonl [file]] Inspect or export the call log
octoport token [--rotate] List tokens / rotate the default token (live rotation: dashboard β†’ Rotate)

Data & privacy principles

  1. Local-first by default β€” SQLite on your machine, 0600.
  2. Metadata-only is first-class: logPayloads: false stores no args/results.
  3. Secrets are redacted before persistence, in every mode.
  4. The dashboard always states exactly what is stored.
  5. Catalog snapshots store hashes, not tool descriptions/schemas.

What octoport is not

  • Not a finished enterprise governance product. SSO, profiles, per-user OAuth, and verified audit exist (see Organization mode), but there's no SCIM, no tenant separation, and no compliance claims yet.
  • Not agent mind-reading. octoport sees transport truth β€” what was called, what failed, what changed. It does not claim to know why a model chose a tool; that requires client-side context it doesn't collect today.
  • Not a context optimizer for Claude Code. Claude Code ships native MCP tool search; octoport doesn't compete with it.
  • Not magic. Tool names are namespaced server__tool (capped at 48 chars with deterministic hashing) and routed through a mapping table β€” never string-parsed back.

Known limitations (v0.10)

  • Server-initiated relay (sampling/elicitation/roots) on a shared server uses in-flight correlation, and refuses when two identities call it at once (mark such servers per_user_oauth to use those features safely).
  • Catalog snapshots/diffs cover shared servers; per-user servers can legitimately show different surfaces per identity and are not snapshotted.
  • Config edits outside the dashboard need a restart (dashboard changes apply hot); rotate a token live from Settings β†’ Rotate.
  • autostart requires a permanent install (npm i -g octoport or a repo checkout) β€” refuses to point launchd at an ephemeral npx cache.
  • Personal-mode tokens are full-admin by default; org mode uses scoped (admin/mcp) tokens, per-user OAuth, and profiles.

Support expectations

MIT-licensed, provided as is β€” a solo-maintained project, so no response-time promises. Issues and PRs are welcome and read; small, focused PRs with tests have the best odds. If you need guarantees, fork freely.

Development

npm install
npm test          # 207 tests: unit + E2E incl. mock-OAuth, mock-OIDC, mock-Vault
npm run build
node dist/cli.js up --open

The telemetry/event schema is documented in docs/events.md. Product direction and priorities live in PIVOT.md (it supersedes ROADMAP.md for ordering); the organization-gateway details stay in ROADMAP.md.

About

πŸ™ One local MCP endpoint for every AI coding tool. 8 arms, 1 port.

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages