Confine container ops to tracked IDs, tighten image/compose/volume checks, enforce binary allow-lists on background processes, and fix scoped npm docs lookup.
web-dev-mcp
An MCP (Model Context Protocol) server that gives AI coding agents a framework-aware toolkit for web development: project/dependency workflow (install, dev server, lint, test, build), and code/project scaffolding, with first-class support for Laravel, CodeIgniter 4, React, Vue, and Nuxt, plus detection stubs for Django, Rails, and Symfony — including combined backend+frontend setups.
See PLAN.md for the full design and roadmap. This README covers what's
implemented today and how to run it.
Implementation status
Implemented v1 (PLAN.md milestones 1–14) plus post-v1 v1.1–v1.5:
- Framework detection & adapters —
detect_frameworkauto-detects Laravel (Sail-aware), CodeIgniter 4, Symfony, Django, Rails backends and React / Vue / Nuxt frontends, including a PHP/Python/Ruby backend + separate frontend living side-by-side (frontend/,client/,web/). - Core workflow tools —
detect_framework,detect_workspace(monorepo package scan),run_install,run_script,start_dev_server(Sailupwhen present),stop_process,get_process_logs,list_processes,run_lint,run_tests,build_project,deploy_project(opt-inconfirm: true; optionalregistryPush). Most workflow tools accept an optionalpackageargument to scope to a monorepo package. - Scaffolding tools —
scaffold_project(vite-react, vite-vue, next, express-api, static-html, laravel, codeigniter, laravel-react, codeigniter-react),generate_component(React TSX/JSX or Vue SFC),generate_api_route,add_dependency. - Laravel tools —
artisan(allow-listed subcommands; destructive ones needconfirm: true;queue:work/queue:listen/reverb:startrun as tracked background processes),generate_laravel_resource,generate_eloquent_relation,generate_filament_resource,generate_nova_resource,laravel_queue_status,composer_require/composer_remove(shared with CodeIgniter backends),run_phpunit/run_pest,laravel_tinker_eval(write-looking expressions needconfirm: true). - CodeIgniter tools —
spark(allow-listed subcommands;migrate:refreshneedsconfirm: true),spark_discover,generate_codeigniter_resource(optionalapiVersion/ ResourceController),generate_codeigniter_shield_auth(confirm: true),run_codeigniter_tests. - Django / Rails / Symfony —
generate_django_resource,generate_rails_resource,generate_symfony_resource(file-based stubs). - React tools —
generate_react_hook,add_react_route(Next.js / react-router / TanStack Router),generate_next_page/generate_next_layout(App Router),run_react_tests,analyze_react_component(incl. missing"use client"/ server→client prop heuristics).generate_componentsupportsclientComponent: true. - Browser tools —
browser_navigate,browser_screenshot,browser_screenshot_baseline,browser_visual_diff,browser_get_console_logs,browser_inspect_dom,browser_click,browser_fill,browser_eval(Playwright-backed; Chromium binaries vianpx playwright install chromium). - Git helpers —
git_status,git_diff,git_diff_summarize,git_log,git_branch(create needsconfirm: true),git_commit(confirm: true; no amend/force/push). - Lighthouse audit —
lighthouse_audit(category details, opportunities,failingByCategory). - Prompts —
new-feature,new-laravel-resource,new-codeigniter-resource,new-react-component,visual-diff-ci. - Docker tools —
docker_build_image,docker_run_container(with workspace-confined volume mounts, image allow-list, and resource limits),docker_list_containers,docker_get_container_logs,docker_exec,docker_stop_container,docker_remove_container,docker_compose_up,docker_compose_down,generate_dockerfile,generate_compose,generate_sail(confirm: true),docker_push_image(confirm: true). - Docs & package lookup —
search_package_docs(npm README via unpkg, Composer metadata via Packagist),search_mdn,search_laravel_docs,search_codeigniter_docs,get_package_info. - Resources & prompts —
workspace://project.json,workspace://logs/{processId},workspace://containers/{containerId}/logs, and reusable promptsnew-feature,new-laravel-resource,new-codeigniter-resource,new-react-component. - Safety — every filesystem path is confined to
WORKSPACE_ROOT(src/lib/sandbox.ts), spawned binaries are restricted to an allow-list, and destructive ops (deploy_project,composer_remove,migrate:fresh,migrate:refresh,git_commit, …) require an explicitconfirm: true. Docker containers are tracked and force-removed on server shutdown. - Both transports work today: stdio (for Cursor/Claude Desktop) and Streamable HTTP (for
remote/shared use), sharing one
createServer()implementation. The HTTP transport includes bearer-token auth and a production-readyDockerfile. - Automated test suite — Vitest tests for sandbox/path confinement, binary allow-list,
process management, Laravel/CodeIgniter subcommand allow-lists, destructive-command
confirm: trueenforcement, Docker guardrails, framework detection, baselines/visual diff, and Lighthouse parsing. - Distribution-ready — install via
npx web-dev-mcpor add to your MCP client config.
Post-v1 roadmap (see PLAN.md §9): v1.4 Vue/Nuxt adapters, v1.5 Sail/polish.
Requirements
- Node.js >= 22 (developed/tested on Node 24)
- For Laravel/CodeIgniter tools: PHP + Composer on
PATH - For scaffolding Laravel/CodeIgniter projects: Composer on
PATH - For browser tools:
npx playwright install chromium(run once afternpm install) - For Docker tools: Docker Engine (Docker Desktop or
dockerd) running and accessible to the current user - For
lighthouse_audit: Chrome/Chromium available (Lighthouse is pulled vianpxon demand) - For git tools:
gitonPATHand a git workspace underWORKSPACE_ROOT
Setup
npm install
npm run build
Running tests
npm run test
Running
stdio (what Cursor/Claude Desktop use):
npm run dev # ts-node/tsx, no build step needed
# or, after `npm run build`:
npm start
Streamable HTTP (remote/shared use):
npm run build
npm run start:http
Environment variables:
| Variable | Default | Purpose |
|---|---|---|
WORKSPACE_ROOT |
current working directory | The project root every tool is confined to. |
MCP_HTTP_HOST |
127.0.0.1 |
Host the HTTP transport binds to. |
MCP_HTTP_PORT |
3939 |
Port the HTTP transport binds to. |
MCP_HTTP_TOKEN |
(unset) | Bearer token required on /mcp when set. Required if binding to a non-localhost host. |
Docker / containerization:
docker build -t web-dev-mcp .
docker run -p 3939:3939 -e MCP_HTTP_TOKEN=change-me -v /path/to/project:/workspace web-dev-mcp
The image exposes the Streamable HTTP transport on port 3939 and uses /workspace as the confined WORKSPACE_ROOT. The Dockerfile uses a multi-stage build so the final image only contains production dependencies plus the compiled dist/ directory.
Using it from Cursor
Add to your MCP config (Cursor Settings → MCP, or .cursor/mcp.json):
{
"mcpServers": {
"web-dev": {
"command": "node",
"args": ["/path/to/web-dev-mcp/dist/transports/stdio.js"],
"env": { "WORKSPACE_ROOT": "${workspaceFolder}" }
}
}
}
Published npm package (recommended)
{
"mcpServers": {
"web-dev": {
"command": "npx",
"args": ["-y", "web-dev-mcp"],
"env": { "WORKSPACE_ROOT": "${workspaceFolder}" }
}
}
}
Claude Desktop config
Add to claude_desktop_config.json:
{
"mcpServers": {
"web-dev": {
"command": "npx",
"args": ["-y", "web-dev-mcp"],
"env": { "WORKSPACE_ROOT": "/path/to/your/project" }
}
}
}
Local checkout
{
"mcpServers": {
"web-dev": {
"command": "node",
"args": ["/path/to/web-dev-mcp/dist/transports/stdio.js"],
"env": { "WORKSPACE_ROOT": "${workspaceFolder}" }
}
}
}
Project layout
src/
config.ts # env vars, allow-lists, timeouts
server.ts # createServer(): registers all tools/resources
transports/
stdio.ts # stdio entrypoint (bin)
http.ts # Streamable HTTP entrypoint
lib/
logger.ts # stderr-only logging (stdout is reserved for JSON-RPC)
sandbox.ts # workspace path confinement + binary allow-list
runCommand.ts # foreground command execution with capped output
processManager.ts # tracks background processes (dev servers, backgrounded scripts)
strings.ts # pascal/camel/kebab-case helpers for codegen
frameworks/
types.ts # FrameworkAdapter interface
detect.ts # workspace inspection -> detected adapter(s)
resolve.ts # picks backend/frontend/primary adapter for a tool call
generic.ts, react.ts, vue.ts, djangoRailsSymfony.ts, laravel.ts, codeigniter.ts, phpBase.ts
packageManager.ts, composer.ts # npm/pnpm/yarn/bun and Composer helpers
tools/
shared.ts # zod schema + result helpers shared by tools
workflow/ # detect_framework, run_install, run_script, start_dev_server,
# stop_process, get_process_logs, list_processes, run_lint,
# run_tests, build_project, deploy_project
scaffold/ # scaffold_project (+ templates/), generate_component,
# generate_api_route, add_dependency
laravel/ # artisan, generate_laravel_resource, composer_require/remove,
# run_phpunit/run_pest, laravel_tinker_eval
codeigniter/ # spark, generate_codeigniter_resource, run_codeigniter_tests
react/ # generate_react_hook, add_react_route, run_react_tests,
# analyze_react_component
browser/ # browserManager, navigate, screenshot, consoleLogs,
# inspectDom, interact
docker/ # dockerManager, buildImage, runContainer, listContainers,
# containerLogs, exec, stopRemove, compose
docs/ # searchPackageDocs, searchMdn, searchLaravelDocs,
# searchCodeIgniterDocs, getPackageInfo
git/ # git_status, git_diff, git_log, git_branch, git_commit
audit/ # lighthouse_audit
resources/ # process/container log resources
prompts/ # new-feature / laravel / codeigniter / react prompts
Screenshot baselines for browser_visual_diff are stored under .web-dev-mcp/baselines/ inside
the workspace (you may commit them for CI, or ignore them locally).
Publishing
npm run build
npm run test
npm version <patch|minor|major>
npm publish
The package is published as web-dev-mcp and exposes dist/transports/stdio.js as the bin entry,
so npx web-dev-mcp launches the stdio transport directly.