Commit Graph

58 Commits

Author SHA1 Message Date
Michal
84947580ff feat: erase stale fish completions and add completion tests
Fish completions are additive — sourcing a new file doesn't remove old
rules. Add `complete -c mcpctl -e` at the top to clear stale entries.
Also add 12 structural tests to prevent completion regressions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 19:16:36 +00:00
Michal
846fbf8ae9 feat: context-aware completions with dynamic resource names
- Hide attach-server/detach-server from --help (only relevant with --project)
- --project shows only project-scoped commands in tab completion
- Tab after resource type fetches live resource names from API
- --project value auto-completes from existing project names
- Stop offering resource types after one is already selected

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 19:08:29 +00:00
Michal
88b9158197 feat: --project flag scopes get servers/instances to project
mcpctl --project NAME get servers — shows only servers attached to the project
mcpctl --project NAME get instances — shows only instances of project servers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 19:03:07 +00:00
Michal
9badb0e478 feat: add tests.sh runner and project routes integration tests
- tests.sh: run all tests with `bash tests.sh`, summary with `--short`
- tests.sh --filter mcpd/cli: run specific package
- project-routes.test.ts: 17 new route-level tests covering CRUD,
  attach/detach, and the ownerId filtering bug fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:57:46 +00:00
Michal
7d114a8aed fix: project list should use RBAC filtering, not ownerId
The list endpoint was filtering by ownerId before RBAC could include
projects the user has view access to via name-scoped bindings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 18:52:13 +00:00
Michal
329315ec71 feat: remove ProjectMember, add expose RBAC role, attach/detach-server commands
- Remove ProjectMember model entirely (RBAC manages project access)
- Add 'expose' RBAC role for /mcp-config endpoint access (edit implies expose)
- Rename CLI flags: --llm-provider → --proxy-mode-llm-provider, --llm-model → --proxy-mode-llm-model
- Add attach-server / detach-server CLI commands (mcpctl --project NAME attach-server SERVER)
- Add POST/DELETE /api/v1/projects/:id/servers endpoints for server attach/detach
- Remove members from backup/restore, apply, get, describe
- Prisma migration to drop ProjectMember table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 17:50:01 +00:00
Michal
f0faa764e2 fix: RBAC name-scoped access — CUID resolution + list filtering
Two bugs fixed:
- GET /api/v1/servers/:cuid now resolves CUID→name before RBAC check,
  so name-scoped bindings match correctly
- List endpoints now filter responses via preSerialization hook using
  getAllowedScope(), so name-scoped users only see their resources

Also adds fulldeploy.sh orchestrator script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 12:26:37 +00:00
Michal
44838dbe9d fix: update shell completions for current CLI commands
Add users, groups, rbac, secrets, templates to resource completions.
Remove stale profiles references. Add login, logout, create, edit,
delete, logs commands. Update config subcommands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 12:00:31 +00:00
Michal
ddc95134fb fix: migrate legacy admin role to granular roles at startup
- Add migrateAdminRole() that runs on mcpd boot
- Converts { role: 'admin', resource: X } → edit + run bindings
- Adds operation bindings for wildcard admin (impersonate, logs, etc.)
- Add tests verifying unknown/legacy roles are denied by canAccess

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:31:15 +00:00
Michal
f3da6c40f4 fix: resolve tsc --build type errors (exactOptionalPropertyTypes)
- Fix resourceName assignment in mapUrlToPermission for strictness
- Use RbacRoleBinding type in restore-service instead of loose cast
- Remove stale ProjectMemberInput export from validation index

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:07:46 +00:00
Michal
c5147e8270 feat: granular RBAC with resource/operation bindings, users, groups
- Replace admin role with granular roles: view, create, delete, edit, run
- Two binding types: resource bindings (role+resource+optional name) and
  operation bindings (role:run + action like backup, logs, impersonate)
- Name-scoped resource bindings for per-instance access control
- Remove role from project members (all permissions via RBAC)
- Add users, groups, RBAC CRUD endpoints and CLI commands
- describe user/group shows all RBAC access (direct + inherited)
- create rbac supports --subject, --binding, --operation flags
- Backup/restore handles users, groups, RBAC definitions
- mcplocal project-based MCP endpoint discovery
- Full test coverage for all new functionality

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 11:05:19 +00:00
Michal
90f3beee50 fix: add missing passwordHash to DB test user factory
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 01:02:41 +00:00
Michal
0c926fcc2c fix: SSE health probe uses proper SSE protocol (GET /sse + POST /messages)
SSE-transport MCP servers (like ha-mcp) use a different protocol flow:
GET /sse to establish event stream, read endpoint event, then POST
JSON-RPC messages to /messages?session_id=... URL. Previously was
POSTing to root which returned 404.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:55:25 +00:00
Michal
b6e97646b0 fix: HTTP health probes use container IP for internal network communication
mcpd and MCP containers share the mcp-servers Docker network. HTTP probes
must use the container's internal IP + containerPort instead of localhost
+ host-mapped port. Also extracts container IP from Docker inspect.

Updated home-assistant template to use ghcr.io/homeassistant-ai/ha-mcp
Docker image (SSE transport) instead of broken npm package.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:52:17 +00:00
Michal
738bfafd46 feat: MCP health probe runner — periodic tool-call probes for instances
Implements Kubernetes-style liveness probes that call MCP tools defined
in server healthCheck configs. For STDIO servers, uses docker exec to
spawn a disposable MCP client that sends initialize + tool call. For
HTTP/SSE servers, sends JSON-RPC directly.

- HealthProbeRunner service with configurable interval/threshold/timeout
- execInContainer added to orchestrator interface + Docker implementation
- Instance findById now includes server relation (fixes describe showing IDs)
- Events appended to instance (last 50), healthStatus tracked as
  healthy/degraded/unhealthy
- 12 unit tests covering probing, thresholds, intervals, cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:38:48 +00:00
Michal
fe95dbaa27 fix: keep stdin open for STDIO servers + describe instance resolves server names
STDIO MCP servers read from stdin and exit on EOF. Docker containers close
stdin by default, causing all STDIO servers to crash immediately. Added
OpenStdin: true to container creation.

Describe instance now resolves server names (like logs command), preferring
RUNNING instances. Added 7 new describe tests covering server name resolution,
healthcheck display, events section, and template detail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:26:28 +00:00
Michal
3c489cbecb feat: container liveness sync + node-runner slim base
- Add syncStatus() to InstanceService: detects crashed/stopped containers,
  marks them ERROR with last log line as context
- Reconcile now syncs container status first (detect dead before counting)
- Add 30s periodic sync loop in main.ts
- Switch node-runner from alpine to slim (Debian) for npm compatibility
  (fixes home-assistant-mcp-server binary not found on Alpine)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:18:28 +00:00
Michal
459a728196 fix: logs command resolves server names, proper replica handling
- `mcpctl logs <server-name>` resolves to first RUNNING instance
- `mcpctl logs <server-name> -i <N>` selects specific replica
- Shows "instance N/M" hint when server has multiple replicas
- Added 5 proper tests: server name resolution, RUNNING preference,
  replica selection, out-of-range error, no instances error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:12:39 +00:00
Michal
6fbf301d35 fix: show server name in instances table, allow logs by server name
- Instance list now shows server NAME instead of cryptic server ID
- Include server relation in findAll query (Prisma include)
- Logs command accepts server name, server ID, or instance ID
  (resolves server name → first RUNNING instance)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:07:42 +00:00
Michal
d1b6526f75 feat: pull images before container creation, use registry path for node-runner
- Default node-runner image now uses mysources.co.uk registry path
- Add pullImage() call before createContainer() to auto-pull missing images
- Update stack/docker-compose.yml with MCPD_NODE_RUNNER_IMAGE and
  MCPD_MCP_NETWORK env vars, fix mcp-servers network naming

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:03:01 +00:00
Michal
5e84f06c65 feat: add node-runner base image for npm-based MCP servers
STDIO servers with packageName (e.g. @leval/mcp-grafana) need a Node.js
container that runs `npx -y <package>`. Previously, packageName was used
as a Docker image reference causing "invalid reference format" errors.

- Add Dockerfile.node-runner: minimal node:20-alpine with npx entrypoint
- Update instance.service.ts: detect npm-based servers and use node-runner
  image with npx command instead of treating packageName as image name
- Fix NanoCPUs: only set when explicitly provided (kernel CFS not available
  on all hosts)
- Add mcp-servers network with explicit name for container isolation
- Configure MCPD_NODE_RUNNER_IMAGE and MCPD_MCP_NETWORK env vars

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 23:41:16 +00:00
Michal
e16b3a3003 fix: proper error handling and --force flag for create commands
- Add global error handler: clean messages instead of stack traces
- Add --force flag to create server/secret/project: updates on 409 conflict
- Strip null values and template-only fields from --from-template payload
- Add tests: 409 handling, --force update, null-stripping from templates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 23:06:33 +00:00
Michal
ae695d2141 feat: add MCP healthcheck probes and new templates (grafana, home-assistant, node-red)
- Add healthCheck spec to templates and servers (tool, arguments, interval, timeout, failureThreshold)
- Add healthStatus, lastHealthCheck, events fields to instances
- Create grafana, home-assistant, node-red templates with healthcheck probes
- Add healthcheck probes to existing templates (github, slack, postgres, jira)
- Show HEALTH column in `get instances` and Events section in `describe instance`
- Display healthCheck details in `describe server` and `describe template`
- Schema + storage + display only; actual probe runner is future work

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 22:48:59 +00:00
Michal
73fb70dce4 feat: add MCP server templates and deployment infrastructure
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>
2026-02-22 22:24:35 +00:00
Michal
8a4ff6e378 fix: remove unused variables from profile cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:43:32 +00:00
Michal
856fb5b5f7 fix: unused deps parameter in project command
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:42:16 +00:00
Michal
6d9a9f572c feat: replace profiles with kubernetes-style secrets
Replace the confused Profile abstraction with a dedicated Secret resource
following Kubernetes conventions. Servers now have env entries with inline
values or secretRef references. Env vars are resolved and passed to
containers at startup (fixes existing gap).

- Add Secret CRUD (model, repo, service, routes, CLI commands)
- Server env: {name, value} or {name, valueFrom: {secretRef: {name, key}}}
- Add env-resolver utility shared by instance startup and config generation
- Remove all profile-related code (models, services, routes, CLI, tests)
- Update backup/restore for secrets instead of profiles
- describe secret masks values by default, --show-values to reveal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:40:58 +00:00
Michal
ede9e10990 fix: enable positional options so -o works on subcommands
Remove global -o/--output from parent program and enable
enablePositionalOptions() so -o yaml/json is parsed by subcommands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:43:35 +00:00
Michal
f9458dffa0 fix: remove unused Project interface from project.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:41:14 +00:00
Michal
68d0013bfe fix: resolve resource names in get/describe (not just IDs)
fetchResource and fetchSingleResource now use resolveNameOrId so
`mcpctl get server ha-mcp` works by name, not just by ID.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:39:21 +00:00
Michal
e3aba76cc8 feat: add create/edit commands, apply-compatible output, better describe
- `create server/profile/project` with all CLI flags (kubectl parity)
- `edit server/profile/project` opens $EDITOR for in-flight editing
- `get -o yaml/json` now outputs apply-compatible format (strips internal fields, wraps in resource key)
- `describe` shows visually clean sectioned output with aligned columns
- Extract shared utilities (resolveResource, resolveNameOrId, stripInternalFields)
- Instances are immutable (no create/edit, like pods)
- Full test coverage for create, edit, and updated describe/get

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 14:33:25 +00:00
Michal
ae1055c4ae fix: add replicas to restore-service server creation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:47:03 +00:00
Michal
bd09ae9687 feat: kubectl-style CLI + Deployment/Pod model for servers/instances
Server = Deployment (defines what to run + desired replicas)
Instance = Pod (ephemeral, auto-created by reconciliation)

Backend:
- Add replicas field to McpServer schema
- Add reconcile() to InstanceService (scales instances to match replicas)
- Remove manual start/stop/restart - instances are auto-managed
- Cascade: deleting server stops all containers then cascades DB
- Server create/update auto-triggers reconciliation

CLI:
- Add top-level delete command (servers, instances, profiles, projects)
- Add top-level logs command
- Remove instance compound command (use get/delete/logs instead)
- Clean up project command (list/show/delete → top-level get/describe/delete)
- Enhance describe for instances with container inspect info
- Add replicas to apply command's ServerSpec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:30:46 +00:00
Michal
5f66fc82ef test: add integration test for full MCP server flow
Tests the complete lifecycle through Fastify routes with in-memory
repositories and a fake streamable-http MCP server:
- External server: register → start virtual instance → proxy tools/list
- Managed server: register with dockerImage → start container → verify spec
- Full lifecycle: register → start → list → stop → remove → delete
- Proxy auth enforcement
- Server update flow
- Error handling (Docker failure → ERROR status)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:34:55 +00:00
Michal
5d13a0c562 feat: add external MCP server support with streamable-http proxy
Support non-containerized MCP servers via externalUrl field and add
streamable-http session management for HA MCP proof of concept.

- Add externalUrl, command, containerPort fields to McpServer schema
- Skip Docker orchestration for external servers (virtual instances)
- Implement streamable-http proxy with Mcp-Session-Id session management
- Parse SSE-framed responses from streamable-http endpoints
- Add command passthrough to Docker container creation
- Create HA MCP example manifest (examples/ha-mcp.yaml)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 12:21:25 +00:00
Michal
b8c5cf718a feat: implement v2 3-tier architecture (mcpctl → mcplocal → mcpd)
Some checks failed
CI / lint (pull_request) Has been cancelled
CI / typecheck (pull_request) Has been cancelled
CI / test (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
CI / package (pull_request) Has been cancelled
- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery
- Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers
- Add mcpd auth (login/logout) and MCP proxy endpoints
- Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag
- Add tiered health monitoring, shell completions, e2e integration tests
- 57 test files, 597 tests passing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:42:06 +00:00
Michal
89b2b1b13d feat: add Docker bootstrap for mcpd with auto-migration and seeding
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
Adds Dockerfile, entrypoint, and server bootstrap so that
`docker compose up` starts postgres, pushes the schema,
seeds default MCP servers, and starts mcpd with all routes wired up.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:34:18 +00:00
Michal
6da4ae495c feat: add backup and restore with encrypted secrets
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
BackupService exports servers/profiles/projects to JSON bundle.
RestoreService imports with skip/overwrite/fail conflict strategies.
AES-256-GCM encryption for sensitive env vars via scrypt-derived keys.
REST endpoints and CLI commands for backup/restore operations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:40:46 +00:00
Michal
9a67e51307 feat: add health monitoring with metrics collection and REST API
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
MetricsCollector tracks per-instance request counts, error rates, latency,
and uptime. HealthAggregator computes system-wide health status. REST
endpoints at /api/v1/health/overview, /health/instances/:id, /metrics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:34:20 +00:00
Michal
9e660140b3 feat: add Kubernetes orchestrator for MCP server deployment
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
KubernetesOrchestrator implements McpOrchestrator interface with K8s API
client, manifest generation (Pod/Deployment), namespace management,
resource limits, and security contexts. 39 new tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:30:49 +00:00
Michal
d0a224e839 feat: add MCP profiles library with builtin templates
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
Pre-configured profile templates for filesystem, GitHub, PostgreSQL,
Slack, memory, and fetch MCP servers. Includes registry, validation,
instantiation utilities, and .mcp.json generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:25:56 +00:00
Michal
6161686441 feat: implement LLM provider strategy pattern
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
Add OpenAI, Anthropic, and Ollama providers with a runtime-switchable
ProviderRegistry for the local LLM proxy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:22:39 +00:00
Michal
3ee0dbe58e docs: add architecture and getting-started docs, CLI e2e tests
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
Architecture doc covers all packages, APIs, and design principles.
Getting-started guide covers installation, quick start, and config.
E2e tests verify all CLI commands are properly registered.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:18:57 +00:00
Michal
a520b9ff47 feat: add claude and project CLI commands
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
Claude command manages .mcp.json files (generate from project, show, add,
remove entries). Project command provides CRUD for projects with profile
assignment management.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:16:57 +00:00
Michal
9c08faa8d2 feat: add apply command for declarative config and interactive setup wizard
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
Apply reads YAML/JSON config files to sync servers, profiles, and projects
to the daemon with create-or-update semantics. Setup provides an interactive
wizard for configuring MCP servers with environment variables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:14:43 +00:00
Michal
4d796e2aa7 feat: add instance lifecycle management with restart, inspect, and CLI commands
Adds restart/inspect methods to InstanceService, state validation for stop,
REST endpoints for restart and inspect, and full CLI command suite for
instance list/start/stop/restart/remove/logs/inspect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:11:48 +00:00
Michal
7c07749580 feat: add audit logging repository, service, and query API
Implements IAuditLogRepository with Prisma, AuditLogService with
configurable retention policy and purge, and REST routes for
querying/filtering audit logs at /api/v1/audit-logs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:09:14 +00:00
Michal
09675f020f feat: add proxy entry point, resource/prompt forwarding, notifications, and health monitoring
Adds main.ts for config-driven proxy startup, extends router with
resources/list, resources/read, prompts/list, prompts/get forwarding,
notification pass-through from upstreams, and HealthMonitor for
connection state tracking with event-driven state changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 05:05:41 +00:00
Michal
4b67a9cc15 feat: implement local LLM proxy architecture with MCP routing
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>
2026-02-21 05:00:20 +00:00
Michal
1b8b886995 feat: add get and describe commands with API client
kubectl-style get (table/json/yaml) and describe commands for servers,
profiles, projects, instances. ApiClient for daemon communication.
118 CLI tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 04:55:45 +00:00