Doramagic Project Pack · Human Manual
apify-mcp-server
Related topics: Core Architecture, Tool System
Project Overview
Related topics: Core Architecture, Tool System
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Core Architecture, Tool System
Project Overview
Apify MCP Server is a Model Context Protocol (MCP) server that provides AI assistants with access to Apify's platform capabilities. The server acts as a bridge between AI models and Apify's cloud infrastructure, enabling AI assistants to search and interact with Actors, documentation, and web content.
Source: README.md:1
What is the Apify MCP Server?
The Apify MCP Server implements the MCP specification to expose Apify platform features as tools that AI assistants can invoke. This allows AI models to:
- Search and discover Actors on the Apify platform
- Fetch detailed information about specific Actors
- Search Apify and Crawlee documentation
- Execute web scraping and automation tasks through the RAG web browser tool
Source: README.md:22-30
Architecture Overview
The project follows a monorepo structure with the following key directories:
| Directory | Purpose |
|---|---|
src/ | Core MCP server implementation |
src/web/ | React UI widgets for MCP Apps (ChatGPT integration) |
tests/unit/ | Unit tests for individual modules |
tests/integration/ | Integration tests for full server functionality |
res/ | Technical documentation and analysis |
Source: DEVELOPMENT.md:1-20
Server Components
The MCP server is built around the ActorsMcpServer class in src/mcp/server.ts, which wraps the low-level MCP Server API. The server exposes tools through request handlers for tool listing and tool calling.
graph TD
A[AI Assistant] -->|MCP Protocol| B[ActorsMcpServer]
B -->|Tool Requests| C[Tool Registry]
C -->|Actors Tools| D[Actor Discovery & Execution]
C -->|Docs Tools| E[Algolia Search API]
C -->|RAG Tools| F[RAG Web Browser]
D -->|API Calls| G[Apify API]
E -->|Search Queries| H[Algolia]
F -->|Browser Actions| I[Crawlee/Puppeteer]Source: res/mcp_resources_analysis.md:1-15
Available Tools
The server provides the following tool categories and individual tools:
Default Tools
When no query parameters are provided, the MCP server loads these tools by default:
| Tool Category | Description |
|---|---|
actors | Search and discover Actors on the Apify platform |
docs | Search Apify and Crawlee documentation |
apify/rag-web-browser | RAG-enabled web browsing for AI consumption |
Source: README.md:48-52
Tool Configuration
Tools can be configured via query parameters or command-line flags:
| Configuration Method | Example |
|---|---|
| Hosted server URL | https://mcp.apify.com?tools=actors,docs,apify/rag-web-browser |
| CLI flag | npx @apify/actors-mcp-server --tools actors,docs |
| Minimal (single Actor) | https://mcp.apify.com?tools=apify/my-actor |
Source: README.md:55-75
Unauthenticated Access
The hosted server allows access without an API token when only specific tools are requested:
| Allowed Tool | Description |
|---|---|
search-actors | Search Actors without authentication |
fetch-actor-details | Get Actor details without authentication |
search-apify-docs | Search Apify docs without authentication |
fetch-apify-docs | Get doc pages without authentication |
Source: README.md:33-35
Deployment Modes
The Apify MCP Server supports multiple deployment configurations:
HTTP Streamable Mode
Runs as an HTTP server compatible with the streamable HTTP transport:
export APIFY_TOKEN="your-apify-token"
export APIFY_META_ORIGIN=STANDBY
apify run -p
The server exposes endpoints at http://localhost:3001 by default.
Source: README.md:14-20
Standard Input/Output (stdio) Mode
Runs as a subprocess communicating via stdin/stdout, suitable for local development and debugging:
npx @modelcontextprotocol/inspector node ./dist/stdio.js
Source: README.md:22-30
Claude Desktop Integration
The server can be configured as a Claude Desktop MCP tool:
{
"mcpServers": {
"apify": {
"command": "node",
"args": ["${__dirname}/dist/stdio.js", "--tools", "${user_config.tools}"],
"env": {
"APIFY_TOKEN": "${user_config.apify_token}"
}
}
}
}
Source: manifest.json:35-45
User Configuration
The server accepts the following user configuration options:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
apify_token | string | Yes* | - | Apify API token from console.apify.com |
tools | string | No | actors,docs,apify/rag-web-browser | Comma-separated list of tool categories or specific Actors |
*Required unless using unauthenticated access with specific tools.
Source: manifest.json:47-65
Documentation Search Architecture
The docs tool integrates with Algolia to provide search across Apify and Crawlee documentation:
graph LR
A[Search Query] -->|Algolia API| B[Algolia Index]
B -->|Results| C[processAlgoliaResponse]
C -->|URLs with fragments| D[LLM Response]
E[Fetch Tool] -->|URL Request| F[Documentation Site]
F -->|HTML Content| EAlgolia Response Processing
The server processes Algolia responses differently based on the documentation source:
| Source | URL Fragments | Content Field |
|---|---|---|
| Apify docs | Supported | Always populated |
| Crawlee docs | Not supported | Not available |
Source: res/algolia.md:1-50
URL Fragment Handling
The server embeds page anchors directly in returned URLs for section-specific navigation:
// Returns ready-to-use URLs with anchors
{ url: "https://docs.apify.com/actors#build-actors", content: "..." }
This approach simplifies the LLM's ability to navigate to specific sections without complex URL reconstruction logic.
Source: res/algolia.md:55-70
MCP Resources
The server exposes MCP resources for specific use cases:
| Resource Type | URI Pattern | Description |
|---|---|---|
| Skyfire usage guide | file://readme.md | Enabled when skyfireMode is true |
| UI widgets | ui://widget/* | React widgets for OpenAI MCP Apps |
Source: res/mcp_resources_analysis.md:15-30
Development Setup
Prerequisites
| Requirement | Version |
|---|---|
| Node.js | >=20.0.0 |
| pnpm | 11+ |
Source: DEVELOPMENT.md:25-30
Installation
corepack enable # enables pnpm via corepack
pnpm install # installs root + src/web workspace packages
Source: DEVELOPMENT.md:30-35
Building
pnpm run build
Builds the TypeScript source to JavaScript in the dist/ directory.
Source: DEVELOPMENT.md:60-65
Testing
The project maintains multiple testing layers:
| Test Layer | Command | Coverage |
|---|---|---|
| Unit tests | pnpm run test:unit | Individual modules in isolation |
| Integration tests | pnpm run test:integration | Full server over all transports |
| LLM evals | CI only (apply validated label) | Multiple AI models via OpenRouter |
Source: DEVELOPMENT.md:8-20
Test Configuration
| Environment Variable | Purpose |
|---|---|
APIFY_TOKEN | Required for integration tests |
PHOENIX_* | Phoenix evaluation secrets |
OPENROUTER_* | OpenRouter API secrets |
Source: DEVELOPMENT.md:15-20
UI Widgets
For OpenAI MCP Apps integration, the server supports React-based UI widgets located in src/web/. Widgets are rendered based on tool output and require the server to run in UI mode:
https://mcp.apify.com?ui=true
Or set the environment variable UI_MODE=true.
Source: DEVELOPMENT.md:50-55
Widget Configuration
Widgets must use the Apify design system tokens:
| Property | Token Pattern | Example |
|---|---|---|
| Text color | theme.color.{cat}.{prop} | theme.color.neutral.text |
| Background | theme.color.{cat}.{prop} | theme.color.primary.background |
| Spacing | theme.space.space{N} | theme.space.space16 |
| Border radius | theme.radius.radius{N} | theme.radius.radius8 |
Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md:1-20
Contribution Guidelines
The project follows conventional commits for versioning and changelog generation:
Branch Naming
feat/add-dataset-tool
fix/connection-timeout
chore/update-dependencies
Commit Format
<type>(<scope>): <description>
Types: feat, fix, refactor, chore, docs, test, etc.
Breaking changes are indicated with ! after the scope.
Source: CONTRIBUTING.md:1-30
Compatibility
| Platform | Claude Desktop Version | Node.js |
|---|---|---|
| macOS (darwin) | >=0.2.16 | >=20.0.0 |
| Windows (win32) | >=0.2.16 | >=20.0.0 |
| Linux | >=0.2.16 | >=20.0.0 |
Source: manifest.json:20-28
Repository Structure
The codebase is split across two repositories:
| Repository | Purpose |
|---|---|
apify-mcp-server (this repo) | Core MCP logic and public code |
apify-mcp-server-internal | Hosted server deployment |
Changes must be synchronized between both repositories. Canary releases are created by adding the beta tag to a PR branch.
Source: README.md:38-42
Source: https://github.com/apify/apify-mcp-server / Human Manual
Core Architecture
Related topics: Project Overview, Transport Layer
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Project Overview, Transport Layer
Core Architecture
The Apify MCP Server implements a Model Context Protocol (MCP) server that exposes Apify platform capabilities as tools for Large Language Models (LLMs). The architecture uses the low-level MCP Server SDK with a custom tool management system, supporting both stdio and HTTP Streamable transports.
System Overview
The server acts as a bridge between LLMs and the Apify platform, enabling AI assistants to:
- Search and discover Actors on the Apify platform
- Execute Actors programmatically
- Access Apify documentation
- Manage Actor runs and retrieve results
- Proxy external MCP servers through Actorized deployments
Source: src/mcp/server.ts:1-50
graph TD
subgraph "Transport Layer"
STDIO[stdio.ts<br/>Standard I/O]
HTTP[dev_server.ts<br/>HTTP Streamable]
end
subgraph "Core Server"
AMS[ActorsMcpServer]
TM[Tool Manager<br/>Map<string, ToolEntry>]
TS[TaskStore]
AS[ActorStore]
end
subgraph "Tool Registry"
HT[Helper Tools]
AT[Actor Tools]
AMT[Actor-MCP Proxy Tools]
end
subgraph "External Services"
APIFY[Apify API]
APIClient[ApifyClient]
end
STDIO --> AMS
HTTP --> AMS
AMS --> TM
AMS --> TS
AMS --> AS
TM --> HT
TM --> AT
TM --> AMT
AMS --> APIClient
APIClient --> APIFYHigh-Level Component Architecture
ActorsMcpServer (Central Coordinator)
The ActorsMcpServer class is the core component that orchestrates all MCP functionality:
| Property | Type | Purpose |
|---|---|---|
server | Server | Low-level MCP SDK server instance |
tools | Map<string, ToolEntry> | Tool registry for all registered tools |
taskStore | TaskStore | Tracks running and completed tasks |
actorStore | ActorStore | Caches Actor metadata and input schemas |
serverMode | ServerMode | Resolved server mode (default/apps) |
options | ActorsMcpServerOptions | Server configuration options |
Source: src/mcp/server.ts:280-320
Tool Entry Types
The server manages three distinct tool types defined in the discriminated union:
type ToolEntry = HelperTool | ActorTool | ActorMcpTool;
| Tool Type | Type Discriminator | Purpose | Source |
|---|---|---|---|
HelperTool | type: 'internal' | Built-in server tools (search, docs) | src/types.ts:135-145 |
ActorTool | type: 'actor' | Dynamic Actor-based tools | src/types.ts:147-153 |
ActorMcpTool | type: 'actor-mcp' | External MCP server proxy via Actor | src/types.ts:155-162 |
Source: src/types.ts:130-175
Transport Architecture
The server supports two transport mechanisms, selected based on deployment context:
Stdio Transport
Used for local CLI clients and the MCP Inspector. Communication occurs through standard input/output streams.
Source: src/index.ts
HTTP Streamable Transport
Used for hosted deployments at mcp.apify.com. Enables remote client connections with streaming response support.
Source: src/mcp/server.ts
| Transport | Use Case | Entry Point |
|---|---|---|
| stdio | Local CLI, MCP Inspector | stdio.ts |
| HTTP Streamable | Hosted server, remote clients | dev_server.ts |
Request Handler Architecture
The server uses low-level MCP SDK request handlers for all protocol operations:
Handler Registration Pattern
server.setRequestHandler(ListToolsRequestSchema, async () => { ... });
server.setRequestHandler(CallToolRequestSchema, async (request) => { ... });
server.setRequestHandler(ListResourcesRequestSchema, async () => { ... });
server.setRequestHandler(ReadResourceRequestSchema, async (request) => { ... });
Source: src/mcp/server.ts:200-250
Central Tool Dispatcher
All tool calls flow through a central dispatcher that routes based on tool type:
graph LR
A[CallTool Request] --> B{Extract toolName}
B --> C{Lookup in tools Map}
C -->|HelperTool| D[Execute call function]
C -->|ActorTool| E[Call Apify API]
C -->|ActorMcpTool| F[Proxy to Actor-MCP]
D --> G[Return result]
E --> G
F --> GSource: src/mcp/server.ts:400-500
Tool Lifecycle Management
Dynamic Tool Loading
Actors are loaded as tools through the loadActorsAsTools() method:
- Fetch Actor list from Apify API or configured Actor IDs
- Transform Actor metadata into
ActorToolentries - Upsert tools into the registry Map
- Send
notifications/tools/list_changedto connected clients
Source: src/mcp/actors.ts
Tool Registration Flow
sequenceDiagram
participant Client
participant Server as ActorsMcpServer
participant API as Apify API
participant Store as tools Map
Client->>Server: initialize (capabilities)
Server->>Server: resolveServerMode()
Server->>API: fetchActors() / getActorDetails()
API-->>Server: Actor metadata
Server->>Store: upsertTools()
Server-->>Client: tools/list response
Client->>Server: notifications/tools/list_changedServer Mode System
The server supports automatic mode detection based on client capabilities:
| Mode | Trigger | Behavior |
|---|---|---|
default | Non-MCP Apps clients | Standard tool responses |
apps | MCP Apps clients (uiMode === 'openai') | Enhanced responses with widget metadata |
Source: src/mcp/server.ts:300-340
Mode Auto-Detection
The serverMode property transitions from 'auto' to either 'default' or 'apps' during the initialize request handler:
// Preliminary value at construction
public serverMode: ServerMode;
// Finalized inside initialize handler
private serverModeResolved: boolean;
Source: src/mcp/server.ts:310-325
Resource System
The server implements MCP resources for UI widgets and documentation:
Resource Types
| Resource Type | URI Pattern | Condition | Source |
|---|---|---|---|
| Skyfire Guide | file://readme.md | skyfireMode === true | src/mcp/resources/resource_service.ts |
| UI Widgets | ui://widget/*.html | uiMode === 'openai' | src/mcp/resources/resource_service.ts |
Resource Handler Implementation
return {
listResources,
readResource,
listResourceTemplates: async () => ({ resourceTemplates: [] }),
};
Source: src/mcp/resources/resource_service.ts
Actor-MCP Proxy Architecture
External MCP servers can be proxied through the Apify platform using the ActorMcpTool type:
graph LR
subgraph "This Server"
A[ActorMcpTool] --> B[proxy.ts]
end
subgraph "Apify Platform"
B -->|callActor| C[Actor Container]
end
subgraph "Remote MCP Server"
C -->|HTTP| D[External Server]
D -->|MCP Response| C
end
C -->|Actor Result| BSource: src/mcp/proxy.ts
Task Management
TaskStore
The TaskStore class manages long-running task execution:
| Method | Purpose |
|---|---|
createTask() | Initialize a new task |
updateTask() | Update task status/progress |
getTask() | Retrieve task details |
listTasks() | List all tasks |
Source: src/mcp/server.ts
Progress Tracking
Long-running operations support progress notifications via createProgressTracker:
const tracker = createProgressTracker(taskId, totalSteps);
tracker.report(progress, total, message);
Source: src/mcp/server.ts
Client Configuration
ApifyClient Integration
The server uses the Apify JavaScript client for API communication:
const apifyClient = new ApifyClient({
token: apifyToken,
});
Source: src/mcp/client.ts
Token Propagation
| Location | Mechanism |
|---|---|
| HTTP Headers | Authorization: Bearer <token> |
| MCP Meta | _meta.apifyToken in tool call |
Source: src/mcp/server.ts:630-650
Configuration Options
The ActorsMcpServerOptions interface defines server configuration:
| Option | Type | Default | Purpose | |
|---|---|---|---|---|
apifyToken | string | Required | Apify API authentication | |
tools | `string \ | string[]` | default | Tool categories/Actors to load |
serverMode | ServerModeOption | 'auto' | Server mode override | |
skyfireMode | boolean | false | Enable Skyfire-specific resources | |
uiMode | UiMode | 'default' | UI response format |
Source: src/mcp/server.ts:200-280
Capability Advertisement
The server advertises the following MCP capabilities during initialization:
capabilities: {
logging: {},
prompts: { listChanged: false },
resources: options.skyfireMode ? { listChanged: false } : undefined,
tools: { listChanged: true },
}
Source: src/mcp/server.ts:210-218
Entry Points
| Entry Point | Transport | File |
|---|---|---|
dist/stdio.js | stdio | src/stdio.ts |
dist/index.js (HTTP) | Streamable HTTP | src/dev_server.ts |
Source: README.md
Source: https://github.com/apify/apify-mcp-server / Human Manual
Transport Layer
Related topics: Core Architecture, Development Setup
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Core Architecture, Development Setup
Transport Layer
The Apify MCP Server implements a dual-transport architecture that supports both local command-line clients and remote HTTP clients. This design allows the same core server logic to operate in different deployment scenarios while maintaining a consistent MCP protocol implementation.
Overview
The transport layer handles the communication between MCP clients and the ActorsMcpServer core. The server supports two primary transport mechanisms:
| Transport Mode | Entry Point | Use Case | Protocol |
|---|---|---|---|
| Stdio | stdio.ts | Local CLI clients, Claude Code, MCP Inspector | Standard I/O via process stdin/stdout |
| HTTP Streamable | dev_server.ts | Remote clients, hosted deployment at mcp.apify.com | Streamable HTTP with Server-Sent Events |
Source: src/index.ts · README.md
Architecture Diagram
graph TB
subgraph "Client Layer"
CLI[CLI Client]
HTTP_CLIENT[HTTP Client]
MCP_INSPECTOR[MCP Inspector]
end
subgraph "Transport Layer"
STDIO[Stdio Transport<br/>stdio.ts]
HTTP[HTTP Transport<br/>dev_server.ts]
WEBSOCKET[WebSocket Support<br/>mcp/server.ts]
end
subgraph "Core Server"
SERVER[ActorsMcpServer<br/>server.ts]
TOOLS[Tool Handlers]
RESOURCES[Resource Handlers]
TASKS[Task Store]
end
CLI --> STDIO
HTTP_CLIENT --> HTTP
MCP_INSPECTOR -->|stdio mode| STDIO
MCP_INSPECTOR -->|http mode| HTTP
STDIO --> SERVER
HTTP --> SERVER
WEBSOCKET --> SERVER
SERVER --> TOOLS
SERVER --> RESOURCES
SERVER --> TASKSStdio Transport
The Standard I/O transport is designed for local development and CLI-based clients. It communicates via process stdin and stdout using JSON-RPC messages.
Entry Point
The stdio transport is initialized in src/stdio.ts:
import { createStdioServer } from '@modelcontextprotocol/sdk/server/stdio';
// Server initialization with transport
const server = new ActorsMcpServer(options);
const transport = createStdioServer();
await server.connect(transport);
Source: src/stdio.ts
Connection Flow
sequenceDiagram
participant Client as MCP Client
participant Stdio as Stdio Transport
participant Server as ActorsMcpServer
Note over Client,Stdio: Process startup
Stdio->>Server: Initialize connection
Server->>Stdio: MCP handshake (initialize)
Client->>Stdio: Initialize response
Stdio->>Server: Handshake complete
loop Message Loop
Client->>Stdio: JSON-RPC Request
Stdio->>Server: Forward request
Server->>Server: Process tool/resource/task
Server->>Stdio: JSON-RPC Response
Stdio->>Client: Response output
end
Note over Client,Stdio: Process termination
Client->>Stdio: SIGINT
Stdio->>Server: CleanupConfiguration
The stdio transport inherits server configuration from environment variables and constructor options:
| Parameter | Source | Description |
|---|---|---|
APIFY_TOKEN | Environment | Apify API authentication token |
serverMode | Constructor | "default", "apps", or "auto" |
skyfireMode | Constructor | Enables Skyfire usage guide resource |
Source: src/stdio.ts · src/mcp/server.ts
HTTP Streamable Transport
The HTTP transport enables remote client connections using the MCP Streamable HTTP specification. This is used for the hosted deployment at mcp.apify.com.
Server Implementation
The HTTP server is implemented using Express in src/dev_server.ts:
import express from 'express';
import { createServer } from 'http';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/http';
const app = express();
const server = createServer(app);
// Streamable HTTP transport with session management
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => crypto.randomUUID(),
onSession: initializeSession,
});
Source: src/dev_server.ts
HTTP Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/mcp | POST | JSON-RPC requests (tools, resources, tasks) |
/mcp | GET | Server-Sent Events for notifications |
/health | GET | Health check endpoint |
Source: src/dev_server.ts
Session Management
graph LR
A[Client] -->|1. POST /mcp| B{Has Session ID?}
B -->|No| C[Create New Session]
B -->|Yes| D[Find Existing Session]
C --> E[Initialize MCP]
D --> E
E --> F[Store in Map]
F --> G[Process Request]
G --> H[Return Response]The transport uses UUID-based session identifiers to maintain separate server instances per client connection.
Source: src/dev_server.ts
Server Card
The ServerCard component provides metadata and capability information about the MCP server for discovery and documentation purposes.
ServerCard Structure
export interface ServerCard {
name: string;
version: string;
description: string;
homepageUrl: string;
repositoryUrl: string;
documentationUrl: string;
capabilities: ServerCapabilities;
auth?: AuthConfig;
configSchema?: Record<string, unknown>;
}
Source: src/server_card.ts
Capability Declaration
The server advertises its capabilities during the MCP initialize handshake:
const capabilities = {
tools: { listChanged: true },
tasks: { list: true, cancel: true, requests: { tools: { call: true } } },
resources: {},
prompts: {},
logging: {},
};
Source: src/mcp/server.ts:146
Internal Exports
The index_internals.ts module exposes internal components for testing and advanced usage scenarios:
| Export | Type | Purpose |
|---|---|---|
ActorsMcpServer | Class | Core MCP server implementation |
createResourceService | Function | Resource service factory |
ToolEntry | Type | Union type for all tool variants |
ServerMode | Enum | Server operating mode |
Source: src/index_internals.ts
Server Modes
The transport layer operates differently based on the selected server mode:
| Mode | Description | Transport Impact |
|---|---|---|
default | Standard Apify tools | All tools available |
apps | OpenAI UI widgets mode | Additional UI widget resources |
auto | Capability-based detection | Mode resolved during initialize |
Source: src/mcp/server.ts
Request Handler Wiring
All transports delegate to the same core request handlers registered in ActorsMcpServer:
graph TD
T1[Stdio Transport] --> S[ActorsMcpServer]
T2[HTTP Transport] --> S
T3[WebSocket Transport] --> S
S --> H1[ListToolsRequestHandler]
S --> H2[CallToolRequestHandler]
S --> H3[ListResourcesRequestHandler]
S --> H4[ReadResourceRequestHandler]
S --> H5[ListTasksRequestHandler]
S --> H6[GetTaskRequestHandler]
H1 --> T[Tool Execution]
H2 --> TSource: src/mcp/server.ts · src/dev_server.ts
Integration with MCP SDK
The transport layer uses the official @modelcontextprotocol/sdk package for protocol implementation:
| SDK Component | Usage |
|---|---|
Server | Low-level MCP protocol server |
StreamableHTTPServerTransport | HTTP transport implementation |
createStdioServer | Stdio transport factory |
RequestHandlerExtra | Request context wrapper |
Source: src/stdio.ts · src/dev_server.ts
Testing Transport Layers
The project includes transport-specific integration tests:
| Test File | Transport | Coverage |
|---|---|---|
tests/integration/suite.ts | All transports | Main test suite |
stdio.ts (in integration) | Stdio | Stdin/stdout messaging |
http.ts (in integration) | HTTP Streamable | REST endpoints |
sse.ts (in integration) | Server-Sent Events | Notification streaming |
Source: DEVELOPMENT.md · tests/integration/
Summary
The Apify MCP Server implements a transport-agnostic architecture where:
- Stdio Transport handles local CLI clients through stdin/stdout JSON-RPC messaging
- HTTP Transport enables remote access via Streamable HTTP with session management
- Core Server (
ActorsMcpServer) remains independent of transport implementation - Capability negotiation occurs during MCP initialize handshake
- All transports delegate to the same request handlers for tools, resources, and tasks
This separation allows the server to serve both local development needs and production hosted deployments while maintaining a single, testable codebase.
Source: https://github.com/apify/apify-mcp-server / Human Manual
Tool System
Related topics: Actor Tools, Storage Access Tools
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Actor Tools, Storage Access Tools
Tool System
The Tool System is the core component of the Apify MCP Server, enabling AI assistants to interact with Apify's platform capabilities through a standardized Model Context Protocol (MCP) interface. The system provides dynamic tool loading, registration, execution, and removal capabilities for three distinct tool types: internal helper tools, Actor tools, and Actor-MCP proxy tools.
Architecture Overview
The Tool System follows a centralized registration model where ActorsMcpServer manages all tool lifecycle operations. Tools are stored in a Map<string, ToolEntry> and exposed to MCP clients via request handlers. Source: src/mcp/server.ts
graph TD
subgraph "MCP Client"
A[Claude / VS Code]
end
subgraph "ActorsMcpServer"
B[Server Instance]
C[Tool Registry Map]
D[setupToolHandlers]
E[Central Dispatcher]
end
subgraph "Tool Types"
F[HelperTool]
G[ActorTool]
H[ActorMcpTool]
end
A -->|tools/call| B
B --> D
D -->|route by type| E
E -->|internal| F
E -->|actor| G
E -->|actor-mcp| H
C -.->|stores| F
C -.->|stores| G
C -.->|stores| HTool Type Definitions
The system defines three tool types through discriminated unions in src/types.ts. Source: src/types.ts:135-174
| Tool Type | Description | Execution Mode |
|---|---|---|
HelperTool | Internal server tools with direct callback execution | Synchronous |
ActorTool | Apify Actor-based tools for scalable execution | Asynchronous via Actor API |
ActorMcpTool | External MCP server tools proxied through Apify | Delegated to origin server |
HelperTool
Internal tools that execute directly within the server process:
type HelperTool = ToolBase & {
type: 'internal';
call: (toolArgs: InternalToolArgs) => Promise<object>;
};
Examples include search-actors, fetch-actor-details, search-apify-docs, and fetch-apify-docs. Source: README.md
ActorTool
Tools that invoke Apify Actors on the platform:
type ActorTool = ToolBase & {
type: 'actor';
actorFullName: string;
memoryMbytes?: number;
};
These tools launch Actors with configurable memory allocation for scalable cloud execution.
ActorMcpTool
Proxied tools from external MCP servers, enabling the Apify platform to bridge between MCP implementations:
type ActorMcpTool = ToolBase & {
type: 'actor-mcp';
originToolName: string;
actorId: string;
serverId: string;
serverUrl: string;
};
Tool Registration Flow
Tools are loaded and registered through a multi-stage process:
sequenceDiagram
participant Client
participant Server as ActorsMcpServer
participant Loader as tools_loader.ts
participant Registry as Tool Registry
Client->>Server: loadActorsAsTools()
Server->>Loader: loadToolsByCategory(tools)
Loader-->>Server: Tool definitions
Server->>Server: upsertTools(toolDefs)
Server->>Registry: Map.set(name, entry)
Server->>Client: sendToolListChanged()Dynamic Loading
The loadActorsAsTools() method handles dynamic tool loading based on configuration. When called, it:
- Resolves tool categories or specific Actor names from configuration
- Loads tool definitions from
src/utils/tools_loader.ts - Calls
upsertTools()to register each tool - Broadcasts
tools/list_changednotification to connected clients Source: res/mcp_server_refactor_analysis.md
Tool Removal
The removeToolsByName() method removes tools from the registry and notifies clients:
removeToolsByName(toolNames: string[]): void
This operation:
- Deletes tools from the internal
Map - Calls
sendToolListChanged()to update clients - Validates that tools exist before removal
Central Dispatcher Pattern
The current implementation uses a central dispatcher in setupToolHandlers() to route tool execution based on tool.type. Source: src/mcp/server.ts
graph LR
A[Request] --> B{tool.type}
B -->|internal| C[Execute callback]
B -->|actor| D[Create Actor client]
B -->|actor-mcp| E[Connect to MCP proxy]
C --> F[Return result]
D --> G[Run Actor]
G --> F
E --> H[Forward request]
H --> FTool Input Validation
Tool arguments are validated using JSON Schema with AJV before execution:
const validate = compileSchema(inputSchema);
const valid = validate(toolArgs);
The compileSchema utility from src/utils/ajv.js provides schema compilation with custom error messages. Source: src/tools/common/search_apify_docs.ts:12
Actor-MCP Proxy Integration
The proxy subsystem in src/mcp/proxy.ts enables tools from external MCP servers to be exposed through the Apify MCP interface. Source: src/mcp/proxy.ts
When an ActorMcpTool is called:
- The server connects to the origin MCP server
- The request is forwarded with original arguments
- Responses are transformed and returned to the client
- Progress notifications are propagated
Default Tools Configuration
The server loads default tools when no specific configuration is provided:
| Tool | Category | Description |
|---|---|---|
actors | Category | Actor discovery and invocation tools |
docs | Category | Apify and Crawlee documentation search |
apify/rag-web-browser | Specific | RAG-enabled web browser for data extraction |
Source: README.md
Unauthenticated Access
Certain tools are explicitly enabled for unauthenticated access:
search-actorsfetch-actor-detailssearch-apify-docsfetch-apify-docs
Access is granted when the tools query parameter includes only these tools. Source: README.md
Tool Registration Factory (Target Architecture)
An upcoming refactor will replace the central dispatcher with callback-per-tool registration patterns:
// Internal tools
registerInternalTool(tool: InternalToolDefinition): RegisteredTool
// Actor tools
registerActorTool(actorDef: ActorDefinition): RegisteredTool
// Actor-MCP proxy tools
registerActorMcpTool(mcpTool: ExternalTool, serverUrl: string, actorId: string): RegisteredTool
Each tool will be self-contained with its own callback, eliminating the need for type-checking in the dispatcher. Source: res/mcp_server_refactor_analysis.md
CLI Configuration
Tools can be configured via command-line flags:
# Load default tools
npx @apify/actors-mcp-server --tools actors,docs,apify/rag-web-browser
# Minimal single-Actor configuration
npx @apify/actors-mcp-server --tools apify/my-actor
Source: README.md
Testing Strategy
The tool system is tested at multiple levels:
| Test Level | Coverage |
|---|---|
| Unit tests | Individual tool execution, schema validation, registration patterns |
| Integration tests | Full tool lifecycle, dynamic loading/removal, notifications |
| Manual testing | MCP client verification, protocol compliance |
Source: DEVELOPMENT.md
Key Integration Tests
Integration tests in tests/integration/suite.ts verify:
tools/listreturns correct tools with proper metadatatools/callexecutes each tool type correctlytools/callreturns proper validation errorsnotifications/tools/list_changedare sent on changesnotifications/progresswork for long-running operations
Source: res/integration_test_coverage_audit.md
Future Refactoring
The Tool System is scheduled for migration from the low-level Server API to the high-level McpServer API:
| Change | Impact |
|---|---|
Replace Server with McpServer | Automatic tool management |
| Remove central dispatcher | ~300 lines removed |
| Convert JSON Schema to Zod | Native schema conversion via Zod v4 |
| Callback-per-tool pattern | Self-contained execution logic |
This refactor will reduce complexity while preserving all existing functionality. Source: res/mcp_server_refactor_analysis.md
Source: https://github.com/apify/apify-mcp-server / Human Manual
Actor Tools
Related topics: Tool System, Storage Access Tools
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Tool System, Storage Access Tools
Actor Tools
Actor Tools are the primary mechanism by which the Apify MCP Server enables AI assistants and MCP clients to execute Apify Actors. These tools bridge the gap between the Model Context Protocol (MCP) and Apify's Actor platform, allowing LLMs to programmatically invoke cloud programs, monitor their execution, and retrieve results.
Overview
Actor Tools serve as wrappers around Apify Actors, exposing them as callable MCP tools with proper input schema validation, result formatting, and execution tracking. The system supports three distinct tool types within the MCP server architecture:
| Tool Type | Description | Type Discriminator |
|---|---|---|
| Internal Tools | Built-in helper tools (e.g., search-actors, fetch-actor-details) | 'internal' |
| Actor Tools | Wrappers around Apify Actors | 'actor' |
| Actor-MCP Tools | Proxies to external MCP servers hosted as Actors | 'actor-mcp' |
Source: src/types.ts
Architecture
Tool Classification Hierarchy
graph TD
A[Tools in MCP Server] --> B[Internal Tools]
A --> C[Actor Tools]
A --> D[Actor-MCP Tools]
C --> C1[call-actor]
C --> C2[call-actor-widget]
C --> C3[Dynamic Actor Tools]
D --> D1[Proxy MCP Tools]Actor Tool Execution Flow
sequenceDiagram
participant Client as MCP Client
participant Server as ActorsMcpServer
participant Factory as ActorToolsFactory
participant Executor as ActorExecutor
participant Apify as Apify Platform
Client->>Server: Tool call request
Server->>Factory: Create/retrieve Actor tool
Factory->>Executor: Execute with input
Executor->>Apify: Start Actor run
Apify-->>Executor: Run metadata
Executor->>Apify: Wait for completion
Apify-->>Executor: Run results
Executor-->>Server: Formatted response
Server-->>Client: MCP responseSource: src/tools/actor_executor.ts
Core Components
ActorExecutor
The ActorExecutor class is responsible for the actual execution of Apify Actors. It handles:
- Actor invocation with input validation
- Run lifecycle management (start, wait, abort)
- Result retrieval from datasets or key-value stores
- Error handling and response formatting
Key responsibilities:
| Responsibility | Description |
|---|---|
callActor() | Initiates an Actor run with provided input |
getActorOutput() | Retrieves output from completed runs |
abortActorRun() | Terminates a running Actor |
| Result formatting | Converts raw results to MCP-compatible responses |
Source: src/tools/actor_executor.ts
ActorToolsFactory
The ActorToolsFactory creates Actor tool definitions based on Actor metadata. It transforms Actor input schemas into MCP-compatible tool definitions with proper validation.
Factory outputs include:
| Output | Purpose |
|---|---|
name | Tool identifier (e.g., apify/web-scraper) |
description | Human-readable tool description |
inputSchema | JSON Schema for tool arguments |
ajvValidate | Compiled AJV validator function |
annotations | MCP tool hints (readOnlyHint, openWorldHint, etc.) |
Source: src/tools/core/actor_tools_factory.ts
Call Actor Common Module
The call_actor_common.ts module provides shared execution logic used by all call-actor variants. It implements the pre-execution phase:
graph LR
A[Input Validation] --> B[Actor Resolution]
B --> C[MCP Tool Name Parsing]
C --> D[Tool Call Execution]
D --> E[Response Formatting]Pre-execution steps:
- Input parsing: Validates and extracts actor name, input, and call options
- Actor resolution: Resolves actor name to stable ID via Apify API
- MCP tool routing: Handles routing for Actor-MCP servers
- Payment validation: Checks if Actor requires payment before execution
Source: src/tools/core/call_actor_common.ts
Call Actor Implementations
The MCP server provides multiple implementations of the call-actor functionality, optimized for different client environments.
Default Call Actor
The default implementation (src/tools/default/call_actor.ts) provides standard execution with result previews. It is used by most MCP clients.
Characteristics:
| Property | Value |
|---|---|
| Mode | Default server mode |
| Output | Limited preview (first 5 items) |
| Widget support | None |
| Use case | General-purpose Actor invocation |
Call Actor Widget (Apps Mode)
The widget variant (src/tools/apps/call_actor.ts) renders interactive MCP App widgets in the response, providing enhanced UX for clients that support it.
Characteristics:
| Property | Value |
|---|---|
| Mode | Apps server mode (ui=true) |
| Output | Full results with widget rendering |
| Widget support | Actor Run widgets, progress tracking |
| Use case | MCP Apps-enabled clients |
Widget annotations applied:
{
title: 'Call Actor (widget)',
readOnlyHint: false,
destructiveHint: true,
idempotentHint: false,
openWorldHint: true,
}
Source: src/tools/apps/call_actor_widget.ts
Execution Modes Comparison
| Feature | Default | Widget (Apps) |
|---|---|---|
| Server mode | default | apps |
| Output preview | Limited | Full |
| Progress notifications | Via logs | Via widget |
| Run status tracking | Manual | Automatic |
| UI rendering | Text only | Interactive widgets |
Actor Resolution
The resolution process maps human-readable actor names to stable actor IDs.
graph TD
A[Input: Actor Name] --> B{User has rented Actor?}
B -->|Yes| C[Check rentedActorsIds]
B -->|No| D[Search Apify Store]
C --> E[Return rented Actor ID]
D --> F[Match by name/version]
F --> G[Return store Actor ID]
E --> H[Resolved Actor]
G --> HSource: src/utils/actor.ts
Resolution Strategy
- User rented Actors: Check if the actor name matches any Actor rented by the user
- Apify Store: Search public Actors for matching name
- Version matching: Support both explicit (
actorName@version) and implicit versioning
Tool Annotations
Actor tools include MCP-compliant annotations to help clients and LLMs understand tool behavior:
| Annotation | Description | Applied Value |
|---|---|---|
title | Short display name | Actor name (e.g., "Call Actor") |
readOnlyHint | Indicates read-only operation | false for call-actor |
openWorldHint | Indicates external network access | true (executes Actors) |
destructiveHint | Indicates destructive operation | true for call-actor |
idempotentHint | Indicates idempotent operation | false for call-actor |
Source: src/tools/apps/call_actor_widget.ts
Input Schema Handling
Actor tools dynamically generate input schemas from Actor definitions:
graph TD
A[Actor Input Schema] --> B[Pruned Definition]
B --> C[JSON Schema]
C --> D[AJV Validator]
D --> E[MCP Tool Schema]Schema Pruning
The schema is pruned to include only fields the LLM needs to provide:
| Field Type | Included | Reason |
|---|---|---|
| Required fields | Yes | Necessary for execution |
| Optional fields with defaults | No | Server applies defaults |
| Hidden fields | No | Internal use only |
Source: src/utils/actor.ts
Error Handling
Actor tools implement robust error handling for various failure scenarios:
| Error Type | Handling | Response |
|---|---|---|
| Invalid input schema | AJV validation failure | Formatted error message |
| Actor not found | Resolution returns error | Early response with error |
| Payment required | Payment validation fails | Error with payment instructions |
| Run timeout | Wait exceeds timeout | Partial results with warning |
| Actor execution error | Run fails | Error details in response |
Source: src/tools/core/call_actor_common.ts
Dynamic Tool Loading
The system supports dynamic loading of Actors as tools:
graph TD
A[Tool Configuration] --> B[Load Actors]
B --> C[Fetch Actor Definitions]
C --> D[Register Tools]
D --> E[Notify Tools Changed]
E --> F[MCP Client Updated]Loading methods:
| Method | Description |
|---|---|
loadActorsAsTools() | Load by actor IDs |
loadToolsByName() | Load by tool names |
loadToolsFromUrl() | Load from MCP server URL |
Source: src/mcp/server.ts
Configuration
Actor tools respect the server's tools configuration parameter:
?tools=actors,docs,apify/rag-web-browser
When the actors category is included, all Actor-related tools become available, including the base call-actor tool and any dynamically loaded Actor tools.
See Also
- Internal Tools - Built-in helper tools
- Actor-MCP Proxy - External MCP server integration
- Tool Annotations - MCP tool metadata
- Server Modes - Default vs Apps modes
Source: https://github.com/apify/apify-mcp-server / Human Manual
Storage Access Tools
Related topics: Actor Tools
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Actor Tools
Storage Access Tools
Storage Access Tools provide MCP (Model Context Protocol) clients with programmatic access to Apify's cloud storage infrastructure. These tools enable AI assistants and automated workflows to read datasets, key-value stores, and Actor run logs without requiring direct API integration.
Overview
The Apify MCP Server exposes storage resources through a collection of specialized tools that wrap the Apify API's storage endpoints. These tools follow the repository's established patterns:
- Input validation via Zod schemas
- Consistent response formatting via
buildMCPResponse() - Payment-required guards for premium operations
- Comprehensive error handling with user-friendly messages
Source: src/tools/common/get_dataset.ts:1-1
Architecture
Tool Classification
Storage Access Tools fall into three categories based on the underlying Apify storage type:
graph TD
A[Storage Access Tools] --> B[Dataset Tools]
A --> C[Key-Value Store Tools]
A --> D[Run Log Tools]
B --> B1[get-dataset]
B --> B2[get-dataset-items]
B --> B3[get-dataset-schema]
C --> C1[get-key-value-store]
C --> C2[get-key-value-store-record]
D --> D1[get-actor-run-log]
D --> D2[run-collection]Data Flow
sequenceDiagram
participant Client as MCP Client
participant Server as ActorsMcpServer
participant Tool as Storage Tool
participant Apify as Apify API
Client->>Server: Tool Request
Server->>Tool: call(toolArgs)
Tool->>Tool: Validate input with Zod
Tool->>Apify: API Request
Apify-->>Tool: Raw Storage Data
Tool->>Tool: Transform & Format
Tool-->>Server: MCP Response
Server-->>Client: Formatted ResultTool Entry Structure
Each storage tool implements the ToolEntry interface with type: 'internal':
export const exampleTool: ToolEntry = Object.freeze({
type: 'internal',
name: HelperTools.DATASET_GET_ITEMS,
description: 'Tool description...',
inputSchema: z.toJSONSchema(inputSchema),
outputSchema: datasetItemsOutputSchema,
ajvValidate: compileSchema(z.toJSONSchema(inputSchema)),
annotations: { /* tool annotations */ },
call: async (toolArgs: InternalToolArgs) => { /* implementation */ },
});
Source: https://github.com/apify/apify-mcp-server / Human Manual
Agentic Payments System
The Agentic Payments System is a payment abstraction layer within the Apify MCP Server that enables AI agents and MCP clients to pay for Actor executions using alternative payment methods ...
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
The Agentic Payments System is a payment abstraction layer within the Apify MCP Server that enables AI agents and MCP clients to pay for Actor executions using alternative payment methods beyond traditional API tokens. The system supports multiple payment schemes including x402 (blockchain-based payments via HTTP 402) and Skyfire (agentic payment tokens), allowing autonomous agents to pay for compute without requiring pre-configured API credentials.
Architecture Overview
The payment system follows a provider-based architecture where a unified PaymentProvider interface abstracts the specifics of each payment scheme. This design allows the MCP server to remain agnostic to payment implementation details while providing a consistent interface for payment validation, credential extraction, and header forwarding.
graph TD
subgraph "MCP Client"
A[Tool Call with Payment]
end
subgraph "Apify MCP Server"
B[Payment Provider Resolution]
C[validatePayment]
D[removePaymentFields]
E[getPaymentHeaders]
F[decorateToolSchema]
end
subgraph "Payment Providers"
G[x402 Provider]
H[Skyfire Provider]
end
subgraph "Apify API"
I[Actor Execution]
J[Payment Verification]
end
A --> B
B --> G
B --> H
C --> D
D --> E
E --> I
F -.->|Decorates| A
I --> JSource: src/payments/types.ts:45-87
Core Types and Interfaces
PaymentProviderId
The system defines two supported payment provider identifiers:
export type PaymentProviderId = 'skyfire' | 'x402';
| Provider | Description |
|---|---|
skyfire | Skyfire agentic payments using PAY tokens in tool arguments |
x402 | x402 protocol using HTTP 402 with PAYMENT-SIGNATURE header |
Source: src/payments/types.ts:14-19
PaymentProvider Interface
Every payment provider must implement the PaymentProvider interface:
| Method | Return Type | Purpose | |
|---|---|---|---|
id | PaymentProviderId (readonly) | Provider identifier | |
decorateToolSchema(tool) | ToolEntry | Add payment fields to tool definitions | |
validatePayment(args, meta, headers) | `string \ | null` | Validate credentials before execution |
getPaymentHeaders(args, meta, headers) | PaymentHeaders | Extract headers for Apify API | |
removePaymentFields(args) | Record<string, unknown> | Clean args before Actor input | |
allowsUnauthenticated | boolean | Whether token-less access is permitted | |
getPaymentRequiredData?() | unknown | Optional x402 structured payment data | |
getUsageGuide?() | `string \ | null` | Optional payment usage documentation |
Source: src/payments/types.ts:45-87
Supporting Types
// Headers forwarded to Apify API requests
export type PaymentHeaders = Record<string, string>;
// MCP request _meta field for payment schemes like x402
export type PaymentMeta = Record<string, unknown> | undefined;
// HTTP headers from MCP transport layer
export type RequestHeaders = Record<string, string | string[] | undefined> | undefined;
Source: src/payments/types.ts:22-35
Payment-Aware Tool Call Context
The PrepareToolCallContextResult type centralizes payment processing for tool calls:
export type PrepareToolCallContextResult = {
paymentRequiredResult?: ReturnType<typeof buildPaymentRequiredResponse>;
toolArgsWithoutPayment: Record<string, unknown>;
toolArgsRedacted: unknown;
apifyClient: ApifyClient;
};
| Field | Type | Purpose | |
|---|---|---|---|
paymentRequiredResult | `MCPResponse \ | undefined` | Structured 402 error response if payment fails |
toolArgsWithoutPayment | Record<string, unknown> | Args stripped of payment fields for AJV validation | |
toolArgsRedacted | unknown | Args with sensitive fields masked for logging | |
apifyClient | ApifyClient | Client configured with payment headers or standard token |
Source: src/payments/helpers.ts:7-16
x402 Payment Provider
The x402 provider enables blockchain-based payments using EIP-3009 TransferWithAuthorization on Base network.
Payment Flow
sequenceDiagram
participant Client
participant MCP_Server
participant Apify_API
Client->>Client: Sign EIP-3009 TransferWithAuthorization
Client->>MCP_Server: Tool call with _meta["x402/payment"]
MCP_Server->>MCP_Server: validatePayment()
MCP_Server->>MCP_Server: getPaymentHeaders()
MCP_Server->>Apify_API: Forward PAYMENT-SIGNATURE header
Apify_API->>Apify_API: Verify signature & settle payment
Apify_API-->>MCP_Server: Actor execution result
MCP_Server-->>Client: Responsex402 Payment Types
export type X402PaymentAccept = {
scheme?: string;
network?: string;
amount?: string;
asset?: string;
payTo?: string;
maxTimeoutSeconds?: number;
extra?: Record<string, unknown>;
};
export type X402PaymentRequirements = {
x402Version?: number;
resource?: Record<string, unknown>;
accepts?: X402PaymentAccept[];
};
Source: src/payments/x402.ts:18-28
Payment Data Extraction
The x402 provider reads payment data from two sources in priority order:
- MCP
_metafield (preferred):meta["x402/payment"]contains the decoded JSON payment object - HTTP
PAYMENT-SIGNATUREheader (fallback): Base64-encoded payment data from HTTP transport
function getEncodedPaymentSignature(
meta?: PaymentMeta,
requestHeaders?: RequestHeaders
): string | undefined {
const metaPayment = meta?.[X402_META_KEY];
if (metaPayment) {
return Buffer.from(JSON.stringify(metaPayment)).toString('base64');
}
return getPaymentSignatureFromHeader(requestHeaders);
}
Source: src/payments/x402.ts:75-86
Caching Mechanism
The x402 provider caches payment requirements at module level to prevent thundering herd during server startup:
| Parameter | Value | |
|---|---|---|
| Cache TTL | 30 minutes | |
| Cached Item | `Promise<X402PaymentRequirements \ | undefined>` |
let cachedRequirementsPromise: Promise<X402PaymentRequirements | undefined> | null = null;
let lastFetchTime = 0;
const CACHE_TTL_MS = 30 * 60 * 1000;
Source: src/payments/x402.ts:35-41
x402 Provider Constants
| Constant | Value | Purpose |
|---|---|---|
X402_META_KEY | x402/payment | Key for MCP _meta field |
PAYMENT_SIGNATURE_HEADER | PAYMENT-SIGNATURE | HTTP header for Apify API |
PAYMENT_PROTOCOL_HEADER | x-apify-payment-protocol | Protocol identification |
PAYMENT_REQUIRED_HEADER | payment-required | Response header for 402 |
FETCH_TIMEOUT_MS | 8000 | Timeout for payment requirements fetch |
Source: src/payments/x402.ts:52-63
Payment Error Handling
402 Response Building
The buildPaymentRequiredResponse function constructs MCP responses for payment failures following the x402 MCP transport spec:
export function buildPaymentRequiredResponse(
errorOrMessage: unknown,
precomputedPaymentData?: unknown
) {
const paymentData = precomputedPaymentData ?? extractPaymentRequiredData(errorOrMessage);
const message = errorOrMessage instanceof Error ? errorOrMessage.message : String(errorOrMessage);
const texts = paymentData
? [
JSON.stringify(paymentData),
'Payment required to run this Actor or access this resource.',
]
: [message];
return buildMCPResponse({ texts, isError: true, structuredContent: paymentData });
}
Source: src/utils/payment_errors.ts:44-60
Payment Data Extraction
Payment-required data is extracted from two sources in priority order:
| Priority | Source | Access Method |
|---|---|---|
| 1 | Captured HTTP header | Axios interceptor stores payment-required response header |
| 2 | API response body | ApifyApiError.data field |
function extractPaymentRequiredData(error: unknown): Record<string, unknown> | undefined {
// Source 1: Captured payment-required header
const captured = (error as ErrorWithPaymentData)[PAYMENT_REQUIRED_DATA];
if (captured && typeof captured === 'object') return captured;
// Source 2: ApifyApiError.data (API response body)
if (error instanceof ApifyApiError) {
const { data } = error;
if (typeof data === 'object' && data !== null) return data as Record<string, unknown>;
}
return undefined;
}
Source: src/utils/payment_errors.ts:66-87
Axios Interceptor
An axios interceptor captures the payment-required response header from Apify API responses:
apifyClient.addInterceptorResponseError(async (error) => {
const response = (error as AxiosError<{ response?: { headers?: Record<string, string> } }>)
?.response;
const paymentData = response?.status === HTTP_PAYMENT_REQUIRED
? decodePaymentRequiredHeader(response.headers?.[PAYMENT_REQUIRED_HEADER])
: undefined;
if (paymentData) {
Object.defineProperty(error as object, PAYMENT_REQUIRED_DATA, {
value: paymentData,
enumerable: false
});
}
return Promise.reject(error);
});
Source: src/utils/payment_errors.ts:18-31
Tool Call Processing Workflow
graph TD
A[Tool Call Received] --> B{Pre-process payment}
B --> C[validatePayment]
C -->|Valid| D[removePaymentFields]
C -->|Invalid| E[Return 402 Response]
D --> F[Redact sensitive fields]
F --> G[Create ApifyClient with payment headers]
G --> H[AJV validation on clean args]
H -->|Valid| I[Execute Actor]
H -->|Invalid| J[Return validation error]
I --> K[Return result]
style E fill:#ff6b6b
style K fill:#51cf66Usage Guide Integration
Payment providers can optionally expose usage guides as MCP resources:
const listResources = async (): Promise<ListResourcesResult> => {
const resources: Resource[] = [];
if (paymentProvider?.getUsageGuide?.()) {
resources.push({
uri: 'file://readme.md',
name: 'readme',
description: 'Apify MCP Server usage guide...',
mimeType: 'text/markdown',
});
}
// ...
};
Source: src/resources/resource_service.ts:27-38
Configuration Reference
| Configuration Option | Provider | Description |
|---|---|---|
APIFY_TOKEN | Standard | Apify API token for traditional authentication |
payment=x402 | x402 | Query parameter to enable x402 payments |
--x402 | x402 | CLI flag to enable x402 protocol |
Source: README.md
Security Considerations
Field Redaction
Sensitive payment fields are redacted before logging to prevent credential exposure:
// From PaymentProvider interface
redactForLogging(args: unknown): unknown;
Field Removal
Payment-specific fields are stripped from tool arguments before passing to Actor input:
removePaymentFields(args: Record<string, unknown>): Record<string, unknown>;
This ensures:
- AJV validation operates on clean schema without payment-specific fields
- Actor input does not contain provider-specific payment data
- Logging contains redacted versions only
Source: https://github.com/apify/apify-mcp-server / Human Manual
Widget System
Related topics: UI Components Library
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: UI Components Library
Widget System
Overview
The Widget System provides interactive, self-contained UI components that render inside MCP (Model Context Protocol) clients, specifically optimized for MCP Apps. Widgets enable rich visual experiences for Actor discovery, details viewing, and run monitoring without requiring the client to implement custom rendering logic.
Architecture
High-Level Architecture
graph TD
subgraph "MCP Client"
A[MCP Apps SDK]
end
subgraph "Apify MCP Server"
B[Resource Handler]
C[Tool Handlers]
D[Available Widgets Registry]
end
subgraph "Widget Bundle"
E[Actor Search Widget]
F[Actor Detail Widget]
G[Actor Run Widget]
end
subgraph "UI Library"
H[@apify/ui-library]
I[@apify/ui-icons]
end
A -->|ui://widget/*| B
B -->|Lookup| D
D -->|Return Widget Path| B
B -->|Read JS Bundle| E
B -->|Read JS Bundle| F
B -->|Read JS Bundle| G
E -->|Import| H
F -->|Import| H
G -->|Import| H
C -->|Tool Output| AWidget Loading Flow
sequenceDiagram
participant Client as MCP Client
participant Server as MCP Server
participant FS as File System
participant Widget as Widget Bundle
Client->>Server: resources/read with ui://widget/actor-detail.html
Server->>Server: Check getMode() === ServerMode.APPS
Server->>Server: Lookup widget in availableWidgets
Server->>FS: Read widget.jsPath
FS-->>Server: widgetJs content
Server->>Server: Wrap in HTML template
Server-->>Client: HTML resource with MIME type
Client->>Widget: Execute module script
Widget->>Widget: useWidgetProps() reads tool output
Widget->>Widget: renderWidget() mounts componentWidget Types
The system implements three primary widget types:
| Widget | File | Purpose |
|---|---|---|
| Actor Search Widget | search-actors-widget.tsx | Search and browse Actors in Apify Store |
| Actor Detail Widget | actor-detail-widget.tsx | Display Actor information, pricing, input schema |
| Actor Run Widget | actor-run-widget.tsx | Show Actor execution progress and results |
Core Components
Widget Initialization (`init-widget.tsx`)
The renderWidget function is the entry point for all widgets:
// src/web/src/utils/init-widget.tsx
renderWidget(WidgetComponent);
This function:
- Creates a root container element
- Renders the widget component into the container
- Injects the necessary styles and context providers
- Returns cleanup functions for hot-reload scenarios
Widget Props Hook (`use-widget-props.ts`)
Widgets receive tool output data through the useWidgetProps hook:
// src/web/src/widgets/actor-detail-widget.tsx
const toolOutput = useWidgetProps<WidgetToolOutput>();
const details = toolOutput?.details;
The hook interface:
| Property | Type | Description | |
|---|---|---|---|
details | `ActorDetails \ | undefined` | Actor information from tool call |
input | Record<string, unknown> | Input parameters | |
meta | WidgetMeta | Metadata about the widget session |
MCP App Context (`mcp-app-context.tsx`)
Provides global state and utilities for widgets:
interface McpAppContextValue {
// Context methods and state
}
Widget Wrapper Pattern
Each widget follows a consistent wrapper pattern:
// src/web/src/widgets/actor-detail-widget.tsx
const ActorDetailWrapper = () => {
const toolOutput = useWidgetProps<WidgetToolOutput>();
const details = toolOutput?.details;
if (!details) {
return <div>No actor details available</div>;
}
return <ActorSearchDetail details={details} />;
};
(async () => {
if (IS_DEV_BUILD) {
const { setupActorDetailWidgetDev } = await import("./actor-detail-widget.dev");
setupActorDetailWidgetDev();
}
renderWidget(ActorDetailWrapper);
})();
Resource Service Integration
URI Scheme
Widgets are exposed as MCP resources using the ui://widget/ URI scheme:
ui://widget/actor-search.html
ui://widget/actor-detail.html
ui://widget/actor-run.html
Source: src/resources/resource_service.ts
Resource Handler Logic
// src/resources/resource_service.ts
if (getMode() === ServerMode.APPS && uri.startsWith('ui://widget/')) {
const widget = getAvailableWidgets().get(uri);
if (!widget || !widget.exists) {
return {
contents: [{
uri,
mimeType: 'text/plain',
text: `Widget ${uri} is not available. ${!widget ? 'Not found in registry.' : `File not found at ${widget.jsPath}`}`,
}],
};
}
try {
const fs = await import('node:fs');
const widgetJs = fs.readFileSync(widget.jsPath, 'utf-8');
const widgetHtml = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>${widget.title}</title>
</head>
<body>
<div id="root"></div>
<script type="module">${widgetJs}</script>
</body>
</html>`;
const widgetContent: ExtendedResourceContents = {
uri,
mimeType: RESOURCE_MIME_TYPE,
text: widgetHtml,
html: widgetHtml,
_meta: widget.meta,
};
return { contents: [widgetContent] };
} catch (error) {
return {
contents: [{
uri,
mimeType: 'text/plain',
text: `Failed to load widget: ${errorMessage}`,
}],
};
}
}
Bundle Size Optimization
Optimization Strategy
Widget bundles are optimized through narrow imports from @apify/ui-library. The top-level barrel import pulls in heavy transitive dependencies (floating UI, markdown helpers), which are avoided by importing specific modules.
Import Patterns
// ❌ AVOID - Pulls entire library
import { Button } from '@apify/ui-library';
// ✅ PREFER - Narrow import
import { Button } from '@apify/ui-library/dist/src/...';
Source: res/web-widget-bundle-size.md
Verified Bundle Sizes
| Widget | Before | After | Reduction |
|---|---|---|---|
| actor-run-widget | ~1.86 MB | ~1.16 MB | 38% |
| actor-detail-widget | ~1.86 MB | ~1.52 MB | 18% |
| search-actors-widget | ~1.87 MB | ~1.53 MB | 18% |
Source: res/web-widget-bundle-size.md
Special Cost Center: Markdown
Markdown rendering is treated as a special cost center. Changes to markdown processing require re-measuring bundle size impact.
Development Workflow
Hot-Reload Development
The development server supports hot-reload for widgets:
APIFY_TOKEN='your-apify-token' pnpm run dev
This starts:
- Web widget builder in watch mode
- MCP server in standby mode on port
3001 - Local esbuild dev server at
http://localhost:3226
Source: DEVELOPMENT.md
Preview Widgets
Widgets can be previewed locally via:
http://localhost:3226/index.html
The preview page links to:
- Actor Search Widget:
/index-actor-search.html - Actor Run Widget:
/index-actor-run.html
UI Mode Requirement
Widget rendering requires the server to run in UI mode. Enable via:
- Query parameter:
/mcp?ui=true - Environment variable:
UI_MODE=true
Widget Tool Output Interface
Each widget expects a specific output structure from the invoking tool:
interface WidgetToolOutput extends Record<string, unknown> {
details?: ActorDetails;
}
interface ActorDetails {
name: string;
description: string;
pricing: PricingInfo;
inputSchema: InputSchema;
// ... other properties
}
Design System Compliance
Widgets must follow the Apify design system rules defined in DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md:
Token Usage
| Token Category | Usage | Example |
|---|---|---|
| Colors | Use theme.color.* | theme.color.neutral.text |
| Spacing | Use theme.space.* | theme.space.space16 |
| Shadows | Use theme.shadow.* | theme.shadow.shadow2 |
Component Structure
// 1. Imports
import styled from 'styled-components';
import { theme } from '@apify/ui-library';
// 2. Constants & Types
export const COMPONENT_VARIANTS = { ... } as const;
// 3. Styled Components
const StyledWrapper = styled.div`...`;
// 4. Component Implementation
export const Component = forwardRef<HTMLElement, Props>((props, ref) => {
// implementation
});
// 5. Display Name
Component.displayName = 'Component';
Skeleton Loading States
Widgets implement skeleton loading states for async content:
// src/web/src/pages/ActorSearch/ActorSearch.skeleton.tsx
const SectionHeaderSkeleton: React.FC = () => {
return (
<SectionHeaderWrapper px="space16" py="space12">
<SkeletonBlock style={{ height: '24px', width: '96px' }} />
<SkeletonBlock style={{ height: '16px', width: '64px' }} />
</SectionHeaderWrapper>
);
};
Configuration
Widget Registry
Widgets are registered in the availableWidgets registry, which tracks:
- Widget URI path
- JavaScript file path
- Title for HTML template
- Existence status
- Metadata
Server Mode
Widget resources are only available when getMode() === ServerMode.APPS. In default mode, requests to ui://widget/* URIs return an error message.
Source: https://github.com/apify/apify-mcp-server / Human Manual
UI Components Library
Related topics: Widget System
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Widget System
UI Components Library
Overview
The Apify MCP Server utilizes a dedicated UI Components Library to render interactive widgets within the MCP Apps environment. These components enable the server to deliver rich, styled user interfaces for displaying Actor information, search results, and run progress directly within AI assistant applications.
The UI components are built using React 18.3.1 and styled-components 6.3.8, with design tokens sourced from the @apify/ui-library package. Source: src/web/package.json
Architecture
Component Location and Structure
UI widgets reside in src/web/src/widgets/ and leverage shared components from src/web/src/components/ui/. The component library follows a consistent pattern where all styled components import the theme object from @apify/ui-library to ensure design consistency across the application. Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Widget Rendering Pipeline
The following diagram illustrates how UI components integrate with the MCP server:
graph TD
A[MCP Client Request] --> B[Server Handler]
B --> C{Server Mode}
C -->|APPS| D[Widget Registry]
C -->|DEFAULT| E[Standard Response]
D --> F[Read Widget JS Bundle]
F --> G[Wrap in HTML Template]
G --> H[Return HTML via Resource]
H --> I[MCP Apps Renderer]
I --> J[React Components Mount]Source: src/resources/resource_service.ts
Bundle Optimization Strategy
The widget bundles must remain self-contained while minimizing payload size. The system uses direct module imports from @apify/ui-library/dist/src/... instead of top-level imports to avoid pulling in heavy transitive dependencies. Source: res/web-widget-bundle-size.md
Bundle size improvements achieved:
| Widget | Before | After | Reduction |
|---|---|---|---|
| actor-run-widget | ~1.86 MB | ~1.16 MB | 37.6% |
| actor-detail-widget | ~1.86 MB | ~1.52 MB | 18.3% |
| search-actors-widget | ~1.87 MB | ~1.53 MB | 18.2% |
Design System Compliance
All UI components must adhere to strict design system rules defined in DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md. These rules ensure visual consistency and maintainability across all widgets. Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Design Tokens
Components must use theme.* tokens exclusively for all styling values. Hardcoded values are strictly forbidden.
// ❌ FORBIDDEN
color: '#1976d2'
padding: '8px'
border-radius: '4px'
// ✅ REQUIRED
color: ${theme.color.primary.action}
padding: ${theme.space.space8}
border-radius: ${theme.radius.radius2}
Available token categories:
| Category | Examples | Purpose |
|---|---|---|
| Colors | theme.color.primary.action, theme.color.neutral.textMuted | Brand colors and semantic variants |
| Spacing | theme.space.space8, theme.space.space16, theme.space.space40 | Padding, margins, gaps |
| Border Radius | theme.radius.radius2, theme.radius.radius3 | Component corners |
| Shadows | theme.shadow1, theme.shadow3, theme.shadowActive | Elevation and depth |
Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Component Import Pattern
All shared UI components should be imported from @apify/ui-library. Components must never be duplicated locally or imported from arbitrary relative paths.
// ✅ Correct
import { Button, Badge, Chip, Text, Heading } from '@apify/ui-library';
// ❌ Never create duplicate implementations
Component Patterns
Styled Components Structure
The project follows a standardized component structure to ensure consistency across all UI elements. Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Component file organization:
// 1. Imports (grouped)
import { forwardRef } from 'react';
import styled from 'styled-components';
import { theme } from '@apify/ui-library';
// 2. Constants & Types
export const COMPONENT_VARIANTS = { ... } as const;
type ComponentVariants = ValueOf<typeof COMPONENT_VARIANTS>;
// 3. Styled Components
const StyledWrapper = styled.div`...`;
// 4. Component Implementation
export const Component = forwardRef<HTMLElement, Props>((props, ref) => {
// implementation
});
// 5. Display Name
Component.displayName = 'Component';
Transient Props Convention
Component props that should not be passed to the underlying DOM element must use the $ prefix:
const StyledButton = styled.button<{ $variant?: string }>`
background: ${({ $variant }) =>
$variant === 'primary'
? theme.color.primary.action
: theme.color.neutral.background
};
`;
Common transient props: $variant, $isActive, $size
Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Typography Components
Typography must use the Text and Heading components from @apify/ui-library rather than direct styling:
// ✅ Correct
import { Text, Heading } from '@apify/ui-library';
<Text type="body" size="regular" weight="normal">Content here</Text>
<Heading type="titleL">Title here</Heading>
// ❌ Never style text elements directly
// ❌ Never use typography tokens
Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Spacing System
The design system defines a consistent spacing scale that must be used for all layout measurements:
| Token | Usage | Example |
|---|---|---|
space4 | Inline elements, icon gaps | gap: ${theme.space.space4} |
space8 | Button padding, small gaps | padding: ${theme.space.space8} |
space12 | Component internal spacing | padding: ${theme.space.space12} |
space16 | Standard component padding | padding: ${theme.space.space16} |
space24 | Section margins | margin: ${theme.space.space24} |
space32 | Section separators | margin: ${theme.space.space32} |
space40, space64, space80 | Large layouts | Container margins |
Rule: Never use arbitrary values like gap: 10px — always round to the nearest design token.
Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Common Pitfalls
Token Misuse
Avoid mixing hardcoded values with design tokens in the same property:
// ❌ WRONG
padding: ${theme.space.space16} 10px;
// ✅ CORRECT
padding: ${theme.space.space16} ${theme.space.space10};
Non-existent Token Properties
Always verify token property names exist in the theme object:
// ❌ WRONG - These properties don't exist
theme.color.neutral.textLight
theme.color.primary.main
// ✅ CORRECT - Use actual property names
theme.color.neutral.textMuted
theme.color.primary.action
Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Widget Output Schemas
UI components receive data through structured output schemas that define the expected data format:
Actor Details Widget Schema
export const actorDetailsWidgetOutputSchema = {
type: 'object',
properties: {
actorDetails: {
type: 'object',
properties: {
actorInfo: {
type: 'object',
description: 'Widget-formatted Actor info (tier-aware pricing, widget display fields).'
},
actorCard: {
type: 'string',
description: 'Rendered Actor card markdown for widget display.'
},
readme: {
type: 'string',
description: 'Formatted Actor README for widget display.'
},
},
required: ['actorInfo', 'actorCard', 'readme'],
},
},
required: ['actorDetails'],
};
Source: src/tools/structured_output_schemas.ts
Actor Search Widget Schema
export const actorSearchOutputSchema = {
type: 'object',
properties: {
actors: {
type: 'array',
items: actorInfoSchema,
description: 'List of Actor cards matching the search query',
},
query: { type: 'string', description: 'The search query used' },
count: { type: 'number', description: 'Number of Actors returned' },
instructions: { type: 'string', description: 'Additional instructions for the LLM.' },
},
required: ['actors', 'query', 'count'],
};
Source: src/tools/structured_output_schemas.ts
Widget Configuration
Server Mode Detection
The UI components library operates differently based on the server mode:
| Mode | Behavior | Widget Tools Available |
|---|---|---|
DEFAULT | Standard MCP response | No widget tools exposed |
APPS | Widget rendering enabled | search-actors-widget, fetch-actor-details-widget, actor-run-widget |
Source: src/utils/server-instructions/index.ts
Resource URI Scheme
Widgets are accessed via the ui://widget/ URI scheme in APPS mode:
ui://widget/search-actors.html
ui://widget/actor-detail.html
ui://widget/actor-run.html
Source: src/resources/resource_service.ts
Development Workflow
Pre-Work Checklist
Before any UI component work, developers should:
- Check MCP availability — Search for
mcp__storybook__*andmcp__figma__*tools - Load design context — Call
mcp__storybook__get-ui-building-instructionsif available - Read existing patterns — Find 1-3 similar components in
src/web/src/**/*{keyword}*.{tsx,ts} - Use Grep for patterns — Search for
theme\.color\.|theme\.space\.|theme\.radius\.
Verification Protocol
Before submitting UI changes, verify:
| Check | Command/Method | Expected Result |
|---|---|---|
| Color audit | Regex ['"]#[0-9a-fA-F]{3,8}['"] | Zero matches |
| Spacing audit | Regex ['"][0-9]+px['"] | Zero matches |
| Import check | All styled-components import theme | 100% compliance |
| Pattern match | Compare to 1-3 similar components | Consistent structure |
Source: DESIGN_SYSTEM_AGENT_INSTRUCTIONS.md
Bundle Optimization Guidelines
Import Optimization
The @apify/ui-library package uses a barrel export pattern. Direct module imports significantly reduce bundle size:
// ❌ Heavy - pulls entire library
import { Button } from '@apify/ui-library';
// ✅ Optimized - only includes Button
import { Button } from '@apify/ui-library/dist/src/primitives/Button';
Cost Centers
| Component/Feature | Bundle Impact | Notes |
|---|---|---|
| Floating UI | High | Heavy transitive dependency |
| Markdown rendering | High | Special cost center - measure impact on changes |
| Convenience components | Medium | Prefer narrow imports |
| Primitive components | Low | Direct module imports sufficient |
Source: res/web-widget-bundle-size.md
Dependencies
Core UI Dependencies
| Package | Version | Purpose |
|---|---|---|
react | ^18.3.1 | UI framework |
react-dom | ^18.3.1 | React DOM rendering |
styled-components | ^6.3.8 | CSS-in-JS styling |
@apify/ui-library | ^1.124.0 | Design system tokens and primitives |
@apify/ui-icons | ^1.27.2 | Icon components |
Build Dependencies
| Package | Version | Purpose |
|---|---|---|
esbuild | ^0.28.0 | Fast bundler for widgets |
typescript | ^5.6.3 | Type safety |
tailwindcss | ^3.4.17 | Utility CSS (used sparingly) |
Source: src/web/package.json
Source: https://github.com/apify/apify-mcp-server / Human Manual
Development Setup
This guide covers everything needed to set up a local development environment for the Apify MCP Server project.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Continue reading this section for the full explanation and source context.
Prerequisites
System Requirements
| Requirement | Minimum Version | Notes |
|---|---|---|
| Node.js | 20.0.0+ | Required runtime |
| pnpm | 11+ | Package manager |
| Claude Desktop | 0.2.16+ | For desktop integration |
Supported Platforms: macOS (darwin), Windows (win32), Linux (linux)
Source: manifest.json:15-24
Repository Architecture
The project uses a monorepo structure with the following key directories:
apify-mcp-server/
├── src/ # Main MCP server source code
│ ├── mcp/ # MCP protocol implementation
│ └── web/ # React widgets for MCP Apps UI
├── tests/
│ ├── unit/ # Unit tests
│ └── integration/ # Integration tests
└── res/ # Resource documentation
Source: DEVELOPMENT.md:50-57
Installation
1. Enable Corepack
The project uses pnpm 11+ as specified in package.json#packageManager. Corepack (bundled with Node 16+) automatically manages the pnpm version:
corepack enable
This is a one-time setup that makes pnpm available system-wide.
2. Install Dependencies
Install all project dependencies in a single command:
pnpm install
This command installs dependencies for both the root workspace and the src/web workspace package simultaneously.
Note: ThedevEngines.packageManageris pinned withonFail: "error", which means runningnpm installoryarn installwill fail. This ensures lockfile consistency.
Source: DEVELOPMENT.md:41-45
Environment Configuration
APIFY_TOKEN Setup
The APIFY_TOKEN is required for most server operations.
#### For Claude Code
Create or edit .claude/settings.local.json:
{
"env": {
"APIFY_TOKEN": "<YOUR_APIFY_API_TOKEN>"
}
}
Restart Claude Code for the changes to take effect. The token is automatically picked up by both Claude Code MCP servers (defined in .mcp.json) and mcpc.
#### For Local Development
Create an environment file .env in the project root:
APIFY_TOKEN="your-apify-token"
Source: DEVELOPMENT.md:14-24
Environment Variables Reference
| Variable | Required | Description |
|---|---|---|
APIFY_TOKEN | Yes | Apify API authentication token |
APIFY_META_ORIGIN | No | Meta origin for tracking (e.g., STANDBY) |
UI_MODE | No | Enable UI mode for widget rendering (true/false) |
Building the Project
Production Build
To build the MCP server for production:
pnpm run build
This compiles the TypeScript source and produces output in the dist/ directory.
Source: DEVELOPMENT.md:64-68
Development Server
For active development with hot-reload capabilities, the project includes a development server at src/dev_server.ts. This server provides:
- Automatic recompilation on file changes
- Debugging endpoints for MCP protocol inspection
- Live widget preview at
http://localhost:3001
Running the Server
HTTP Streamable Mode
Run the server as an HTTP server using Apify CLI:
export APIFY_TOKEN="your-apify-token"
export APIFY_META_ORIGIN=STANDBY
apify run -p
The server will be exposed at http://localhost:3001.
Source: README.md:28-34
Standard I/O (stdio) Mode
For use with the MCP Inspector or local clients:
export APIFY_TOKEN="your-apify-token"
npx @modelcontextprotocol/inspector node ./dist/stdio.js
The Inspector will display a URL for browser-based debugging.
Source: README.md:40-46
Testing
Testing Layers
The project implements a multi-layer testing strategy:
| Layer | Command | Coverage |
|---|---|---|
| Unit Tests | pnpm run test:unit | Individual modules in isolation |
| Integration Tests | pnpm run test:integration | Full server over all transports against real Apify API |
| Interactive Verification | mcpc @stdio tools-call ... | End-to-end during development |
| LLM Evaluations | CI only | Multiple models via OpenRouter |
Source: DEVELOPMENT.md:26-36
Unit Tests
Unit tests verify individual modules without external dependencies:
pnpm run test:unit
No credentials are required for unit tests.
Integration Tests
Integration tests verify the complete MCP server functionality:
pnpm run test:integration
Requirements:
- Valid
APIFY_TOKENenvironment variable - Compiled production build (
pnpm run build)
Interactive Probing with mcpc
For manual verification during development:
mcpc @stdio tools-call ...
LLM Evaluations
LLM evaluations run in CI and require the validated label on the PR:
# Trigger eval workflow
# 1. Apply the 'validated' label to your PR
# Environment variables required in CI:
PHOENIX_* # Phoenix evaluation platform credentials
OPENROUTER_* # OpenRouter API credentials
Evaluations run automatically:
- When
validatedlabel is applied to a PR - On every merge to the
masterbranch
Results are posted to Phoenix for analysis.
Source: DEVELOPMENT.md:35-38
Development Workflow
Mermaid: Development Workflow
graph TD
A[Clone Repository] --> B[Enable corepack]
B --> C[pnpm install]
C --> D[Configure APIFY_TOKEN]
D --> E{Development Mode}
E -->|HTTP Stream| F[apify run -p]
E -->|stdio| G[node ./dist/stdio.js]
E -->|Widget Dev| H[src/web dev server]
F --> I[Debug with MCP Inspector]
G --> I
H --> J[Browser Preview: localhost:3001]
I --> K{Testing}
K -->|Unit| L[pnpm run test:unit]
K -->|Integration| M[pnpm run test:integration]
K -->|Manual| N[mcpc probing]
L --> O[Validate & Submit PR]
M --> O
N --> OBranch Naming
All feature branches must follow the format:
<type>/<short-description>
Where <type> matches conventional commit types:
| Type | Use Case |
|---|---|
feat | New features |
fix | Bug fixes |
chore | Maintenance tasks |
refactor | Code refactoring |
docs | Documentation updates |
Examples:
feat/add-dataset-toolfix/connection-timeoutchore/update-dependencies
Source: CONTRIBUTING.md:8-13
Commit Messages
All commits and PR titles must follow the Conventional Commits format:
<type>(<scope>)!: <description>
| Component | Required | Description |
|---|---|---|
| type | Yes | feat, fix, chore, refactor, docs, etc. |
| scope | Yes | The affected component/module |
! | No | Indicates breaking change |
| description | Yes | Brief summary of changes |
Examples:
feat: Add new tool for fetching actor details
feat!: Migrate to new MCP SDK version
fix: Handle connection errors gracefully
chore: Update dependencies
Source: CONTRIBUTING.md:17-35
UI Widget Development
Widget Architecture
The MCP Apps (ChatGPT Apps) UI widgets are built as a separate React project within src/web/. Widgets are rendered based on tool output—modifying widget data requires changing the corresponding tool's return value.
UI Mode
Widget rendering requires the server to run in UI mode:
Via Query Parameter:
/mcp?ui=true
Via Environment Variable:
export UI_MODE=true
Via CLI Flag:
npx @apify/actors-mcp-server --ui true
Widget Preview
Preview widgets during development:
# Actor Search Widget
# Open: http://localhost:3001/index-actor-search.html
# Actor Run Widget
# Open: http://localhost:3001/index-actor-run.html
Source: DEVELOPMENT.md:58-62
Code Quality Standards
Naming Conventions
| Element | Convention | Example |
|---|---|---|
| Types/Interfaces | PascalCase | ActorDetails, ToolConfig |
| Variables/Functions | camelCase | actorName, fetchActorDetails() |
| Constants | SCREAMING_SNAKE_CASE | MAX_RETRIES, WIDGET_REGISTRY |
| Zod Validators | Suffix with Validator | ActorValidator |
String Formatting
Single-line strings: Use single quotes
const message = 'Operation completed';
Multi-line strings: Use dedent for LLM-facing content
import dedent from 'dedent';
const description = dedent`
Line 1
Line 2
`;
Avoid:
[].join('\n')for multiline strings- Hardcoded hex colors or pixel values in UI code
Source: CONTRIBUTING.md:56-75
Troubleshooting
Common Issues
| Issue | Solution |
|---|---|
pnpm install fails | Ensure Node.js 20+ is installed |
| Wrong pnpm version | Run corepack enable |
| Tests fail with "Token required" | Set APIFY_TOKEN environment variable |
| Widgets not rendering | Verify UI_MODE=true is set |
Node Version Management
The .nvmrc file pins the development tooling Node version (currently 24). This is intentionally higher than the published floor to support modern tooling features.
# Check current Node version
node --version
# Switch to project-required version (requires nvm)
nvm use
Verifying Installation
Run the following commands to verify your setup:
# Verify pnpm version
pnpm --version # Should be 11+
# Verify Node version
node --version # Should be 20+
# Run unit tests
pnpm run test:unit
# Build project
pnpm run build
If all commands succeed, your development environment is properly configured.
Source: https://github.com/apify/apify-mcp-server / Human Manual
Doramagic Pitfall Log
Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.
First-time setup may fail or require extra isolation and rollback planning.
Users may get misleading failures or incomplete behavior unless configuration is checked carefully.
The project may affect permissions, credentials, data exposure, or host boundaries.
The project may affect permissions, credentials, data exposure, or host boundaries.
Doramagic Pitfall Log
Doramagic extracted 16 source-linked risk signals. Review them before installing or handing real data to the project.
1. Installation risk: fix: Allow calling MCP server actors in normal (one-shot) mode
- Severity: high
- Finding: Installation risk is backed by a source signal: fix: Allow calling MCP server actors in normal (one-shot) mode. Treat it as a review item until the current version is checked.
- User impact: First-time setup may fail or require extra isolation and rollback planning.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/857
2. Configuration risk: Remove the flat-fields back-compat shim from `_meta.x402` once all consumers read `accepts[]`
- Severity: high
- Finding: Configuration risk is backed by a source signal: Remove the flat-fields back-compat shim from
_meta.x402once all consumers readaccepts[]. Treat it as a review item until the current version is checked. - User impact: Users may get misleading failures or incomplete behavior unless configuration is checked carefully.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/892
3. Security or permission risk: Do not include the rag web browser when ?payment=x402
- Severity: high
- Finding: Security or permission risk is backed by a source signal: Do not include the rag web browser when ?payment=x402. Treat it as a review item until the current version is checked.
- User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/875
4. Security or permission risk: Perf: `search-actors` tools returns huuuge `inputFields` object
- Severity: high
- Finding: Security or permission risk is backed by a source signal: Perf:
search-actorstools returns huuugeinputFieldsobject. Treat it as a review item until the current version is checked. - User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/888
5. Security or permission risk: feat(telemetry): track tool result size in bytes
- Severity: high
- Finding: Security or permission risk is backed by a source signal: feat(telemetry): track tool result size in bytes. Treat it as a review item until the current version is checked.
- User impact: The project may affect permissions, credentials, data exposure, or host boundaries.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/838
6. Project risk: Project risk needs validation
- Severity: medium
- Finding: Project risk is backed by a source signal: Project risk needs validation. Treat it as a review item until the current version is checked.
- User impact: The project should not be treated as fully validated until this signal is reviewed.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: identity.distribution | github_repo:911256711 | https://github.com/apify/apify-mcp-server | repo=apify-mcp-server; install=@apify/actors-mcp-server
7. Installation risk: chore(core): collapse array indices in dataset fields to prevent nextStep schema bloat
- Severity: medium
- Finding: Installation risk is backed by a source signal: chore(core): collapse array indices in dataset fields to prevent nextStep schema bloat. Treat it as a review item until the current version is checked.
- User impact: First-time setup may fail or require extra isolation and rollback planning.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/894
8. Installation risk: feat: Add structured output to remaining storage tools
- Severity: medium
- Finding: Installation risk is backed by a source signal: feat: Add structured output to remaining storage tools. Treat it as a review item until the current version is checked.
- User impact: First-time setup may fail or require extra isolation and rollback planning.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/884
9. Installation risk: feat: migrate direct actor tools to canonical RunResponse shape
- Severity: medium
- Finding: Installation risk is backed by a source signal: feat: migrate direct actor tools to canonical RunResponse shape. Treat it as a review item until the current version is checked.
- User impact: First-time setup may fail or require extra isolation and rollback planning.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/852
10. Installation risk: test: Consolidate duplicated MCP server test fixtures
- Severity: medium
- Finding: Installation risk is backed by a source signal: test: Consolidate duplicated MCP server test fixtures. Treat it as a review item until the current version is checked.
- User impact: First-time setup may fail or require extra isolation and rollback planning.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/847
11. Configuration risk: feat: Dataset tools correctness and coverage
- Severity: medium
- Finding: Configuration risk is backed by a source signal: feat: Dataset tools correctness and coverage. Treat it as a review item until the current version is checked.
- User impact: Users may get misleading failures or incomplete behavior unless configuration is checked carefully.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: Source-linked evidence: https://github.com/apify/apify-mcp-server/issues/784
12. Capability assumption: README/documentation is current enough for a first validation pass.
- Severity: medium
- Finding: README/documentation is current enough for a first validation pass.
- User impact: The project should not be treated as fully validated until this signal is reviewed.
- Recommended check: Open the linked source, confirm whether it still applies to the current version, and keep the first run isolated.
- Evidence: capability.assumptions | github_repo:911256711 | https://github.com/apify/apify-mcp-server | README/documentation is current enough for a first validation pass.
Source: Doramagic discovery, validation, and Project Pack records
Community Discussion Evidence
These external discussion links are review inputs, not standalone proof that the project is production-ready.
Count of project-level external discussion links exposed on this manual page.
Open the linked issues or discussions before treating the pack as ready for your environment.
Community Discussion Evidence
Doramagic exposes project-level community discussion separately from official documentation. Review these links before using apify-mcp-server with real data or production workflows.
- feat(telemetry): track tool result size in bytes - github / github_issue
- chore(core): collapse array indices in dataset fields to prevent nextSte - github / github_issue
- Remove the flat-fields back-compat shim from
_meta.x402once all consu - github / github_issue - Do not include the rag web browser when ?payment=x402 - github / github_issue
- design: Calibrate get-dataset-schema output detail - github / github_issue
- refactor: Extract storage tool helpers - github / github_issue
- feat: Add structured output to remaining storage tools - github / github_issue
- Perf:
search-actorstools returns huuugeinputFieldsobject - github / github_issue - [[Bug]: Inconsistent
search-actorsschema and results](https://github.com/apify/apify-mcp-server/issues/889) - github / github_issue - fix: Allow calling MCP server actors in normal (one-shot) mode - github / github_issue
- chore: Add mixpanel analytics for storage tools + error rates - github / github_issue
- tools/list response contains
type: "unknown"in an input schema — reje - github / github_issue
Source: Project Pack community evidence and pitfall evidence