251 lines
11 KiB
Markdown
251 lines
11 KiB
Markdown
# 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`](./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_framework` auto-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` (Sail `up` when present), `stop_process`,
|
||
`get_process_logs`, `list_processes`, `run_lint`, `run_tests`, `build_project`,
|
||
`deploy_project` (opt-in `confirm: true`; optional `registryPush`). Most workflow tools accept
|
||
an optional `package` argument 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 need `confirm: true`;
|
||
`queue:work`/`queue:listen`/`reverb:start` run 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 need `confirm: true`).
|
||
- **CodeIgniter tools** — `spark` (allow-listed subcommands; `migrate:refresh` needs
|
||
`confirm: true`), `spark_discover`, `generate_codeigniter_resource` (optional `apiVersion` /
|
||
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_component` supports `clientComponent: 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 via `npx playwright install chromium`).
|
||
- **Git helpers** — `git_status`, `git_diff`, `git_diff_summarize`, `git_log`, `git_branch` (create needs
|
||
`confirm: 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 prompts `new-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 explicit `confirm: 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-ready `Dockerfile`.
|
||
- **Automated test suite** — Vitest tests for sandbox/path confinement, binary allow-list,
|
||
process management, Laravel/CodeIgniter subcommand allow-lists, destructive-command `confirm: true`
|
||
enforcement, Docker guardrails, framework detection, baselines/visual diff, and Lighthouse parsing.
|
||
- **Distribution-ready** — install via `npx web-dev-mcp` or 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 >= 18.17 (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 after `npm 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 via `npx` on demand)
|
||
- For git tools: `git` on `PATH` and a git workspace under `WORKSPACE_ROOT`
|
||
|
||
## Setup
|
||
|
||
```bash
|
||
npm install
|
||
npm run build
|
||
```
|
||
|
||
## Running tests
|
||
|
||
```bash
|
||
npm run test
|
||
```
|
||
|
||
## Running
|
||
|
||
**stdio** (what Cursor/Claude Desktop use):
|
||
|
||
```bash
|
||
npm run dev # ts-node/tsx, no build step needed
|
||
# or, after `npm run build`:
|
||
npm start
|
||
```
|
||
|
||
**Streamable HTTP** (remote/shared use):
|
||
|
||
```bash
|
||
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**:
|
||
|
||
```bash
|
||
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`):
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"web-dev": {
|
||
"command": "node",
|
||
"args": ["/path/to/web-dev-mcp/dist/transports/stdio.js"],
|
||
"env": { "WORKSPACE_ROOT": "${workspaceFolder}" }
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Published npm package (recommended)
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"web-dev": {
|
||
"command": "npx",
|
||
"args": ["-y", "web-dev-mcp"],
|
||
"env": { "WORKSPACE_ROOT": "${workspaceFolder}" }
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Claude Desktop config
|
||
|
||
Add to `claude_desktop_config.json`:
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"web-dev": {
|
||
"command": "npx",
|
||
"args": ["-y", "web-dev-mcp"],
|
||
"env": { "WORKSPACE_ROOT": "/path/to/your/project" }
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Local checkout
|
||
|
||
```json
|
||
{
|
||
"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
|
||
|
||
```bash
|
||
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.
|