docs/skills/woods-mcp-config/SKILL.md
Use this guide to produce a correct .mcp.json for your environment. Answer the environment detection questions first, then use the matching template.
1. Is the Rails app running in Docker?
2. Which AI tool?
.mcp.json in your Rails app root (or ~/.claude/claude_desktop_config.json for global).cursor/mcp.json.windsurf/mcp.jsonAll three tools use the same JSON format.
3. Do you need Tier 2–4 console tools? (diagnostics, SQL, Ruby eval, job control)
The Index Server runs as a host process reading local files. The Console Server boots Rails in-process via the rake task.
{
"mcpServers": {
"codebase": {
"command": "woods-mcp-start",
"args": ["./tmp/woods"]
},
"rails-console": {
"command": "bundle",
"args": ["exec", "rake", "woods:console"],
"cwd": "/absolute/path/to/your/rails-app"
}
}
}
woods-mcp-start is a self-healing wrapper that validates manifest.json before starting and auto-installs missing dependencies. Use it instead of woods-mcp for local development.
cwd must be an absolute path to the Rails app root (where Rakefile lives). Relative paths are not supported for cwd.
The Index Server reads volume-mounted output on the host. The Console Server runs inside the container via docker exec -i.
{
"mcpServers": {
"codebase": {
"command": "woods-mcp-start",
"args": ["./tmp/woods"]
},
"rails-console": {
"command": "docker",
"args": [
"exec", "-i",
"your_app_web_1",
"bundle", "exec", "rake", "woods:console"
]
}
}
}
The -i flag is required — it keeps stdin open for the MCP protocol. Without it, the container rejects input immediately.
Find your container name with:
docker ps --format '{{.Names}}'
Docker Compose generates names like <project>-<service>-<index> (e.g., myapp-web-1). The name in your MCP config must match exactly.
For Tier 2–4 tools, use the bridge architecture. The woods-console-mcp binary runs on the host and communicates with the container via JSON-lines over stdio.
First, create ~/.woods/console.yml:
connection:
mode: docker
service: web
compose_file: /absolute/path/to/docker-compose.yml
Then configure the MCP client:
{
"mcpServers": {
"codebase": {
"command": "woods-mcp-start",
"args": ["./tmp/woods"]
},
"rails-console": {
"command": "woods-console-mcp",
"env": {
"WOODS_CONSOLE_CONFIG": "/Users/yourname/.woods/console.yml"
}
}
}
}
docker compose exec)If you use docker compose (v2), use this form instead of docker exec:
{
"mcpServers": {
"rails-console": {
"command": "docker",
"args": [
"compose", "-f", "/absolute/path/to/docker-compose.yml",
"exec", "-i", "web",
"bundle", "exec", "rake", "woods:console"
]
}
}
}
Note: -f with an absolute path bypasses Docker Compose override files. If your project uses docker-compose.override.yml, cd to the project directory and use the compose default instead, or run via a wrapper script.
When the Console Server runs as a Rack middleware endpoint instead of a subprocess:
{
"mcpServers": {
"codebase": {
"command": "woods-mcp-start",
"args": ["./tmp/woods"]
},
"rails-console": {
"type": "streamable-http",
"url": "http://localhost:3000/mcp/console"
}
}
}
Requires config.console_mcp_enabled = true in your initializer. See CONSOLE_MCP_SETUP.md Option C for full setup.
For Rails apps running on a remote server or in a staging environment:
# ~/.woods/console.yml
connection:
mode: ssh
host: app.example.com
user: deploy
command: cd /app && bundle exec rails runner -
{
"mcpServers": {
"codebase": {
"command": "woods-mcp-start",
"args": ["/local/path/to/extracted/tmp/woods"]
},
"rails-console": {
"command": "woods-console-mcp",
"env": {
"WOODS_CONSOLE_CONFIG": "/Users/yourname/.woods/console.yml"
}
}
}
}
The Index Server always reads local files. For SSH setups, copy the extraction output locally with rsync or mount it via SSHFS.
Wrong path for the Index Server
The Index Server takes a path to the extraction output directory, not the Rails root:
# Wrong — points to Rails root
"args": ["/path/to/your/rails-app"]
# Correct — points to extraction output
"args": ["/path/to/your/rails-app/tmp/woods"]
Container path instead of host path
The Index Server runs on the host and cannot access container paths:
# Wrong — container-internal path
"args": ["/app/tmp/woods"]
# Correct — host path to volume-mounted output
"args": ["./tmp/woods"]
Missing -i flag for docker exec
Without -i, Docker closes stdin immediately and the MCP protocol breaks:
# Wrong
"args": ["exec", "your_app_web_1", "bundle", "exec", "rake", ...]
# Correct
"args": ["exec", "-i", "your_app_web_1", "bundle", "exec", "rake", ...]
Relative cwd path
The cwd field in MCP config requires an absolute path on most clients:
# Wrong
"cwd": "./my-rails-app"
# Correct
"cwd": "/Users/yourname/work/my-rails-app"
Container name mismatch
Docker Compose container names include the project name and replica index. Check with docker ps --format '{{.Names}}' and copy the exact name shown.