Skip to content

Command Line Tools

MCP Integration

The wheels binary can run as a Model Context Protocol (MCP) server over stdio, letting an AI IDE invoke subcommands — generate, migrate, test, routes, and so on — as structured tool calls instead of shell strings. The AI gets a typed tool catalog; you skip the quoting and parsing that trips up shell-based automation.

You'll use this for:

  • Letting Claude Code, Cursor, or another MCP-aware IDE run wheels commands directly, with arguments marshalled as JSON rather than parsed out of chat.
  • Avoiding shell-escaping bugs when an agent wants to pass attribute lists (title:string, body:text) or path arguments.
  • Automating routine work — generating scaffolds, running migrations, seeding databases — from an editor session without copy-pasting commands.

LuCLI ships a generic mcp subcommand that wraps any installed module's public functions as MCP tools over stdio JSON-RPC. Running wheels mcp wheels starts that server bound to the Wheels Module — every public function in cli/lucli/Module.cfc becomes a tool named after the function itself (for example, generate, migrate). Tool names appear unprefixed in tools/list; the wheels server entry in your MCP config is what namespaces them per client. The AI IDE spawns wheels as a subprocess, speaks newline-delimited JSON-RPC over stdin/stdout, and receives tool results the same way. No network listener is involved.

Add an .mcp.json file to your project root (or wherever your IDE expects it). Most AI IDEs auto-load this file when the project opens:

.mcp.json
{
"mcpServers": {
"wheels": {
"command": "wheels",
"args": ["mcp", "wheels"]
}
}
}

That's the whole configuration. The first wheels is the binary name; the second is the module name to expose. The IDE launches the subprocess on demand — you don't need to keep wheels mcp wheels running yourself, and the server exits when the IDE disconnects.

Don't try wheels mcp on its own to see this snippet: on the released launcher, LuCLI reserves the mcp verb and a bare invocation exits with mcp: missing module name instead of reaching the Wheels Module's help text. To check the server from a shell, use the --once smoke test below. There is no setup wizard and no generated file — add the .mcp.json snippet manually.

Before wiring it into an IDE, you can confirm the server starts and enumerates tools with the built-in --once helper:

smoke-test — run in your project root
wheels mcp wheels --once tools/list

That runs a single MCP method and exits — useful for smoke-testing without opening a long-lived stdio session. The output is a JSON-RPC response listing every exposed tool with its input schema.

Every public function in the Wheels Module is auto-discovered as an MCP tool. Names in tools/list are the bare function names — 18 tools on a 4.0.3 install:

| Tool | Purpose | |---|---| | generate | Scaffold a model, controller, view, migration, scaffold, route, test, property, or helper. | | destroy | Remove a previously generated component. The default resource type cascades (model + controller + views + tests + route + drop-table migration); model, controller, and view are scoped to that artefact only. | | migrate | Run, roll back, or inspect database migrations. | | seed | Run convention-based seeds against the configured environment. | | db | Database utility operations (schema, reset, status). | | test | Run the app or core test suite and return results. | | reload | Reload the app via the running dev server. | | routes | List registered routes. | | info | Print project, framework, and environment info. | | analyze | Run the codebase analyzer (conventions, anti-patterns, drift). | | validate | Run configuration and schema validation checks. | | doctor | Diagnose install, project, and runtime issues. | | stats | Count models, controllers, routes, tests, migrations. | | notes | Surface TODO, FIXME, HACK, OPTIMIZE annotations from the codebase. | | create | Create an application (currently only wheels create app <name>; forwards to wheels new). | | upgrade | Scan the project for breaking changes (check, read-only) or swap vendor/wheels/ to a newer release (apply, writes with a backup). | | deploy | Kamal-style production deploys (full deploy, rollback, config, setup, bootstrap, exec). | | packages | Search, show, add, update, and remove Wheels packages; manage the registry cache. |

A handful of public CLI commands are excluded from MCP discovery via mcpHiddenTools() in Module.cfc. They stay reachable from the terminal but never appear in an MCP tools/list:

  • start, stop — dev server lifecycle. Stateful, long-lived processes don't fit the single-call MCP model.
  • console — interactive CFML REPL. Requires a live stdin/stdout loop, which the MCP transport owns.
  • new — scaffolds an entire new project. Destructive and requires interactive prompts for project context.
  • browser — multi-step browser testing flow with its own subcommand tree.
  • jobsjobs work is a long-lived worker poll loop with no single-call MCP semantics.
  • mcpToolSpecs — the per-tool inputSchema registry LuCLI reads; not itself a tool.
  • mcp — the meta command itself; exposing it would let an agent recursively launch MCP servers.
  • d — short alias for destroy, excluded to avoid a duplicate tool entry (the canonical destroy is exposed).
  • g — short alias for generate, excluded for the same duplicate-entry reason as d.
  • main — the bare wheels no-args dispatch target; it is not a subcommand.
  • Any function whose name begins with $ — internal helpers kept public only so unit tests can reach them (a CFML testing carve-out). mcpHiddenTools() discovers these structurally via getMetaData(this), so a future $helper added to the module cannot accidentally surface as a callable MCP tool without a manual denylist update.

If you need one of these behaviours from an AI IDE, invoke it via a shell tool — don't try to expose it as an MCP tool.

The server never responds / the IDE shows zero tools. The most common cause: GUI-launched editors (VS Code, Cursor, Claude Desktop opened from the dock or Start menu) don't inherit your shell's PATH, so the bare "command": "wheels" in .mcp.json can't be found — and most clients fail silently. Fix it by using the absolute binary path:

.mcp.json
{"mcpServers": {"wheels": {"command": "/opt/homebrew/bin/wheels", "args": ["mcp", "wheels"]}}}

(which wheels in a terminal prints the path to use — e.g. /usr/bin/wheels on apt/yum installs, %USERPROFILE%\scoop\shims\wheels.exe on Scoop.) Launching the editor from a terminal (code .) also works, since the child inherits the shell environment.

Tools appear but calls fail. Run wheels mcp wheels by hand in a terminal at your project root — startup errors that the IDE swallows print directly there.

Earlier versions of the framework shipped an in-dev-server MCP endpoint at /wheels/mcp, implemented as a CFML view that spoke Streamable HTTP JSON-RPC. That endpoint is deprecated as of Wheels 4.0. It still responds for backwards compatibility, but it emits a one-time warning to the wheels_mcp log on first use per JVM and will be removed in a future release.

Migrate to the stdio surface by switching your IDE's MCP server definition to the .mcp.json shown above. The stdio server covers the same tool set, does not require a running dev server for file-based operations (generate, migrate, stats, and so on), and is the only surface that will be maintained going forward.