A Ruby generator that scaffolds a VSCode extension from any MCP server.
Point this tool at an MCP server (git repo, local path, or HTTP endpoint). It connects, lists the server's tools, and produces a one-off VSCode extension whose WebviewView renders a form for each tool. Press a button, and the extension calls tools/call directly — no LLM in the loop.
The generated extension is yours to keep. There is no re-generation cycle: edit the output freely once it is created.
- Ruby 4.0.x with
bundler - Node.js 22 (the repo pins it via
mise) bundle config set --local path vendor/bundle && bundle install
To build or sideload the generated extension, you also need @vscode/vsce.
Slash commands are the way to drive this tool. Open Claude Code on this repository and run:
/mcp2vscodeext:new https://github.com/bash0C7/chiebukuro-mcp
That single command scaffolds the full extension. After it finishes:
cd chiebukuro-mcp
npm install
npm run compile
code . # then press F5 to open the Extension Development HostSOURCE can be a git URL, an HTTPS MCP endpoint, or a local path (see SOURCE types).
| Command | When to use it |
|---|---|
/mcp2vscodeext:new <SOURCE> |
One-shot. Derives NAME, uses defaults, runs everything. Start here. |
/mcp2vscodeext:plan |
After :new, if you want to pick which tools to surface, choose panel over sidebar, etc. |
/mcp2vscodeext:refine |
After the extension exists, to polish the WebviewView UI. |
SOURCE is a single string. The generator classifies it:
| Form | Kind | How it is run |
|---|---|---|
git@*, *.git, github / gitlab / bitbucket / codeberg URL |
:git_repo |
Shallow-cloned to tmp/sources/<sha>/, then detected |
Any other http(s):// |
:http_endpoint |
Connected with MCP::Client::HTTP |
| An existing local path | :filepath |
Detected by inspecting the directory |
For :filepath, the detector picks the first match of:
package.jsonwith abinentry and@modelcontextprotocol/sdkin dependencies → Node MCP (node <bin>)pyproject.tomlwith[project.scripts]andmcpin dependencies → Python MCP (uvx --from . <script>)Gemfilewithgem "mcp"and a*.gemspecwithspec.executables→ Ruby MCP (bundle exec exe/<name>)
The generated extension ships with its own slash commands for acceptance testing. Open Claude Code on the generated directory, then:
| Command | What it does |
|---|---|
/mcp2vscodeext:acceptance-register |
Builds the harness and registers it via claude mcp add |
/mcp2vscodeext:acceptance-run <scenario> |
Walks the scenario, stopping at each Checkpoint with a screenshot |
/mcp2vscodeext:acceptance-scenario-new <name> |
Scaffolds a new scenario file |
/mcp2vscodeext:acceptance-scenario-update <name> |
Updates an existing scenario |
/mcp2vscodeext:acceptance-upgrade |
Re-syncs the harness after a generator release |
A 00-smoke scenario is generated automatically. Walk it with /mcp2vscodeext:acceptance-run smoke.
<out>/
├── package.json # Activity Bar icon contribution (no commands)
├── .vscode/launch.json
├── media/icon.svg
├── src/
│ ├── extension.ts # Registers the WebviewViewProvider
│ ├── view/provider.ts # Resolves the view and bridges callTool
│ ├── view/client.ts # @modelcontextprotocol/sdk client
│ ├── view/webview.html # Schema-driven form (raw-JSON fallback)
│ ├── tools.generated.ts # Snapshot of tools/list (the only frozen file)
│ ├── acceptance_hook.ts # File-watch IPC, runs only if ACCEPTANCE_HARNESS=1
│ └── mcpProvider.ts # Only when WITH_CHAT_PROVIDER=1
├── acceptance/ # Acceptance harness
│ ├── server/ # MCP server exposing test helpers
│ └── scenarios/ # Scenario markdown files (smoke included)
├── .claude/commands/mcp2vscodeext/
│ ├── acceptance-register.md # Register the harness with `claude mcp add`
│ ├── acceptance-run.md # Walk a scenario with screenshot checkpoints
│ ├── acceptance-scenario-new.md / acceptance-scenario-update.md
│ └── acceptance-upgrade.md # Re-sync the harness after a generator update
├── ruby/ # Only when RUNTIME=bundle or gem
├── README.md / CLAUDE.md / LICENSE
└── .gitignore
For when you do not want to use the slash commands — driving rake directly.
bundle exec rake mcp2vscodeext:new[my-ext] \
SOURCE="https://github.com/bash0C7/chiebukuro-mcp" \
YES=1# 1. Connect to the MCP server and snapshot tools/list
bundle exec rake mcp2vscodeext:introspect NAME=my-ext SOURCE=... YES=1
# → tmp/my-ext.introspect.json
# 2. Render templates using the snapshot
bundle exec rake mcp2vscodeext:render NAME=my-ext OUT=./my-ext PUBLISHER=acme PLACEMENT=sidebar
# 3. Verify the output layout (optional: also runs `vsce package --dry-run`)
bundle exec rake mcp2vscodeext:verify OUT=./my-ext| ENV | Default | Purpose |
|---|---|---|
NAME |
(required) | Extension name (can also be the positional argument to :new) |
SOURCE |
(required) | Git URL, HTTP URL, or local path |
YES |
0 |
Skip the confirmation prompt before spawning the server |
CMD + ARGS |
(auto) | Override detection and run this command instead |
OUT |
./<NAME> |
Output directory |
PLACEMENT |
sidebar |
sidebar (Activity Bar) or panel (wider bottom panel) |
RUNTIME |
node-bundled |
node-bundled, bundle, or gem (use bundle to ship Ruby logic) |
INCLUDE_TOOLS |
(all) | Comma-separated tool names (snake_case) |
EXCLUDE_TOOLS |
(none) | Comma-separated tool names |
WITH_CHAT_PROVIDER |
0 |
Also register registerMcpServerDefinitionProvider |
FORCE |
0 |
Overwrite OUT if it already exists |
ENV_FOR_TARGET |
— | KEY=val,KEY=val passed to the spawned server (not stored) |
HEADERS |
— | Key=Value,Key=Value passed to HTTP transport (not stored) |
bundle exec rake -T lists every task with its description.
bundle exec rake -Tlists all tasks.bundle exec rake dev:testruns the test suite (Test::Unit, isolated per file viaRUBY_BOX=1).bundle exec rake dev:e2eruns the end-to-end pipeline: generate →npm install→tsc→vsce package→ golden diff.bundle exec rake dev:acceptancebuilds a fresh demo extension, builds the harness, and prints the slash commands to walk the smoke scenario by hand.
Project conventions, pitfalls, and design rules live in CLAUDE.md.
MIT