git clone https://github.com/2captcha/2captcha-mcp.git
cd 2captcha-mcp
npm ci
npm test # 22+ tests, no network and no token needed
npm run lintThe tests spawn the real server.js against a fake Streamable-HTTP remote, so
they need neither an API token nor a working internet connection. If a test
asks you for either, that is a bug in the test.
To run against the live service:
export API_TOKEN=your-2captcha-api-key
node connect-check.mjs https://mcp.2captcha.com/mcp "$API_TOKEN"
node examples/01_marketplace_rows_for_nothing.mjsA thin stdio bridge to the hosted 2Captcha Web MCP service. Tool schemas are fetched from the server at runtime, never declared here — that is what keeps the package from drifting from the service.
So the answer to "can we add a tool?" is almost always no, not here: tools
are added to the server, and this package picks them up automatically. What
does belong here is the local surface — group membership in tool_groups.js,
the prompts in prompts.js, and the connection, caching and budget behaviour
in server.js.
If you add a tool group or move a tool between groups, tool-groups.test.js
asserts the surface is internally consistent. Note that adding a tool to the
server without adding it to a group means default clients never see it; the
server prints a note when it spots one, which is how the last such gap was
found.
The code has a deliberate and slightly unusual style: four-space indent,
snake_case, the brace of a multi-line block on its own line but on the same
line for function declarations, and no spaces around binary operators.
There is no Prettier, on purpose. Prettier cannot express this style, so
adding it would reformat every line in the repo and make every subsequent diff
unreadable. ESLint is configured to enforce the parts that matter —
correctness, unused code, strict equality, indent width — and to leave the
rest alone. Run npm run lint before opening a PR.
One rule is worth calling out: console.log is banned in server.js because
stdout is the MCP transport. A stray write there corrupts the protocol
stream and the client disconnects with no useful error. Use console.error or
the log() helper. The --help and --version paths are the documented
exception; they exit before the transport is connected.
Comments explain why, not what. Several comments in this repo record a bug that actually happened, so that the shape of the fix survives. Please keep that habit.
- One concern per PR.
npm testandnpm run lintpass.- New behaviour comes with a test. The e2e harness in
test/proxy.test.jsmakes this cheaper than it looks: spawn the server against the fake remote and assert on what a client sees. - Update
CHANGELOG.mdunder## Unreleased. - Do not bump the version or edit
2captcha-mcp.mjs. Versions are set bynode scripts/release.mjs <version>, which writes all four files that carry one, and the bundle is generated bynpm run build.
Maintainers only — see docs/RELEASING.md. Short version:
npm run release -- <version>, review, tag, push. The tag triggers npm,
the MCP Registry, the .mcpb bundle and the container image.
Use the issue templates. For anything security-related, follow
SECURITY.md instead of opening an issue.