@silkweave/edge 0.1.0 → 3.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Silkweave
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # @silkweave/edge
2
+
3
+ Web-Standard edge/serverless adapter for [Silkweave](https://github.com/silkweave/silkweave) - deploy your actions as a **stateless** MCP server on any `(Request) => Response` runtime: **Cloudflare Workers, Vercel, Bun, Deno, Hono**, and Next.js.
4
+
5
+ It uses only Web Standard APIs (`Request`/`Response`/`ReadableStream`/Web Crypto) and the SDK's `WebStandardStreamableHTTPServerTransport` - no Express, no port binding - so the same handler drops onto any edge or serverless platform.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add @silkweave/core @silkweave/edge
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Vanilla serverless function (Vercel / Bun / Deno)
16
+
17
+ ```typescript
18
+ // api/mcp.ts
19
+ import { silkweave } from '@silkweave/core'
20
+ import { edge } from '@silkweave/edge'
21
+ import { MyAction } from '../actions/my-action.js'
22
+
23
+ const { adapter, handler } = edge()
24
+
25
+ await silkweave({ name: 'my-tools', description: 'My MCP Server', version: '1.0.0' })
26
+ .adapter(adapter)
27
+ .action(MyAction)
28
+ .start()
29
+
30
+ export default { fetch: handler }
31
+ ```
32
+
33
+ ### Next.js App Router
34
+
35
+ ```typescript
36
+ // app/api/mcp/route.ts
37
+ import { silkweave } from '@silkweave/core'
38
+ import { edge } from '@silkweave/edge'
39
+ import { MyAction } from '../../../actions/my-action.js'
40
+
41
+ const { adapter, GET, POST, DELETE } = edge()
42
+
43
+ await silkweave({ name: 'my-tools', description: 'My MCP Server', version: '1.0.0' })
44
+ .adapter(adapter)
45
+ .action(MyAction)
46
+ .start()
47
+
48
+ export { GET, POST, DELETE }
49
+ ```
50
+
51
+ > For Next.js, [`@silkweave/nextjs`](https://www.npmjs.com/package/@silkweave/nextjs) wraps this adapter with catch-all path normalization and end-to-end tRPC types - prefer it over wiring `edge()` by hand.
52
+
53
+ ### Cloudflare Workers
54
+
55
+ See the full [`examples/cloudflare`](https://github.com/silkweave/silkweave/tree/master/examples/cloudflare) example - a Worker with stateless MCP + Google Workspace OAuth 2.1 and OAuth state in Cloudflare KV, with a from-scratch setup guide.
56
+
57
+ ## How It Works
58
+
59
+ - Uses `WebStandardStreamableHTTPServerTransport` from the MCP SDK in **stateless mode** (`sessionIdGenerator: undefined`)
60
+ - Each request creates a fresh `McpServer` + transport, registers tools, handles the request, and returns a Web Standard `Response`
61
+ - Only `POST` carries JSON-RPC; `GET` (standing SSE stream) and `DELETE` (session teardown) return `405`, since stateless mode has no session to attach a stream to or tear down (a `GET` stream would otherwise hang the request on serverless runtimes like Cloudflare Workers)
62
+ - Actions are registered as MCP tools using `PascalCase` names (same as the stdio and http adapters)
63
+ - Tool results use `smartToolResult()` by default. Large payloads (> 4096 chars) are automatically split into a text summary + embedded resource to reduce LLM context bloat. Actions can override this with a custom `toolResult` hook.
64
+ - Logging goes to `process.stderr` (serverless log drain) and MCP client notifications
65
+
66
+ ## Streaming Actions
67
+
68
+ Streaming actions (see [`@silkweave/core`](https://www.npmjs.com/package/@silkweave/core)) work identically to [`@silkweave/mcp`](https://www.npmjs.com/package/@silkweave/mcp)'s `http()` adapter - chunks are delivered as `notifications/progress` over the Streamable HTTP transport when the client sends `_meta.progressToken`, with the JSON-stringified chunk in the `message` field. The tool call resolves with the buffered chunk array as the `CallToolResult`.
69
+
70
+ The same AI-host caveat applies as for stdio/http MCP: chunks reach the wire as standard MCP progress notifications, but most LLM hosts today consume them for UI rendering rather than as incremental data fed into the model's context. See the [`@silkweave/mcp` README](https://www.npmjs.com/package/@silkweave/mcp#what-this-means-for-ai-hosts) for the full discussion.
71
+
72
+ ## Auth
73
+
74
+ `edge()` serves the full OAuth 2.1 surface when you pass an `auth` config - protected-resource metadata (RFC 9728), `/authorize`, `/token`, `/register`, and the provider callback - alongside the MCP transport, all from the one handler. Pass a bearer-validating `AuthConfig` from [`@silkweave/auth`](https://www.npmjs.com/package/@silkweave/auth), or a full provider (e.g. `google()`) from `@silkweave/auth/oauth`:
75
+
76
+ ```typescript
77
+ import { google } from '@silkweave/auth/oauth'
78
+
79
+ const { adapter, handler } = edge({ auth: google({ /* clientId, clientSecret, resourceUrl, store, ... */ }) })
80
+ ```
81
+
82
+ ## Options
83
+
84
+ ```typescript
85
+ const { adapter, handler } = edge({
86
+ enableJsonResponse: true // Return JSON instead of SSE streams
87
+ })
88
+ ```
89
+
90
+ | Option | Type | Default | Description |
91
+ |--------|------|---------|-------------|
92
+ | `enableJsonResponse` | `boolean` | `false` | Return JSON responses instead of SSE streams |
93
+ | `auth` | `AuthConfig` | - | Bearer-token validation + OAuth routes (see [Auth](#auth)) |
94
+ | `path` | `string` | `/mcp` | The MCP transport path |
95
+
96
+ ## Compound Return Pattern
97
+
98
+ Unlike other Silkweave adapters that are simple `AdapterFactory` functions, `edge()` returns a compound object:
99
+
100
+ ```typescript
101
+ interface EdgeAdapter {
102
+ adapter: AdapterGenerator // Pass to silkweave().adapter()
103
+ handler: (request: Request) => Promise<Response> // The request handler
104
+ GET: (request: Request) => Promise<Response> // Alias for handler
105
+ POST: (request: Request) => Promise<Response> // Alias for handler
106
+ DELETE: (request: Request) => Promise<Response> // Alias for handler
107
+ }
108
+ ```
109
+
110
+ This is because edge/serverless platforms export request handlers rather than starting long-lived servers. The `adapter` property integrates with the Silkweave builder, while `handler`/`GET`/`POST`/`DELETE` are exported from your route file.
111
+
112
+ ## Deployment
113
+
114
+ ### Vercel configuration
115
+
116
+ ```json
117
+ {
118
+ "framework": null,
119
+ "functions": {
120
+ "api/mcp.ts": {
121
+ "memory": 1024,
122
+ "maxDuration": 60
123
+ }
124
+ },
125
+ "rewrites": [
126
+ { "source": "/mcp", "destination": "/api/mcp" }
127
+ ]
128
+ }
129
+ ```
130
+
131
+ ### CORS
132
+
133
+ CORS is not handled by the adapter (beyond OAuth/preflight). Configure it in your host framework - Next.js middleware, `vercel.json` headers, or Worker response headers:
134
+
135
+ ```json
136
+ {
137
+ "headers": [
138
+ {
139
+ "source": "/api/mcp",
140
+ "headers": [
141
+ { "key": "Access-Control-Allow-Origin", "value": "*" },
142
+ { "key": "Access-Control-Allow-Methods", "value": "POST, OPTIONS" },
143
+ { "key": "Access-Control-Allow-Headers", "value": "Content-Type, Authorization" }
144
+ ]
145
+ }
146
+ ]
147
+ }
148
+ ```
149
+
150
+ ## See Also
151
+
152
+ - [Silkweave README](https://github.com/silkweave/silkweave) - Full documentation
153
+ - [`@silkweave/core`](https://www.npmjs.com/package/@silkweave/core) - Core library
154
+ - [`@silkweave/mcp`](https://www.npmjs.com/package/@silkweave/mcp) - MCP stdio and HTTP adapters
155
+ - [`examples/cloudflare`](https://github.com/silkweave/silkweave/tree/master/examples/cloudflare) - Cloudflare Worker + Google OAuth + KV example
@@ -0,0 +1,20 @@
1
+ import { AuthConfig } from "@silkweave/auth";
2
+ import { AdapterGenerator } from "@silkweave/core";
3
+
4
+ //#region src/adapter/edge.d.ts
5
+ interface EdgeAdapterOptions {
6
+ enableJsonResponse?: boolean;
7
+ auth?: AuthConfig;
8
+ path?: string;
9
+ }
10
+ interface EdgeAdapter {
11
+ adapter: AdapterGenerator;
12
+ handler: (request: Request) => Promise<Response>;
13
+ GET: (request: Request) => Promise<Response>;
14
+ POST: (request: Request) => Promise<Response>;
15
+ DELETE: (request: Request) => Promise<Response>;
16
+ }
17
+ declare function edge(options?: EdgeAdapterOptions): EdgeAdapter;
18
+ //#endregion
19
+ export { EdgeAdapter, EdgeAdapterOptions, edge };
20
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +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;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,iBA0DxB,IAAA,CAAK,OAAA,GAAS,kBAAA,GAA0B,WAAA"}
@@ -0,0 +1,150 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
3
+ import { generateProtectedResourceMetadata, validateToken } from "@silkweave/auth";
4
+ import { registerTools } from "@silkweave/mcp/tools";
5
+ //#region src/adapter/edge.ts
6
+ const CORS_HEADERS = {
7
+ "Access-Control-Allow-Origin": "*",
8
+ "Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
9
+ "Access-Control-Allow-Headers": "*",
10
+ "Access-Control-Max-Age": "86400"
11
+ };
12
+ async function parseOAuthRequest(url, request) {
13
+ let body;
14
+ if (request.method === "POST") {
15
+ const contentType = request.headers.get("content-type") ?? "";
16
+ const text = await request.text();
17
+ if (contentType.includes("json")) body = JSON.parse(text);
18
+ else body = Object.fromEntries(new URLSearchParams(text));
19
+ }
20
+ return {
21
+ method: request.method,
22
+ url,
23
+ headers: Object.fromEntries(request.headers.entries()),
24
+ body
25
+ };
26
+ }
27
+ function oauthResponseToResponse(oauthRes) {
28
+ const responseBody = oauthRes.body ? typeof oauthRes.body === "string" ? oauthRes.body : JSON.stringify(oauthRes.body) : null;
29
+ return new Response(responseBody, {
30
+ status: oauthRes.status,
31
+ headers: oauthRes.headers
32
+ });
33
+ }
34
+ async function routeOAuth(url, request, provider, callbackPath) {
35
+ const oauthReq = await parseOAuthRequest(url, request);
36
+ let oauthRes;
37
+ if (url.pathname === "/.well-known/oauth-authorization-server") oauthRes = provider.metadata();
38
+ else if (url.pathname === "/authorize") oauthRes = await provider.authorize(oauthReq);
39
+ else if (url.pathname === callbackPath) oauthRes = await provider.callback(oauthReq);
40
+ else if (url.pathname === "/token") oauthRes = await provider.token(oauthReq);
41
+ else oauthRes = await provider.register(oauthReq);
42
+ return oauthResponseToResponse(oauthRes);
43
+ }
44
+ function edge(options = {}) {
45
+ const mcpPath = options.path ?? "/mcp";
46
+ const callbackPath = options.auth?.callbackPath ?? "/auth/callback";
47
+ let _actions = [];
48
+ let _options = null;
49
+ let _context = null;
50
+ let _readyResolve;
51
+ const _ready = new Promise((resolve) => {
52
+ _readyResolve = resolve;
53
+ });
54
+ const validPaths = new Set([mcpPath]);
55
+ if (options.auth?.authorizationServers?.length && options.auth.resourceUrl) validPaths.add("/.well-known/oauth-protected-resource");
56
+ if (options.auth?.provider) {
57
+ validPaths.add("/.well-known/oauth-authorization-server");
58
+ validPaths.add("/authorize");
59
+ validPaths.add(callbackPath);
60
+ validPaths.add("/token");
61
+ validPaths.add("/register");
62
+ }
63
+ const oauthPaths = options.auth?.provider ? {
64
+ "/.well-known/oauth-authorization-server": ["GET"],
65
+ "/authorize": ["GET"],
66
+ [callbackPath]: ["GET"],
67
+ "/token": ["POST"],
68
+ "/register": ["POST"]
69
+ } : null;
70
+ const handleRequest = async (request) => {
71
+ const url = new URL(request.url);
72
+ if (!validPaths.has(url.pathname)) return new Response("Not Found", { status: 404 });
73
+ if (request.method === "OPTIONS") return new Response(null, {
74
+ status: 200,
75
+ headers: CORS_HEADERS
76
+ });
77
+ if (url.pathname === "/.well-known/oauth-protected-resource") {
78
+ const metadata = generateProtectedResourceMetadata(options.auth.resourceUrl, options.auth.authorizationServers, options.auth.requiredScopes);
79
+ return new Response(JSON.stringify(metadata), { headers: {
80
+ ...CORS_HEADERS,
81
+ "Content-Type": "application/json",
82
+ "Cache-Control": "max-age=3600"
83
+ } });
84
+ }
85
+ if (oauthPaths) {
86
+ const methods = oauthPaths[url.pathname];
87
+ if (methods) {
88
+ if (!methods.includes(request.method)) return new Response("Method not allowed", { status: 405 });
89
+ return routeOAuth(url, request, options.auth.provider, callbackPath);
90
+ }
91
+ }
92
+ if (request.method !== "POST") return new Response("Method Not Allowed", {
93
+ status: 405,
94
+ headers: {
95
+ ...CORS_HEADERS,
96
+ Allow: "POST"
97
+ }
98
+ });
99
+ await _ready;
100
+ let requestContext = _context;
101
+ if (options.auth) {
102
+ const result = await validateToken(request.headers.get("authorization"), options.auth, _context.fork({ request }));
103
+ if (result.error) return new Response(JSON.stringify(result.error.body), {
104
+ status: result.error.statusCode,
105
+ headers: result.error.headers
106
+ });
107
+ if (result.auth) requestContext = _context.fork({ auth: result.auth });
108
+ }
109
+ const transport = new WebStandardStreamableHTTPServerTransport({
110
+ sessionIdGenerator: void 0,
111
+ enableJsonResponse: options.enableJsonResponse
112
+ });
113
+ const server = new McpServer({
114
+ name: _options.name,
115
+ description: _options.description,
116
+ version: _options.version
117
+ }, { capabilities: {
118
+ tools: {},
119
+ logging: {}
120
+ } });
121
+ registerTools(server, _actions, requestContext);
122
+ await server.connect(transport);
123
+ return transport.handleRequest(request);
124
+ };
125
+ const adapter = (silkweaveOptions, baseContext) => {
126
+ _options = silkweaveOptions;
127
+ _context = baseContext.fork({ adapter: "edge" });
128
+ return {
129
+ context: _context,
130
+ start: async (actions) => {
131
+ _actions = actions;
132
+ _readyResolve();
133
+ },
134
+ stop: async () => {
135
+ _actions = [];
136
+ }
137
+ };
138
+ };
139
+ return {
140
+ adapter,
141
+ handler: handleRequest,
142
+ GET: handleRequest,
143
+ POST: handleRequest,
144
+ DELETE: handleRequest
145
+ };
146
+ }
147
+ //#endregion
148
+ export { edge };
149
+
150
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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, SilkweaveContext, SilkweaveOptions } from '@silkweave/core'\nimport { registerTools } from '@silkweave/mcp/tools'\n\nexport interface EdgeAdapterOptions {\n enableJsonResponse?: boolean\n auth?: AuthConfig\n path?: string\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 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, _actions, requestContext)\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 = 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":"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"}
package/package.json CHANGED
@@ -1,7 +1,54 @@
1
1
  {
2
2
  "name": "@silkweave/edge",
3
- "version": "0.1.0",
4
- "publishConfig": {
5
- "access": "public"
3
+ "version": "3.1.0",
4
+ "description": "Silkweave Web-Standard edge/serverless adapter (Cloudflare Workers, Vercel, Bun, Deno, Hono)",
5
+ "license": "MIT",
6
+ "homepage": "https://www.silkweave.dev",
7
+ "bugs": {
8
+ "url": "https://github.com/silkweave/silkweave/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+ssh://git@github.com/silkweave/silkweave.git",
13
+ "directory": "packages/edge"
14
+ },
15
+ "type": "module",
16
+ "main": "./build/index.mjs",
17
+ "types": "./build/index.d.mts",
18
+ "files": [
19
+ "build"
20
+ ],
21
+ "exports": {
22
+ ".": {
23
+ "@silkweave/source": "./src/index.ts",
24
+ "types": "./build/index.d.mts",
25
+ "default": "./build/index.mjs"
26
+ }
27
+ },
28
+ "dependencies": {
29
+ "@modelcontextprotocol/sdk": "^1.29.0",
30
+ "zod": "^3.25.0",
31
+ "@silkweave/auth": "3.1.0",
32
+ "@silkweave/core": "3.1.0",
33
+ "@silkweave/mcp": "3.1.0"
34
+ },
35
+ "devDependencies": {
36
+ "@eslint/js": "^10.0.1",
37
+ "@stylistic/eslint-plugin": "^5.10.0",
38
+ "@types/node": "^22.0.0",
39
+ "eslint": "^10.4.0",
40
+ "rimraf": "^6.1.3",
41
+ "tsdown": "^0.21.8",
42
+ "tsx": "^4.21.0",
43
+ "typescript": "^5.9.3",
44
+ "typescript-eslint": "^8.56.1"
45
+ },
46
+ "scripts": {
47
+ "clean": "rimraf build",
48
+ "build": "tsdown",
49
+ "watch": "tsdown --watch",
50
+ "typecheck": "tsc --noEmit",
51
+ "lint": "eslint",
52
+ "check": "pnpm lint && pnpm typecheck"
6
53
  }
7
54
  }