Local ledger for development ports with an MCP server
The server defines 8 tools with good naming conventions (verb_noun pattern: current_context, resolve_url, resolve_port, render_env, status, slot_new, slot_release, list_all_projects). Descriptions are present and detailed (ranging 100-250 chars), explaining what each tool does and when to use it. Tool annotations are properly applied (readOnly, mutating, destroy). However, input schemas are not visible in the provided source code excerpt, only parameter names and descriptions are shown in comments. The schema structure (JSON type definitions, enums, constraints) cannot be verified. Error handling guidance is present in descriptions ('Refuses while any service is listening') but recovery paths are minimal. Composition is well-designed: tools have single responsibilities and chain via cwd/project/slot parameters. Parameter naming follows conventions (service, project, slot, cwd, confirm, cascade, format, infra_from). Some parameters accept free-form strings where enums would improve clarity (e.g., 'format' in render_env could be constrained to {dotenv, export, json, mise, direnv, claude-env} rather than relying on description).
The project and slot resolved from the working directory, with the service names. Returns no port numbers.
Names of every project and slot in the ledger. No port numbers.
Every environment variable of the current slot (service ports, derived values, PORT_KEEPER_PROJECT/SLOT) in a format: dotenv, export, json, mise, direnv or claude-env. Leases ports for services that have none yet. For your own use: to write .env.local run the `port-keeper env` command instead of writing the file by hand, and do not echo these numbers to the user.
Bare port number of one service. Prefer resolve_url unless the caller needs the number itself (a tcp service, a config value).
Full URL (e.g. http://localhost:23417) of one service in the current slot. Pass project and slot to look up another project; both are required together.
Create a slot for the current project and lease its ports. Returns the existing slot when the name is taken. Omit name for the next free number.
Input schemas not fully specified in source. Parameter types, constraints, and required/optional flags cannot be verified from the provided code excerpt. Only parameter names and descriptions visible in comments.
Free-form string parameters lack enum constraints. 'format' parameter in render_env accepts one of {dotenv, export, json, mise, direnv, claude-env} but is not enforced as enum, LLM could hallucinate invalid formats like 'yaml' or 'toml'.
Error recovery paths minimal. Some tools describe refusal conditions ('Refuses while any service is listening') but do not guide next steps. Should say: 'Cannot release while services are running. Call status() to see listening processes, then stop them before retrying slot_release.'
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 61 | 2025-06-18+ | v2 |
Release a slot and its ports. Refuses while any service is listening. Requires confirm=true.
Ledger versus reality for the current slot: each service's state (leased, active, stale, hijacked) and the listening process when known.
Output schemas not documented. Tools return structured data (ContextOut, ServiceInfo types visible in code) but no documentation of response field structure for agents to plan downstream actions.