Files
mcp_web_dev_server/PLAN.md
T
2026-07-31 13:12:54 -04:00

27 KiB
Raw Blame History

Web Dev MCP Server — Implementation Plan

1. Goal

Build a general-purpose Model Context Protocol (MCP) server that gives any MCP-compatible AI agent (Cursor, Claude Desktop, etc.) a full toolkit for web development: scaffolding code, running the dev workflow (install/build/test/lint/deploy), running/managing Docker containers for containerized dev & testing, inspecting a live app in a real browser, and looking up framework/library/API docs. The generic tool layer stays framework-agnostic (Vue, Svelte, plain HTML/CSS/JS, etc.), with first-class, dedicated support for Laravel and CodeIgniter (PHP backends) and React (JS/TS frontend) — including combined setups (e.g. Laravel/CodeIgniter API backend + React frontend).

  • Framework detection & adapters: the server auto-detects the project type (composer.json + artisan → Laravel; spark CLI + app/Config → CodeIgniter 4; package.json with react dependency → React/Vite/CRA/Next) and exposes both generic tools (dispatched through the right adapter) and framework-specific tools (artisan_*/spark_*, React component/hook generators).

  • Language/runtime: Node.js + TypeScript

  • Transports: stdio (local, for Cursor/Claude Desktop) and HTTP/SSE (Streamable HTTP) for remote/shared use

  • SDK: @modelcontextprotocol/sdk (official TypeScript SDK)

2. High-Level Architecture

web-dev-mcp/
├── src/
│   ├── server.ts              # MCP server bootstrap, tool/resource registration
│   ├── transports/
│   │   ├── stdio.ts           # stdio transport entrypoint (bin)
│   │   └── http.ts            # Streamable HTTP/SSE transport (Express)
│   ├── tools/
│   │   ├── scaffold/          # project & code generation tools
│   │   ├── workflow/          # install/build/test/lint/run/deploy
│   │   ├── browser/           # Playwright-backed inspection tools
│   │   ├── docker/            # Docker image/container tools
│   │   ├── laravel/           # artisan/composer-backed Laravel tools
│   │   ├── codeigniter/       # spark/composer-backed CodeIgniter tools
│   │   ├── react/             # React component/hook/route generators
│   │   ├── docs/              # docs/package lookup tools
│   │   └── fs/                # safe file read/write/search helpers
│   ├── resources/             # MCP resources (e.g. exposing project files, logs)
│   ├── prompts/                # reusable prompt templates (e.g. "new component")
│   ├── lib/
│   │   ├── processManager.ts  # tracks long-running child processes (dev servers)
│   │   ├── containerManager.ts # tracks Docker containers started by the server
│   │   ├── sandbox.ts         # path/command allow-listing & workspace confinement
│   │   ├── frameworks/
│   │   │   ├── types.ts       # FrameworkAdapter interface
│   │   │   ├── detect.ts      # inspects the workspace, returns detected framework(s)
│   │   │   ├── laravel.ts     # Laravel adapter (composer, artisan, phpunit/pest)
│   │   │   ├── codeigniter.ts # CodeIgniter adapter (composer, spark CLI, phpunit)
│   │   │   ├── react.ts       # React adapter (vite/CRA/Next-aware, npm/pnpm/yarn)
│   │   │   └── generic.ts     # fallback adapter for unrecognized projects
│   │   └── logger.ts
│   └── config.ts              # env vars, workspace root, allow-lists
├── test/
├── package.json
├── tsconfig.json
├── Dockerfile
└── README.md

Core design principles:

  • Workspace-scoped: every tool operates relative to a configured project root; no path may escape it (prevent path traversal).
  • Stateless tool calls, stateful process registry: dev servers/watchers started by a tool persist in an in-memory processManager keyed by an id returned to the agent, so the agent can logs/stop them later.
  • Composable, small tools rather than a few "do everything" mega-tools, so the agent can chain them and results stay predictable.
  • Adapter pattern for frameworks: generic tools (run_install, start_dev_server, run_tests, run_lint, build_project) delegate to a FrameworkAdapter resolved via detect.ts. LaravelAdapter, CodeIgniterAdapter, and ReactAdapter are first-class, purpose-built implementations; anything else falls back to GenericAdapter (plain npm-script/Makefile heuristics). A project can have two active adapters at once (e.g. Laravel or CodeIgniter API + separate React SPA, or Laravel + Inertia/React in resources/js), in which case tools accept a target: "backend" | "frontend" argument to disambiguate. Laravel and CodeIgniter share a common PhpFrameworkAdapter base (Composer install/require, PHPUnit test running) and each override the CLI-specific bits (artisan vs spark).

3. Tool Catalog

3.1 Scaffolding & Code Generation

  • scaffold_project — create a new project from a template: laravel (composer create-project laravel/laravel), codeigniter (composer create-project codeigniter4/appstarter), laravel-react/codeigniter-react (PHP API backend + a separate vite-react frontend in a sibling folder, or Laravel + Inertia/React starter kit), vite-react, vite-vue, next, express-api, static-html, etc.
  • generate_component — generic UI component generator for non-React frameworks (Vue SFC, Svelte, etc.); for React projects this delegates to generate_react_component (§3.7) so React gets its richer, convention-aware generator.
  • generate_api_route — scaffold a backend route/handler for the detected framework (Laravel route + controller, CodeIgniter route + controller via spark make:controller, Next.js API route, Express router, Fastify, etc.).
  • add_dependency — add/remove a dependency, auto-detecting npm/pnpm/yarn (package.json) vs. Composer (composer.json) from lockfiles/manifest presence; for combined projects takes an explicit ecosystem: "npm" | "composer" argument.

3.2 Dev Workflow

  • detect_framework — inspect the workspace and return the detected adapter(s) (laravel, codeigniter, react, a combination like laravel+react, or generic) plus key metadata (PHP/Composer version, Node/package-manager, Vite/CRA/Next/Inertia presence).
  • run_install — install dependencies for the detected project(s): composer install for Laravel/CodeIgniter, npm/pnpm/yarn/bun install for React; runs both when a project has composer.json and package.json side by side.
  • run_script — run a package.json script (e.g. dev, build, test) as a tracked background or foreground process.
  • start_dev_server — start the dev server, wait for the "ready" URL/port, return the URL + process id. For Laravel: php artisan serve (or Laravel Sail via docker_compose_up). For CodeIgniter: php spark serve. For React: the framework's own dev server (Vite/CRA/Next).
  • stop_process / get_process_logs — manage previously started long-running processes.
  • run_lint / run_format — run ESLint/Prettier for React, Laravel Pint/PHP-CS-Fixer for Laravel, or PHP_CodeSniffer/PHP-CS-Fixer for CodeIgniter (whichever is configured), and return structured diagnostics.
  • run_tests — run the test runner: Vitest/Jest/Playwright for React, PHPUnit/Pest for Laravel, PHPUnit (with CIUnit test case support) for CodeIgniter; returns parsed pass/fail results either way, with a target argument for combined projects.
  • build_project — production build, surfacing build errors/warnings (JS bundle build for React; composer install --no-dev --optimize-autoloader plus artisan config:cache/route:cache/view:cache for Laravel, or CodeIgniter's equivalent config/route caching where applicable).
  • deploy_project — optional pluggable deploy step (Vercel/Netlify CLI for React, Forge/Envoyer/custom script for Laravel, or a generic PHP-hosting/rsync script for CodeIgniter) behind explicit opt-in config.

3.3 Browser Preview & Inspection (Playwright-backed)

  • browser_navigate — open a URL (e.g. the local dev server) in a headless/headed browser session.
  • browser_screenshot — capture a screenshot (full page or element selector) for visual verification.
  • browser_get_console_logs — return console/network errors captured since navigation.
  • browser_inspect_dom — query the DOM (selector → outerHTML/text/computed styles) for a given page.
  • browser_click / browser_fill / browser_eval — minimal interaction primitives for smoke-testing UI flows.

3.4 Docker (Container Management)

  • docker_build_image — build an image from a Dockerfile in the workspace (docker build), streaming build output back to the agent.
  • docker_run_container — run a container from an image (a locally built one, or an allow-listed base image like node, nginx, postgres), with port mapping, env vars, and volume mounts restricted to WORKSPACE_ROOT; returns a container id.
  • docker_list_containers — list containers started by this server (id, image, status, ports).
  • docker_get_container_logs — tail logs from a running/stopped container.
  • docker_exec — run a one-off command inside a running container (e.g. npm test inside the container) and return stdout/stderr.
  • docker_stop_container / docker_remove_container — stop/remove a previously started container.
  • docker_compose_up / docker_compose_down — optional: bring up/down a docker-compose.yml-defined stack for multi-service local dev (app + DB + cache, etc.).

Use case: let the agent validate that the app builds and runs correctly in a clean containerized environment (not just the host machine), or spin up dependent services (Postgres, Redis) for local development/testing. Also doubles as the runtime for Laravel Saildocker_compose_up on a Sail-generated docker-compose.yml gives Laravel projects PHP/MySQL/Redis without any local PHP install.

3.5 Laravel Tools (PHP backend)

  • artisan — run a whitelisted php artisan subcommand and return stdout/stderr; allow-listed commands include make:controller, make:model, make:migration, make:seeder, make:factory, make:request, make:resource, make:middleware, migrate, migrate:rollback, migrate:fresh (requires confirm: true), db:seed, route:list, config:clear, cache:clear, queue:work (tracked as a background process like a dev server).
  • generate_laravel_resource — one-shot scaffold of a full resource (model + migration + factory + seeder + apiResource/resource controller) for a given name, wrapping the relevant artisan make:* calls and wiring the route.
  • composer_require / composer_remove — add/remove a Composer dependency (mirrors add_dependency but for PHP packages).
  • run_phpunit / run_pest — run the Laravel test suite (auto-picked based on which is configured in composer.json/phpunit.xml), returning parsed pass/fail results.
  • laravel_tinker_eval — evaluate a short PHP expression/snippet via artisan tinker --execute for quick data/model inspection (read-only by convention; write operations require confirm: true).

3.6 CodeIgniter Tools (PHP backend)

  • spark — run a whitelisted php spark subcommand and return stdout/stderr; allow-listed commands include make:controller, make:model, make:migration, make:seeder, make:entity, make:filter, make:command, make:validation, migrate, migrate:rollback, migrate:refresh (requires confirm: true), db:seed, routes (list routes), cache:clear.
  • generate_codeigniter_resource — one-shot scaffold of a full resource (model + migration + seeder + ResourceController) for a given name, wrapping the relevant spark make:* calls and wiring the route in app/Config/Routes.php.
  • run_codeigniter_tests — thin wrapper over run_tests for CodeIgniter's PHPUnit-based test suite (CIUnitTestCase), returning parsed pass/fail results.

CodeIgniter shares composer_require/composer_remove (§3.5) and search_package_docs/get_package_info (§3.7) with Laravel, since both are Composer-based PHP frameworks — only the CLI (spark vs artisan) and generated file conventions differ.

3.7 React Tools (JS/TS frontend)

  • generate_react_component — scaffold a function component (TSX/JSX, matching the project's existing TS/JS + styling convention — CSS Modules/Tailwind/styled-components) with an optional colocated test file (React Testing Library) and Storybook story.
  • generate_react_hook — scaffold a custom hook file (useXyz.ts) plus a matching test.
  • add_react_route — add a route entry for the detected router (react-router, Next.js App/Pages Router file conventions, or TanStack Router).
  • run_react_tests — thin wrapper over run_tests specialized to parse Jest/Vitest + React Testing Library output (e.g. surfacing which assertions/queries failed).
  • analyze_react_component — static scan of a component file for common issues (missing key in lists, hook-rule violations, unused props) as a fast pre-check before/instead of a full lint run.

3.8 Docs & Package Lookup

  • search_package_docs — fetch README/docs for an npm or Composer/Packagist package to ground the agent in the actual installed version's API.
  • search_mdn — look up a web platform API on MDN.
  • search_laravel_docs — look up a topic in the Laravel documentation, version-matched to the project's laravel/framework constraint in composer.json.
  • search_codeigniter_docs — look up a topic in the CodeIgniter 4 user guide, version-matched to the project's codeigniter4/framework constraint in composer.json.
  • get_package_info — installed version, available scripts/artisan/spark commands, and key deps from package.json/composer.json (whichever applies).

3.9 Filesystem Helpers (sandboxed to workspace root)

  • read_file / write_file / list_dir / search_code — thin, sandboxed wrappers (useful when this server is used standalone, without an IDE's native file tools).

3.10 Resources & Prompts

  • Resource: workspace://project.json — exposes detected project metadata (framework/adapter(s), package manager, scripts, PHP/Node versions) so the agent doesn't need a tool round-trip.
  • Resource: workspace://logs/{processId} — live log tail for a running process.
  • Resource: workspace://containers/{containerId}/logs — live log tail for a running container.
  • Prompt: new-feature — a template prompt guiding the agent through scaffold → implement → test → verify-in-browser.
  • Prompt: new-laravel-resource — guides the agent through generate_laravel_resource → migrate → write feature test → verify via route:list/tinker.
  • Prompt: new-codeigniter-resource — guides the agent through generate_codeigniter_resource → migrate → write a PHPUnit test → verify via spark routes.
  • Prompt: new-react-component — guides the agent through generate_react_component → wire into a route/page → verify via browser screenshot.

4. Transport Design

  • stdio: default entrypoint (bin/web-dev-mcp), used when launched by Cursor/Claude Desktop via their MCP config (command + args). No auth needed (local process).
  • HTTP/SSE (Streamable HTTP): src/transports/http.ts runs an Express app exposing the MCP Streamable HTTP endpoint, so the same tool implementations can be reused remotely (e.g. a shared team server, or containerized in CI). Add a lightweight bearer-token auth middleware for this mode since it's network-reachable.
  • Both transports share the same createServer() factory from src/server.ts — only the transport wiring differs.

5. Safety & Sandboxing

  • All filesystem/tool paths resolved against a configured WORKSPACE_ROOT and rejected if they resolve outside it.
  • Shell/process execution restricted to an allow-list of known package-manager/tool binaries (npm, pnpm, yarn, node, npx, git, php, composer, artisan-via-php, spark-via-php) — no arbitrary shell strings from the model.
  • artisan, spark, and composer_require/composer_remove further restrict which subcommands may run via their own allow-lists (see §3.5/§3.6); anything destructive (migrate:fresh, migrate:reset, migrate:refresh, db:wipe) requires confirm: true.
  • Long-running processes (dev servers) capped with idle/max-lifetime timeouts and a max concurrent count.
  • Destructive operations (deploy_project, dependency removal, git write ops) require an explicit confirm: true argument in the tool schema, so the agent must deliberately opt in.
  • HTTP transport requires an auth token env var (MCP_HTTP_TOKEN); refuses to bind to non-localhost without it set.
  • Docker-specific guardrails:
    • Volume mounts are restricted to paths inside WORKSPACE_ROOT (read-write) — no mounting of arbitrary host paths.
    • docker_run_container rejects --privileged, host network mode, and host PID/IPC namespace sharing.
    • Non-locally-built images are restricted to a configurable allow-list (e.g. node, nginx, postgres, redis) to reduce supply-chain risk; running an arbitrary/unlisted image requires confirm: true.
    • Default CPU/memory limits applied to every container unless overridden; a max-concurrent-container cap is enforced.
    • All containers started by the server are tracked in containerManager and force-stopped/removed on server shutdown.
    • Tool calls fail fast with a clear error if the Docker daemon isn't running/reachable, rather than hanging.

6. Tech Stack

Concern Choice
MCP SDK @modelcontextprotocol/sdk
Language TypeScript (strict mode), compiled to ESM
HTTP server Express (for the HTTP/SSE transport)
Browser automation Playwright
Container management dockerode (Docker Engine API client) — falls back to a clear error if the Docker daemon/socket isn't available
Process management execa (child process handling)
Schema validation zod (tool input schemas)
Testing Vitest
Linting/formatting ESLint + Prettier
Packaging npm package with a bin entry; optional Docker image for the HTTP mode

Prerequisite for Docker tools: Docker Engine (Docker Desktop or dockerd) must be installed and running on the host; the server talks to it via the local Docker socket/named pipe. This is a runtime dependency of the tools, not of the MCP server process itself.

Prerequisite for Laravel/CodeIgniter tools: PHP (matching the project's composer.json constraint) and Composer must be on PATH, or the project uses Laravel Sail/a docker-compose.yml and all artisan/spark/composer_*/test calls are transparently routed through docker_exec into the app container instead of the host shell. The adapter picks whichever is available at detect_framework time. CodeIgniter has no Sail-equivalent bundled, but the same Docker routing applies if the project ships its own docker-compose.yml.

Prerequisite for React tools: none beyond Node.js — React itself is just an npm dependency, so the React adapter reuses the same Node/npm/pnpm/yarn tooling as the generic JS workflow tools, with Vite/CRA/Next-specific conventions layered on top.

7. Implementation Milestones

  1. Bootstrap — repo scaffold, package.json, TS config, MCP server skeleton that registers zero tools and runs over stdio; verify it connects in Cursor.
  2. Framework adapter foundationFrameworkAdapter interface, shared PhpFrameworkAdapter base, detect.ts (Laravel/CodeIgniter/React/generic detection), GenericAdapter, ReactAdapter, LaravelAdapter, CodeIgniterAdapter skeletons, and detect_framework tool.
  3. Core workflow toolsrun_install, run_script, start_dev_server, stop_process, get_process_logs, run_lint, run_tests, build_project, all dispatched through the resolved adapter(s). Includes the processManager and sandbox path/command guards.
  4. Scaffolding toolsscaffold_project (incl. laravel/codeigniter/laravel-react/codeigniter-react templates), generate_component, generate_api_route, add_dependency.
  5. Laravel toolsartisan (with its subcommand allow-list), generate_laravel_resource, composer_require/composer_remove, run_phpunit/run_pest, laravel_tinker_eval.
  6. CodeIgniter toolsspark (with its subcommand allow-list), generate_codeigniter_resource, run_codeigniter_tests (reusing composer_require/composer_remove from the Laravel milestone via the shared PhpFrameworkAdapter base).
  7. React toolsgenerate_react_component, generate_react_hook, add_react_route, run_react_tests, analyze_react_component.
  8. Browser tools — integrate Playwright, implement browser_navigate, browser_screenshot, browser_get_console_logs, browser_inspect_dom, interaction primitives.
  9. Docker tools — integrate dockerode, implement containerManager, docker_build_image, docker_run_container, docker_list_containers, docker_get_container_logs, docker_exec, docker_stop_container/docker_remove_container, and docker_compose_up/docker_compose_down (incl. Laravel Sail routing); enforce the Docker-specific guardrails from §5.
  10. Docs/package lookup toolssearch_package_docs, search_mdn, search_laravel_docs, search_codeigniter_docs, get_package_info.
  11. Resources & prompts — project metadata resource, process/container log-tail resources, new-feature/new-laravel-resource/new-codeigniter-resource/new-react-component prompt templates.
  12. HTTP/SSE transport — Express wiring, auth token middleware, containerization (Dockerfile).
  13. Hardening & tests — Vitest suite per tool (mocking child processes/Playwright/dockerode/artisan/spark calls), confirm-flag enforcement tests, path-traversal tests, Docker guardrail tests, Laravel/CodeIgniter subcommand allow-list tests.
  14. Docs & distribution — README with Cursor/Claude Desktop config snippets, publish as an npm package (npx web-dev-mcp).

8. Example Cursor MCP Config (stdio mode, post-implementation)

{
  "mcpServers": {
    "web-dev": {
      "command": "npx",
      "args": ["-y", "web-dev-mcp"],
      "env": { "WORKSPACE_ROOT": "${workspaceFolder}" }
    }
  }
}

9. Post-v1 Enhancements

9.0 Goal

Extend web-dev-mcp beyond v1 without breaking existing tools/adapters. Work ships in phased releases v1.1v1.5. Each phase adds tools that reuse the existing sandbox, processManager, FrameworkAdapter, and confirm: true patterns.

9.1 Architecture deltas

  • New FrameworkKind values (v1.4): vue, nuxt, django, rails, symfony.
  • Monorepo model (v1.3): DetectedWorkspace { root, packages: DetectedPackage[] } alongside todays DetectedProject; workflow tools gain an optional package / scoped cwd still confined to WORKSPACE_ROOT.
  • Screenshot baseline store (v1.1): PNGs under .web-dev-mcp/baselines/{name}.png, resolved via sandbox helpers.
  • Audit binary allow-list (v1.1): lighthouse (and npx) for performance audits.
  • Sail-aware Laravel (v1.5): when laravel/sail + compose file exist, prefer Sail/docker compose for devCommand.

9.2 Tool catalog — v1.1 Agent productivity

Tool Behavior
git_status git status --porcelain=v1 + branch + ahead/behind; read-only
git_diff staged/unstaged/file-scoped diff; truncated via maxToolOutputChars
git_log recent commits (-n, optional path); read-only
git_branch list or create branch (create requires confirm: true)
git_commit stage workspace-only paths + commit message; confirm: true; no amend/force
browser_screenshot_baseline save current page/element PNG under .web-dev-mcp/baselines/{name}.png
browser_visual_diff compare live screenshot vs baseline (pixelmatch); return diff PNG + mismatch %
lighthouse_audit run Lighthouse headless against a URL; return category scores + top opportunities

9.3 Tool catalog — v1.2 Framework depth

Next.js (still kind: 'react'): enrich describe() with router / rsc; generate_next_page / generate_next_layout; clientComponent on generators; RSC-aware analyze_react_component.

Laravel: generate_eloquent_relation; generate_filament_resource / generate_nova_resource (detect package or hint install); expanded artisan allow-list (queue:*, reverb:start as background); laravel_queue_status.

CodeIgniter: generate_codeigniter_shield_auth (confirm + package detect); versioned ResourceController options on resource generator; spark_discover (filtered php spark list).

9.4 Tool catalog — v1.3 Platform

Tool / change Behavior
detect_workspace / enhanced detect_framework Scan apps/*, packages/*, composer paths; list packages + adapters
package / scoped cwd on workflow tools Scope install/dev/test/build to one package root
generate_dockerfile Emit stack-aware Dockerfile templates
generate_compose Emit docker-compose.yml (app + db + redis presets)
generate_sail Wrap php artisan sail:install when Laravel detected
docker_push_image Push local/allow-listed image; confirm: true; credentials via env
deploy_project Optional registryPush after build; keep script + confirm

9.5 Tool catalog — v1.4 New adapters

  • Detect Vue (vue / .vue + Vite) and Nuxt (nuxt / nuxt.config.*); adapters implement FrameworkAdapter.
  • Wire SFC-aware generate_component; reuse existing vite-vue scaffold template.
  • Django / Rails / Symfony: detection + install/dev/test first; deeper generators later.

9.6 Tool catalog — v1.5 Polish

Tool / change Behavior
Laravel Sail devCommand When laravel/sail + compose file exist, start_dev_server runs vendor/bin/sail up (else docker compose up)
git_diff_summarize Read-only git diff --numstat summary: per-file + total insertions/deletions
lighthouse_audit (richer) Returns category details, cross-category opportunities, failingByCategory
visual-diff-ci prompt Baseline create / visual-diff / threshold pass-fail CI helper
generate_django_resource File stubs: models/views/urls/admin for a Django app
generate_rails_resource File stubs: model + controller + optional routes.rb wire
generate_symfony_resource File stubs: Entity + Repository + Controller

9.7 Safety (all post-v1 phases)

  • Workspace path confinement for every file/baseline/git path argument.
  • Binary allow-list only; no arbitrary shell strings.
  • Destructive / write ops (git_commit, branch create, docker_push_image, Shield install, deploy) require confirm: true.
  • Never git push --force; never mount the Docker socket.
  • No secrets in tool args — registry auth via environment only.

9.8 Milestones

  1. v1.1 — Git helpers, screenshot baselines, visual diff, Lighthouse audit (+ tests/docs).
  2. v1.2 — Next.js App Router depth; Laravel Eloquent/Filament/Nova/queue; CodeIgniter Shield/versioning/spark_discover.
  3. v1.3 — Monorepo detection/scoping; Dockerfile/compose/Sail generators; docker_push_image.
  4. v1.4 — Vue/Nuxt adapters (+ Django/Rails/Symfony detection stubs or full adapters).
  5. v1.5 — Sail-default dev, polish prompts/summaries, remaining framework generators.