@phake/mcp 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -148
- package/dist/index-zhw318hb.js +3149 -0
- package/dist/index.js +5 -5
- package/dist/mcp-server.d.ts +4 -0
- package/dist/runtime/worker/index.js +1 -1
- package/dist/shared/utils/elicitation.d.ts +1 -1
- package/package.json +3 -5
- package/dist/index-1zv84kf7.js +0 -22961
package/README.md
CHANGED
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
# @phake/mcp
|
|
2
2
|
|
|
3
|
-
A TypeScript library for building MCP (Model Context Protocol) servers
|
|
3
|
+
A TypeScript library for building [MCP (Model Context Protocol)](https://modelcontextprotocol.io) servers on Cloudflare Workers.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@phake/mcp)
|
|
6
|
+
[](LICENSE)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
---
|
|
8
9
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
10
|
+
- [Requirements](#requirements)
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Getting Started](#getting-started)
|
|
13
|
+
- [Usage](#usage)
|
|
14
|
+
- [Defining Tools](#defining-tools)
|
|
15
|
+
- [Authenticated Tools](#authenticated-tools)
|
|
16
|
+
- [Authentication Strategies](#authentication-strategies)
|
|
17
|
+
- [Storage Backends](#storage-backends)
|
|
18
|
+
- [API Reference](#api-reference)
|
|
19
|
+
- [Endpoints](#endpoints)
|
|
20
|
+
- [Configuration](#configuration)
|
|
21
|
+
- [Contributing](#contributing)
|
|
22
|
+
- [License](#license)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- [Bun](https://bun.sh) or Node.js 20+
|
|
29
|
+
- [Wrangler](https://developers.cloudflare.com/workers/wrangler/) CLI
|
|
30
|
+
- A Cloudflare account with Workers and KV access
|
|
17
31
|
|
|
18
32
|
## Installation
|
|
19
33
|
|
|
@@ -21,80 +35,84 @@ A TypeScript library for building MCP (Model Context Protocol) servers, designed
|
|
|
21
35
|
bun add @phake/mcp
|
|
22
36
|
```
|
|
23
37
|
|
|
24
|
-
##
|
|
38
|
+
## Getting Started
|
|
25
39
|
|
|
26
|
-
###
|
|
40
|
+
### 1. Create the KV namespace
|
|
27
41
|
|
|
28
|
-
```
|
|
29
|
-
|
|
42
|
+
```bash
|
|
43
|
+
wrangler kv namespace create TOKENS
|
|
44
|
+
```
|
|
30
45
|
|
|
31
|
-
|
|
32
|
-
adapter: "worker",
|
|
33
|
-
tools: [
|
|
34
|
-
// your tool definitions
|
|
35
|
-
],
|
|
36
|
-
});
|
|
46
|
+
### 2. Bind it in your Wrangler config
|
|
37
47
|
|
|
38
|
-
|
|
48
|
+
Use the namespace ID printed in the previous step.
|
|
49
|
+
|
|
50
|
+
`wrangler.toml`
|
|
51
|
+
```toml
|
|
52
|
+
[[kv_namespaces]]
|
|
53
|
+
binding = "TOKENS"
|
|
54
|
+
id = "<your-kv-namespace-id>"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`wrangler.jsonc`
|
|
58
|
+
```jsonc
|
|
59
|
+
{
|
|
60
|
+
"kv_namespaces": [
|
|
61
|
+
{
|
|
62
|
+
"binding": "TOKENS",
|
|
63
|
+
"id": "<your-kv-namespace-id>"
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
39
67
|
```
|
|
40
68
|
|
|
41
|
-
###
|
|
69
|
+
### 3. Generate an encryption key
|
|
42
70
|
|
|
43
|
-
|
|
44
|
-
import { createHttpApp, createAuthApp } from "@phake/mcp/runtime/node";
|
|
71
|
+
Tokens at rest are encrypted with AES-256-GCM. Generate a 32-byte key:
|
|
45
72
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
],
|
|
50
|
-
});
|
|
73
|
+
```bash
|
|
74
|
+
# OpenSSL
|
|
75
|
+
openssl rand -base64 32 | tr '+/' '-_' | tr -d '='
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
# Node.js
|
|
78
|
+
node -e "const {randomBytes}=require('crypto'); console.log(randomBytes(32).toString('base64url'))"
|
|
53
79
|
```
|
|
54
80
|
|
|
55
|
-
|
|
81
|
+
### 4. Set the encryption key
|
|
56
82
|
|
|
57
|
-
|
|
83
|
+
**Production** - add as a Wrangler secret:
|
|
58
84
|
|
|
59
|
-
|
|
85
|
+
```bash
|
|
86
|
+
wrangler secret put RS_TOKENS_ENC_KEY
|
|
87
|
+
# paste the generated key when prompted
|
|
88
|
+
```
|
|
60
89
|
|
|
61
|
-
|
|
62
|
-
|--------|------|-------------|
|
|
63
|
-
| `adapter` | `"worker" \| "node"` | Runtime adapter |
|
|
64
|
-
| `tools` | `SharedToolDefinition[]` | Array of tool definitions to register |
|
|
90
|
+
**Local development** - add to `.dev.vars`:
|
|
65
91
|
|
|
66
|
-
|
|
92
|
+
```ini
|
|
93
|
+
RS_TOKENS_ENC_KEY=<your-generated-key>
|
|
94
|
+
```
|
|
67
95
|
|
|
68
|
-
|
|
69
|
-
|--------|------|
|
|
70
|
-
| Core | `@phake/mcp` |
|
|
71
|
-
| Node runtime | `@phake/mcp/runtime/node` |
|
|
72
|
-
| Worker runtime | `@phake/mcp/runtime/worker` |
|
|
96
|
+
### 5. Create your Worker
|
|
73
97
|
|
|
74
|
-
|
|
98
|
+
```typescript
|
|
99
|
+
import { createMCPServer } from "@phake/mcp";
|
|
75
100
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
| `none` | No authentication required | - |
|
|
101
|
+
const server = createMCPServer({
|
|
102
|
+
adapter: "worker",
|
|
103
|
+
tools: [
|
|
104
|
+
// your tool definitions
|
|
105
|
+
],
|
|
106
|
+
});
|
|
83
107
|
|
|
84
|
-
|
|
108
|
+
export default server;
|
|
109
|
+
```
|
|
85
110
|
|
|
86
|
-
|
|
87
|
-
|---------|--------|--------------|
|
|
88
|
-
| `MemoryTokenStore` | Tokens, transactions, codes | TTL expiration, size limits (10K tokens), LRU eviction |
|
|
89
|
-
| `MemorySessionStore` | Sessions | TTL (24h), size limit (10K), per-API-key limits (5) |
|
|
90
|
-
| `KvTokenStore` | Tokens, transactions, codes | Cloudflare KV + memory fallback, AES-256-GCM encryption |
|
|
91
|
-
| `KvSessionStore` | Sessions | Cloudflare KV + memory fallback, encryption, API-key indexing |
|
|
92
|
-
| `FileTokenStore` | RS token mappings | JSON file persistence, AES-256-GCM encryption, secure permissions (0600) |
|
|
93
|
-
| `SqliteSessionStore` | Sessions | SQLite via better-sqlite3 + Drizzle ORM, WAL mode, atomic transactions |
|
|
111
|
+
## Usage
|
|
94
112
|
|
|
95
|
-
|
|
113
|
+
### Defining Tools
|
|
96
114
|
|
|
97
|
-
Use `defineTool` to create a type-safe tool
|
|
115
|
+
Use `defineTool` to create a type-safe tool, then pass it to `createMCPServer`.
|
|
98
116
|
|
|
99
117
|
```typescript
|
|
100
118
|
import { z } from "zod";
|
|
@@ -125,14 +143,24 @@ const greetTool = defineTool({
|
|
|
125
143
|
});
|
|
126
144
|
```
|
|
127
145
|
|
|
146
|
+
**Tool definition fields:**
|
|
147
|
+
|
|
148
|
+
| Field | Type | Required | Description |
|
|
149
|
+
|-------|------|----------|-------------|
|
|
150
|
+
| `name` | `string` | Yes | Unique tool identifier |
|
|
151
|
+
| `description` | `string` | Yes | Description shown to the LLM |
|
|
152
|
+
| `inputSchema` | `ZodObject` | Yes | Zod schema for input validation |
|
|
153
|
+
| `outputSchema` | `ZodRawShape` | No | Zod schema for structured output |
|
|
154
|
+
| `handler` | `function` | Yes | `(args, context) => Promise<ToolResult>` |
|
|
155
|
+
| `requiresAuth` | `boolean` | No | Reject calls without a provider token |
|
|
156
|
+
| `title` | `string` | No | Human-readable display title |
|
|
157
|
+
| `annotations` | `object` | No | MCP hints (`readOnlyHint`, `destructiveHint`, etc.) |
|
|
158
|
+
|
|
128
159
|
### Authenticated Tools
|
|
129
160
|
|
|
130
|
-
Set `requiresAuth: true` to have the dispatcher automatically reject calls
|
|
161
|
+
Set `requiresAuth: true` to have the dispatcher automatically reject unauthenticated calls. Use `context.resolvedHeaders` to forward auth to external APIs.
|
|
131
162
|
|
|
132
163
|
```typescript
|
|
133
|
-
import { defineTool } from "@phake/mcp";
|
|
134
|
-
import { z } from "zod";
|
|
135
|
-
|
|
136
164
|
const profileTool = defineTool({
|
|
137
165
|
name: "get_profile",
|
|
138
166
|
description: "Fetch the authenticated user's profile",
|
|
@@ -150,7 +178,44 @@ const profileTool = defineTool({
|
|
|
150
178
|
});
|
|
151
179
|
```
|
|
152
180
|
|
|
153
|
-
|
|
181
|
+
**Available context properties:**
|
|
182
|
+
|
|
183
|
+
| Property | Description |
|
|
184
|
+
|----------|-------------|
|
|
185
|
+
| `sessionId` | Current MCP session ID |
|
|
186
|
+
| `providerToken` | Access token for external API calls |
|
|
187
|
+
| `resolvedHeaders` | Ready-to-use auth headers for `fetch` |
|
|
188
|
+
| `authStrategy` | Active auth strategy |
|
|
189
|
+
| `signal` | `AbortSignal` for cancellation |
|
|
190
|
+
|
|
191
|
+
### Authentication Strategies
|
|
192
|
+
|
|
193
|
+
Set `AUTH_STRATEGY` in your environment (or let it be inferred from which keys are present):
|
|
194
|
+
|
|
195
|
+
| Strategy | Description | Required env vars |
|
|
196
|
+
|----------|-------------|-------------------|
|
|
197
|
+
| `oauth` | Full OAuth 2.1 PKCE flow with RS token => provider token mapping | `OAUTH_CLIENT_ID`, `OAUTH_CLIENT_SECRET`, `OAUTH_SCOPES`, `OAUTH_REDIRECT_URI`, `PROVIDER_CLIENT_ID`, `PROVIDER_CLIENT_SECRET`, `PROVIDER_ACCOUNTS_URL` |
|
|
198
|
+
| `bearer` | Static Bearer token | `BEARER_TOKEN` |
|
|
199
|
+
| `api_key` | Static API key via header (default: `x-api-key`) | `API_KEY`, `API_KEY_HEADER` |
|
|
200
|
+
| `custom` | Arbitrary custom request headers | `CUSTOM_HEADERS` |
|
|
201
|
+
| `none` | No authentication | - |
|
|
202
|
+
|
|
203
|
+
### Storage Backends
|
|
204
|
+
|
|
205
|
+
| Backend | Use case | Notes |
|
|
206
|
+
|---------|----------|-------|
|
|
207
|
+
| `KvTokenStore` | Tokens, transactions, codes | Cloudflare KV + memory fallback, AES-256-GCM encryption |
|
|
208
|
+
| `KvSessionStore` | Sessions | Cloudflare KV + memory fallback, encryption, API-key indexing |
|
|
209
|
+
| `MemoryTokenStore` | Tokens, transactions, codes | TTL expiration, 10K token limit, LRU eviction |
|
|
210
|
+
| `MemorySessionStore` | Sessions | TTL (24h), 10K limit, per-API-key limit (5) |
|
|
211
|
+
| `FileTokenStore` | RS token mappings | File persistence, AES-256-GCM - **experimental** |
|
|
212
|
+
| `SqliteSessionStore` | Sessions | SQLite + Drizzle ORM, WAL mode - **experimental** |
|
|
213
|
+
|
|
214
|
+
## API Reference
|
|
215
|
+
|
|
216
|
+
### `createMCPServer(options)`
|
|
217
|
+
|
|
218
|
+
Creates an MCP server instance.
|
|
154
219
|
|
|
155
220
|
```typescript
|
|
156
221
|
import { createMCPServer } from "@phake/mcp";
|
|
@@ -159,79 +224,34 @@ const server = createMCPServer({
|
|
|
159
224
|
adapter: "worker",
|
|
160
225
|
tools: [greetTool, profileTool],
|
|
161
226
|
});
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Tool Handler Reference
|
|
165
227
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
| `name` | `string` | Yes | Unique tool name |
|
|
169
|
-
| `description` | `string` | Yes | Description shown to the LLM |
|
|
170
|
-
| `inputSchema` | `ZodObject` | Yes | Zod schema for input validation |
|
|
171
|
-
| `outputSchema` | `ZodRawShape` | No | Zod schema for structured output |
|
|
172
|
-
| `handler` | `function` | Yes | `(args, context) => Promise<ToolResult>` |
|
|
173
|
-
| `requiresAuth` | `boolean` | No | Reject calls without a provider token |
|
|
174
|
-
| `title` | `string` | No | Human-readable display title |
|
|
175
|
-
| `annotations` | `object` | No | MCP hints (`readOnlyHint`, `destructiveHint`, etc.) |
|
|
176
|
-
|
|
177
|
-
The `context` object provides:
|
|
228
|
+
export default server;
|
|
229
|
+
```
|
|
178
230
|
|
|
179
|
-
|
|
|
180
|
-
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `resolvedHeaders` | Ready-to-use auth headers for `fetch` |
|
|
184
|
-
| `authStrategy` | Active auth strategy |
|
|
185
|
-
| `signal` | `AbortSignal` for cancellation |
|
|
231
|
+
| Option | Type | Description |
|
|
232
|
+
|--------|------|-------------|
|
|
233
|
+
| `adapter` | `"worker"` | Runtime adapter |
|
|
234
|
+
| `tools` | `SharedToolDefinition[]` | Tools to register |
|
|
186
235
|
|
|
187
|
-
|
|
236
|
+
### Built-in Tools
|
|
188
237
|
|
|
189
238
|
| Tool | Input | Output | Description |
|
|
190
239
|
|------|-------|--------|-------------|
|
|
191
|
-
| `echo` | `{ message, uppercase? }` | `{ echoed, length }` | Echoes back a message
|
|
192
|
-
| `health` | `{ verbose? }` | `{ status, timestamp, runtime, uptime? }` | Reports server health
|
|
240
|
+
| `echo` | `{ message, uppercase? }` | `{ echoed, length }` | Echoes back a message |
|
|
241
|
+
| `health` | `{ verbose? }` | `{ status, timestamp, runtime, uptime? }` | Reports server health |
|
|
193
242
|
|
|
194
|
-
|
|
243
|
+
### Package Exports
|
|
195
244
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
│ └── http-worker/ # Cloudflare Workers adapter (itty-router)
|
|
205
|
-
│ ├── index.ts
|
|
206
|
-
│ ├── mcp.handler.ts
|
|
207
|
-
│ ├── routes.discovery.ts
|
|
208
|
-
│ ├── routes.oauth.ts
|
|
209
|
-
│ └── security.ts
|
|
210
|
-
├── runtime/
|
|
211
|
-
│ └── node/
|
|
212
|
-
│ ├── capabilities.ts
|
|
213
|
-
│ ├── context.ts
|
|
214
|
-
│ ├── mcp.ts
|
|
215
|
-
│ └── storage/
|
|
216
|
-
│ ├── file.ts
|
|
217
|
-
│ └── sqlite.ts
|
|
218
|
-
├── shared/
|
|
219
|
-
│ ├── auth/ # Authentication strategies
|
|
220
|
-
│ ├── config/ # Environment configuration (40+ fields)
|
|
221
|
-
│ ├── crypto/ # AES-256-GCM utilities
|
|
222
|
-
│ ├── http/ # CORS, JSON-RPC responses
|
|
223
|
-
│ ├── mcp/ # Protocol dispatcher, security, server internals
|
|
224
|
-
│ ├── oauth/ # Full OAuth 2.0 implementation (PKCE, CIMD, discovery)
|
|
225
|
-
│ ├── services/ # HTTP client
|
|
226
|
-
│ ├── storage/ # Token/session store interfaces and implementations
|
|
227
|
-
│ ├── tools/ # Tool definitions, registry, execution
|
|
228
|
-
│ ├── types/ # Shared type definitions
|
|
229
|
-
│ └── utils/ # Base64, cancellation, logger, pagination, etc.
|
|
230
|
-
├── mcp-server.ts # Server factory
|
|
231
|
-
└── index.ts # Main entry point
|
|
232
|
-
```
|
|
245
|
+
| Export | Path |
|
|
246
|
+
|--------|------|
|
|
247
|
+
| Core | `@phake/mcp` |
|
|
248
|
+
| Worker runtime | `@phake/mcp/runtime/worker` |
|
|
249
|
+
|
|
250
|
+
> **Node.js runtime** (`@phake/mcp/runtime/node`) is available but experimental and untested.
|
|
251
|
+
|
|
252
|
+
## Endpoints
|
|
233
253
|
|
|
234
|
-
|
|
254
|
+
### MCP
|
|
235
255
|
|
|
236
256
|
| Method | Path | Description |
|
|
237
257
|
|--------|------|-------------|
|
|
@@ -240,7 +260,7 @@ src/
|
|
|
240
260
|
| `DELETE` | `/mcp` | Session termination |
|
|
241
261
|
| `GET` | `/health` | Health check |
|
|
242
262
|
|
|
243
|
-
|
|
263
|
+
### OAuth
|
|
244
264
|
|
|
245
265
|
| Path | Description |
|
|
246
266
|
|------|-------------|
|
|
@@ -253,27 +273,57 @@ src/
|
|
|
253
273
|
| `/revoke` | Token revocation |
|
|
254
274
|
| `/register` | Dynamic client registration |
|
|
255
275
|
|
|
256
|
-
##
|
|
276
|
+
## Configuration
|
|
257
277
|
|
|
258
|
-
|
|
259
|
-
|---------|-------------|
|
|
260
|
-
| `bun run build` | Build with Bun |
|
|
261
|
-
| `bun run typecheck` | Run TypeScript type checking |
|
|
278
|
+
All configuration is read from environment variables / Wrangler bindings.
|
|
262
279
|
|
|
263
|
-
|
|
280
|
+
| Variable | Required | Description |
|
|
281
|
+
|----------|----------|-------------|
|
|
282
|
+
| `TOKENS` | Yes | Cloudflare KV namespace binding for token/session storage |
|
|
283
|
+
| `RS_TOKENS_ENC_KEY` | Yes | Base64url-encoded 32-byte AES-256-GCM encryption key |
|
|
284
|
+
| `AUTH_STRATEGY` | No | `oauth` \| `bearer` \| `api_key` \| `custom` \| `none` (inferred if unset) |
|
|
285
|
+
| `OAUTH_CLIENT_ID` | OAuth only | OAuth client ID |
|
|
286
|
+
| `OAUTH_CLIENT_SECRET` | OAuth only | OAuth client secret |
|
|
287
|
+
| `OAUTH_SCOPES` | OAuth only | Space-separated OAuth scopes |
|
|
288
|
+
| `OAUTH_REDIRECT_URI` | OAuth only | Redirect URI after authorization |
|
|
289
|
+
| `API_KEY` | api_key only | Static API key value |
|
|
290
|
+
| `BEARER_TOKEN` | bearer only | Static Bearer token value |
|
|
291
|
+
| `BASE_URL` | No | Base URL override (for reverse proxies) |
|
|
292
|
+
| `LOG_LEVEL` | No | `debug` \| `info` \| `warning` \| `error` (default: `info`) |
|
|
264
293
|
|
|
265
|
-
|
|
266
|
-
- `zod` - Schema validation
|
|
267
|
-
- `jose` - JWT and JWS/JWE
|
|
268
|
-
- `oauth4webapi` - OAuth 2.0 for Web API
|
|
269
|
-
- `itty-router` - Lightweight router (Workers)
|
|
270
|
-
- `hono` / `@hono/node-server` - Node.js HTTP framework (optional)
|
|
271
|
-
- `drizzle-orm` / `better-sqlite3` - Database layer (optional)
|
|
294
|
+
## Contributing
|
|
272
295
|
|
|
273
|
-
|
|
296
|
+
```bash
|
|
297
|
+
# Install dependencies
|
|
298
|
+
bun install
|
|
299
|
+
|
|
300
|
+
# Build
|
|
301
|
+
bun run build
|
|
302
|
+
|
|
303
|
+
# Type check
|
|
304
|
+
bun run typecheck
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Project structure:**
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
src/
|
|
311
|
+
├── adapters/
|
|
312
|
+
│ └── http-worker/ # Cloudflare Workers adapter
|
|
313
|
+
├── shared/
|
|
314
|
+
│ ├── auth/ # Authentication strategies
|
|
315
|
+
│ ├── config/ # Environment configuration
|
|
316
|
+
│ ├── crypto/ # AES-256-GCM utilities
|
|
317
|
+
│ ├── mcp/ # Protocol dispatcher and server internals
|
|
318
|
+
│ ├── oauth/ # OAuth 2.0 (PKCE, CIMD, discovery)
|
|
319
|
+
│ ├── storage/ # Token/session store interfaces and implementations
|
|
320
|
+
│ └── tools/ # Tool definitions, registry, execution
|
|
321
|
+
├── mcp-server.ts # Server factory
|
|
322
|
+
└── index.ts # Package entry point
|
|
323
|
+
```
|
|
274
324
|
|
|
275
|
-
|
|
325
|
+
Inspired by [streamable-mcp-server-template](https://github.com/iceener/streamable-mcp-server-template).
|
|
276
326
|
|
|
277
327
|
## License
|
|
278
328
|
|
|
279
|
-
|
|
329
|
+
[MIT](LICENSE)
|