TypeScript MCP proxy
A monetized Actor from any existing MCP server. Supports stdio, HTTP, and SSE.
src/main.ts
src/billing.ts
1/**2 * MCP Server - Main Entry Point3 *4 * This file serves as the entry point for the MCP Server Actor.5 * It sets up a proxy server that forwards requests to the locally running6 * MCP server, which provides a Model Context Protocol (MCP) interface.7 */8
9// Apify SDK - toolkit for building Apify Actors (Read more at https://docs.apify.com/sdk/js/)10import { Actor, log } from 'apify';11
12import { startServer } from './server.js';13
14// This is an ESM project, and as such, it requires you to specify extensions in your relative imports15// Read more about this here: https://nodejs.org/docs/latest-v18.x/api/esm.html#mandatory-file-extensions16// Note that we need to use `.js` even when inside TS files17// import { router } from './routes.js';18
19// Configuration constants for the MCP server20// Command to run the Everything MCP Server21// TODO: Do not forget to install the MCP server in package.json (using `npm install ...`)22const MCP_COMMAND = ['npx', '@modelcontextprotocol/server-everything'];23
24// Check if the Actor is running in standby mode25const STANDBY_MODE = process.env.APIFY_META_ORIGIN === 'STANDBY';26const SERVER_PORT = parseInt(process.env.ACTOR_WEB_SERVER_PORT || '3001', 10);27
28// Initialize the Apify Actor environment29// The init() call configures the Actor to correctly work with the Apify-provided environment - mainly the storage infrastructure. It is necessary that every Actor performs an init() call.30await Actor.init();31
32// Charge for Actor start33await Actor.charge({ eventName: 'actor-start' });34
35if (!STANDBY_MODE) {36 // If the Actor is not in standby mode, we should not run the MCP server37 const msg = 'This Actor is not meant to be run directly. It should be run in standby mode.';38 log.error(msg);39 await Actor.exit({ statusMessage: msg });40}41
42await startServer({43 serverPort: SERVER_PORT,44 command: MCP_COMMAND,45});A template for running and monetizing a Model Context Protocol server using stdio transport on Apify platform . This allows you to run any stdio MCP server as a standby Actor and connect via either the streamable HTTP transport with an MCP client .
Change the MCP_COMMAND to spawn your stdio MCP server in src/main.ts, and don't forget to install the required MCP server in the package.json (using npm install ...).
By default, this template runs an Everything MCP Server using the following command:
const MCP_COMMAND = ['npx','@modelcontextprotocol/server-everything',];
Alternatively, you can use the mcp-remote tool to turn a remote MCP server into an Actor. For example, to connect to a remote server with authentication:
const MCP_COMMAND = ['npx','mcp-remote','https://mcp.apify.com','--header','Authorization: Bearer TOKEN',];
Feel free to configure billing logic in .actor/pay_per_event.json and src/billing.ts.
Push your Actor to the Apify platform, configure standby mode , and then connect to the Actor standby URL with your MCP client using the endpoint: https://me--my-mcp-server.apify.actor/mcp (streamable HTTP transport ).
Important: When connecting to your deployed MCP server, you must pass your Apify API token in the Authorization header as a Bearer token. For example:
Authorization: Bearer <YOUR_APIFY_API_TOKEN>
This is required for authentication and to access your Actor endpoint.
This template uses the Pay Per Event (PPE) monetization model, which provides flexible pricing based on defined events.
To charge users, define events in JSON format and save them on the Apify platform. Here is an example schema with the tool-request event:
[{"tool-request": {"eventTitle": "Price for completing a tool request","eventDescription": "Flat fee for completing a tool request.","eventPriceUsd": 0.05}}]
In the Actor, trigger the event with:
await Actor.charge({ eventName: 'tool-request' });
This approach allows you to programmatically charge users directly from your Actor, covering the costs of execution and related services.
To set up the PPE model for this Actor:
- Configure Pay Per Event: establish the Pay Per Event pricing schema in the Actor's Monetization settings. First, set the Pricing model to
Pay per eventand add the schema. An example schema can be found in pay_per_event.json.
TypeScript Cheerio crawler
A fast HTTP crawler that extracts data from every page. Good for simple sites like blogs, news, or product listings, but it can't run client-side JavaScript.
TypeScript one-page scraper
Get data from one web page with Cheerio. The simplest way to start scraping.
TypeScript Puppeteer scraper
A headless Chrome scraper that renders JavaScript before extracting data. Good for social feeds, dashboards, or single-page apps.
TypeScript Playwright scraper
A Playwright-based browser scraper supporting multiple browsers and contexts.
TypeScript Camoufox scraper
A Firefox-based browser built to look like a real user and bypass bot protection.
Playwright test runner
An automated browser test runner with results you can access via API.