Skip to content

futurity-mcp Library

futurity-mcp is a minimal MCP (Model Context Protocol) server library for Bun, making it easy to build custom integrations for Futurity.

Terminal window
bun add futurity-mcp
import { z } from "zod";
import { mcp } from "futurity-mcp";
const app = mcp({
name: "my-server",
version: "1.0.0",
});
app.tool("greet", {
description: "Greet a user",
input: z.object({
name: z.string(),
}),
handler: async ({ name }) => {
return { message: `Hello, ${name}!` };
},
});
app.listen(3000);

Run it:

3000/mcp
bun run server.ts

Create an MCP application.

const app = mcp({
name: "my-server", // required
version: "1.0.0", // required
path: "/mcp", // default: "/mcp"
instructions: "...", // optional system instructions
capabilities: { ... }, // optional MCP capabilities
});

Options:

OptionTypeRequiredDescription
namestringYesServer name
versionstringYesServer version
pathstringNoMCP endpoint path (default: /mcp)
instructionsstringNoSystem instructions for AI
capabilitiesobjectNoMCP capabilities config
oauthobjectNoOAuth configuration
authfunctionNoAuthentication middleware

Register a tool that Corint can use.

app.tool("add", {
description: "Add two numbers",
input: z.object({
a: z.number(),
b: z.number(),
}),
handler: async ({ a, b }) => {
return { sum: a + b };
},
});

Options:

OptionTypeRequiredDescription
descriptionstringYesWhat the tool does
inputZodSchemaNoInput validation schema
handlerfunctionYesImplementation

Tool without input:

app.tool("ping", {
description: "Health check",
handler: async () => {
return { status: "ok" };
},
});

Register a resource that provides data.

app.resource("config://settings", {
description: "Application settings",
fetch: async () => {
return { theme: "dark", language: "en" };
},
});

Options:

OptionTypeRequiredDescription
descriptionstringYesWhat the resource provides
fetchfunctionYesReturns resource data

Apply a plugin to the app.

import { cors } from "futurity-mcp";
app.use(
cors({
allowOrigin: "*",
allowMethods: ["GET", "POST", "DELETE", "OPTIONS"],
})
);

Add middleware directly.

app.middleware(async (req, next) => {
console.log(`${req.method} ${req.url}`);
return next(req);
});

Start the server.

// HTTP (default)
await app.listen(3000);
// WebSocket
await app.listen(3000, "websocket");

Stop the server.

await app.stop();

Get count of active sessions (HTTP transport).

console.log(app.activeSessions); // e.g., 5
import { mcp, cors } from "futurity-mcp";
const app = mcp({ name: "server", version: "1.0.0" });
app.use(
cors({
allowOrigin: "*", // or specific origin
allowMethods: ["GET", "POST", "DELETE", "OPTIONS"],
allowHeaders: ["Content-Type", "Authorization", "Accept", "Mcp-Session-Id"],
exposeHeaders: ["Mcp-Session-Id"],
maxAge: 86400,
credentials: false,
})
);
app.listen(3000);

Configure OAuth metadata for /.well-known/oauth-authorization-server:

const app = mcp({
name: "server",
version: "1.0.0",
oauth: {
issuer: "https://auth.example.com",
authorizationEndpoint: "https://auth.example.com/oauth/authorize",
tokenEndpoint: "https://auth.example.com/oauth/token",
jwksUri: "https://auth.example.com/.well-known/jwks.json",
scopesSupported: ["openid", "profile"],
},
});
const app = mcp({
name: "server",
version: "1.0.0",
auth: async (req) => {
const token = req.headers.get("authorization")?.replace("Bearer ", "");
if (!token) return false;
return await validateToken(token);
},
});

State is shared across all sessions:

const state = {
counter: 0,
items: new Map<string, string>(),
};
app.tool("increment", {
description: "Increment the counter",
handler: async () => {
state.counter++;
return { counter: state.counter };
},
});
app.tool("set", {
description: "Set a key-value pair",
input: z.object({ key: z.string(), value: z.string() }),
handler: async ({ key, value }) => {
state.items.set(key, value);
return { key, value };
},
});
app.tool("get", {
description: "Get a value by key",
input: z.object({ key: z.string() }),
handler: async ({ key }) => {
return { value: state.items.get(key) ?? null };
},
});

The HTTP transport supports multiple concurrent client sessions:

const app = mcp({ name: "server", version: "1.0.0" });
// Tools and resources are registered once, replicated per session
app.tool("example", {
description: "Example tool",
handler: async () => ({ ok: true })
});
await app.listen(3000);
// Check active sessions
console.log(app.activeSessions);
// Stop server
await app.stop();

For advanced use cases, use transports directly:

import { StreamableHttpServer, StreamableHttpTransport } from "futurity-mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new StreamableHttpServer({
port: 3000,
path: "/mcp",
onSession: async (transport: StreamableHttpTransport) => {
const mcp = new McpServer({ name: "server", version: "1.0.0" });
// register tools on mcp...
await mcp.connect(transport);
},
});
await server.start();
import type {
McpApp,
McpAppOptions,
ToolOptions,
ResourceOptions,
Middleware,
AuthMiddleware,
StreamableHttpServer,
StreamableHttpServerOptions,
StreamableHttpTransport,
WebSocketTransport,
WebSocketTransportOptions,
} from "futurity-mcp";

Use the discovery CLI to test your implementation:

Terminal window
bun run discover http://localhost:3000/mcp