Skip to content

Latest commit

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

@futurity/plugins

A minimal MCP (Model Context Protocol) server library for Bun with auth forwarding support.

Quick Start

Create a new plugin

bun create futurity-plugin my-plugin
cd my-plugin
bun run src/index.ts

Or add to an existing project

bun add @futurity/plugins

Basic usage

import{mcp,t}from"@futurity/plugins";constapp=mcp({name: "my-plugin",version: "1.0.0",});app.tool("hello",{description: "Say hello",input: t.obj({name: t.str}),handler: async({ name })=>({greeting: `Hello, ${name}!`,}),});// Option A: Use the fetch handler (works in any runtime)Bun.serve({port: 3000,fetch: app.fetch});// Option B: Convenience method (Bun only)awaitapp.listen(3000);

Note: The WebSocket transport (app.listen(port, "websocket")) is Bun-only. The HTTP transport (app.fetch) works in any runtime that supports the Fetch API.

API

mcp(options)

Create an MCP application.

constapp=mcp({name: "my-server",// requiredversion: "1.0.0",// requiredpath: "/mcp",// default: "/mcp"instructions: "...",// optional system instructionscapabilities: { ... },// optional MCP capabilitiespluginManifest: { ... },// optional auth forwarding manifest});

app.tool(name, options)

Register a tool.

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

Tools without input:

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

app.resource(uri, options)

Register a resource.

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

app.use(plugin)

Apply a plugin.

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

app.middleware(fn)

Add middleware directly.

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

app.fetch

The standard Fetch API handler. Works in any runtime (Bun, Deno, Cloudflare Workers, Node with a fetch-compatible adapter, etc.):

Bun.serve({port: 3000,fetch: app.fetch});

app.listen(port, transport?) (Bun only)

Convenience method to start the server. Requires Bun.

// HTTP (default)awaitapp.listen(3000);// WebSocket (Bun only)awaitapp.listen(3000,"websocket");

CORS

import{mcp,cors}from"@futurity/plugins";constapp=mcp({name: "server",version: "1.0.0"});app.use(cors({allowOrigin: "*",allowMethods: ["GET","POST","DELETE","OPTIONS"],allowHeaders: ["Content-Type","Authorization","Accept","Mcp-Session-Id"],exposeHeaders: ["Mcp-Session-Id"],maxAge: 86400,credentials: false,}));app.listen(3000);

OAuth

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

constapp=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"],},});

Authentication

There are two auth modes for Futurity plugins:

ModeDescriptionUse Case
Auth Forwarding (v1)Platform manages OAuth tokensSimple integrations
Chained Auth (v2)Plugin manages sessions & tokensComplex integrations, multi-service

Auth Forwarding (v1)

Auth forwarding lets the Futurity platform manage OAuth tokens on behalf of your plugin. Instead of implementing OAuth end-to-end, you declare your auth requirements in a signed manifest.

1. Generate a signing keypair

bun run keygen

This prints an Ed25519 keypair. Keep the private key secret; register the public key with the Futurity API.

2. Configure the plugin manifest

constapp=mcp({name: "my-plugin",version: "1.0.0",pluginManifest: {specVersion: 2,pluginId: "my-plugin",name: "My Plugin",version: "1.0.0",signingKey: process.env.FUTURITY_SIGNING_KEY!,auth: {type: "forwarding",tokenEndpoint: "https://auth.example.com/oauth2/token",authorizationEndpoint: "https://auth.example.com/oauth2/authorize",requiredScopes: ["read","write"],deliveryMethod: "header",// "header" (default) or "query"maxTokenTtl: 3600,// optional, seconds},mcpUrl: "https://my-plugin.example.com/mcp",},});

3. Serve the manifest

The signed manifest is automatically served at:

GET /.well-known/futurity/plugin

The response includes an X-Futurity-Signature header with an Ed25519 JWS signature.

Chained Auth (v2)

For plugins that need to manage their own sessions and store third-party tokens, use chained auth. The plugin controls the OAuth flow and issues its own tokens.

constapp=mcp({name: "my-plugin",version: "1.0.0",pluginManifest: {specVersion: 2,pluginId: "my-plugin",name: "My Plugin",version: "1.0.0",signingKey: process.env.PLUGIN_SIGNING_KEY!,auth: {type: "chained",authorizationEndpoint: "https://plugin.example.com/auth/authorize",callbackEndpoint: "https://plugin.example.com/auth/callback",tokenEndpoint: "https://plugin.example.com/auth/token",requiredUserContext: ["user_id","email"],},mcpUrl: "https://plugin.example.com/mcp",},chainedAuth: {sessionStore: mySessionStore,platformJwksUrl: "https://platform.example.com/.well-known/jwks.json",pluginSigningKey: process.env.PLUGIN_SIGNING_KEY!,handlers: {onAuthorize: async(userContext,platformState,platformCallback)=>{ ... },onCallback: async(req)=>{ ... },onToken: async(req)=>{ ... },},},});

See docs/chained-auth.md for full documentation including:

  • Complete implementation guide
  • Request binding for anti-replay protection
  • Session management
  • Platform integration guide

Signing utilities

import{generateKeyPair,signPayload,verifyPayload}from"@futurity/plugins";const{ privateKey, publicKey }=generateKeyPair();constjws=signPayload('{"hello":"world"}',privateKey);constvalid=verifyPayload('{"hello":"world"}',jws,publicKey);// true

Authentication

Custom auth middleware:

constapp=mcp({name: "server",version: "1.0.0",auth: async(req)=>{consttoken=req.headers.get("authorization")?.replace("Bearer ","");if(!token)returnfalse;returnawaitvalidateToken(token);},});

Stateful Patterns

conststate={counter: 0,items: newMap<string,string>(),};app.tool("increment",{handler: async()=>{state.counter++;return{counter: state.counter};},});app.tool("set",{input: z.object({key: z.string(),value: z.string()}),handler: async({ key, value })=>{state.items.set(key,value);return{ key, value };},});

Multi-Session Support

The HTTP transport supports multiple concurrent client sessions.

constapp=mcp({name: "server",version: "1.0.0"});app.tool("example",{handler: async()=>({ok: true})});awaitapp.listen(3000);console.log(app.activeSessions);awaitapp.stop();

Direct Transport Usage

import{StreamableHttpServer,StreamableHttpTransport}from"@futurity/plugins";import{McpServer}from"@modelcontextprotocol/sdk/server/mcp.js";constserver=newStreamableHttpServer({port: 3000,path: "/mcp",onSession: async(transport: StreamableHttpTransport)=>{constmcp=newMcpServer({name: "server",version: "1.0.0"});awaitmcp.connect(transport);},});awaitserver.start();

Examples

The examples/ directory in this repo contains runnable examples. Clone the repo and run them directly:

git clone https://github.com/futuritywork/plugins.git
cd plugins
bun examples/calculator.ts # Math operations and unit conversion
bun examples/cors.ts # CORS configuration
bun examples/database.ts # Document database
bun examples/filesystem.ts # Virtual filesystem
bun examples/oauth.ts # OAuth metadata
bun examples/stateful.ts # Counter, notes, key-value store
bun examples/todo-app.ts # Todo list with CRUD
bun examples/weather-api.ts # Weather data API
bun examples/monday/index.ts # monday.com integration with auth forwarding

monday.com Integration Example

A complete monday.com MCP server is included demonstrating auth forwarding:

# Set environment variablesexport FUTURITY_SIGNING_KEY="your-private-key-base64"# Run the server
bun examples/monday/index.ts

Features:

  • Boards: List and get board details
  • Items: Full CRUD operations
  • Updates: Read and create comments
  • Groups: Create new groups

Types

importtype{// AppMcpApp,McpAppOptions,ToolOptions,ResourceOptions,Middleware,AuthMiddleware,WellKnownEntry,// Plugin ManifestPluginManifest,PluginManifestOptions,Auth,AuthForwarding,ChainedAuth,// Chained AuthSession,PendingSession,SessionStore,UserContext,ChainedAuthConfig,ChainedAuthHandlers,PlatformAssertionClaims,VerifiedPlatformAssertion,// TransportsStreamableHttpServer,StreamableHttpServerOptions,StreamableHttpTransport,WebSocketTransport,WebSocketTransportOptions,}from"@futurity/plugins";

Chained Auth Utilities

import{// Session managementcreatePendingSession,activateSession,expireSession,revokeSession,isSessionValid,InMemorySessionStore,// Token generationgeneratePluginToken,validatePluginToken,generateRefreshToken,// State managementgenerateChainedState,parseChainedState,// Request bindinghashPluginToken,hashRequest,validatePlatformAssertion,validateAuthenticatedRequest,// JWT validationvalidateUserContextJwt,clearJwksCache,}from"@futurity/plugins";

License

Copyright © 2025 Futurity Technologies Pte Ltd

This software is licensed under the Business Source License 1.1 (BSL). You may use, copy, modify, and redistribute for non-production purposes. Production use requires a commercial license until the Change Date (2030-01-01), after which the software becomes available under the GNU General Public License v3.0 or later.

See LICENSE for full terms.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages