@silkweave/edge 3.2.0 → 3.2.1
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 +3 -0
- package/build/index.d.mts +13 -0
- package/build/index.d.mts.map +1 -1
- package/build/index.mjs +109 -30
- package/build/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -92,6 +92,9 @@ const { adapter, handler } = edge({
|
|
|
92
92
|
| `enableJsonResponse` | `boolean` | `false` | Return JSON responses instead of SSE streams |
|
|
93
93
|
| `auth` | `AuthConfig` | - | Bearer-token validation + OAuth routes (see [Auth](#auth)) |
|
|
94
94
|
| `path` | `string` | `/mcp` | The MCP transport path |
|
|
95
|
+
| `allowedHosts` | `string[]` | - | Opt-in DNS-rebinding protection: when set, the transport validates the inbound `Host` header against this list (browser pages on other hosts are rejected) |
|
|
96
|
+
| `allowedOrigins` | `string[]` | - | Opt-in DNS-rebinding protection: validate the inbound `Origin` header against this list |
|
|
97
|
+
| `corsOrigin` | `string` | `*` | The `Access-Control-Allow-Origin` value. Set to a specific origin (pair with `allowedOrigins`) instead of reflecting every origin |
|
|
95
98
|
| `filterActions` | `FilterActions` | - | Per-request tool filter, applied before tools are registered on every POST (the stateless transport recomputes the tool list per request, so permission changes apply on the next `tools/list`). Receives the actions (with their `tags`) and a request stand-in `{ headers, url, method, toolName }` - `method` is the JSON-RPC method (skip DB lookups on `initialize`/`ping`), `toolName` is set for `tools/call`. May be async. A throw surfaces as its `SilkweaveError.statusCode` (e.g. 401) with a JSON-RPC error body, or 500 for other errors - never an empty tool list |
|
|
96
99
|
| `onToolCall` | `OnToolCall` | - | Telemetry hook invoked once per tool call, fire-and-forget (never awaited on the result path; errors logged and swallowed). Events carry `{ action, tool, transport: 'mcp', durationMs, ok, errorCode?, errorMessage?, resultBytes?, sideloaded?, context }` |
|
|
97
100
|
|
package/build/index.d.mts
CHANGED
|
@@ -7,6 +7,19 @@ interface EdgeAdapterOptions {
|
|
|
7
7
|
enableJsonResponse?: boolean;
|
|
8
8
|
auth?: AuthConfig;
|
|
9
9
|
path?: string;
|
|
10
|
+
/**
|
|
11
|
+
* DNS-rebinding protection. When `allowedHosts`/`allowedOrigins` are set the
|
|
12
|
+
* transport validates the inbound `Host`/`Origin` against them (browser pages
|
|
13
|
+
* on other origins are then rejected). Off by default to preserve the
|
|
14
|
+
* any-origin behavior; set these when the server is reachable from a browser.
|
|
15
|
+
*/
|
|
16
|
+
allowedHosts?: string[];
|
|
17
|
+
allowedOrigins?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* `Access-Control-Allow-Origin` value. Defaults to `'*'`. Set to a specific
|
|
20
|
+
* origin to stop reflecting every origin (pair with `allowedOrigins`).
|
|
21
|
+
*/
|
|
22
|
+
corsOrigin?: string;
|
|
10
23
|
/**
|
|
11
24
|
* Per-request tool filter, applied before `registerTools()` on every POST
|
|
12
25
|
* (the stateless transport recomputes the tool list per request). See
|
package/build/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapter/edge.ts"],"mappings":";;;;;UAMiB,kBAAA;EACf,kBAAA;EACA,IAAA,GAAO,UAAA;EACP,IAAA
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapter/edge.ts"],"mappings":";;;;;UAMiB,kBAAA;EACf,kBAAA;EACA,IAAA,GAAO,UAAA;EACP,IAAA;;;;;;;EAOA,YAAA;EACA,cAAA;EATO;;;;EAcP,UAAA;EAQA;;;;;;AAKF;EALE,aAAA,GAAgB,aAAA;;EAEhB,UAAA,GAAa,UAAA;AAAA;AAAA,UAGE,WAAA;EACf,OAAA,EAAS,gBAAA;EACT,OAAA,GAAU,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA;EACvC,GAAA,GAAM,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA;EACnC,IAAA,GAAO,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA;EACpC,MAAA,GAAS,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA;AAAA;AAAA,iBAiGxB,IAAA,CAAK,OAAA,GAAS,kBAAA,GAA0B,WAAA"}
|
package/build/index.mjs
CHANGED
|
@@ -4,18 +4,69 @@ import { generateProtectedResourceMetadata, validateToken } from "@silkweave/aut
|
|
|
4
4
|
import { validateActionDisposition } from "@silkweave/core";
|
|
5
5
|
import { filterErrorResponse, registerTools, rpcInfo } from "@silkweave/mcp/tools";
|
|
6
6
|
//#region src/adapter/edge.ts
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
function buildCorsHeaders(origin) {
|
|
8
|
+
return {
|
|
9
|
+
"Access-Control-Allow-Origin": origin,
|
|
10
|
+
"Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
|
|
11
|
+
"Access-Control-Allow-Headers": "*",
|
|
12
|
+
"Access-Control-Max-Age": "86400"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** A malformed OAuth request (e.g. non-JSON body) - surfaced as a 400, not a 500. */
|
|
16
|
+
var OAuthRequestError = class extends Error {
|
|
17
|
+
constructor(code, message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.name = "OAuthRequestError";
|
|
21
|
+
}
|
|
12
22
|
};
|
|
23
|
+
/** Transport DNS-rebinding config, enabled only when host/origin allow-lists are set. */
|
|
24
|
+
function dnsRebindingOptions(options) {
|
|
25
|
+
if (!options.allowedHosts && !options.allowedOrigins) return {};
|
|
26
|
+
return {
|
|
27
|
+
enableDnsRebindingProtection: true,
|
|
28
|
+
...options.allowedHosts ? { allowedHosts: options.allowedHosts } : {},
|
|
29
|
+
...options.allowedOrigins ? { allowedOrigins: options.allowedOrigins } : {}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Map a thrown handler error to a JSON error Response (400 for a bad OAuth body, else 500). */
|
|
33
|
+
function edgeErrorResponse(error, corsHeaders) {
|
|
34
|
+
if (error instanceof OAuthRequestError) return new Response(JSON.stringify({
|
|
35
|
+
error: error.code,
|
|
36
|
+
error_description: error.message
|
|
37
|
+
}), {
|
|
38
|
+
status: 400,
|
|
39
|
+
headers: {
|
|
40
|
+
...corsHeaders,
|
|
41
|
+
"Content-Type": "application/json"
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
console.error("edge handler error:", error);
|
|
45
|
+
return new Response(JSON.stringify({
|
|
46
|
+
jsonrpc: "2.0",
|
|
47
|
+
error: {
|
|
48
|
+
code: -32603,
|
|
49
|
+
message: "Internal server error"
|
|
50
|
+
},
|
|
51
|
+
id: null
|
|
52
|
+
}), {
|
|
53
|
+
status: 500,
|
|
54
|
+
headers: {
|
|
55
|
+
...corsHeaders,
|
|
56
|
+
"Content-Type": "application/json"
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
13
60
|
async function parseOAuthRequest(url, request) {
|
|
14
61
|
let body;
|
|
15
62
|
if (request.method === "POST") {
|
|
16
63
|
const contentType = request.headers.get("content-type") ?? "";
|
|
17
64
|
const text = await request.text();
|
|
18
|
-
if (contentType.includes("json"))
|
|
65
|
+
if (contentType.includes("json")) try {
|
|
66
|
+
body = JSON.parse(text);
|
|
67
|
+
} catch {
|
|
68
|
+
throw new OAuthRequestError("invalid_request", "Request body is not valid JSON");
|
|
69
|
+
}
|
|
19
70
|
else body = Object.fromEntries(new URLSearchParams(text));
|
|
20
71
|
}
|
|
21
72
|
return {
|
|
@@ -45,12 +96,15 @@ async function routeOAuth(url, request, provider, callbackPath) {
|
|
|
45
96
|
function edge(options = {}) {
|
|
46
97
|
const mcpPath = options.path ?? "/mcp";
|
|
47
98
|
const callbackPath = options.auth?.callbackPath ?? "/auth/callback";
|
|
99
|
+
const CORS_HEADERS = buildCorsHeaders(options.corsOrigin ?? "*");
|
|
48
100
|
let _actions = [];
|
|
49
101
|
let _options = null;
|
|
50
102
|
let _context = null;
|
|
51
103
|
let _readyResolve;
|
|
52
|
-
|
|
104
|
+
let _readyReject;
|
|
105
|
+
const _ready = new Promise((resolve, reject) => {
|
|
53
106
|
_readyResolve = resolve;
|
|
107
|
+
_readyReject = reject;
|
|
54
108
|
});
|
|
55
109
|
const validPaths = new Set([mcpPath]);
|
|
56
110
|
if (options.auth?.authorizationServers?.length && options.auth.resourceUrl) validPaths.add("/.well-known/oauth-protected-resource");
|
|
@@ -68,7 +122,7 @@ function edge(options = {}) {
|
|
|
68
122
|
"/token": ["POST"],
|
|
69
123
|
"/register": ["POST"]
|
|
70
124
|
} : null;
|
|
71
|
-
const
|
|
125
|
+
const handleRequestInner = async (request) => {
|
|
72
126
|
const url = new URL(request.url);
|
|
73
127
|
if (!validPaths.has(url.pathname)) return new Response("Not Found", { status: 404 });
|
|
74
128
|
if (request.method === "OPTIONS") return new Response(null, {
|
|
@@ -98,6 +152,21 @@ function edge(options = {}) {
|
|
|
98
152
|
}
|
|
99
153
|
});
|
|
100
154
|
await _ready;
|
|
155
|
+
const rawBody = await request.clone().json().catch(() => void 0);
|
|
156
|
+
if (Array.isArray(rawBody)) return new Response(JSON.stringify({
|
|
157
|
+
jsonrpc: "2.0",
|
|
158
|
+
error: {
|
|
159
|
+
code: -32600,
|
|
160
|
+
message: "JSON-RPC batch requests are not supported"
|
|
161
|
+
},
|
|
162
|
+
id: null
|
|
163
|
+
}), {
|
|
164
|
+
status: 400,
|
|
165
|
+
headers: {
|
|
166
|
+
...CORS_HEADERS,
|
|
167
|
+
"Content-Type": "application/json"
|
|
168
|
+
}
|
|
169
|
+
});
|
|
101
170
|
let requestContext = _context;
|
|
102
171
|
if (options.auth) {
|
|
103
172
|
const result = await validateToken(request.headers.get("authorization"), options.auth, _context.fork({ request }));
|
|
@@ -108,28 +177,26 @@ function edge(options = {}) {
|
|
|
108
177
|
if (result.auth) requestContext = _context.fork({ auth: result.auth });
|
|
109
178
|
}
|
|
110
179
|
let activeActions = _actions;
|
|
111
|
-
if (options.filterActions) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
}
|
|
180
|
+
if (options.filterActions) try {
|
|
181
|
+
activeActions = await options.filterActions(_actions, {
|
|
182
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
183
|
+
url: request.url,
|
|
184
|
+
...rpcInfo(rawBody)
|
|
185
|
+
});
|
|
186
|
+
} catch (error) {
|
|
187
|
+
const mapped = filterErrorResponse(error, rawBody);
|
|
188
|
+
return new Response(JSON.stringify(mapped.body), {
|
|
189
|
+
status: mapped.status,
|
|
190
|
+
headers: {
|
|
191
|
+
...CORS_HEADERS,
|
|
192
|
+
"Content-Type": "application/json"
|
|
193
|
+
}
|
|
194
|
+
});
|
|
129
195
|
}
|
|
130
196
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
131
197
|
sessionIdGenerator: void 0,
|
|
132
|
-
enableJsonResponse: options.enableJsonResponse
|
|
198
|
+
enableJsonResponse: options.enableJsonResponse,
|
|
199
|
+
...dnsRebindingOptions(options)
|
|
133
200
|
});
|
|
134
201
|
const server = new McpServer({
|
|
135
202
|
name: _options.name,
|
|
@@ -143,15 +210,27 @@ function edge(options = {}) {
|
|
|
143
210
|
await server.connect(transport);
|
|
144
211
|
return transport.handleRequest(request);
|
|
145
212
|
};
|
|
213
|
+
const handleRequest = async (request) => {
|
|
214
|
+
try {
|
|
215
|
+
return await handleRequestInner(request);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
return edgeErrorResponse(error, CORS_HEADERS);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
146
220
|
const adapter = (silkweaveOptions, baseContext) => {
|
|
147
221
|
_options = silkweaveOptions;
|
|
148
222
|
_context = baseContext.fork({ adapter: "edge" });
|
|
149
223
|
return {
|
|
150
224
|
context: _context,
|
|
151
225
|
start: async (actions) => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
226
|
+
try {
|
|
227
|
+
actions.forEach(validateActionDisposition);
|
|
228
|
+
_actions = actions;
|
|
229
|
+
_readyResolve();
|
|
230
|
+
} catch (error) {
|
|
231
|
+
_readyReject(error);
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
155
234
|
},
|
|
156
235
|
stop: async () => {
|
|
157
236
|
_actions = [];
|
package/build/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/adapter/edge.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js'\nimport { AuthConfig, generateProtectedResourceMetadata, OAuthRequest, OAuthResponse, validateToken } from '@silkweave/auth'\nimport { Action, AdapterGenerator, OnToolCall, SilkweaveContext, SilkweaveOptions, validateActionDisposition } from '@silkweave/core'\nimport { filterErrorResponse, registerTools, rpcInfo, type FilterActions } from '@silkweave/mcp/tools'\n\nexport interface EdgeAdapterOptions {\n enableJsonResponse?: boolean\n auth?: AuthConfig\n path?: string\n /**\n * Per-request tool filter, applied before `registerTools()` on every POST\n * (the stateless transport recomputes the tool list per request). See\n * `FilterActions` for the request stand-in (`headers`/`url`/`method`/\n * `toolName`) and error semantics (a throw surfaces as its\n * `SilkweaveError.statusCode` or 500 - never an empty tool list).\n */\n filterActions?: FilterActions\n /** Telemetry hook invoked once per tool call (fire-and-forget). */\n onToolCall?: OnToolCall\n}\n\nexport interface EdgeAdapter {\n adapter: AdapterGenerator\n handler: (request: Request) => Promise<Response>\n GET: (request: Request) => Promise<Response>\n POST: (request: Request) => Promise<Response>\n DELETE: (request: Request) => Promise<Response>\n}\n\nconst CORS_HEADERS: Record<string, string> = {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': '*',\n 'Access-Control-Max-Age': '86400'\n}\n\nasync function parseOAuthRequest(url: URL, request: Request): Promise<OAuthRequest> {\n let body: Record<string, string> | undefined\n if (request.method === 'POST') {\n const contentType = request.headers.get('content-type') ?? ''\n const text = await request.text()\n if (contentType.includes('json')) {\n body = JSON.parse(text)\n } else {\n body = Object.fromEntries(new URLSearchParams(text))\n }\n }\n return {\n method: request.method,\n url,\n headers: Object.fromEntries(request.headers.entries()),\n body\n }\n}\n\nfunction oauthResponseToResponse(oauthRes: OAuthResponse): Response {\n const responseBody = oauthRes.body\n ? (typeof oauthRes.body === 'string' ? oauthRes.body : JSON.stringify(oauthRes.body))\n : null\n return new Response(responseBody, { status: oauthRes.status, headers: oauthRes.headers })\n}\n\nasync function routeOAuth(\n url: URL,\n request: Request,\n provider: NonNullable<AuthConfig['provider']>,\n callbackPath: string\n): Promise<Response> {\n const oauthReq = await parseOAuthRequest(url, request)\n let oauthRes\n if (url.pathname === '/.well-known/oauth-authorization-server') {\n oauthRes = provider.metadata()\n } else if (url.pathname === '/authorize') {\n oauthRes = await provider.authorize(oauthReq)\n } else if (url.pathname === callbackPath) {\n oauthRes = await provider.callback(oauthReq)\n } else if (url.pathname === '/token') {\n oauthRes = await provider.token(oauthReq)\n } else {\n oauthRes = await provider.register(oauthReq)\n }\n return oauthResponseToResponse(oauthRes)\n}\n\nexport function edge(options: EdgeAdapterOptions = {}): EdgeAdapter {\n const mcpPath = options.path ?? '/mcp'\n const callbackPath = options.auth?.callbackPath ?? '/auth/callback'\n\n let _actions: Action[] = []\n let _options: SilkweaveOptions | null = null\n let _context: SilkweaveContext | null = null\n let _readyResolve: () => void\n const _ready = new Promise<void>((resolve) => {\n _readyResolve = resolve\n })\n\n // Pre-compute valid paths for fast rejection of bogus requests\n const validPaths = new Set<string>([mcpPath])\n if (options.auth?.authorizationServers?.length && options.auth.resourceUrl) {\n validPaths.add('/.well-known/oauth-protected-resource')\n }\n if (options.auth?.provider) {\n validPaths.add('/.well-known/oauth-authorization-server')\n validPaths.add('/authorize')\n validPaths.add(callbackPath)\n validPaths.add('/token')\n validPaths.add('/register')\n }\n\n // OAuth path → allowed methods (built once, not per-request)\n const oauthPaths: Record<string, string[]> | null = options.auth?.provider\n ? {\n '/.well-known/oauth-authorization-server': ['GET'],\n '/authorize': ['GET'],\n [callbackPath]: ['GET'],\n '/token': ['POST'],\n '/register': ['POST']\n }\n : null\n\n const handleRequest = async (request: Request): Promise<Response> => {\n const url = new URL(request.url)\n\n // Fast rejection - no async work, no allocations for unknown paths\n if (!validPaths.has(url.pathname)) {\n return new Response('Not Found', { status: 404 })\n }\n\n // CORS preflight\n if (request.method === 'OPTIONS') {\n return new Response(null, { status: 200, headers: CORS_HEADERS })\n }\n\n // Protected resource metadata (RFC 9728)\n if (url.pathname === '/.well-known/oauth-protected-resource') {\n const metadata = generateProtectedResourceMetadata(options.auth!.resourceUrl!, options.auth!.authorizationServers!, options.auth!.requiredScopes)\n return new Response(JSON.stringify(metadata), {\n headers: { ...CORS_HEADERS, 'Content-Type': 'application/json', 'Cache-Control': 'max-age=3600' }\n })\n }\n\n // OAuth provider routes\n if (oauthPaths) {\n const methods = oauthPaths[url.pathname]\n if (methods) {\n if (!methods.includes(request.method)) {\n return new Response('Method not allowed', { status: 405 })\n }\n return routeOAuth(url, request, options.auth!.provider!, callbackPath)\n }\n }\n\n // MCP transport (stateless): only POST carries JSON-RPC. A standing-stream\n // GET or a session-teardown DELETE has no session to act on - and the SDK's\n // GET handler would open an SSE stream that never closes, hanging the request\n // on serverless runtimes (e.g. Cloudflare Workers). Answer them with 405, which\n // the Streamable HTTP spec explicitly permits for servers without a GET stream.\n if (request.method !== 'POST') {\n return new Response('Method Not Allowed', {\n status: 405,\n headers: { ...CORS_HEADERS, Allow: 'POST' }\n })\n }\n\n // wait for silkweave().start() to complete\n await _ready\n\n let requestContext = _context!\n if (options.auth) {\n const result = await validateToken(request.headers.get('authorization'), options.auth, _context!.fork({ request }))\n if (result.error) {\n return new Response(JSON.stringify(result.error.body), {\n status: result.error.statusCode,\n headers: result.error.headers\n })\n }\n if (result.auth) {\n requestContext = _context!.fork({ auth: result.auth })\n }\n }\n\n let activeActions = _actions\n if (options.filterActions) {\n // Clone so the transport can still consume the original body stream.\n const body: unknown = await request.clone().json().catch(() => undefined)\n try {\n activeActions = await options.filterActions(_actions, {\n headers: Object.fromEntries(request.headers.entries()),\n url: request.url,\n ...rpcInfo(body)\n })\n } catch (error) {\n const mapped = filterErrorResponse(error, body)\n return new Response(JSON.stringify(mapped.body), {\n status: mapped.status,\n headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' }\n })\n }\n }\n\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: options.enableJsonResponse\n })\n\n const server = new McpServer({\n name: _options!.name,\n description: _options!.description,\n version: _options!.version\n }, {\n capabilities: { tools: {}, logging: {} }\n })\n\n registerTools(server, activeActions, requestContext, { onToolCall: options.onToolCall })\n\n await server.connect(transport)\n return transport.handleRequest(request)\n }\n\n const adapter: AdapterGenerator = (silkweaveOptions: SilkweaveOptions, baseContext: SilkweaveContext) => {\n _options = silkweaveOptions\n _context = baseContext.fork({ adapter: 'edge' })\n return {\n context: _context,\n start: async (actions) => {\n actions.forEach(validateActionDisposition)\n _actions = actions\n _readyResolve()\n },\n stop: async () => {\n _actions = []\n }\n }\n }\n\n return {\n adapter,\n handler: handleRequest,\n GET: handleRequest,\n POST: handleRequest,\n DELETE: handleRequest\n }\n}\n"],"mappings":";;;;;;AA8BA,MAAM,eAAuC;CAC3C,+BAA+B;CAC/B,gCAAgC;CAChC,gCAAgC;CAChC,0BAA0B;CAC3B;AAED,eAAe,kBAAkB,KAAU,SAAyC;CAClF,IAAI;AACJ,KAAI,QAAQ,WAAW,QAAQ;EAC7B,MAAM,cAAc,QAAQ,QAAQ,IAAI,eAAe,IAAI;EAC3D,MAAM,OAAO,MAAM,QAAQ,MAAM;AACjC,MAAI,YAAY,SAAS,OAAO,CAC9B,QAAO,KAAK,MAAM,KAAK;MAEvB,QAAO,OAAO,YAAY,IAAI,gBAAgB,KAAK,CAAC;;AAGxD,QAAO;EACL,QAAQ,QAAQ;EAChB;EACA,SAAS,OAAO,YAAY,QAAQ,QAAQ,SAAS,CAAC;EACtD;EACD;;AAGH,SAAS,wBAAwB,UAAmC;CAClE,MAAM,eAAe,SAAS,OACzB,OAAO,SAAS,SAAS,WAAW,SAAS,OAAO,KAAK,UAAU,SAAS,KAAK,GAClF;AACJ,QAAO,IAAI,SAAS,cAAc;EAAE,QAAQ,SAAS;EAAQ,SAAS,SAAS;EAAS,CAAC;;AAG3F,eAAe,WACb,KACA,SACA,UACA,cACmB;CACnB,MAAM,WAAW,MAAM,kBAAkB,KAAK,QAAQ;CACtD,IAAI;AACJ,KAAI,IAAI,aAAa,0CACnB,YAAW,SAAS,UAAU;UACrB,IAAI,aAAa,aAC1B,YAAW,MAAM,SAAS,UAAU,SAAS;UACpC,IAAI,aAAa,aAC1B,YAAW,MAAM,SAAS,SAAS,SAAS;UACnC,IAAI,aAAa,SAC1B,YAAW,MAAM,SAAS,MAAM,SAAS;KAEzC,YAAW,MAAM,SAAS,SAAS,SAAS;AAE9C,QAAO,wBAAwB,SAAS;;AAG1C,SAAgB,KAAK,UAA8B,EAAE,EAAe;CAClE,MAAM,UAAU,QAAQ,QAAQ;CAChC,MAAM,eAAe,QAAQ,MAAM,gBAAgB;CAEnD,IAAI,WAAqB,EAAE;CAC3B,IAAI,WAAoC;CACxC,IAAI,WAAoC;CACxC,IAAI;CACJ,MAAM,SAAS,IAAI,SAAe,YAAY;AAC5C,kBAAgB;GAChB;CAGF,MAAM,aAAa,IAAI,IAAY,CAAC,QAAQ,CAAC;AAC7C,KAAI,QAAQ,MAAM,sBAAsB,UAAU,QAAQ,KAAK,YAC7D,YAAW,IAAI,wCAAwC;AAEzD,KAAI,QAAQ,MAAM,UAAU;AAC1B,aAAW,IAAI,0CAA0C;AACzD,aAAW,IAAI,aAAa;AAC5B,aAAW,IAAI,aAAa;AAC5B,aAAW,IAAI,SAAS;AACxB,aAAW,IAAI,YAAY;;CAI7B,MAAM,aAA8C,QAAQ,MAAM,WAC9D;EACA,2CAA2C,CAAC,MAAM;EAClD,cAAc,CAAC,MAAM;GACpB,eAAe,CAAC,MAAM;EACvB,UAAU,CAAC,OAAO;EAClB,aAAa,CAAC,OAAO;EACtB,GACC;CAEJ,MAAM,gBAAgB,OAAO,YAAwC;EACnE,MAAM,MAAM,IAAI,IAAI,QAAQ,IAAI;AAGhC,MAAI,CAAC,WAAW,IAAI,IAAI,SAAS,CAC/B,QAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,KAAK,CAAC;AAInD,MAAI,QAAQ,WAAW,UACrB,QAAO,IAAI,SAAS,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAc,CAAC;AAInE,MAAI,IAAI,aAAa,yCAAyC;GAC5D,MAAM,WAAW,kCAAkC,QAAQ,KAAM,aAAc,QAAQ,KAAM,sBAAuB,QAAQ,KAAM,eAAe;AACjJ,UAAO,IAAI,SAAS,KAAK,UAAU,SAAS,EAAE,EAC5C,SAAS;IAAE,GAAG;IAAc,gBAAgB;IAAoB,iBAAiB;IAAgB,EAClG,CAAC;;AAIJ,MAAI,YAAY;GACd,MAAM,UAAU,WAAW,IAAI;AAC/B,OAAI,SAAS;AACX,QAAI,CAAC,QAAQ,SAAS,QAAQ,OAAO,CACnC,QAAO,IAAI,SAAS,sBAAsB,EAAE,QAAQ,KAAK,CAAC;AAE5D,WAAO,WAAW,KAAK,SAAS,QAAQ,KAAM,UAAW,aAAa;;;AAS1E,MAAI,QAAQ,WAAW,OACrB,QAAO,IAAI,SAAS,sBAAsB;GACxC,QAAQ;GACR,SAAS;IAAE,GAAG;IAAc,OAAO;IAAQ;GAC5C,CAAC;AAIJ,QAAM;EAEN,IAAI,iBAAiB;AACrB,MAAI,QAAQ,MAAM;GAChB,MAAM,SAAS,MAAM,cAAc,QAAQ,QAAQ,IAAI,gBAAgB,EAAE,QAAQ,MAAM,SAAU,KAAK,EAAE,SAAS,CAAC,CAAC;AACnH,OAAI,OAAO,MACT,QAAO,IAAI,SAAS,KAAK,UAAU,OAAO,MAAM,KAAK,EAAE;IACrD,QAAQ,OAAO,MAAM;IACrB,SAAS,OAAO,MAAM;IACvB,CAAC;AAEJ,OAAI,OAAO,KACT,kBAAiB,SAAU,KAAK,EAAE,MAAM,OAAO,MAAM,CAAC;;EAI1D,IAAI,gBAAgB;AACpB,MAAI,QAAQ,eAAe;GAEzB,MAAM,OAAgB,MAAM,QAAQ,OAAO,CAAC,MAAM,CAAC,YAAY,KAAA,EAAU;AACzE,OAAI;AACF,oBAAgB,MAAM,QAAQ,cAAc,UAAU;KACpD,SAAS,OAAO,YAAY,QAAQ,QAAQ,SAAS,CAAC;KACtD,KAAK,QAAQ;KACb,GAAG,QAAQ,KAAK;KACjB,CAAC;YACK,OAAO;IACd,MAAM,SAAS,oBAAoB,OAAO,KAAK;AAC/C,WAAO,IAAI,SAAS,KAAK,UAAU,OAAO,KAAK,EAAE;KAC/C,QAAQ,OAAO;KACf,SAAS;MAAE,GAAG;MAAc,gBAAgB;MAAoB;KACjE,CAAC;;;EAIN,MAAM,YAAY,IAAI,yCAAyC;GAC7D,oBAAoB,KAAA;GACpB,oBAAoB,QAAQ;GAC7B,CAAC;EAEF,MAAM,SAAS,IAAI,UAAU;GAC3B,MAAM,SAAU;GAChB,aAAa,SAAU;GACvB,SAAS,SAAU;GACpB,EAAE,EACD,cAAc;GAAE,OAAO,EAAE;GAAE,SAAS,EAAE;GAAE,EACzC,CAAC;AAEF,gBAAc,QAAQ,eAAe,gBAAgB,EAAE,YAAY,QAAQ,YAAY,CAAC;AAExF,QAAM,OAAO,QAAQ,UAAU;AAC/B,SAAO,UAAU,cAAc,QAAQ;;CAGzC,MAAM,WAA6B,kBAAoC,gBAAkC;AACvG,aAAW;AACX,aAAW,YAAY,KAAK,EAAE,SAAS,QAAQ,CAAC;AAChD,SAAO;GACL,SAAS;GACT,OAAO,OAAO,YAAY;AACxB,YAAQ,QAAQ,0BAA0B;AAC1C,eAAW;AACX,mBAAe;;GAEjB,MAAM,YAAY;AAChB,eAAW,EAAE;;GAEhB;;AAGH,QAAO;EACL;EACA,SAAS;EACT,KAAK;EACL,MAAM;EACN,QAAQ;EACT"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/adapter/edge.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js'\nimport { AuthConfig, generateProtectedResourceMetadata, OAuthRequest, OAuthResponse, validateToken } from '@silkweave/auth'\nimport { Action, AdapterGenerator, OnToolCall, SilkweaveContext, SilkweaveOptions, validateActionDisposition } from '@silkweave/core'\nimport { filterErrorResponse, registerTools, rpcInfo, type FilterActions } from '@silkweave/mcp/tools'\n\nexport interface EdgeAdapterOptions {\n enableJsonResponse?: boolean\n auth?: AuthConfig\n path?: string\n /**\n * DNS-rebinding protection. When `allowedHosts`/`allowedOrigins` are set the\n * transport validates the inbound `Host`/`Origin` against them (browser pages\n * on other origins are then rejected). Off by default to preserve the\n * any-origin behavior; set these when the server is reachable from a browser.\n */\n allowedHosts?: string[]\n allowedOrigins?: string[]\n /**\n * `Access-Control-Allow-Origin` value. Defaults to `'*'`. Set to a specific\n * origin to stop reflecting every origin (pair with `allowedOrigins`).\n */\n corsOrigin?: string\n /**\n * Per-request tool filter, applied before `registerTools()` on every POST\n * (the stateless transport recomputes the tool list per request). See\n * `FilterActions` for the request stand-in (`headers`/`url`/`method`/\n * `toolName`) and error semantics (a throw surfaces as its\n * `SilkweaveError.statusCode` or 500 - never an empty tool list).\n */\n filterActions?: FilterActions\n /** Telemetry hook invoked once per tool call (fire-and-forget). */\n onToolCall?: OnToolCall\n}\n\nexport interface EdgeAdapter {\n adapter: AdapterGenerator\n handler: (request: Request) => Promise<Response>\n GET: (request: Request) => Promise<Response>\n POST: (request: Request) => Promise<Response>\n DELETE: (request: Request) => Promise<Response>\n}\n\nfunction buildCorsHeaders(origin: string): Record<string, string> {\n return {\n 'Access-Control-Allow-Origin': origin,\n 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',\n 'Access-Control-Allow-Headers': '*',\n 'Access-Control-Max-Age': '86400'\n }\n}\n\n/** A malformed OAuth request (e.g. non-JSON body) - surfaced as a 400, not a 500. */\nclass OAuthRequestError extends Error {\n constructor(public readonly code: string, message: string) {\n super(message)\n this.name = 'OAuthRequestError'\n }\n}\n\n/** Transport DNS-rebinding config, enabled only when host/origin allow-lists are set. */\nfunction dnsRebindingOptions(options: EdgeAdapterOptions): Record<string, unknown> {\n if (!options.allowedHosts && !options.allowedOrigins) { return {} }\n return {\n enableDnsRebindingProtection: true,\n ...(options.allowedHosts ? { allowedHosts: options.allowedHosts } : {}),\n ...(options.allowedOrigins ? { allowedOrigins: options.allowedOrigins } : {})\n }\n}\n\n/** Map a thrown handler error to a JSON error Response (400 for a bad OAuth body, else 500). */\nfunction edgeErrorResponse(error: unknown, corsHeaders: Record<string, string>): Response {\n if (error instanceof OAuthRequestError) {\n return new Response(JSON.stringify({ error: error.code, error_description: error.message }), {\n status: 400,\n headers: { ...corsHeaders, 'Content-Type': 'application/json' }\n })\n }\n console.error('edge handler error:', error)\n return new Response(JSON.stringify({ jsonrpc: '2.0', error: { code: -32_603, message: 'Internal server error' }, id: null }), {\n status: 500,\n headers: { ...corsHeaders, 'Content-Type': 'application/json' }\n })\n}\n\nasync function parseOAuthRequest(url: URL, request: Request): Promise<OAuthRequest> {\n let body: Record<string, string> | undefined\n if (request.method === 'POST') {\n const contentType = request.headers.get('content-type') ?? ''\n const text = await request.text()\n if (contentType.includes('json')) {\n try {\n body = JSON.parse(text)\n } catch {\n throw new OAuthRequestError('invalid_request', 'Request body is not valid JSON')\n }\n } else {\n body = Object.fromEntries(new URLSearchParams(text))\n }\n }\n return {\n method: request.method,\n url,\n headers: Object.fromEntries(request.headers.entries()),\n body\n }\n}\n\nfunction oauthResponseToResponse(oauthRes: OAuthResponse): Response {\n const responseBody = oauthRes.body\n ? (typeof oauthRes.body === 'string' ? oauthRes.body : JSON.stringify(oauthRes.body))\n : null\n return new Response(responseBody, { status: oauthRes.status, headers: oauthRes.headers })\n}\n\nasync function routeOAuth(\n url: URL,\n request: Request,\n provider: NonNullable<AuthConfig['provider']>,\n callbackPath: string\n): Promise<Response> {\n const oauthReq = await parseOAuthRequest(url, request)\n let oauthRes\n if (url.pathname === '/.well-known/oauth-authorization-server') {\n oauthRes = provider.metadata()\n } else if (url.pathname === '/authorize') {\n oauthRes = await provider.authorize(oauthReq)\n } else if (url.pathname === callbackPath) {\n oauthRes = await provider.callback(oauthReq)\n } else if (url.pathname === '/token') {\n oauthRes = await provider.token(oauthReq)\n } else {\n oauthRes = await provider.register(oauthReq)\n }\n return oauthResponseToResponse(oauthRes)\n}\n\nexport function edge(options: EdgeAdapterOptions = {}): EdgeAdapter {\n const mcpPath = options.path ?? '/mcp'\n const callbackPath = options.auth?.callbackPath ?? '/auth/callback'\n const CORS_HEADERS = buildCorsHeaders(options.corsOrigin ?? '*')\n\n let _actions: Action[] = []\n let _options: SilkweaveOptions | null = null\n let _context: SilkweaveContext | null = null\n let _readyResolve: () => void\n let _readyReject: (error: unknown) => void\n const _ready = new Promise<void>((resolve, reject) => {\n _readyResolve = resolve\n _readyReject = reject\n })\n\n // Pre-compute valid paths for fast rejection of bogus requests\n const validPaths = new Set<string>([mcpPath])\n if (options.auth?.authorizationServers?.length && options.auth.resourceUrl) {\n validPaths.add('/.well-known/oauth-protected-resource')\n }\n if (options.auth?.provider) {\n validPaths.add('/.well-known/oauth-authorization-server')\n validPaths.add('/authorize')\n validPaths.add(callbackPath)\n validPaths.add('/token')\n validPaths.add('/register')\n }\n\n // OAuth path → allowed methods (built once, not per-request)\n const oauthPaths: Record<string, string[]> | null = options.auth?.provider\n ? {\n '/.well-known/oauth-authorization-server': ['GET'],\n '/authorize': ['GET'],\n [callbackPath]: ['GET'],\n '/token': ['POST'],\n '/register': ['POST']\n }\n : null\n\n const handleRequestInner = async (request: Request): Promise<Response> => {\n const url = new URL(request.url)\n\n // Fast rejection - no async work, no allocations for unknown paths\n if (!validPaths.has(url.pathname)) {\n return new Response('Not Found', { status: 404 })\n }\n\n // CORS preflight\n if (request.method === 'OPTIONS') {\n return new Response(null, { status: 200, headers: CORS_HEADERS })\n }\n\n // Protected resource metadata (RFC 9728)\n if (url.pathname === '/.well-known/oauth-protected-resource') {\n const metadata = generateProtectedResourceMetadata(options.auth!.resourceUrl!, options.auth!.authorizationServers!, options.auth!.requiredScopes)\n return new Response(JSON.stringify(metadata), {\n headers: { ...CORS_HEADERS, 'Content-Type': 'application/json', 'Cache-Control': 'max-age=3600' }\n })\n }\n\n // OAuth provider routes\n if (oauthPaths) {\n const methods = oauthPaths[url.pathname]\n if (methods) {\n if (!methods.includes(request.method)) {\n return new Response('Method not allowed', { status: 405 })\n }\n return routeOAuth(url, request, options.auth!.provider!, callbackPath)\n }\n }\n\n // MCP transport (stateless): only POST carries JSON-RPC. A standing-stream\n // GET or a session-teardown DELETE has no session to act on - and the SDK's\n // GET handler would open an SSE stream that never closes, hanging the request\n // on serverless runtimes (e.g. Cloudflare Workers). Answer them with 405, which\n // the Streamable HTTP spec explicitly permits for servers without a GET stream.\n if (request.method !== 'POST') {\n return new Response('Method Not Allowed', {\n status: 405,\n headers: { ...CORS_HEADERS, Allow: 'POST' }\n })\n }\n\n // wait for silkweave().start() to complete\n await _ready\n\n // JSON-RPC batching was removed from the MCP spec (2025-06-18). A batch also\n // defeats per-request filterActions (rpcInfo reflects only the first message\n // while the transport would execute every entry), so reject batches before\n // dispatch. Parsed once here and reused by the filter below.\n const rawBody: unknown = await request.clone().json().catch(() => undefined)\n if (Array.isArray(rawBody)) {\n return new Response(\n JSON.stringify({ jsonrpc: '2.0', error: { code: -32_600, message: 'JSON-RPC batch requests are not supported' }, id: null }),\n { status: 400, headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' } }\n )\n }\n\n let requestContext = _context!\n if (options.auth) {\n const result = await validateToken(request.headers.get('authorization'), options.auth, _context!.fork({ request }))\n if (result.error) {\n return new Response(JSON.stringify(result.error.body), {\n status: result.error.statusCode,\n headers: result.error.headers\n })\n }\n if (result.auth) {\n requestContext = _context!.fork({ auth: result.auth })\n }\n }\n\n let activeActions = _actions\n if (options.filterActions) {\n try {\n activeActions = await options.filterActions(_actions, {\n headers: Object.fromEntries(request.headers.entries()),\n url: request.url,\n ...rpcInfo(rawBody)\n })\n } catch (error) {\n const mapped = filterErrorResponse(error, rawBody)\n return new Response(JSON.stringify(mapped.body), {\n status: mapped.status,\n headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' }\n })\n }\n }\n\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n enableJsonResponse: options.enableJsonResponse,\n ...dnsRebindingOptions(options)\n })\n\n const server = new McpServer({\n name: _options!.name,\n description: _options!.description,\n version: _options!.version\n }, {\n capabilities: { tools: {}, logging: {} }\n })\n\n registerTools(server, activeActions, requestContext, { onToolCall: options.onToolCall })\n\n await server.connect(transport)\n return transport.handleRequest(request)\n }\n\n // Top-level guard: any throw (malformed OAuth body, a boot-failure rejection\n // from `await _ready`, an unexpected error) becomes a JSON error Response\n // rather than an opaque host 500 / unhandled rejection on the serverless runtime.\n const handleRequest = async (request: Request): Promise<Response> => {\n try {\n return await handleRequestInner(request)\n } catch (error) {\n return edgeErrorResponse(error, CORS_HEADERS)\n }\n }\n\n const adapter: AdapterGenerator = (silkweaveOptions: SilkweaveOptions, baseContext: SilkweaveContext) => {\n _options = silkweaveOptions\n _context = baseContext.fork({ adapter: 'edge' })\n return {\n context: _context,\n start: async (actions) => {\n try {\n actions.forEach(validateActionDisposition)\n _actions = actions\n _readyResolve()\n } catch (error) {\n // Reject `_ready` so awaiting handlers get a 500 instead of hanging\n // forever, then rethrow so the builder's start() rejects too.\n _readyReject(error)\n throw error\n }\n },\n stop: async () => {\n _actions = []\n }\n }\n }\n\n return {\n adapter,\n handler: handleRequest,\n GET: handleRequest,\n POST: handleRequest,\n DELETE: handleRequest\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silkweave/edge",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "Silkweave Web-Standard edge/serverless adapter (Cloudflare Workers, Vercel, Bun, Deno, Hono)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://www.silkweave.dev",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
30
30
|
"zod": "^3.25.0",
|
|
31
|
-
"@silkweave/auth": "3.2.
|
|
32
|
-
"@silkweave/core": "3.2.
|
|
33
|
-
"@silkweave/mcp": "3.2.
|
|
31
|
+
"@silkweave/auth": "3.2.1",
|
|
32
|
+
"@silkweave/core": "3.2.1",
|
|
33
|
+
"@silkweave/mcp": "3.2.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@eslint/js": "^10.0.1",
|