Skip to main content
Glama
README.md
# web-speed-mcpb

The Claude Desktop extension for [Web Speed](https://getwebspeed.io). Double-click
it, paste a key, done.

This repo builds one artifact: `web-speed.mcpb`. It contains no Web Speed logic —
the engine is hosted, and this is the ~1.5 MB of plumbing that lets Claude Desktop
reach it.

## Why this exists

Installing Web Speed on Claude Desktop used to mean hand-editing
`claude_desktop_config.json` with an absolute path and a pasted API key. That is
the single place people got stuck, and it produced silent drift — three configs on
one machine, pointing at three different interpreters, with the same key in
plaintext in all of them.

## What's inside

```
manifest.json        the extension descriptor (validated in CI)
server/index.js      ~30 lines: hand stdio to mcp-remote, pointed at the hosted API
node_modules/        mcp-remote, vendored
icon.png             512×512
```

`server/index.js` runs the same invocation the `/account` install tab has been
handing out by hand:

```
mcp-remote https://api.getwebspeed.io/mcp/sse --header "X-Web-Speed-Key: ..."
```

That command was already proven against this server. The extension's job is to
stop the user having to type it.

### Why mcp-remote is vendored

The manual instructions use `npx -y mcp-remote@latest`. Inside a bundle that is
three problems:

1. `npx` resolves over the network on **every start** — a flaky connection becomes
   "the extension is broken".
2. `@latest` means an upstream release can break a working install overnight, with
   no version pinned anywhere the user can see.
3. On Windows, Claude Desktop wraps commands in `cmd.exe`, which breaks on the
   space in `C:\Program Files\nodejs`. The manual instructions work around this
   with a global `npm install`; a vendored copy sidesteps it.

Node itself ships **inside** Claude Desktop on macOS and Windows, so there is no
runtime for the user to install.

## Building

```bash
pnpm install --prod
pnpm dlx @anthropic-ai/mcpb validate manifest.json
pnpm dlx @anthropic-ai/mcpb pack . web-speed.mcpb
```

Two things in `pnpm-workspace.yaml` are load-bearing and easy to delete by
accident:

- **The file must exist**, even empty. If you have a pnpm workspace root
  anywhere above this directory — a `pnpm-workspace.yaml` in `$HOME` will do it —
  then without a local one `pnpm install` resolves against that instead and
  `node_modules` lands somewhere else entirely.
- **`nodeLinker: hoisted`.** The bundle ships `node_modules` inside the archive, so
  the tree has to be real directories. pnpm's default symlinks into `.pnpm/` pack
  as broken links and the extension dies on load. In pnpm 10+ this setting lives
  in `pnpm-workspace.yaml`, not `.npmrc` — putting it in `.npmrc` silently does
  nothing.

Verify a build actually runs before releasing it:

```bash
pnpm dlx @anthropic-ai/mcpb unpack web-speed.mcpb /tmp/ws-check
find /tmp/ws-check -type l          # must print nothing
WEBSPEED_API_KEY=wsp_... node /tmp/ws-check/server/index.js
```

The last command should sit waiting on stdin rather than exiting. Sending it an
MCP `initialize` frame should return `serverInfo`.

## Configuration

| Variable | Default | |
|---|---|---|
| `WEBSPEED_API_KEY` | — | Required. Supplied by Claude Desktop from the install form. |
| `WEBSPEED_MCP_URL` | `https://api.getwebspeed.io/mcp/sse` | Override for local testing. |

## Releasing

Tag `v*`. CI validates, packs, signs, and attaches `web-speed.mcpb` to the release.

`manifest.json`'s `version` and `package.json`'s `version` must match — CI fails the
build if they don't. The API server serves the download as a redirect to the
release asset, pinned by `MCPB_RELEASE_TAG`, so **bump that env var on Railway when
you tag** or `/download/web-speed.mcpb` keeps pointing at the previous release.

## License

GPL-3.0-or-later.