How to Build & Deploy an MCP Server with TypeScript
The Model Context Protocol (MCP) standardizes how Large Language Models interface with external APIs and execution environments. By writing a single MCP server, your custom engineering tools instantly become compatible with Claude Desktop, Cursor, and any other MCP-compliant client, eliminating the need to maintain disparate plugin architectures.
While MCP servers can run locally via stdio, executing them exclusively on developer hardware severely limits agentic workflows. By deploying an MCP server to a cloud container platform like Apify, your AI agents gain persistent 24/7 access to your internal tools.
This technical guide demonstrates how to scaffold an MCP server in TypeScript, define a custom execution tool, and deploy it to a serverless container.
Why deploy MCP servers to the cloud?
Deploying MCP infrastructure to a cloud platform like Apify provides three distinct engineering advantages:
- Persistent Availability: Cloud deployment ensures your AI agent can process asynchronous background tasks (like nightly Web Scrape aggregations) without requiring your local machine to remain online.
- Infrastructure Abstraction: Running via an HTTP SSE (Server-Sent Events) endpoint allows you to share access with a broader engineering team via a stable
https://...URL, bypassing complex local network tunneling. - Automated Provisioning: Apify natively handles TLS termination, request load balancing, and container scaling.
Architectural constraints and failure modes
Before deploying an MCP server to production, engineers must account for inherent architectural limitations:
- Execution Timeouts: When an AI model calls an MCP tool, the client expects a relatively synchronous response. If your MCP tool triggers a deeply nested database query or a heavy web scraping operation that takes 5+ minutes, the SSE connection may time out, causing the LLM client to error. You must architect long-running tasks asynchronously.
- Context Window Bloat: Your MCP server must vigorously sanitize its output. If your tool returns a massive JSON payload (e.g., thousands of database rows), it will instantly max out the LLM's context window, resulting in massive API charges and token exhaustion.
- Debugging Opacity: When an MCP server runs locally, standard
console.logdebugging is straightforward. When deployed via SSE, you are reliant on the hosting platform's container logging telemetry to debug why a tool failed mid-execution.
Step 1: Initialize the project
We utilize the official Apify TypeScript MCP template, which comes pre-configured with Anthropic's SDK and the Apify deployment harness.
Execute the following in your terminal:
# Scaffold the project using the Apify CLI
apify create my-mcp-server --template ts-mcp-proxy
cd my-mcp-server
This generates an Actor directory structure properly configured to expose the @modelcontextprotocol/sdk.
Step 2: Define your executable tools
Navigate to src/main.ts. This file registers the tools your AI agent can invoke.
For demonstration, we will define a synchronous tool that calculates shipping constraints based on input parameters.
// src/tools/shipping.ts
import { Tool } from "@modelcontextprotocol/sdk/types.js";
// The schema is strictly parsed; LLMs read these descriptions to understand the tool's purpose
export const shippingTool: Tool = {
name: "calculate_shipping",
description: "Calculates enterprise shipping cost based on weight and precise destination",
inputSchema: {
type: "object",
properties: {
weight: { type: "number", description: "Package weight in kilograms" },
destination: { type: "string", description: "Strict ISO-3166 country code (e.g., US, DE)" }
},
required: ["weight", "destination"]
}
};
// The execution logic triggered when the LLM invokes the tool
export const calculateShipping = async ({ weight, destination }) => {
// In production, this would query a logistics API
const rateMatrix = { 'US': 5, 'DE': 8, 'UK': 10 };
const rate = rateMatrix[destination] || 15; // default fallback
return {
success: true,
data: { cost: weight * rate, currency: "USD" }
};
};
Step 3: Verify Actor configuration
Review the .actor/actor.json file. The critical parameter is webServerMcpPath, which instructs the Apify runtime to expose your server port via an SSE stream rather than a standard REST endpoint.
{
"actorSpecification": 1,
"name": "enterprise-shipping-mcp",
"usesStandbyMode": true,
"webServerMcpPath": "/sse"
}
Architectural Note: usesStandbyMode is mandatory for interactive MCP deployments. It instructs Apify to maintain a "warm" container state. If disabled, the container will cold-boot on every LLM request, introducing unacceptable latency into the chat interface.
Step 4: Deploy to the Apify cloud
Push your committed code to the Apify platform using the CLI:
# Authenticate if necessary
apify login
# Build the Docker container and push to the registry
apify push
Navigate to your Apify Console dashboard. Your new Actor will display a status of Ready.
Step 5: Connect Claude Desktop
- In the Apify Console, locate your Actor's Standby URL (typically formatted as
https://[username]--[actorname].apify.actor/mcp). - Open your local
claude_desktop_config.jsonconfiguration file:- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
- Append your new server credentials:
{
"mcpServers": {
"apify-shipping-tool": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://[YOUR_ACTOR_URL]/mcp"],
"env": {
"APIFY_TOKEN": "YOUR_PRIVATE_APIFY_TOKEN"
}
}
}
}
Restart the Claude Desktop application completely. You can now prompt the LLM directly: "Calculate the shipping cost for a 12kg package to DE," and Claude will route the execution to your Apify container.
Next steps for autonomous agents
With the foundational infrastructure deployed, you can begin exposing complex backend systems to your LLMs:
- Database integrations: Expose secure, read-only PostgreSQL views to an AI analyst.
- Legacy API wrapping: Wrap older SOAP or GraphQL endpoints in a single MCP tool for modern AI access.
- Web Extraction: Integrate Apify's managed scraping Actors directly into your MCP server to give your agents live internet access.
Local MCP servers communicate via standard input/output (stdio) directly on your local CPU. Remote MCP servers, like those deployed on Apify, communicate via HTTP Server-Sent Events (SSE), allowing the LLM to interact with cloud infrastructure.
Yes. The Model Context Protocol is language-agnostic. Apify maintains a dedicated Python MCP template for data science teams who prefer building their agents in Python.
Apify utilizes a consumption-based pricing model. You are billed strictly for the Compute Units (CU) consumed while your server actively processes requests or maintains Standby mode. They offer a perpetual $5 monthly free tier for prototyping.




