27 KiB
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;sparkCLI +app/Config→ CodeIgniter 4;package.jsonwithreactdependency → 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
processManagerkeyed by an id returned to the agent, so the agent canlogs/stopthem 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 aFrameworkAdapterresolved viadetect.ts.LaravelAdapter,CodeIgniterAdapter, andReactAdapterare first-class, purpose-built implementations; anything else falls back toGenericAdapter(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 inresources/js), in which case tools accept atarget: "backend" | "frontend"argument to disambiguate. Laravel and CodeIgniter share a commonPhpFrameworkAdapterbase (Composer install/require, PHPUnit test running) and each override the CLI-specific bits (artisanvsspark).
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 separatevite-reactfrontend 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 togenerate_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 viaspark 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 explicitecosystem: "npm" | "composer"argument.
3.2 Dev Workflow
detect_framework— inspect the workspace and return the detected adapter(s) (laravel,codeigniter,react, a combination likelaravel+react, orgeneric) plus key metadata (PHP/Composer version, Node/package-manager, Vite/CRA/Next/Inertia presence).run_install— install dependencies for the detected project(s):composer installfor Laravel/CodeIgniter,npm/pnpm/yarn/bun installfor React; runs both when a project hascomposer.jsonandpackage.jsonside by side.run_script— run apackage.jsonscript (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 viadocker_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 atargetargument for combined projects.build_project— production build, surfacing build errors/warnings (JS bundle build for React;composer install --no-dev --optimize-autoloaderplusartisan config:cache/route:cache/view:cachefor 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 likenode,nginx,postgres), with port mapping, env vars, and volume mounts restricted toWORKSPACE_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 testinside 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 adocker-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 Sail — docker_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 whitelistedphp artisansubcommand and return stdout/stderr; allow-listed commands includemake:controller,make:model,make:migration,make:seeder,make:factory,make:request,make:resource,make:middleware,migrate,migrate:rollback,migrate:fresh(requiresconfirm: 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/resourcecontroller) for a given name, wrapping the relevantartisan make:*calls and wiring the route.composer_require/composer_remove— add/remove a Composer dependency (mirrorsadd_dependencybut for PHP packages).run_phpunit/run_pest— run the Laravel test suite (auto-picked based on which is configured incomposer.json/phpunit.xml), returning parsed pass/fail results.laravel_tinker_eval— evaluate a short PHP expression/snippet viaartisan tinker --executefor quick data/model inspection (read-only by convention; write operations requireconfirm: true).
3.6 CodeIgniter Tools (PHP backend)
spark— run a whitelistedphp sparksubcommand and return stdout/stderr; allow-listed commands includemake:controller,make:model,make:migration,make:seeder,make:entity,make:filter,make:command,make:validation,migrate,migrate:rollback,migrate:refresh(requiresconfirm: 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 relevantspark make:*calls and wiring the route inapp/Config/Routes.php.run_codeigniter_tests— thin wrapper overrun_testsfor 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 overrun_testsspecialized 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 (missingkeyin 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'slaravel/frameworkconstraint incomposer.json.search_codeigniter_docs— look up a topic in the CodeIgniter 4 user guide, version-matched to the project'scodeigniter4/frameworkconstraint incomposer.json.get_package_info— installed version, available scripts/artisan/spark commands, and key deps frompackage.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 throughgenerate_laravel_resource→ migrate → write feature test → verify viaroute:list/tinker. - Prompt:
new-codeigniter-resource— guides the agent throughgenerate_codeigniter_resource→ migrate → write a PHPUnit test → verify viaspark routes. - Prompt:
new-react-component— guides the agent throughgenerate_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.tsruns 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 fromsrc/server.ts— only the transport wiring differs.
5. Safety & Sandboxing
- All filesystem/tool paths resolved against a configured
WORKSPACE_ROOTand 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, andcomposer_require/composer_removefurther 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) requiresconfirm: true.- Long-running processes (dev servers) capped with idle/max-lifetime timeouts and a max concurrent count.
- Destructive operations (
deploy_project, dependency removal,gitwrite ops) require an explicitconfirm: trueargument 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_containerrejects--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 requiresconfirm: 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
containerManagerand 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.
- Volume mounts are restricted to paths inside
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.jsonconstraint) and Composer must be onPATH, or the project uses Laravel Sail/adocker-compose.ymland allartisan/spark/composer_*/test calls are transparently routed throughdocker_execinto the app container instead of the host shell. The adapter picks whichever is available atdetect_frameworktime. CodeIgniter has no Sail-equivalent bundled, but the same Docker routing applies if the project ships its owndocker-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
- Bootstrap — repo scaffold,
package.json, TS config, MCP server skeleton that registers zero tools and runs over stdio; verify it connects in Cursor. - Framework adapter foundation —
FrameworkAdapterinterface, sharedPhpFrameworkAdapterbase,detect.ts(Laravel/CodeIgniter/React/generic detection),GenericAdapter,ReactAdapter,LaravelAdapter,CodeIgniterAdapterskeletons, anddetect_frameworktool. - Core workflow tools —
run_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 theprocessManagerand sandbox path/command guards. - Scaffolding tools —
scaffold_project(incl.laravel/codeigniter/laravel-react/codeigniter-reacttemplates),generate_component,generate_api_route,add_dependency. - Laravel tools —
artisan(with its subcommand allow-list),generate_laravel_resource,composer_require/composer_remove,run_phpunit/run_pest,laravel_tinker_eval. - CodeIgniter tools —
spark(with its subcommand allow-list),generate_codeigniter_resource,run_codeigniter_tests(reusingcomposer_require/composer_removefrom the Laravel milestone via the sharedPhpFrameworkAdapterbase). - React tools —
generate_react_component,generate_react_hook,add_react_route,run_react_tests,analyze_react_component. - Browser tools — integrate Playwright, implement
browser_navigate,browser_screenshot,browser_get_console_logs,browser_inspect_dom, interaction primitives. - Docker tools — integrate
dockerode, implementcontainerManager,docker_build_image,docker_run_container,docker_list_containers,docker_get_container_logs,docker_exec,docker_stop_container/docker_remove_container, anddocker_compose_up/docker_compose_down(incl. Laravel Sail routing); enforce the Docker-specific guardrails from §5. - Docs/package lookup tools —
search_package_docs,search_mdn,search_laravel_docs,search_codeigniter_docs,get_package_info. - Resources & prompts — project metadata resource, process/container log-tail resources,
new-feature/new-laravel-resource/new-codeigniter-resource/new-react-componentprompt templates. - HTTP/SSE transport — Express wiring, auth token middleware, containerization (Dockerfile).
- 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.
- 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.1–v1.5. Each phase adds tools that reuse the existing sandbox, processManager, FrameworkAdapter, and confirm: true patterns.
9.1 Architecture deltas
- New
FrameworkKindvalues (v1.4):vue,nuxt,django,rails,symfony. - Monorepo model (v1.3):
DetectedWorkspace { root, packages: DetectedPackage[] }alongside today’sDetectedProject; workflow tools gain an optionalpackage/ scopedcwdstill confined toWORKSPACE_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(andnpx) for performance audits. - Sail-aware Laravel (v1.5): when
laravel/sail+ compose file exist, prefer Sail/docker composefordevCommand.
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 implementFrameworkAdapter. - Wire SFC-aware
generate_component; reuse existingvite-vuescaffold 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) requireconfirm: true. - Never
git push --force; never mount the Docker socket. - No secrets in tool args — registry auth via environment only.
9.8 Milestones
- v1.1 — Git helpers, screenshot baselines, visual diff, Lighthouse audit (+ tests/docs).
- v1.2 — Next.js App Router depth; Laravel Eloquent/Filament/Nova/queue; CodeIgniter Shield/versioning/
spark_discover. - v1.3 — Monorepo detection/scoping; Dockerfile/compose/Sail generators;
docker_push_image. - v1.4 — Vue/Nuxt adapters (+ Django/Rails/Symfony detection stubs or full adapters).
- v1.5 — Sail-default dev, polish prompts/summaries, remaining framework generators.