TypeScript MCP server
Example of how to Actorize a STDIO Model Context Protocol server.
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';11import { stdioToSse } from './lib/server.js';12import { getLogger } from './lib/getLogger.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 Sequential Thinking MCP server21// TODO: Do not forget to install the MCP server in package.json (using `npm install ...`)22const MCP_COMMAND = 'npx @modelcontextprotocol/server-sequential-thinking';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 || '', 10);27
28// Logger configuration29const LOG_LEVEL = 'info';30const OUTPUT_TRANSPORT = 'sse';31
32// Initialize the Apify Actor environment33// The init() call configures the Actor for its environment. It's recommended to start every Actor with an init()34await Actor.init();35
36// Charge for Actor start37await Actor.charge({ eventName: 'actor-start' });38
39if (!STANDBY_MODE) {40 // If the Actor is not in standby mode, we should not run the MCP server41 const msg = 'This Actor is not meant to be run directly. It should be run in standby mode.';42 log.error(msg);43 await Actor.exit({ statusMessage: msg });44}45
46const logger = getLogger({47 logLevel: LOG_LEVEL,48 outputTransport: OUTPUT_TRANSPORT,49});50await stdioToSse({51 port: SERVER_PORT,52 stdioCmd: MCP_COMMAND,53 logger,54});
MCP server template
A template for running and monetizing a Model Context Protocol server over stdio on Apify platform. This allows you to run any stdio MCP server as a standby Actor and connect via SSE transport with an MCP client.
How to use
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 a Sequential Thinking MCP Server server using the following command:
npx @modelcontextprotocol/server-sequential-thinking
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 (e.g., https://me--my-mcp-server.apify.actor/sse
).
Pay per event
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 event
and add the schema. An example schema can be found in .actor/pay_per_event.json.
Resources
Start with TypeScript
Scrape single page with provided URL with Axios and extract data from page's HTML with Cheerio.
Starter
Crawlee + Cheerio
A scraper example that uses Cheerio to parse HTML. It's fast, but it can't run the website's JavaScript or pass JS anti-scraping challenges.
Crawlee + Puppeteer + Chrome
Example of a Puppeteer and headless Chrome web scraper. Headless browsers render JavaScript and are harder to block, but they're slower than plain HTTP.
Crawlee + Playwright + Chrome
Web scraper example with Crawlee, Playwright and headless Chrome. Playwright is more modern, user-friendly and harder to block than Puppeteer.
Crawlee + Playwright + Camoufox
Web scraper example with Crawlee, Playwright and headless Camoufox. Camoufox is a custom stealthy fork of Firefox. Try this template if you're facing anti-scraping challenges.
Playwright + Chrome Test Runner
Example of using the Playwright Test project to run automated website tests in the cloud and display their results. Usable as an API.