mctxdocs
mctxdocs

Server Requirements

Technical requirements for building MCP servers compatible with mctx. Learn the mctx.json schema, directory structure, build configuration, and what the platform expects from your server.

Required: mctx.json File

Every MCP server deployed on mctx requires a mctx.json configuration file in the repository root (or subdirectory for monorepos).

This file follows the official MCP server manifest specification with one mctx-specific addition: the entrypoint field.

Minimal Example

{
  "version": "1.0.0",
  "description": "Get real-time weather data for any location",
  "entrypoint": "dist/index.js"
}

Full Example

{
  "name": "Weather API",
  "version": "1.0.0",
  "description": "Get real-time weather data for any location worldwide",
  "entrypoint": "dist/index.js",
  "instructions": "Use 'get_weather' for current conditions. Provide city name or coordinates.",
  "capabilities": {
    "tools": {
      "listChanged": false
    }
  }
}

Field Reference

Required Fields

FieldTypeDescription
versionstringSemantic version (e.g., 1.0.0, 2.1.3-beta.1)
descriptionstringWhat your server does (1-500 characters)
entrypointstringPath to built JavaScript file (.js or .mjs)

Optional Fields

FieldTypeDescription
namestringDisplay name suggestion (can be overridden in dashboard)
instructionsstringInstructions for AI models using your server (max 2000 chars)
capabilitiesobjectMCP capability declarations

Version Format

The version field must follow semantic versioning:

MAJOR.MINOR.PATCH[-PRERELEASE]

Valid examples:

  • 1.0.0 - Initial release
  • 1.1.0 - New feature added
  • 1.1.1 - Bug fix
  • 2.0.0-beta.1 - Pre-release version

Important: Each deployment requires a unique version. Bump the version before pushing updates to trigger a new deployment.

Description Guidelines

Good descriptions are concise, action-oriented, and specific:

Good:

"Query financial data from SEC filings with natural language"

Bad:

"A server that does things with data"

Best practices:

  • Keep under 200 characters for optimal display
  • Start with a verb
  • Mention what makes your server unique
  • Avoid generic phrases

Entrypoint

The entrypoint is the path to your compiled JavaScript file, relative to mctx.json.

Common patterns:

Build ToolTypical Entrypoint
tscdist/index.js
esbuilddist/index.js
Rollupbuild/index.js
unbuild.output/index.mjs

Requirements:

  • Must be a .js or .mjs file
  • Must export a default HTTP handler (Cloudflare Worker format)
  • Must be committed to your repository (or built during CI)

Example handler:

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Handle MCP JSON-RPC requests
  },
};

Instructions Field

The instructions field provides context to AI models about how to use your server effectively.

Example:

{
  "instructions": "Use 'search_docs' for finding documentation. Use 'get_page' with a URL to retrieve specific content. Results are markdown-formatted."
}

Tips:

  • Explain tool purposes briefly
  • Mention expected input formats
  • Note any limitations or special requirements

Capabilities Field

The capabilities field declares what MCP protocol features your server supports.

Important: Capabilities are protocol-level flags only. They do NOT contain tool/resource/prompt definitions. Your actual tools, resources, and prompts are discovered via your server's tools/list, resources/list, and prompts/list handlers.

{
  "capabilities": {
    "tools": {
      "listChanged": false
    },
    "resources": {
      "subscribe": true,
      "listChanged": true
    },
    "prompts": {
      "listChanged": true
    }
  }
}

Capability flags:

CapabilityDescription
tools.listChangedServer may send notifications/tools/list_changed
resources.subscribeServer supports resource subscriptions
resources.listChangedServer may send notifications/resources/list_changed
prompts.listChangedServer may send notifications/prompts/list_changed

Common configurations:

Server TypeCapabilities
Tools-only{ "tools": {} } or omit entirely
Static resources{ "resources": {} }
Dynamic resources{ "resources": { "subscribe": true, "listChanged": true } }

If omitted, defaults to { "tools": {} }.

Directory Structure

Recommended project structure:

my-mcp-server/
├── src/
│   └── index.ts      # Main entry point
├── dist/
│   └── index.js      # Built output (committed or CI-built)
├── mctx.json         # mctx configuration
├── package.json
└── tsconfig.json

For monorepos:

my-monorepo/
├── packages/
│   └── my-mcp-server/
│       ├── mctx.json       # Your config here
│       ├── src/
│       └── dist/
│           └── index.js
└── package.json

When deploying, enter packages/my-mcp-server as the path in the mctx dashboard.

Build Configuration

Your build output must be a single JavaScript file committed to your repository. This is the same pattern GitHub uses for shared Actions - bundle your dependencies, commit the output, and it just works.

esbuild Example

// build.js
import * as esbuild from "esbuild";

await esbuild.build({
  entryPoints: ["src/index.ts"],
  bundle: true,
  outfile: "dist/index.js",
  format: "esm",
  platform: "browser",
});

Or via package.json script:

{
  "scripts": {
    "build": "esbuild src/index.ts --bundle --format=esm --platform=browser --outfile=dist/index.js"
  }
}

TypeScript Configuration

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "outDir": "dist",
    "strict": true
  }
}

Handler Interface

Your entrypoint must export a default object with a fetch method:

interface Env {
  // Environment variables (set in mctx dashboard)
  API_KEY?: string;
  DATABASE_URL?: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== "POST") {
      return new Response("Method not allowed", { status: 405 });
    }

    const body = await request.json();
    const { method, params, id } = body;

    // Handle MCP JSON-RPC methods
    // Return JSON-RPC response with proper headers
  },
};

Required Methods

Your server must implement these JSON-RPC methods:

MethodRequired?Description
initialize❌ NoPlatform handles this automatically
notifications/initialized❌ NoPlatform handles this
tools/list✅ Yes (if you have tools)Return available tools
tools/call✅ Yes (if you have tools)Execute tool logic
resources/list✅ Yes (if you have resources)Return available resources
resources/read✅ Yes (if you have resources)Return resource content
prompts/list✅ Yes (if you have prompts)Return available prompts
prompts/get✅ Yes (if you have prompts)Return prompt messages

Platform-managed initialization: mctx intercepts MCP initialize requests and responds directly using your mctx.json configuration. Your server code does NOT need to handle initialize.

JSON-RPC Response Format

All responses must follow JSON-RPC 2.0 specification:

Success response:

{
  "jsonrpc": "2.0",
  "result": { ... },
  "id": 1
}

Error response:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32601,
    "message": "Method not found"
  },
  "id": 1
}

Required headers:

Content-Type: application/json
MCP-Protocol-Version: 2025-11-25

Standard Error Codes

CodeConstantDescription
-32700PARSE_ERRORInvalid JSON
-32600INVALID_REQUESTInvalid JSON-RPC
-32601METHOD_NOT_FOUNDMethod does not exist
-32602INVALID_PARAMSInvalid method parameters
-32603INTERNAL_ERRORServer error

Resource Limits

Your MCP server runs as a Cloudflare Worker with these limits per request:

ResourceLimitNotes
CPU time10,000msTotal compute time (not wall clock)
Subrequests50Maximum outbound fetch() calls

Tips for staying within limits:

  • Cache expensive computations when possible
  • Batch multiple API calls into fewer requests
  • Keep tool implementations focused and efficient

Environment Variables

Access environment variables via the env parameter passed to your handler:

interface Env {
  API_KEY: string;
  DATABASE_URL: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const apiKey = env.API_KEY;
    // Use the API key in your tool implementations
  },
};

Set these in the mctx dashboard under Environment Variables.

Security: All environment variables are:

  • Encrypted at rest - AES-256-GCM encryption via WebCrypto
  • Decrypted only at deploy time - Injected into your worker, never stored in plaintext
  • Never exposed - Not visible in logs, API responses, or dashboard after creation

Logging

Use console.* methods for debugging. Your output is streamed in real-time to your dashboard when you open the logs modal:

console.log(`[INFO] Processing request for ${toolName}`);
console.warn(`[WARN] Rate limit approaching`);
console.error(`[ERROR] API call failed: ${error.message}`);

Best practices:

  • Use structured prefixes ([INFO], [WARN], [ERROR])
  • Log important events (tool calls, external API calls)
  • Never log secrets or API keys
  • Keep log messages concise

Validation

mctx validates your mctx.json when you:

  1. Select a repository in the deployment form
  2. Push a new version to your branch

Common validation errors:

ErrorSolution
"mctx.json not found"Add the file to your repository root or specified path
"Invalid version format"Use semver format (e.g., 1.0.0)
"Entrypoint file not found"Ensure the built file exists and is committed
"Description too long"Keep under 500 characters

Next Steps


See something wrong? Report it or suggest an improvement — your feedback helps make these docs better.