The closing stage. mcpd now hosts the Stage 5 SPA, the Docker image
bundles the build artifact, a smoke test exercises the personality
HTTP surface end-to-end, and the user-facing docs spell out the
mental model.
mcpd:
- Add @fastify/static dep.
- New routes/web-ui.ts: registers /ui/* against a static bundle. Looks
for the bundle at $MCPD_WEB_ROOT, then /usr/share/mcpd/web (the
Docker image path), then a dev-tree fallback. Logs and skips
cleanly if missing — API-only deploys keep working.
- SPA fallback: any /ui/<path> that doesn't match a file falls through
to index.html so direct hits to react-router URLs work.
- /ui/* falls through to `kind: skip` in mapUrlToPermission, so the
static assets are served unauthenticated. Each API call from the
SPA still carries the bearer token.
Deploy:
- Dockerfile.mcpd builds the @mcpctl/web bundle in the same builder
stage and copies dist/ to /usr/share/mcpd/web in the runtime image.
Smoke (personality.smoke.test.ts):
- Live mcpd flow: create secret/llm/agent/personality, attach an
agent-direct prompt, verify the binding listing, reject double-
attach (409) + foreign-agent prompt (400), set defaultPersonality
by name, detach + delete cleanup.
Docs:
- New docs/personalities.md: VLAN-on-ethernet model, system-block
ordering table, three prompt scopes, CLI walkthrough, web UI
walkthrough, full API surface, RBAC notes.
- agents.md and chat.md cross-link.
- README's Agents section gains a Personalities subsection.
Test count after Stage 6:
mcpd: 801/801 cli: 430/430
web: 7/7 db: 58/62 (4 pre-existing)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New workspace package @mcpctl/web — a Vite + React 19 SPA that talks
to mcpd's existing HTTP API. Bundles to a static dist/ which Stage 6
will bake into the RPM and serve from mcpd at /ui via @fastify/static.
Pages:
/ui/projects list projects
/ui/projects/:name/prompts CRUD project prompts (Monaco editor)
/ui/agents list agents
/ui/agents/:name tabs: Direct prompts | Personalities
/ui/personalities/:id bind/unbind prompts to a personality
Auth: paste a session token (mcpctl auth login) or PAT (mcpctl_pat_*)
once on a login screen, kept in localStorage; logout clears it.
API client: 60-line fetch wrapper, attaches the bearer header from
storage, throws an ApiError with status + parsed body on non-2xx.
A 200-line useFetch hook provides loading/error/data without a
state-management library — we are not building Notion.
UX:
- Dark terminal-adjacent theme so the page feels like the CLI.
- Monaco @monaco-editor/react for prompt content (markdown mode,
word-wrap, search, multi-cursor).
- Personality detail's "attach prompt" picker filters in-scope
candidates: agent-direct + same-project + globals.
Dev loop: pnpm --filter @mcpctl/web dev (vite at :5173, proxies
/api to https://mcpctl.ad.itaz.eu — override with MCPCTL_API_URL).
Build: pnpm --filter @mcpctl/web build → src/web/dist/.
Tests: 7 vitest cases covering the bearer header / 4xx body / 204
no-content path on the api wrapper, and the login storage round-trip
+ help toggle. Production build green: 269 KB JS / 84 KB gzipped.
Typecheck clean (TS strict + exactOptionalPropertyTypes carried over).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mcpd can now deploy MCP server instances as Kubernetes pods instead of
Docker containers. Set MCPD_ORCHESTRATOR=kubernetes to enable.
- Add @kubernetes/client-node with thin wrapper (context enforcement
via MCPD_K8S_CONTEXT to prevent multi-cluster mishaps)
- Rewrite KubernetesOrchestrator: pod CRUD, pod IP extraction,
exec via SPDY (one-shot + interactive), log streaming
- Manifest generator: stdin:true for STDIO servers, args (not command)
to preserve runner image entrypoint, security hardening
- Orchestrator selection in main.ts via MCPD_ORCHESTRATOR env var
- 25 unit tests for k8s orchestrator, all 624 tests pass
Tested end-to-end on local k3s:
- mcpd deployed via Pulumi, creates pods in mcpctl-servers namespace
- NetworkPolicy verified: only mcpd can reach MCP server pods
- Python runner (uvx) successfully runs aws-documentation-mcp-server
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add warmup() to LlmProvider interface for eager subprocess startup
- ManagedVllmProvider.warmup() starts vLLM in background on project load
- ProviderRegistry.warmupAll() triggers all managed providers
- NamedProvider proxies warmup() to inner provider
- paginate stage generates LLM-powered descriptive page titles when
available, cached by content hash, falls back to generic "Page N"
- project-mcp-endpoint calls warmupAll() on router creation so vLLM
is loading while the session initializes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ink-based TUI that shows exactly what an LLM sees through MCP.
Browse tools/resources/prompts, execute them, and see raw JSON-RPC
traffic in a protocol log. Supports gated session flow with
begin_session, raw JSON-RPC input, and session reconnect.
- McpSession class wrapping HTTP transport with typed methods
- 12 React/Ink components (header, protocol-log, menu, tool/resource/prompt views, etc.)
- 21 unit tests for McpSession against a mock MCP server
- Fish + Bash completions with project name argument
- bun compile with --external react-devtools-core
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce a Helm-chart-like template system for MCP servers. Templates are
YAML files in templates/ that get seeded into the DB on startup. Users can
browse them with `mcpctl get templates`, inspect with `mcpctl describe
template`, and instantiate with `mcpctl create server --from-template=`.
Also adds Portainer deployment scripts, mcplocal systemd service,
Streamable HTTP MCP endpoint, and RPM packaging for mcpctl-local.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add STDIO and HTTP upstream transports, McpRouter with tool namespacing
and discovery, and StdioProxyServer for aggregating multiple MCP servers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
McpOrchestrator interface with DockerContainerManager implementation,
instance service for lifecycle management, instance API routes,
and docker-compose with mcpd service. 127 tests passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add validation schemas (Zod), repository pattern with Prisma, service layer
with business logic (NotFoundError, ConflictError), and REST routes for
MCP server and profile CRUD. 86 mcpd tests passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add CLI entry point with Commander.js, config management (~/.mcpctl/config.json
with Zod validation), output formatters (table/json/yaml), config and status
commands with dependency injection for testing. Fix sanitizeString regex ordering.
67 tests passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add registry client that queries Official, Glama, and Smithery MCP
registries with caching, request deduplication, retry logic, and
result ranking/dedup. Includes 53 tests covering all components.
Also fix null priority values in cancelled tasks (19-21) that broke
Task Master, and add new tasks 25-27 for registry completion and
CLI discover/install commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>