Repository navigation
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
betegon
force-pushed
the
bt/code-mode-http
branch
from
October 27, 2026 13:28
2fbe908 to
c74cfe6
Compare
betegon
force-pushed
the
bt/cloudflare-test-runtime
branch
from
October 27, 2026 13:28
7fb178a to
49d10be
Compare
betegon
added a commit
that referenced
this pull request
Oct 27, 2026
The Cloudflare test plugin still used an older Miniflare/workerd than Wrangler, so updating the direct dependency alone left different runtimes in local and integration tests. Switch to `@cloudflare/vitest-plugin` 1.4.6 and align Miniflare/workerd with Wrangler. Miniflare 5 removed `fetchMock`; an Undici outbound service preserves the existing fixtures and `disableNetConnect()` policy. This is the prerequisite for #1670 (HTTP Code Mode), followed by #1675 (agent evals). Only seven test/dependency files move here; the broker, permissions and production integration remain in #1670. Validated independently on Node 24: **443 Cloudflare tests across 34 files**, root typechecks, lint and frozen install. The earlier full workspace run had unrelated CLI fixture/platform failures; CLI fixes are excluded. No deployment performed.
betegon
force-pushed
the
bt/code-mode-http
branch
from
October 27, 2026 13:44
c74cfe6 to
9be4926
Compare
betegon
marked this pull request as ready for review
October 29, 2026 21:17
Sentry's token endpoint always returns `scope` (process_token_details), so the optional schema field and its upstreamScopes tests and docs are not needed. Code Mode does not read upstreamScopes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
main moved the stdio server into the CLI (#1731), so the rejection of hosted-only Code Mode skills moves from mcp-server's resolve.ts to the CLI's `sentry mcp` config, and `buildServer` no longer takes `sdkVersion`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
Code Mode carried its own copy of the bounded body loop. Expose that loop from toolkit-core as `readBoundedStream(stream, maxBytes)` and use it for Sentry responses and the sandbox result. The configured API base comes from server settings, so the extra URL validation in `http.ts` goes too; the broker's origin and prefix check is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
Code Mode rebuilt the region host, attribution headers and bearer header by hand. It now takes them from the same API service the other tools use: `apiServiceForOrganization()` resolves the organization's region, and `requestTarget()` returns that service's origin and headers. The broker no longer handles the access token, and a malformed token fails the same way as in every other tool. This replaces mcp-core's `validate-region-url` export. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
Authorization walked the 1.9 MB search schema, parsed on first use. It now matches the method and path of each `@sentry/api` operation, which the generator writes next to the schema, as the CLI does with its generated catalog. The schema stays for `search_sentry_api`, and the drift test checks that both files describe the catalog's release. The defensive schema parsing and its tests go away, as do the access-test fixtures for OpenAPI `security`, which authorization never read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
`/.mcp/tools.json` converted Code Mode's Zod schemas at runtime, and `toolDefinitions.json` left them out, so the chat listed both tools without a description. The definitions generator now emits them next to the registry tools, and the route serves the generated file as it did before. The generator also stops overriding `toolCount` for hosted-only skills: its only reader, the consent screen, hides the count for Code Mode skills. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
…eferences `CODE_MODE_SKILLS` and the `hostedOnly` skill flag listed the same two skills, and five call sites repeated the membership check. Derive the list from `hostedOnly` and check it with `isCodeModeSkill()`. The consent screen also kept remembered API Read/Write choices through a project consent, where those skills are hidden. That threaded the OAuth resource into the preference cookie for a rare case. A project consent now saves what it shows, like every other consent, and API skills start unchecked again on the next organization consent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
- Drop the request-size and nested-input limit tests: main's handler and toolkit-core tests own those limits. - Drop the upstreamScopes scenarios (dashboard copy with an org:read token, recorded scopes on a 403): Code Mode never reads upstreamScopes. - Replace the grant-visibility tests with one table, which also checks that API Read and API Write are listed and how they are annotated. - Merge the API error, ignored-rejection and handled-rejection cases into fewer tests with the same assertions. - Reduce the consent round trip to the case that matters: approving API Write requests no extra upstream scopes. - Move the integration test next to the code it exercises. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
`docs/testing/code-mode.md` described the design and permissions, not how to test, and carried the PR's investigation notes and validation status. Move it to `docs/architecture/code-mode.md`, keep the design, permissions, schema, limits and telemetry, and cut the narrative and stale notes. Replace the 1.1 MB PNG with a Mermaid diagram, as the OAuth docs do, so it can be edited in a pull request. Shorten the Cloudflare architecture section to a summary and a link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
From an independent review of the cleanup: - Deriving `CODE_MODE_SKILLS` from `hostedOnly` meant a future hosted-only skill would grant arbitrary API access by itself. List the two skills again, and test that each is `hostedOnly` so stdio never serves them. - Every skill's generated `toolCount` matches its `tools` again, Code Mode skills included. - Restore the check that a caught 403 does not revoke the grant. - Docs: say which checks the broker and `ApiAuthorization` run, that reads are GET and HEAD, that direct `Sentry-Bearer` connections default to API Write, and that only the program text can contain concrete URLs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
Warden flagged that a 304 from a conditional request would come back as a 502. A 304 can't happen: `sentry.request()` has no `headers` option and raw `fetch` is blocked, so no program can send `If-Match` or `If-None-Match`. The broker now forwards only `accept` and `content-type`, and the 304 special case goes away; any 3xx is still refused before it can redirect the token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
Warden: the sandbox parsed a JSON content type before checking the status, so an error response with a body that was not JSON surfaced as "API response was not valid JSON" without its status, path or headers. A failed request now keeps the raw text as `data`; only a successful response with an invalid JSON body is an error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
`search_sentry_api` (2,310 characters) and `execute_sentry_code` (3,259) exceeded the repository's description budget, which some clients enforce. Both keep every rule and the published examples, in fewer words: 2,045 and 2,042 characters. The length test now covers the Code Mode definitions too, since they are registered outside the tool registry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
`buildServer()` turns `listChanged` off after registering its tools because each request's catalog is fixed. Code Mode registers two more tools afterwards. Today the SDK only sets the capability on the first registration, but that is an SDK detail, so set it the same way `buildServer()` does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Code Mode is the MCP equivalent of
sentry api: agents can use published API operations without a dedicated MCP tool.The client's agent writes JavaScript; our Cloudflare sandbox executes authenticated HTTP calls and returns the result.
For example: “Copy this dashboard for two projects, preserving its widgets and filters.” The existing tool catalog cannot do this; Code Mode can.
search_sentry_apidiscovers the schema andexecute_sentry_coderuns the program. This version is HTTP-only; the SDK remains future work.Prerequisite #1676 is merged. Stack: this PR → #1675 (agent evals). #1807 (shared path matcher with the CLI) is also stacked on this PR. Runtime and permission safety tests remain here.
sequenceDiagram participant Agent as Agent / MCP client participant Sandbox as Sandbox<br/>(no token, no network) participant Broker as Broker in the parent Worker<br/>(holds the token) participant API as Sentry API Agent->>Sandbox: execute_sentry_code(code) Sandbox->>Broker: sentry.request(...) via RPC Broker->>API: checks permissions, adds Authorization API-->>Broker: HTTP response Broker-->>Sandbox: response data Sandbox-->>Agent: program resultHow it fits
One composition. The hosted handler calls
registerCodeModeTools(server, env.LOADER, context)on the server it builds for each request.ApiAuthorizationis always applied; there is no standalone worker or eval-only path. Tool definitions live inmcp-core/src/code-mode.tsand are generated intotoolDefinitions.jsonwith the other tools. The runtime lives inmcp-cloudflare/src/code-mode/.Requests go through
SentryApiService, like every other tool: the organization's regional host, MCP client attribution and the bearer header come from it, so the broker never handles the token itself.The API data ships with the deploy, as in Cloudflare's Code Mode server: nothing fetches it at runtime. For the
@sentry/apirelease in the pnpm catalog (0.428.0: 173 paths, 273 operations), the same release the CLI buildssentry apiandsentry schemafrom:generated/openapi.json.txtis the dereferenced OpenAPI document. It is a Workers Text module that each search sandbox parses.generated/operations.jsonholds the method and path of each operation, which authorization matches. This is how the CLI ships its generated catalog.To move to a new release, bump the catalog and run
pnpm --filter @sentry/mcp-cloudflare generate:openapi; a test fails if either file differs from the installed@sentry/api.Permissions
The Sentry token authenticates API calls; its OAuth scopes and the user's Sentry permissions set the maximum access.
The permission screen controls which of those actions this MCP connection may perform, without changing the token or its scopes.
/mcpcovers organizations authorized by the Sentry token;/mcp/{org}is restricted to that organization. Project-scoped connections do not expose Code Mode.Sentry-Bearerconnections default to all active skills, including API Write: the client already holds the token.skills/disable-skillscan narrow access; token permissions and connection constraints still apply.sentry mcp,@sentry/mcp-server) rejects the API skills. Shared upstream OAuth scopes stay unchanged; the broker checks the MCP grant on every call, and Sentry still enforces token, role and resource permissions. Credentials stay outside generated code.Debugging
tools/callspan records:gen_ai.tool.call.arguments.code, like every tool's arguments)ok,error,timeout,internal_error)METHOD template status, withdeniedwhen this connection's policy refused themapp.code_mode.execution) and every operation by path template (app.code_mode.request).pnpm run devwithAuthorization: Sentry-Bearer <token>and?skills=api-readruns the same code path against a real account.Design, permissions and limits:
docs/architecture/code-mode.md.Validation and before production
Executions close pending RPC, abort in-flight HTTP and block requests whose authorization finishes after execution ends. Programs must await API calls before returning; accepted writes cannot be rolled back.
An independent review of the cleanup found nothing that widens what a request can reach. Its smaller findings are fixed in
d10ff0f: Code Mode skills are listed explicitly instead of derived fromhostedOnly, the 403-does-not-revoke check is back, and the docs are corrected.Warden's findings:
f4150e1. The sandbox cannot send conditional headers, so the broker no longer forwards them and a 304 cannot occur.cc37b12. A failed response whose body is not JSON keeps its HTTP details.listChanged:initializealready advertisedlistChanged: false, because the SDK sets the capability only on the firstregisterTool. That is an SDK detail, so929dbccsets it explicitly after Code Mode registers, asbuildServer()does.7ac6e60. Both descriptions now fit the repo's 2,048-character budget, with the same rules and the same published examples:search_sentry_apiwent from 2,310 to 2,045 characters andexecute_sentry_codefrom 3,259 to 2,042. The length test now covers them.Passed locally on
929dbcc:sentry mcptests.The remaining CLI failures (upgrade,
cli fix, db permissions and others) are the same 24 that fail onmainin a root container.Agent evals in #1675 passed 35/35 with
claude-opus-5-5on this composition before the cleanup and before the descriptions were shortened. After it, the harness tests pass against the cleaned branch (61 tests, real eval worker). The model runs were not repeated.Pending before production: real hosted OAuth-to-API authorization and Cloudflare CPU/termination/concurrency enforcement. Local workerd tests do not establish these platform guarantees; the
internal_errorissues and metrics above will show whether hosted CPU limits trigger. No production deployment performed.https://claude.ai/code/session_017M6odW3kt5i65zATxfz9RX
Generated by Claude Code