@@ -5,8 +5,7 @@ Cloudflare Workers deployment configuration and patterns.
55## Architecture Overview
66
77The deployment consists of:
8- - ** Worker** : Main HTTP server with OAuth flow
9- - ** Durable Object** : MCP transport handling WebSocket connections
8+ - ** Worker** : Stateless HTTP server with OAuth flow and MCP handler
109- ** KV Storage** : OAuth token storage
1110- ** Static Assets** : React UI for setup instructions
1211
@@ -16,30 +15,30 @@ The deployment consists of:
1615
1716``` jsonc
1817{
19- " name" : " sentry-mcp-oauth " ,
18+ " name" : " sentry-mcp" ,
2019 " main" : " ./src/server/index.ts" ,
2120 " compatibility_date" : " 2025-03-21" ,
2221 " compatibility_flags" : [
2322 " nodejs_compat" ,
24- " nodejs_compat_populate_process_env"
23+ " nodejs_compat_populate_process_env" ,
24+ " global_fetch_strictly_public"
2525 ],
2626 " keep_vars" : true ,
27-
27+
2828 // Bindings
29- " durable_objects" : {
30- " bindings" : [{
31- " name" : " SENTRY_MCP" ,
32- " class_name" : " SentryMCP"
33- }]
34- },
3529 " kv_namespaces" : [{
36- " binding" : " KV " ,
37- " id" : " your-kv-namespace-id "
30+ " binding" : " OAUTH_KV " ,
31+ " id" : " 8dd5e9bafe1945298e2d5ca3b408a553 "
3832 }],
39-
40- // SPA configuration
41- " site" : {
42- " bucket" : " ./dist/client"
33+ " ai" : {
34+ " binding" : " AI"
35+ },
36+
37+ // Static assets configuration
38+ " assets" : {
39+ " directory" : " ./public" ,
40+ " binding" : " ASSETS" ,
41+ " not_found_handling" : " single-page-application"
4342 }
4443}
4544```
@@ -51,7 +50,12 @@ Required in production:
5150SENTRY_CLIENT_ID=your_oauth_app_id
5251SENTRY_CLIENT_SECRET=your_oauth_app_secret
5352COOKIE_SECRET=32_char_random_string
54- SENTRY_HOST=sentry.io # Optional for self-hosted
53+ ```
54+
55+ Optional overrides for self-hosted deployments:
56+ ``` bash
57+ # Leave unset to target the SaaS host
58+ SENTRY_HOST=sentry.example.com # Hostname only (self-hosted only)
5559```
5660
5761Development (.dev.vars):
@@ -61,27 +65,36 @@ SENTRY_CLIENT_SECRET=dev_secret
6165COOKIE_SECRET=dev-cookie-secret
6266```
6367
64- ## Durable Object Setup
68+ ## MCP Handler Setup
6569
66- The MCP transport runs as a Durable Object :
70+ The MCP handler uses a stateless architecture with AsyncLocalStorage :
6771
6872``` typescript
69- export class SentryMCP extends DurableObject {
70- async fetch(request : Request ): Promise <Response > {
71- // Handle WebSocket upgrade
72- if (request .headers .get (" Upgrade" ) === " websocket" ) {
73- const [client, server] = Object .values (new WebSocketPair ());
74-
75- await this .handleWebSocket (server );
76- return new Response (null , {
77- status: 101 ,
78- webSocket: client
79- });
80- }
81-
82- return new Response (" Not found" , { status: 404 });
83- }
84- }
73+ import { experimental_createMcpHandler as createMcpHandler } from " agents/mcp" ;
74+ import { serverContextStorage } from " @sentry/mcp-server/internal/context-storage" ;
75+
76+ const mcpHandler: ExportedHandler <Env > = {
77+ async fetch(request : Request , env : Env , ctx : ExecutionContext ): Promise <Response > {
78+ // Extract auth props from ExecutionContext (set by OAuth provider)
79+ const oauthCtx = ctx as OAuthExecutionContext ;
80+
81+ // Build complete ServerContext from OAuth props + constraints
82+ const serverContext: ServerContext = {
83+ userId: oauthCtx .props .userId ,
84+ clientId: oauthCtx .props .clientId ,
85+ accessToken: oauthCtx .props .accessToken ,
86+ grantedScopes: expandedScopes ,
87+ constraints: verification .constraints ,
88+ sentryHost ,
89+ mcpUrl: oauthCtx .props .mcpUrl ,
90+ };
91+
92+ // Run MCP handler within ServerContext (AsyncLocalStorage)
93+ return serverContextStorage .run (serverContext , () => {
94+ return createMcpHandler (server , { route: " /mcp" })(request , env , ctx );
95+ });
96+ },
97+ };
8598```
8699
87100## OAuth Provider Setup
@@ -212,19 +225,16 @@ Tests validate (using Vitest):
212225
213226First-time setup:
214227``` bash
215- # Create KV namespace
216- npx wrangler kv:namespace create KV
217-
218- # Create Durable Object namespace
219- npx wrangler durable-objects namespace create SENTRY_MCP
228+ # Create KV namespace for OAuth token storage
229+ npx wrangler kv:namespace create OAUTH_KV
220230
221- # Update wrangler.jsonc with IDs
231+ # Update wrangler.jsonc with the namespace ID
222232```
223233
224234## Multi-Region Considerations
225235
226236Cloudflare Workers run globally, but consider:
227- - Durable Objects have a home region
237+ - Workers are stateless and edge-deployed
228238- KV is eventually consistent globally
229239- Use regional hints for performance
230240
@@ -275,7 +285,7 @@ export default {
275285Monitor via Cloudflare dashboard:
276286- Request rates
277287- Error rates
278- - Durable Object usage
288+ - CPU time and memory usage
279289- KV operations
280290
281291## Troubleshooting
@@ -286,9 +296,9 @@ Monitor via Cloudflare dashboard:
286296 - Ensure callback URL matches Sentry app config
287297 - Check protocol (http vs https)
288298
289- 2 . ** Durable Object not found **
290- - Verify namespace binding in wrangler.jsonc
291- - Check class export in main file
299+ 2 . ** AsyncLocalStorage context missing **
300+ - Verify serverContextStorage.run() wraps MCP handler
301+ - Check ExecutionContext.props contains OAuth data
292302
2933033 . ** Environment variables missing**
294304 - Use ` wrangler secret put ` for production
0 commit comments