Skip to content

ConcurrentMCPServer

The main entry point for the framework. ConcurrentMCPServer handles tool registration, middleware composition, transport selection, and lifecycle management.

import { ConcurrentMCPServer } from "@casys/mcp-server";
const server = new ConcurrentMCPServer(options: ConcurrentServerOptions);
interface ConcurrentServerOptions {
name: string; // Server name (shown to clients)
version: string; // Semver version
maxConcurrent?: number; // Default: 10
backpressureStrategy?: "sleep" | "queue" | "reject"; // Default: "sleep"
backpressureSleepMs?: number; // Default: 10
rateLimit?: RateLimitOptions; // Optional rate limiting
validateSchema?: boolean; // Default: false
enableSampling?: boolean; // Enable LLM sampling bridge
samplingClient?: SamplingClient; // Custom sampling client
logger?: (msg: string) => void; // Default: console.error
auth?: AuthOptions; // OAuth2/Bearer config
}
interface RateLimitOptions {
maxRequests: number; // Max requests per window
windowMs: number; // Window size in milliseconds
}
interface AuthOptions {
provider: AuthProvider; // Use presets (createGoogleAuthProvider, etc.) or JwtAuthProvider
}

All registration must happen before calling start() or startHttp().

server.registerTool(tool: MCPTool, handler: ToolHandler): void;

Register a single tool with its handler:

server.registerTool(
{
name: "greet",
description: "Greet someone",
inputSchema: {
type: "object",
properties: { name: { type: "string" } },
required: ["name"],
},
requiredScopes: ["read"], // Optional — requires this scope if auth is configured
},
({ name }) => `Hello, ${name}!`,
);
server.registerTools(tools: MCPTool[], handlers: Map<string, ToolHandler>): void;

Bulk-register tools. Map keys must match tool names exactly.

server.registerResource(resource: MCPResource, handler: ResourceHandler): void;

Register a single resource. See MCP Apps for ui:// resources.

server.registerResources(
resources: MCPResource[],
handlers: Map<string, ResourceHandler>,
): void;

Bulk-register resources.

server.use(middleware: Middleware): this;

Add a custom middleware to the pipeline. Returns this for chaining:

server
.use(logging)
.use(metrics)
.use(caching);

See the Middleware Pipeline guide for patterns and recipes.

await server.start(): Promise<void>;

Start with STDIO transport. Use this for local tools (Claude Desktop, Cursor, etc.). Blocks until the server is stopped.

await server.startHttp(options: HttpServerOptions): Promise<void>;

Start with Streamable HTTP transport. Includes SSE streaming, session management, and RFC 9728 discovery.

interface HttpServerOptions {
port: number;
hostname?: string; // Default: "0.0.0.0"
}
await server.stop(): Promise<void>;

Graceful shutdown. Waits for in-flight requests to complete before closing.

server.getMetrics(): QueueMetrics;
// { inFlight: number, queued: number }
server.getRateLimitMetrics(): { keys: number, totalRequests: number } | null;

Returns null if rate limiting is not configured.

server.getToolCount(): number;
server.getToolNames(): string[];
server.getResourceCount(): number;
server.getResourceUris(): string[];
server.sendToSession(sessionId: string, message: Record<string, unknown>): void;

Push a message to a specific SSE session.

server.broadcastNotification(
method: string,
params?: Record<string, unknown>,
): void;

Push a notification to all connected SSE clients.

server.getSSEClientCount(): number;