Skybridge is the root of your app: one config object that names your server, wires OAuth, and registers your tools through a handler. It runs an Express-backed HTTP server that serves MCP at /mcp, and you export its type for generateHelpers.
Example
The app registers one tool and exports its type for the typed client hooks. A separate entry file runs it.server.ts and the run() call in index.ts lets tests and evals import the app without starting a server.
Constructor
config merges the MCP implementation info, the SDK’s ServerOptions, and Skybridge’s own fields. Every type is inferred from it: the config passed to handler from setup, the auth claims from oauth, and the tool registry from what handler returns.
name, version
The MCP implementation info (name, version, and optionally title, description, icons, websiteUrl). SDK ServerOptions such as instructions or capabilities are forwarded when you set them; registering tools and views advertises those capabilities for you.
icons is the app’s icon, a standard MCP field. Hosts choose whether and where to show it. Tools can carry their own icons too.
handler
Receives a fresh McpServer and must return the chain of registrations. That return value is what carries your tool types into typeof app.
The handler runs for every request, so keep it to registration. Anything else in its body (a connection pool, a timer, a file read) runs per request too: move it into setup, whose result is the handler’s second argument. Skybridge warns once in the console when a handler takes more than 50ms. The handler must stay synchronous.
setup
Loads what the app needs before it serves: a connection pool, a client, remote config, secrets. It runs once, at run() or on the first request, never when the module is imported. Its awaited result is passed to handler as the second argument, and to oauth when oauth is a function.
src/server.ts
oauth
An identity provider (oauth: workosProvider({ ... })), a raw OAuthConfig, or a function of the setup result returning either. Providers defer discovery: nothing runs at module import, the network call happens once at run(). When set, it mounts the well-known OAuth metadata and bearer-token verification on /mcp.
The config also carries the claim shape its verifier produces, so handlers read extra.http.authInfo.extra typed, with no declaration of their own. See Type the Claims You Read.
json
Options for the express.json() parser Skybridge pre-applies, for example to raise the default 100kb body-size limit.
skills
Set to true to serve Agent Skills over MCP from src/skills and declare the io.modelcontextprotocol/skills capability.
Skills over MCP tracks SEP-2640, which is still under review. The feature is experimental and may change with the spec.
onMcpError
Replaces the error reporter of the built-in /mcp handler. By default, Skybridge logs each error that the MCP SDK handler reports, except UnsupportedProtocolVersionError. The log line is console.error("Error handling MCP request:", error).
When you set onMcpError, it receives every error that the MCP SDK handler or its Node adapter reports. This includes:
- Requests the SDK rejects before any tool runs, such as an unsupported protocol version or a malformed header.
- Failures to build or serve the per-request server.
UnsupportedProtocolVersionError also reaches your function, because the skip belongs to the default reporter. Filter it yourself if you do not want it.
Node adapter errors, such as a request after the handler is closed, reach only onMcpError. The default reporter does not log them.
The option only reports. It does not change the response. It can run before the response is sent, so keep it fast and synchronous. Skybridge does not await a returned promise, so a rejected promise is an unhandled rejection, which ends the process by default in Node. An error that the function throws is dropped.
Other errors go elsewhere:
- Tool errors are valid MCP results. Read them with
getToolError. - Express errors on
/mcpgo to youruseOnErrorhandlers, then to the default Express handler. That handler also logs them.
src/server.ts
Properties
express
The underlying Express app, for custom routes, middleware, and settings. Register handlers before run().
Alpic Cloud routes traffic only to
/mcp. Custom routes work locally and on self-hosted deployments.Methods
use and useOnError return the app, so calls chain.
use
app.use.
useOnError
/mcp route. A default handler runs last, responding with a 500 JSON-RPC error when nothing else has sent a response.
run
setup and oauth, applies your middleware, mounts /mcp, and listens (default port 3000). On serverless platforms, export what it returns so the platform can route requests to it. See Deploy for the per-platform setup.
connect
run() sets the transport up for you.
McpServer
The server your handler registers tools on
registerTool
Define the tools and views the app exposes
generateHelpers
Turn
AppType into typed client hooks