{"id":"b17f219e-1f97-439b-a3a8-4ae75286b301","slug":"porthaven","kind":"mcp","name":"porthaven","summary":"A safe haven for every port on your machine. See every dev server, start whole stacks in dependency order, give each git branch its own port, and let coding agents do the same via MCP. macOS, Linux, W","owner":"KirtiJha","repoUrl":"https://github.com/KirtiJha/porthaven","license":"MIT","licenseTier":"permissive","trust":"community","stars":2,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-10-20T05:44:43.000Z","addedAt":"2026-10-21T09:53:07.761Z","logoUrl":"https://avatars.githubusercontent.com/u/22167738?u=519e4b765d99bead366eedc468bc95f61bf0c3f8&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["cloud-infra","developer-tools","data-analytics"],"tags":["cli","dashboard","dev-server","developer-tools","devtools","localhost","port-manager","ports"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T13:58:57.852Z","sample":false,"url":"https://conduits.dev/tools/porthaven","language":"Python","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<div align=\"center\">\n\n<img src=\"web/public/porthaven.svg\" width=\"72\" alt=\"Porthaven logo\" />\n\n# Porthaven\n\n**A safe haven for every port on your machine.**\n\nSee every app listening on a port: what it is, which project it belongs to, whether it answers, and who talks to whom.\nStart whole stacks in dependency order, give each git branch its own port, and let your coding agent do the same,\nwithout leaving servers behind.\n\n[![CI](https://github.com/KirtiJha/porthaven/actions/workflows/ci.yml/badge.svg)](https://github.com/KirtiJha/porthaven/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-2dd4bf.svg)](LICENSE)\n![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-60a5fa.svg)\n![macOS · Linux · Windows](https://img.shields.io/badge/runs%20on-macOS%20·%20Linux%20·%20Windows-a78bfa.svg)\n![Zero dependencies](https://img.shields.io/badge/backend%20dependencies-0-34d399.svg)\n\n<img src=\"docs/images/hero.jpg\" alt=\"Porthaven landing page with a live preview of the dashboard\" width=\"900\" />\n\n</div>\n\n## Why\n\nEvery project brings a dev server, an API, a database and a watcher. They pile up on ports you never chose:\n\n- `EADDRINUSE` on :5173, and then `lsof`, a pid and `ps` just to find out what holds it.\n- Vite and Next quietly move to the next free port, so your bookmark now opens a different project.\n- `kill <pid>` hits a child process, and `make dev` starts it again.\n- A server bound to `0.0.0.0` is reachable from the café Wi-Fi. Last week's prototype is still holding 400 MB.\n- Two branches, or two coding agents, both want :3000. The frontend has the API's port hard-coded.\n- The API moved to :8001 this morning, but the frontend's `.env` still says :8000.\n- Your coding agent's session ended an hour ago. The three dev servers it started are still running.\n\nPorthaven turns that into one live, searchable dashboard, with a command line for when you are already in a terminal\nand an MCP server for when your coding agent is the one starting servers.\n\n## Quick start\n\nYou need Python 3.9 or newer. Node 20+ is needed only once, to build the UI.\n\n**macOS / Linux**\n\n```bash\ngit clone https://github.com/KirtiJha/porthaven.git && cd porthaven\nmake run          # builds the UI the first time, starts Porthaven, opens http://localhost:7475\nmake install      # optional: a `porthaven` command on your PATH (~/.local/bin)\n```\n\n**Windows (PowerShell)**\n\n```powershell\ngit clone https://github.com/KirtiJha/porthaven.git; cd porthaven\ncd web; npm install; npm run build; cd ..\nbin\\porthaven.cmd    # starts Porthaven and opens http://localhost:7475\n```\n\nThe tour of every feature is at http://localhost:7475/welcome.\n\n## Features\n\n<img src=\"docs/images/features.jpg\" alt=\"Porthaven features\" width=\"900\" />\n\n### See\n- **Live port map.** Every listening TCP port, refreshed every two seconds and grouped by project. Each row shows:\n  - the framework (Vite, Next, Uvicorn, Django, Postgres…) and the page title;\n  - HTTP status and response time, uptime, connections, and CPU and memory sparklines.\n- **Network warnings** for anything reachable from other devices, with the Wi-Fi URL for phone testing.\n- **Forgotten servers.** Dev servers with no connections and no CPU for hours are flagged, with the memory\n  they hold.\n- **Port map.** Every port on one line: neighbours together, saved apps that are not running, ports taken from a\n  saved app, and the next free ports one click away.\n- **Sort and scan.** Sort by port, name, response time, uptime, CPU or memory; a memory bar shows what holds the most.\n- **Search, filters and pins.** Search on port, project, command and notes; `:51` finds ports starting with 51.\n- **Docker-aware.** Published container ports show the container and image.\n\n### Act\n- **Stop the whole app, not just the pid.** Porthaven walks up from the port's process through launchers\n  (`make`, `npm`, shells, reloaders) and stops the whole tree. It stops at your terminal, editor or agent.\n- **Graceful first.** SIGTERM (or `taskkill`) first; force only after a grace period you choose.\n- **Bulk stop** of several ports or apps, and a one-click clean-up of idle servers.\n- **Changed your mind?** A server that stops stays in the list for a few seconds with a Restart button.\n- **Guard rails.** No sudo, ever. Porthaven won't stop itself, other users' processes, or anything it doesn't show.\n  System services and desktop apps need you to type the port number to confirm.\n\n### Run\n- **Saved apps.** Save a command, folder and port once, then start, stop and restart with one click.\n  - Output is live and coloured, with clickable URLs and a jump to error lines.\n  - Groups start and stop together, and crashed apps can restart automatically.\n- **Port conflicts handled before they happen.** See who holds the port, then take the next free one\n  (Porthaven sets `PORT` and fills `{port}` in the command) or take the port over.\n- **Stable names.** `http://shop.localhost:7475` reaches the app on whatever port it is on today, websockets and\n  hot reload included.\n- **Outlives restarts.** Apps keep running when Porthaven stops or restarts, and Porthaven picks them up again.\n- **Find projects.** Porthaven scans a folder for npm, pnpm and yarn scripts, Makefile targets, Django, FastAPI,\n  Flask and Streamlit apps, and Compose files.\n- **Sleep when quiet.** An app with no traffic for the time you choose is stopped to free its memory, and the next\n  request to its stable name starts it again.\n- **Workspaces.** Save what is running (\"Shop, full stack\"), then restore it later in one click, or switch to it and\n  stop everything else.\n\n### Stacks\n\n<img src=\"docs/images/stacks.jpg\" alt=\"A stack starting in dependency order\" width=\"900\" />\n\n- **Dependencies.** \"Storefront starts after Shop API\": Porthaven starts the API first and waits for its health\n  check (`/health`, or just the port) before starting what needs it. Cycles and missing apps are reported up front.\n- **Apps find each other.** Write `{url:api}` or `{port:api}` in a command or environment variable, and Porthaven\n  fills in the port the API is on today. Every app also gets `PORTHAVEN_<APP>_PORT` and `PORTHAVEN_<APP>_URL`.\n- **`porthaven.toml`.** Commit the stack to the repo; whoever clones it runs `porthaven up`. Two apps from different\n  folders that expect the same port are flagged before they collide.\n\n```toml\ngroup = \"Shop\"\n\n[apps.api]\ncommand = \".venv/bin/uvicorn main:app --reload --port {port}\"\ncwd = \"backend\"\nport = 8000\nhealth = \"/health\"\n\n[apps.web]\nname = \"Storefront\"\ncommand = \"npm run dev -- --port {port} --strictPort\"\ncwd = \"frontend\"\nport = 5173\ndepends_on = [\"api\"]\nenv = { VITE_API_URL = \"{url:api}\" }\nsleep_after = 60\n```\n\n- **Docker Compose services in a stack.** `compose = \"postgres\"` makes one service of the folder's compose file a\n  member of the stack: Porthaven runs it with `docker compose up`, keeps its output, waits for its container's\n  health check before starting what depends on it, and stops it with `docker compose stop`. Project discovery lists\n  each compose service.\n\n```toml\n[apps.db]\ncompose = \"postgres\"          # a service of docker-compose.yml in this folder (or compose_file = \"...\")\n\n[apps.api]\ncommand = \"uvicorn main:app --port {port}\"\ndepends_on = [\"db\"]\nenv = { DATABASE_URL = \"postgres://dev@localhost:{port:db}/shop\" }\n```\n\n- **Git worktrees.** Run any saved app from another worktree of its repo. It gets its own port and its own address\n  (`http://feature-x.api.localhost:7475`), so parallel branches, and parallel coding agents, stop fighting over one\n  port. Cards show the branch each app runs from.\n\n### For coding agents\n\n<img src=\"docs/images/agents.jpg\" alt=\"A coding agent using Porthaven's MCP tools\" width=\"900\" />\n\nPorthaven includes an [MCP](https://modelcontextprotocol.io) server, so Claude Code, Cursor, Windsurf and other agents\ncan see ports, start stacks, read logs and free ports with the same guard rails you have.\n\n```bash\nclaude mcp add porthaven -- porthaven mcp\n```\n\nFor Cursor, Windsurf and other clients, add this to their MCP settings (Settings → Connect a coding agent shows the\nfull path for your machine):\n\n```json\n{ \"mcpServers\": { \"porthaven\": { \"command\": \"porthaven\", \"args\": [\"mcp\"] } } }\n```\n\nTools: `list_ports`, `port_info`, `list_apps`, `start_app`, `stop_app`, `restart_app`, `app_logs`, `stop_port`,\n`find_free_ports`, `stack_up`, `stack_down`, `run_in_worktree`, `recent_requests`, `recent_activity`,\n`service_map`, `port_drift`, `port_history`, `search_logs`, `my_servers`, `stop_my_servers`. The agent starts\nPorthaven if it isn't running, and its actions show in Activity as \"by agent\".\n\n- **No servers left behind.** Porthaven notes which coding-agent session (Claude Code, Codex, Gemini CLI, Copilot\n  CLI, Cursor Agent, Aider, opencode, Goose, Amp…) started each dev server, whether through MCP or the agent's own\n  shell. When the session ends, its servers show under \"Left by coding agents\" with the memory they hold, and one\n  click stops them. Settings can stop them on their own once nobody is connected. Agents can clean up after\n  themselves with `my_servers` and `stop_my_servers`.\n\n### Connect the dots\n\n<img src=\"docs/images/map.jpg\" alt=\"The service map: a storefront calling its API, the API holding a database connection\" width=\"900\" />\n\n- **Service map.** Who talks to whom, drawn from the live TCP connections between your processes: browser →\n  storefront → API → Postgres. Links carrying traffic animate; a link whose server went away turns red and stays on\n  the map for half an hour, and a dependency you declared but that isn't running is marked as broken.\n- **Port drift.** Porthaven reads the files where projects write down each other's addresses (`.env` files,\n  vite/next/nuxt configs, proxy configs, compose files) and checks every `localhost:PORT` against what is running:\n  \"Storefront expects Shop API on :8000, but Shop API is on :8001\". One click changes the line (only that line,\n  keeping its line endings), or ignore it.\n- **Port history.** Who held each port, and when, for 30 days: \"what was on :3000 yesterday at 3 pm?\" from the port's\n  details, `porthaven history 3000 --at \"yesterday 3pm\"` or the `port_history` tool.\n- **Trusted HTTPS for stable names.** `https://shop.localhost:7443/` with a lock in the browser, for OAuth callbacks,\n  secure cookies and service workers. Porthaven makes a certificate authority on your machine (or uses mkcert's)\n  and a certificate for each name on first use. `porthaven https setup`, then `porthaven https trust` once.\n- **Share a port.** A link and QR code to open a dev server on your phone over Wi-Fi, or a public link through\n  cloudflared or ngrok when one is installed. The app stays on 127.0.0.1: the link goes through a relay that only\n  lets in visitors who have its secret, ends on its own after the time you choose, and refuses debuggers, notebooks\n  and databases. A banner shows what is shared until it ends.\n\n### Understand\n- **Search every app's output.** One search box (text or regex) over the output of every saved app, newest first,\n  with \"errors only\" and a list of the errors written in the last ten minutes, by app.\n- **Activity timeline.** One lane per port, with markers for launches, crashes and conflicts, plus a\n  weekday-by-hour heatmap and an event log.\n- **Insights.** A week of history:\n  - memory by project, and ports over time;\n  - health (checks OK, average and p95 response time);\n  - top-five lists, and suggestions with one-click fixes.\n- **Request inspector.** Every request through an app's stable name is recorded: method, path, status, time and\n  size, with its headers and the start of each body. Replay a request as it was, or edit the method, path, headers\n  and body first; copy it as `curl`; export everything as a HAR file for the browser's dev tools.\n- **Memory that keeps growing.** A dev server whose memory grew by 500 MB (you choose) and is still growing is\n  flagged (\"Storefront +640 MB in 2 h\"), with a Restart button.\n- **Exposure guard.** A Werkzeug debug console or Django debug pages reachable from the network are flagged as\n  critical or high, with a notification and the fix.\n- **Watch and notify.** A banner, a toast and a desktop notification when a watched port goes down.\n- **Install as an app.** Porthaven installs as its own window with a dock badge (Settings → Install as an app).\n- **In your editor and launcher.** [Extras](extras) include a VS Code / Cursor / Windsurf extension (ports in the\n  status bar; open, stop, start apps), Raycast script commands, an Alfred script filter (`porthaven ls --alfred`) and\n  a menu-bar plugin for SwiftBar, xbar and Argos.\n\n### Keyboard\n\n| Keys | Action | Keys | Action |\n|---|---|---|---|\n| `⌘K` / `Ctrl K` | Command palette (type a port number) | `o` | Open in browser |\n| `/` | Search | `c` | Copy URL |\n| `1`–`6` | Ports · Apps · Map · Logs · Activity · Insights | `p` / `w` | Pin / watch |\n| `j` `k` | Move between rows | `x` / `⇧X` | Stop process / whole app |\n| `Space` | Select for bulk stop | `?` | All shortcuts |\n\n## Command line\n\n```bash\nporthaven                  # the dashboard (same as `porthaven serve`)\nporthaven ls [--all]       # listening ports; --json for scripts\nporthaven who 5173         # what is on a port: command, folder, app, HTTP answer\nporthaven kill 5173 --app  # stop the whole app on a port (asks first; -y to skip)\nporthaven free 3000 -n 5   # the next free ports\nporthaven open 5173        # open in the browser\nporthaven up               # start the apps in ./porthaven.toml, dependencies first\nporthaven down             # stop them\nporthaven init             # write a porthaven.toml from the saved apps in this folder\nporthaven start shop       # start a saved app and its dependencies; `porthaven stop shop`\nporthaven mcp              # MCP server (stdio) for coding agents\nporthaven map              # which local services talk to which\nporthaven drift [--fix]    # config files that point at a port the service has moved away from\nporthaven history 3000 --at \"yesterday 3pm\"   # who held a port, and when\nporthaven logs timeout --errors              # search every saved app's output\nporthaven share 5173       # a link for your phone (--public through cloudflared or ngrok; --stop)\nporthaven agents [--stop]  # servers coding agents started and left running\nporthaven https setup      # trusted HTTPS for stable names; `trust`, `status`, `off`\nporthaven service install  # start at login (launchd, systemd or Task Scheduler); uninstall / status\n```\n\nThe commands that change things talk to the running dashboard and start it if needed.\n\n## How it works\n\n<img src=\"docs/images/architecture.jpg\" alt=\"Porthaven architecture\" width=\"900\" />\n\n```mermaid\nflowchart LR\n  OS[\"Sockets and processes<br/>lsof · ps (macOS, Linux)<br/>netstat · PowerShell (Windows)\"] --> Scanner\n  Scanner --> Classifier[\"Classifier<br/>project · framework · launcher\"]\n  Servers[\"Your servers\"] -->|HTTP checks| Prober\n  Classifier --> Engine\n  Prober --> Engine[\"Engine<br/>events · idle · conflicts · guard rails\"]\n  Engine --> API[\"Local server<br/>JSON API · live stream\"] --> UI[\"Dashboard & CLI\"]\n  Engine --> Proxy[\"Stable names<br/>app.localhost → port\"]\n  Engine <--> Supervisor[\"Supervisor<br/>saved apps · logs\"]\n  Engine <--> Store[(\"~/.porthaven<br/>apps · notes · history\")]\n```\n\nA small local server reads the machine every two seconds (about 0.2 s of work on macOS). It works out what each\nlistening process is and which app launched it, asks each web server for its status and title, and streams the\npicture to your browser. Everything is the Python standard library, plus the tools your OS already has.\n\n## Security\n\n- **Loopback only.** Porthaven listens on `127.0.0.1` and `::1`, never on your network.\n- **DNS rebinding blocked.** It answers only requests addressed to its own `localhost` port.\n- **Session token.** Every change needs a per-session token that only Porthaven's own page can read.\n- **Same rules for agents.** The MCP server uses the same guard rails: it won't stop Porthaven itself, other users'\n  processes, desktop apps or system services.\n- **Shares are opt-in and short.** A shared link goes through a relay that needs the link's secret, ends on its own\n  (8 hours at most) and never shares debuggers, notebooks, databases or debug pages. The app itself stays on\n  127.0.0.1.\n- **Your CA stays yours.** The HTTPS certificate authority's key is kept in `~/.porthaven/tls` (readable by you only)\n  and is trusted only when you run `porthaven https trust`; certificates are issued only for `*.localhost` names.\n- **No sudo, no telemetry.** State lives in `~/.porthaven` (move it with `PORTHAVEN_HOME`).\n\nSee [SECURITY.md](SECURITY.md) for how to report a vulnerability.\n\n## Platform notes\n\n| | macOS | Linux | Windows |\n|---|---|---|---|\n| Reads ports and processes with | `lsof`, `ps` | `/proc`, `ps` | `netstat`, PowerShell |\n| Stops processes with | signals | signals | `taskkill` |\n| Knows each process's folder | ✓ | ✓ | from its command line |\n| Start at login | launchd | systemd user service | Task Scheduler |\n| Trusting the HTTPS CA | login keychain | system store (sudo) and NSS | user certificate store |\n\n## Contributing\n\nIssues and pull requests are welcome. [CONTRIBUTING.md](CONTRIBUTING.md) covers setup, tests and the project layout.\n`make test` runs the backend tests (a real server and a real app included) and the UI type check. CI runs them on\nmacOS, Linux and Windows.\n\n## License\n\n[MIT](LICENSE) © Kirti Nath Jha\n"}