Skip to main content
Glama

πŸ™ 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>.

Related MCP server: MCPHub

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.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    MCP Hub aggregates and proxies multiple Model Context Protocol servers into a unified Streamable HTTP interface. It allows users to combine diverse stdio, SSE, and HTTP-based servers while providing tool namespacing, health monitoring, and secure authentication.
    700 npm
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    A centralized management platform that aggregates multiple Model Context Protocol (MCP) servers into a single unified endpoint for AI agents. It provides a web interface for hot-swappable tool management, proxying of existing servers, and AI-powered generation of custom MCP plugins.
    1
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCPGate aggregates multiple MCP servers into a single unified endpoint, enabling centralized tool management with granular filtering, automatic namespacing, and observability. Features a real-time web dashboard and optional PostgreSQL-backed audit trails for monitoring and controlling AI tool access across local and remote deployments.
    6 npm
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Self-hosted MCP proxy and aggregation platform. Register multiple upstream MCP servers and expose them through a single unified endpoint with namespace routing, multi-transport support (HTTP/SSE, stdio, OpenAPI→MCP), per-tool overrides, and a web admin UI.
    17
    MIT