AI agents & the MCP server
The daemon knows what’s actually running: which processes and Docker containers
advertised PZ_TUNNEL, their ports, the tunnel domains and health paths,
who-talks-to-whom between tunnels, and which HTTP routes were exercised. Port Zero
exposes this observed runtime truth two ways:
portzero inspect— for humans: readable text, no JSON.portzero mcp— for AI coding agents: a Model Context Protocol server (JSON-RPC 2.0 over stdio).
Both read the same daemon state, fresh on each call.
portzero agents setup
The fastest path for any of the coding agents below: run one command instead of hand-copying JSON into a config file.
$ portzero agents setup
It detects which of Claude Code, Codex, pi.dev, opencode, and Grok Build are installed, then for each one it finds:
- registers the
portzero mcpserver (via the agent’s ownmcp addcommand where one exists — Claude Code, Codex — or a safe read-modify-write of its config file otherwise, preserving any other servers already configured), and - writes a short marker-delimited block into that agent’s user-level instructions file
(
~/.claude/CLAUDE.md,~/.config/opencode/AGENTS.md,~/.grok/AGENTS.md) explaining the MCP tools below, so the agent knows to reach for them.
Safe to re-run any time — already-configured agents are left alone, and content
outside the marker block in an instructions file is never touched. Codex and pi.dev
currently have no confirmed user-level instructions file, so only their MCP
registration step runs. Use --dry-run to preview changes without writing anything.
portzero inspect
$ portzero inspect
portzero inspect — observed runtime truth
Daemon: running
TUNNELS
api--alice.tunnel.portzero.cloud
url: https://api--alice.tunnel.portzero.cloud
health: /health
source: container myapp-api-1 (abc123def456)
web.portzero.local
url: http://web.portzero.local
health: /healthz
source: process pid 456 (/work/web)
OBSERVED EDGES (who-talks-to-whom)
web--alice.tunnel.portzero.cloud -> api--alice.tunnel.portzero.cloud [http, 12 req]
EXERCISED ROUTES (smoke-test inventory)
api--alice.tunnel.portzero.cloud
GET /health x30
POST /users x3 (tests: signup flow)
For a machine-readable view, use the MCP server.
The MCP server (portzero mcp)
portzero mcp speaks the MCP stdio transport: newline-delimited JSON-RPC 2.0 on
stdin/stdout. An agent launches it as a subprocess. portzero agents setup (above)
registers it automatically for supported agents; for anything else, or to see what it
writes, register it by hand, for example in a Claude Code mcpServers config:
{
"mcpServers": {
"portzero": {
"command": "portzero",
"args": ["mcp"]
}
}
}
Tools
Every tool returns a JSON text block. The daemon-state tools take no arguments; the two
cloud-backed feedback tools take typed arguments, passed the standard MCP way as the
arguments object inside tools/call params.
| Tool | Arguments | Returns |
|---|---|---|
overview | none | Everything at once: services, tunnels, observed edges, exercised routes, and the observability caveat. |
list_services | none | Discovered processes/containers with PZ_TUNNEL: domain, port, source (process pid + cwd, or container id/name), health path. |
list_tunnels | none | Tunnel domains (Local + Cloud), resolved URLs, health paths, and cloud review status. |
observed_edges | none | from → to dependency edges between tunnels (protocol, request count, last seen). |
exercised_routes | none | HTTP routes hit per tunnel (method, path, count) — a smoke-test inventory. |
list_feedback | status? | Feedback threads from portzero.cloud: reviewer comments pinned on your tunneled app. Requires portzero login. |
propose_fix | thread_id, fix_commit, fix_summary, and optional cost args (agent?, model?, tokens_in?, tokens_out?, cost_usd?, session_id?) | Marks a feedback thread as fixed by a commit. The optional cost args attach what the fix cost, so per-comment cost accrues. Requires portzero login. |
cost_of_commit | sha | Attributed agent cost of one commit, with provenance + confidence. Consent-gated. |
cost_of_pr | number | Aggregate agent cost of a PR (sum over its commits), with provenance. Consent-gated. |
cost_of_lines | file, start, end | Cost of a line range: blames locally to a set of commits, then resolves their cost. Consent-gated. |
submit_bug_report | title, body, context? | Reports a bug in Port Zero itself (not the user’s app) to the Port Zero team. Requires portzero login. |
submit_feature_request | title, body, context? | Requests a Port Zero feature on the user’s behalf. Requires portzero login. |
list_feedback and propose_fix are the same Review records
workflow available via the CLI; without stored credentials they return an
isError: true result with a “Not logged in” message.
submit_bug_report and submit_feature_request send product feedback
straight to the Port Zero team. They deliberately differ in how freely an agent
should reach for them:
- Bug reports have no gate — if the
portzeroCLI, daemon, tunnels, the dashboard, or the cloud API misbehaves, file one with reproduction steps. - Feature requests carry a high bar: an agent should submit one only when the missing feature would make things much easier for the user, and only after asking the user and getting explicit confirmation — never on its own initiative.
Both require portzero login and return the same “Not logged in” isError
result otherwise.
Measuring agent cost
Port Zero measures what the agent labor costs, not just what it produced. Cost
attaches to the review loop you already run: per comment, per commit, per PR, and
per line. The three cost_of_* tools above read it; propose_fix’s optional cost
args and the session-end hook below record it.
The session-end cost hook
portzero agents installs a session-end hook in each supported coding agent.
When an agent session ends, the hook reads the session’s usage, attributes it to
the commits made in that window (git HEAD/reflog), and — on a consented repo —
records it. The hook uploads usage metadata only: agent, model, token counts,
dollar cost. It never sends your prompts, your code, or any session content.
Consent is the trade
What you grant, per repo, is a training-data licence: permission for Port Zero to use that repo’s review history — diffs, comments, fix commits, verdicts — plus cost/usage metadata in its training corpus. Sessions are never included, on any plan.
That licence is what pays for the features offered on a data-for-access basis, and granting it is what turns them on for the repo:
- Cost tracking — on free and paid plans alike.
- The review link — PR replies flowing back into a comment thread, and the commits referencing a thread shown with the lines they changed. Included outright on Team and Enterprise, which do not license their data for training at all.
The licence is the thing you are agreeing to; those features are what it buys. The dashboard shows the exact Terms version at the moment you grant it, and records that version with your consent.
- Default off, per repo. Set it in app.portzero.net on the repo’s configuration page. It works for a free personal account on a repo with no GitHub App, not just teams.
- Not consented? Nothing is stored — no history, no aggregates. The only thing
you see is an ephemeral end-of-session teaser: the hook prints that session’s
cost once and persists nothing, and the
cost_of_*tools return aconsent_requiredresult pointing at the dashboard toggle. - Turn it off any time. Cost tracking turns off with it. Revoking stops future capture and removes the repo from the corpus (it cannot untrain models already trained).
Who sees what
Cost visibility is per repo, set alongside consent:
- Private (default). Each contributor sees only their own cost. Team owners and admins always see everyone’s.
- Team. Any team member sees per-person breakdowns.
- The PR line is separate. A
post_to_prswitch — independent of visibility — posts one line to the PR showing only the aggregate total across all contributors, never a per-person breakdown. It can be on even while cost stays private.
Every number carries its provenance — measured, reported, or inferred —
and unattributed cost is shown as unknown, never $0.
Privacy
Hooks upload usage metadata only: never your prompts, your code, or any session content. Session data is excluded from training regardless of consent. See Terms and Privacy for the training-data grant in full.
Extraction skill for AI agents
portzero skill install drops a PaaS-agnostic extraction skill into your project
(default .claude/skills/, or --print / --dir for other agent tools). It teaches an
AI coding agent to consume the MCP tools above (plus your compose file) and extract
everything needed to configure production hosting on any platform — which containers
are public vs. internal, ports, health paths, service dependencies, and a smoke-test
route list. The skill extracts and interprets only; it contains no platform-specific
templates.
Observability caveat
Only traffic addressed via tunnel names is observed. Container-to-container traffic
over compose-internal DNS — e.g. one compose service reaching another as
http://db:5432 on the shared compose network — never passes through the daemon and
does not appear in observed edges or exercised routes. Treat the edge/route data as
a lower bound on real dependencies: everything shown is real, but internal
service-to-service calls that never used a tunnel name are invisible. When extracting a
production topology, combine this with your compose file, which shows the internal
wiring.
One-shot prompt for a repo
Paste this into Claude Code, Cursor, or any agent working in your repo:
Install Port Zero (https://portzero.net/install.sh) and set PZ_TUNNEL so this
project's dev server gets a stable web.<project>.portzero.local URL. Docs:
https://portzero.net/llms.txt
See /llms.txt for the condensed reference agents should read first.