This repository (public) provides:
- The core MCP server implementation (published as an NPM package)
- The stdio entry point (CLI)
- An Express HTTP server for local development and testing
The hosted server (mcp.apify.com) is implemented in an internal Apify repository that depends on this package.
For general information about the Apify MCP Server, features, tools, and client setup, see the README.md.
src/
mcp/ MCP protocol implementation
tools/ MCP tool implementations
resources/ Resources and widgets metadata
utils/ Shared utilities
web/ React UI widgets (built into dist/web)
tests/
unit/ Unit tests
integration/ Integration tests
Key entry points:
src/index.ts- Main library export (ActorsMcpServerclass)src/index_internals.ts- Internal exports for testing / advanced usagesrc/stdio.ts- Standard input/output (CLI) entry pointsrc/dev_server.ts- Express HTTP server for local development (npm start)src/input.ts- Input processing and validation
The minimum supported Node.js version is 20 (engines.node >= 20 in package.json).
Why Node.js 20:
@segment/analytics-node (used for telemetry) declares engines: { node: ">=20" }, which makes Node.js 20 the hard floor for this package.
- The
.nvmrcfile pins the latest Node.js version for development tooling (lint, type-check, build) — this is intentionally higher than the minimum supported version.
Refer to the CONTRIBUTING.md file.
npm install
cd src/web && npm installWidget code lives in src/web/ (a self-contained React project). Widgets are rendered based on tool output — to add data to a widget, modify the corresponding tool's return value.
UI mode: Widget rendering requires the server to run in UI mode. Use
?ui=true(e.g.,/mcp?ui=true) or setUI_MODE=true.
See the OpenAI Apps SDK documentation for background on MCP Apps and widgets.
npm run buildBuilds the core TypeScript project and src/web/ widgets, then copies widgets into dist/web/. Required before running integration tests or the compiled server.
APIFY_TOKEN='your-apify-token' npm run devStarts the web widgets builder in watch mode and the MCP server in standby mode on port 3001. Editing src/web/src/widgets/*.tsx triggers a hot-reload — the next widget render uses updated code without restarting the server. Adding new widget filenames requires reconnecting the MCP client to pick them up.
- Get your
APIFY_TOKENfrom Apify Console - Preview widgets via the local esbuild dev server at
http://localhost:3226/index.html
The MCP server listens on port 3001. The HTTP server implementation is in src/dev_server.ts. The hosted production server behind mcp.apify.com is located in the internal Apify repository.
Create or edit .claude/settings.local.json:
{
"env": {
"APIFY_TOKEN": "<YOUR_APIFY_API_TOKEN>"
}
}Restart Claude Code for the change to take effect. This token is picked up by both Claude Code MCP servers (defined in .mcp.json) and mcpc.
| Layer | Command | What it covers |
|---|---|---|
| Unit tests | npm run test:unit |
Individual modules in isolation — no credentials needed |
| Integration tests | npm run test:integration |
Full server over all transports against real Apify API (requires APIFY_TOKEN + npm run build) |
| mcpc probing | mcpc @stdio tools-call ... |
Interactive end-to-end verification during development |
| LLM evals | CI only — apply validated label |
Runs evals/run_evaluation.ts against multiple models via OpenRouter; requires PHOENIX_* and OPENROUTER_* secrets |
To trigger the eval workflow on a PR, apply the validated label.
The workflow then runs automatically and posts results to Phoenix.
It also runs automatically on every merge to the master branch.
tests/unit/— unit tests for individual modulestests/integration/— integration tests for MCP server functionalitytests/integration/suite.ts— main integration test suite where all test cases should be added- Other files in this directory set up different transport modes (stdio, SSE, streamable-http) that all use
suite.ts
tests/helpers.ts— shared test utilitiestests/const.ts— test constants
mcpc (@apify/mcpc) provides a CLI feedback loop against the local server.
npm install -g @apify/mcpc
npm run build
mcpc --config .mcp.json stdio connect @stdio
mcpc @stdio tools-list # verifyArguments use key:=value syntax (auto-parses as JSON):
mcpc @stdio tools-list
mcpc @stdio tools-call search-actors keywords:="web scraper" limit:=5
mcpc --json @stdio tools-call search-actors keywords:="scraper" | jq ‘.content[0].text’Key behaviors to verify:
search-actors— test valid keywords, empty keywordsfetch-actor-details— test valid Actor, non-existent Actorcall-actor— test with valid input; check async modeget-actor-output— test field filtering with dot notation, non-existent datasetsearch-apify-docs/fetch-apify-docs— test relevant and non-existent queries
Run MCPJam with npx @mcpjam/inspector@latest.
- Click "Add new server", enter URL
http://localhost:3001/mcp?ui=true, select "No authentication" - App Builder — select a tool, fill arguments, execute, view rendered widget
- Chat — add an OpenAI/Anthropic/OpenRouter API key to chat with widget rendering inline
Test widget rendering on chatgpt.com by exposing the local server via ngrok. See the Apify ChatGPT integration docs for background.
The ngrok credentials are in 1Password. The static domain mcp-apify.ngrok.dev is already set up — add to ~/.config/ngrok/ngrok.yml:
tunnels:
app:
addr: 3001
proto: http
domain: mcp-apify.ngrok.devThen start the tunnel:
ngrok start appThe MCP server API will be reachable at https://mcp-apify.ngrok.dev/?ui=true.
- Go to chatgpt.com and open Settings → Connectors
- Click "Add a custom connector"
- Enter the URL:
https://mcp-apify.ngrok.dev/?ui=true - Save and start a new chat
Important: After restarting ngrok, use the Refresh button in the connector settings to reconnect — ChatGPT does not detect the tunnel restart automatically.