@phake/mcp
v0.3.7
Published
A TypeScript library for building [MCP (Model Context Protocol)](https://modelcontextprotocol.io) servers - works on both Cloudflare Workers and Node.js.
Readme
@phake/mcp
A TypeScript library for building MCP (Model Context Protocol) servers - works on both Cloudflare Workers and Node.js.
Why @phake/mcp?
- Multiple auth strategies: OAuth 2.1, Google/GitHub presets, Bearer, API Key, Custom headers
- Encrypted token storage: AES-256-GCM at rest + proactive refresh
- Cloudflare Workers native: KV storage, memory fallback, zero config
- Production-ready: CIMD validation, OAuth discovery, DNS rebinding protection
- Quick scaffold:
bun create @phake/mcpto get started
See Comparison Guide for full feature comparison with official SDK.
Requirements
- Bun 1.x or Node.js 20+
- Wrangler CLI (for Cloudflare Workers deployments)
- A Cloudflare account with Workers and KV access (for Worker deployments)
Installation
bun add @phake/mcp
# or
npm install @phake/mcpQuick Start (Scaffold)
Scaffold a new MCP server with one command:
# Interactive (prompts for template)
bun create @phake/mcp
# With options
bun create @phake/mcp my-mcp-app --template cloudflare-workers --installAvailable templates:
| Template | Description |
|----------|-------------|
| cloudflare-workers | Cloudflare Workers + Hono (default) |
| cloudflare-workers-google | Cloudflare Workers + Google OAuth |
| node-hono | Node.js + Bun + Hono |
Options:
| Option | Description |
|--------|-------------|
| -t, --template | Template name |
| -i, --install | Auto install dependencies |
| -p, --pm | Package manager: npm, bun, yarn, pnpm |
Getting Started
1. Create the KV namespace
wrangler kv namespace create TOKENS2. Bind it in your Wrangler config
wrangler.toml
[[kv_namespaces]]
binding = "TOKENS"
id = "<your-kv-namespace-id>"3. Generate an encryption key
openssl rand -base64 32 | tr '+/' '-_' | tr -d '='4. Set the encryption key
Production:
wrangler secret put RS_TOKENS_ENC_KEYLocal development - add to .dev.vars:
RS_TOKENS_ENC_KEY=<your-generated-key>5. Create your Worker
import { createMCPServer } from "@phake/mcp";
const server = createMCPServer({
adapter: "worker",
tools: [/* your tools */],
});
export default server;For detailed setup, see Getting Started Guide.
Usage
Defining Tools
import { z } from "zod";
import { defineTool } from "@phake/mcp";
const greetTool = defineTool({
name: "greet",
description: "Returns a greeting for the given name",
inputSchema: z.object({
name: z.string().describe("Name to greet"),
}),
outputSchema: z.object({
message: z.string().describe("The greeting message"),
}),
handler: async (args) => {
return { message: `Hello, ${args.name}!` };
},
});Authenticated Tools
const profileTool = defineTool({
name: "get_profile",
description: "Fetch the authenticated user's profile",
inputSchema: z.object({}),
requiresAuth: true,
handler: async (_args, context) => {
const response = await fetch("https://api.example.com/me", {
headers: context.resolvedHeaders,
});
return await response.json();
},
});Cloudflare Bindings
Access Cloudflare worker bindings (AI, Vectorize, D1, R2, KV, etc.) in your tools:
import { createMCPServer, defineTool, type ToolContext } from "@phake/mcp";
interface Env extends Cloudflare.Env {
AI: unknown;
VECTORIZE: unknown;
MY_BUCKET: unknown;
}
const searchTool = defineTool({
name: "search_vectors",
inputSchema: z.object({ query: z.string() }),
handler: async (args, context: ToolContext<Env>) => {
// Type-safe access to bindings
const ai = context.bindings?.AI;
const vectorize = context.bindings?.VECTORIZE;
return {
content: [{
type: "text",
text: `AI: ${!!ai}, Vectorize: ${!!vectorize}`
}]
};
},
});
const server = createMCPServer<Env>({
tools: [searchTool],
});Getting User Info (OAuth)
Fetch user profile from OAuth providers using context.getUser():
const userTool = defineTool({
name: "get_user_info",
requiresAuth: true,
inputSchema: z.object({}),
handler: async (_, context) => {
// Get token with error handling
const { data: token, error: tokenError } = context.getToken();
if (tokenError || !token) {
return { content: [{ type: "text", text: tokenError }], isError: true };
}
// Get user info with error handling
const { data, error } = await context.getUser();
if (error || !data) {
return { content: [{ type: "text", text: error }], isError: true };
}
return {
content: [{
type: "text",
text: JSON.stringify({ email: data.email, name: data.name })
}]
};
},
});The getUser() method automatically detects the provider based on AUTH_STRATEGY:
google→https://www.googleapis.com/oauth2/v2/userinfogithub→https://api.github.com/user
Authentication Strategies
| Strategy | Description |
|----------|-------------|
| oauth | Full OAuth 2.1 PKCE flow with RS token => provider token mapping |
| google | Same as OAuth with Google preset endpoints |
| github | Same as OAuth with GitHub preset endpoints |
| bearer | Static Bearer token |
| api_key | Static API key via header |
| custom | Arbitrary custom headers |
| none | No authentication |
See Authentication Guide for detailed configuration.
API Reference
createMCPServer(options)
Creates an MCP server instance.
const server = createMCPServer({
adapter: "worker",
tools: [greetTool, profileTool],
});defineTool(def)
Type-safe tool factory. See API Reference for the full field reference.
toolFail(defaults)
Creates a typed error factory with preset default fields:
const fail = toolFail({ ok: false, items: null });
return fail("spreadsheet_id is required");
// => { ok: false, items: null, error: "spreadsheet_id is required" }Built-in Tools
| Tool | Input | Output | Description |
|------|-------|--------|-------------|
| echo | { message, uppercase? } | { echoed, length } | Echoes back a message |
| health | { verbose? } | { status, timestamp, runtime, uptime? } | Reports server health |
Package Exports
| Export | Path | Description |
|--------|------|-------------|
| Core | @phake/mcp | defineTool, createMCPServer, helpers |
| Worker runtime | @phake/mcp/runtime/worker | Cloudflare Workers adapter |
| Node runtime | @phake/mcp/runtime/node | Node.js adapter (experimental) |
Contributing
# Install dependencies
bun install
# Run tests
bun test
# Type check
bun run typecheck
# Build
bun run build