Skip to main content
The main class for building MCP servers with Skybridge.

Import

import { McpServer } from "skybridge/server";

Constructor

const server = new McpServer(
  serverInfo: { name: string; version: string },
  options: McpServerOptions
);

Parameters

ParameterTypeDescription
serverInfo.namestringName of your MCP server
serverInfo.versionstringVersion of your server
optionsMcpServerOptionsConfiguration options

Options

type McpServerOptions = {
  // Additional options as needed
};

Methods

registerWidget

Register an interactive widget with UI. See registerWidget for details.
server.registerWidget(name, resourceConfig, toolConfig, handler);

registerTool

Register a tool without UI (inherited from MCP SDK).
server.registerTool(name, config, handler);

use

Register Express middleware on the underlying HTTP server. Supports optional path filtering.
// Global middleware
server.use(cors());

// Path-scoped middleware
server.use("/api", authMiddleware);

mcpMiddleware

Register MCP protocol-level middleware using an onion model. Middleware wraps request/notification handlers and can inspect, modify, or short-circuit them. Must be registered before calling server.run() or server.connect().
server.mcpMiddleware(handler);
server.mcpMiddleware(filter, handler);

Parameters

ParameterTypeDescription
filterMcpMiddlewareFilterOptional. Determines which methods the middleware applies to. Omit for catch-all.
handlerMcpMiddlewareFnThe middleware function. Call next() to continue the chain.

Filter patterns

PatternExampleMatches
Exact method"tools/call"Only tools/call
Wildcard"tools/*"Any method starting with tools/
Category"request"All requests (with extra context)
Category"notification"All notifications (extra is undefined)
Array["tools/call", "resources/read"]Multiple patterns (OR logic)

Middleware signature

type McpMiddlewareFn = (
  request: { method: string; params: Record<string, unknown> },
  extra: McpExtra | undefined,
  next: () => Promise<unknown>,
) => Promise<unknown> | unknown;
  • request — the incoming MCP request with method and params
  • extra — SDK context (McpExtra) for requests, undefined for notifications
  • next() — invoke the next middleware or original handler. Can only be called once per middleware.

Type-safe filters

When using an exact method string, both params and extra are narrowed automatically:
server.mcpMiddleware("tools/call", (request, extra, next) => {
  // request.params is typed as CallToolRequest["params"]
  // extra is typed as McpExtra (not undefined)
  console.log(`Tool called: ${request.params.name}`);
  return next();
});

Examples

Logging all requests:
server.mcpMiddleware("request", (request, extra, next) => {
  console.log(`[MCP] ${request.method}`, request.params);
  return next();
});
Auth guard on tool calls:
server.mcpMiddleware("tools/call", async (request, extra, next) => {
  const token = extra.requestInfo?.headers?.["authorization"];
  if (!token) {
    throw new Error("Unauthorized");
  }
  return next();
});
Modifying params:
server.mcpMiddleware("tools/call", (request, extra, next) => {
  request.params = { ...request.params, injectedAt: Date.now() };
  return next();
});
Multiple middleware (onion order):
const server = new McpServer({ name: "my-app", version: "1.0" }, {})
  .mcpMiddleware((request, extra, next) => {
    console.log("outer: before");
    const result = await next();
    console.log("outer: after");
    return result;
  })
  .mcpMiddleware((request, extra, next) => {
    console.log("inner: before");
    return next();
  });
// Logs: outer: before → inner: before → handler → outer: after

Type Export Pattern

Export the server type for client-side type inference:
const server = new McpServer({ name: "my-app", version: "1.0" }, {})
  .registerWidget("search", {}, { inputSchema: { query: z.string() } }, async ({ query }) => {
    return { structuredContent: { results: [] } };
  });

// Export for generateHelpers
export type AppType = typeof server;

Method Chaining

You must use method chaining for type inference to work. See Type Safety: Method Chaining for details.

Example

import { McpServer } from "skybridge/server";
import { z } from "zod";

const server = new McpServer(
  { name: "hotel-booking", version: "1.0.0" },
  {}
)
  .registerWidget("search-hotels", {
    description: "Search for hotels",
  }, {
    inputSchema: {
      city: z.string().describe("City to search"),
      checkIn: z.string().describe("Check-in date"),
      checkOut: z.string().describe("Check-out date"),
      guests: z.number().optional().default(2),
    },
    outputSchema: {
      hotels: z.array(z.object({
        id: z.string(),
        name: z.string(),
        price: z.number(),
        rating: z.number(),
      })),
    },
  }, async ({ city, checkIn, checkOut, guests }) => {
    const hotels = await searchHotels({ city, checkIn, checkOut, guests });

    return {
      content: [{ type: "text", text: `Found ${hotels.length} hotels in ${city}` }],
      structuredContent: { hotels },
    };
  })
  .registerWidget("hotel-details", {
    description: "Get hotel details",
  }, {
    inputSchema: {
      hotelId: z.string(),
    },
  }, async ({ hotelId }) => {
    const hotel = await getHotel(hotelId);

    return {
      content: [{ type: "text", text: `Showing details for ${hotel.name}` }],
      structuredContent: hotel,
    };
  });

export type AppType = typeof server;
export default server;

Exported Types

The following middleware types are available from skybridge/server:
import type {
  McpExtra,
  McpMiddlewareFn,
  McpMiddlewareFilter,
  McpTypedMiddlewareFn,
  McpMethodString,
} from "skybridge/server";