Add website agent discovery metadata#453
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds multiple /.well-known discovery endpoints and builders, a Zod-based Goccia tool input schema with byte limits and validators, a WebMCP client tool integrator that validates and calls server APIs, updates the server run handler to use the validator, and expands tests for discovery and schema behavior. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser as Browser (WebMcpTools)
participant ModelCtx as navigator.modelContext / registerTool
participant Validator as validateGocciaToolInput
participant API as Server (/api/execute or /api/test)
Browser->>ModelCtx: register tools (goccia.execute, goccia.test)
Browser->>Validator: validate input payload
alt validation ok
Browser->>API: POST validated payload
API->>Validator: validate server-side
Validator-->>API: ok
API-->>Browser: JSON result (200)
else validation fails
Validator-->>Browser: error (CODE_TOO_LARGE / INVALID_INPUT / MISSING_CODE)
Browser-->>Browser: abort request, show error
end
Browser->>ModelCtx: cleanup on unmount (clearContext / unregister)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Review rate limit: 0/5 reviews remaining, refill in 55 minutes and 3 seconds. Comment |
Benchmark Results407 benchmarks Interpreted: 🟢 73 improved · 🔴 29 regressed · 305 unchanged · avg +2.0% arraybuffer.js — Interp: 🟢 4, 10 unch. · avg +1.8% · Bytecode: 14 unch. · avg +0.2%
arrays.js — Interp: 🟢 3, 🔴 1, 15 unch. · avg +0.9% · Bytecode: 🟢 3, 16 unch. · avg +0.7%
async-await.js — Interp: 🟢 1, 5 unch. · avg +1.0% · Bytecode: 🔴 1, 5 unch. · avg -2.4%
async-generators.js — Interp: 2 unch. · avg -0.5% · Bytecode: 2 unch. · avg +0.4%
base64.js — Interp: 10 unch. · avg +0.3% · Bytecode: 10 unch. · avg +0.1%
classes.js — Interp: 🟢 1, 🔴 2, 28 unch. · avg -0.5% · Bytecode: 🔴 2, 29 unch. · avg +0.8%
closures.js — Interp: 🟢 2, 9 unch. · avg +1.4% · Bytecode: 🟢 1, 10 unch. · avg -1.2%
collections.js — Interp: 🟢 1, 🔴 5, 6 unch. · avg -1.1% · Bytecode: 🟢 2, 🔴 1, 9 unch. · avg +0.2%
csv.js — Interp: 🔴 1, 12 unch. · avg -0.6% · Bytecode: 🟢 2, 🔴 1, 10 unch. · avg +0.3%
destructuring.js — Interp: 🟢 7, 🔴 1, 14 unch. · avg +2.4% · Bytecode: 🟢 6, 16 unch. · avg +2.7%
fibonacci.js — Interp: 🟢 2, 6 unch. · avg +0.9% · Bytecode: 🟢 1, 🔴 1, 6 unch. · avg +0.6%
float16array.js — Interp: 🟢 8, 🔴 1, 23 unch. · avg +1.5% · Bytecode: 🟢 14, 🔴 4, 14 unch. · avg +11.9%
for-of.js — Interp: 7 unch. · avg +0.4% · Bytecode: 7 unch. · avg +0.6%
generators.js — Interp: 🟢 3, 1 unch. · avg +3.4% · Bytecode: 4 unch. · avg -0.8%
iterators.js — Interp: 🟢 8, 34 unch. · avg +1.0% · Bytecode: 🟢 6, 🔴 3, 33 unch. · avg +0.5%
json.js — Interp: 🟢 8, 12 unch. · avg +1.9% · Bytecode: 🟢 1, 19 unch. · avg +0.6%
jsx.jsx — Interp: 🔴 5, 16 unch. · avg -2.0% · Bytecode: 🟢 2, 🔴 2, 17 unch. · avg -0.8%
modules.js — Interp: 🟢 3, 6 unch. · avg +1.9% · Bytecode: 🟢 2, 🔴 1, 6 unch. · avg +0.9%
numbers.js — Interp: 11 unch. · avg +1.4% · Bytecode: 🟢 2, 🔴 2, 7 unch. · avg -0.6%
objects.js — Interp: 🟢 3, 4 unch. · avg +1.7% · Bytecode: 🟢 2, 🔴 1, 4 unch. · avg +0.1%
promises.js — Interp: 12 unch. · avg -0.6% · Bytecode: 🟢 2, 10 unch. · avg +1.2%
regexp.js — Interp: 🟢 1, 10 unch. · avg +1.1% · Bytecode: 11 unch. · avg +0.7%
strings.js — Interp: 🟢 1, 🔴 1, 17 unch. · avg +0.3% · Bytecode: 🔴 10, 9 unch. · avg -2.8%
tsv.js — Interp: 9 unch. · avg -0.1% · Bytecode: 🔴 1, 8 unch. · avg +0.3%
typed-arrays.js — Interp: 🟢 10, 🔴 2, 10 unch. · avg +14.5% · Bytecode: 🟢 6, 🔴 6, 10 unch. · avg -1.9%
uint8array-encoding.js — Interp: 🟢 5, 🔴 2, 11 unch. · avg +20.7% · Bytecode: 🟢 7, 🔴 5, 6 unch. · avg +4.4%
weak-collections.js — Interp: 🟢 2, 🔴 8, 5 unch. · avg -8.9% · Bytecode: 🟢 7, 🔴 1, 7 unch. · avg +28.0%
Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context. |
Suite Timing
Measured on ubuntu-latest x64. |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
website/src/lib/goccia-api.ts (1)
18-22:⚠️ Potential issue | 🟠 MajorWiden the pre-parse body cap.
MAX_BODY_BYTES = MAX_CODE_BYTES + 1_024is too tight now that the code limit is only 8 KiB: valid snippets can still serialize to more than 9 KiB of JSON when they contain lots of escapes or newlines, so the request gets rejected before the later byte check runs. Please make this envelope cap much more generous or move the enforcement to a post-parse check.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/src/lib/goccia-api.ts` around lines 18 - 22, The pre-parse envelope cap MAX_BODY_BYTES is too small (MAX_CODE_BYTES + 1_024) and rejects valid JSON that expands with escapes/newlines; increase the allowance or defer enforcement until after JSON.parse. Update the MAX_BODY_BYTES definition in website/src/lib/goccia-api.ts (the MAX_BODY_BYTES and MAX_CODE_BYTES symbols) to a much more generous value (e.g. add ~8 KiB–64 KiB headroom or use MAX_CODE_BYTES * 2) or remove the strict pre-parse cap and perform the size check after parsing the body so the existing per-field byte validation still runs.
🧹 Nitpick comments (1)
website/src/components/webmcp-tools.tsx (1)
113-127: Avoid unhandled promise rejections in context registration calls.Lines 114 and 127 intentionally discard promises. If either async API rejects, it can surface as unhandled rejection noise in production.
Suggested fix
+const swallow = <T,>(p: Promise<T>) => p.catch(() => undefined); + export function WebMcpTools() { useEffect(() => { @@ const tools = buildTools(); if (modelContext.provideContext) { - void modelContext.provideContext({ tools }); + void swallow(Promise.resolve(modelContext.provideContext({ tools }))); return () => { if (modelContext.clearContext) { - void modelContext.clearContext(); + void swallow(Promise.resolve(modelContext.clearContext())); } else { - void modelContext.provideContext?.({ tools: [] }); + void swallow(Promise.resolve(modelContext.provideContext?.({ tools: [] }))); } }; } @@ const controller = new AbortController(); for (const tool of tools) { - void modelContext.registerTool(tool, { signal: controller.signal }); + void swallow( + Promise.resolve(modelContext.registerTool(tool, { signal: controller.signal })), + ); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/src/components/webmcp-tools.tsx` around lines 113 - 127, The code currently discards promises from modelContext.provideContext, modelContext.clearContext and modelContext.registerTool which can lead to unhandled promise rejections; update the logic to handle rejections by awaiting these calls or attaching .catch handlers (e.g., await or void promise.catch(...)) and ensure registerTool loop respects the AbortController signal and handles per-tool rejections so failures are logged/ignored instead of bubbling as unhandled rejections; specifically update usages of modelContext.provideContext, modelContext.clearContext and modelContext.registerTool (and the AbortController usage) to consistently handle async errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@website/src/app/.well-known/mcp/server-card.json/route.ts`:
- Around line 27-30: The GET handler currently calls fetchLatestRelease without
handling failures, so wrap the call in a try/catch (or check its result) and
ensure you pass a fallback tag value of "nightly" into
buildMcpServerCardResponse when fetchLatestRelease throws or returns undefined;
update the GET function to catch errors from fetchLatestRelease and set const
tag = release?.tagName ?? "nightly" (or assign "nightly" in the catch) before
calling buildMcpServerCardResponse so the well-known endpoint always returns
discovery metadata.
In `@website/src/components/webmcp-tools.tsx`:
- Around line 61-67: The current code calls fetch(endpoint, ...) and awaits
response, but if fetch rejects (network/CORS/offline) the async call will throw
and `execute` will propagate an exception instead of returning the consistent
tool result object; update the call site in the function (e.g., the execute
handler that builds `endpoint`/`payload` and currently assigns
`response`/`body`) to wrap the fetch + response.json() in a try/catch and on any
transport or parse error return a normalized tool response object (use the same
schema other branches return — e.g., an object with an error/status field and
the original endpoint/payload context) rather than letting the exception escape;
ensure you still attempt response.json() only when response is available and
include any available status/code in the normalized response.
In `@website/src/lib/agent-discovery.ts`:
- Around line 85-86: The discovery metadata currently advertises OAuth/OIDC
features that aren't implemented: remove the unsupported fields
(id_token_signing_alg_values_supported, jwks_uri, token_endpoint and any
id_token-related entries in claims_supported) from the discovery object so the
advertised capabilities match the running server; alternatively, if you prefer
to support OIDC, implement the missing pieces instead: add route handlers for
/oauth/token and /oauth/authorize, serve a valid JWKS at the declared jwks_uri,
integrate a JWT library to sign id_tokens with RS256 and expose the public key
in the JWKS, and ensure claims_supported only lists claims you actually emit.
In `@website/src/lib/goccia-tool-schema.ts`:
- Around line 1-12: The JSON schema in gocciaRunInputSchema uses maxLength
(character count) but MAX_GOCCIA_CODE_BYTES is a byte limit, so either enforce
byte-length at schema-validation time or document the mismatch: implement a
byte-aware check by adding a custom schema keyword/format (e.g., "maxBytes":
MAX_GOCCIA_CODE_BYTES) and register a validator that calls
Buffer.byteLength(value, "utf8") <= MAX_GOCCIA_CODE_BYTES (tie this into the
same validator used for gocciaRunInputSchema), or alternatively update the code
property's description to explicitly state maxLength is character-based and that
the server-side function (the runtime check in goccia-api.ts that uses
Buffer.byteLength) is the authoritative byte limit; pick one approach and apply
consistently so MAX_GOCCIA_CODE_BYTES and gocciaRunInputSchema remain correct
and unambiguous.
---
Outside diff comments:
In `@website/src/lib/goccia-api.ts`:
- Around line 18-22: The pre-parse envelope cap MAX_BODY_BYTES is too small
(MAX_CODE_BYTES + 1_024) and rejects valid JSON that expands with
escapes/newlines; increase the allowance or defer enforcement until after
JSON.parse. Update the MAX_BODY_BYTES definition in
website/src/lib/goccia-api.ts (the MAX_BODY_BYTES and MAX_CODE_BYTES symbols) to
a much more generous value (e.g. add ~8 KiB–64 KiB headroom or use
MAX_CODE_BYTES * 2) or remove the strict pre-parse cap and perform the size
check after parsing the body so the existing per-field byte validation still
runs.
---
Nitpick comments:
In `@website/src/components/webmcp-tools.tsx`:
- Around line 113-127: The code currently discards promises from
modelContext.provideContext, modelContext.clearContext and
modelContext.registerTool which can lead to unhandled promise rejections; update
the logic to handle rejections by awaiting these calls or attaching .catch
handlers (e.g., await or void promise.catch(...)) and ensure registerTool loop
respects the AbortController signal and handles per-tool rejections so failures
are logged/ignored instead of bubbling as unhandled rejections; specifically
update usages of modelContext.provideContext, modelContext.clearContext and
modelContext.registerTool (and the AbortController usage) to consistently handle
async errors.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b1257f32-67e8-451a-a3a6-44ee28d2c060
📒 Files selected for processing (13)
website/src/__tests__/agent-discovery.test.tswebsite/src/app/.well-known/agent-skills/gocciascript-api/SKILL.md/route.tswebsite/src/app/.well-known/agent-skills/index.json/route.tswebsite/src/app/.well-known/jwks.json/route.tswebsite/src/app/.well-known/mcp/server-card.json/route.tswebsite/src/app/.well-known/oauth-authorization-server/route.tswebsite/src/app/.well-known/oauth-protected-resource/route.tswebsite/src/app/.well-known/openid-configuration/route.tswebsite/src/app/layout.tsxwebsite/src/components/webmcp-tools.tsxwebsite/src/lib/agent-discovery.tswebsite/src/lib/goccia-api.tswebsite/src/lib/goccia-tool-schema.ts
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
website/src/lib/agent-discovery.ts (1)
68-80:⚠️ Potential issue | 🟠 Major
/.well-known/openid-configurationis still not valid OIDC metadata.
buildOpenIdConfiguration()just mirrors the OAuth AS fields, but OpenID Discovery requires theopenidscope and required OP metadata such assubject_types_supportedandid_token_signing_alg_values_supported. RFC 8414 also says zero-element claims must be omitted, soresponse_types_supported: []/grant_types_supported: []are not valid authorization-server metadata either. Either remove the OpenID document until the site is a real OP, or publish a fully conforming provider document. (openid.net)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/src/lib/agent-discovery.ts` around lines 68 - 80, The OpenID document generated by buildOpenIdConfiguration() is invalid: update buildOAuthAuthorizationServerMetadata(origin) and/or buildOpenIdConfiguration(origin) so they omit empty-array claims (do not return response_types_supported: [] or grant_types_supported: []), ensure scopes_supported includes "openid" (API_SCOPES must contain "openid" for OIDC), and when exposing OpenID configuration include required OP metadata such as subject_types_supported and id_token_signing_alg_values_supported (and any other mandatory OpenID Connect Discovery fields). Alternatively, if you do not intend to act as an OpenID Provider, remove buildOpenIdConfiguration() / the /.well-known/openid-configuration endpoint so you do not publish a non-conformant document.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@website/src/lib/goccia-tool-schema.ts`:
- Around line 86-121: The exported JSON Schema from gocciaRunInputSchema
currently marks "code" as required but omits the non-empty constraint, allowing
clients to send an empty string that the runtime rejects; update the "code"
property in gocciaRunInputSchema to include minLength: 1 so the schema enforces
non-empty source code (keep existing description, maxBytes and required array
unchanged).
- Around line 64-84: validateGocciaToolInput currently maps missing/invalid
"code" to INVALID_INPUT because it only checks for "exceeds" in the message;
update the errorCode logic in validateGocciaToolInput (which uses
gocciaToolInputZodSchema.safeParse and returns GocciaToolValidationResult) to
return "MISSING_CODE" when the first Zod issue targets the "code" field and
indicates a missing/required value (e.g., issue.path[0] === "code" and either
issue.code corresponds to a missing/required error or issue.message includes
"Required" or similar), keep the existing "CODE_TOO_LARGE" branch for the
message.includes("exceeds") case, and fall back to "INVALID_INPUT" otherwise so
downstream code no longer needs to string-match for "code is required".
---
Duplicate comments:
In `@website/src/lib/agent-discovery.ts`:
- Around line 68-80: The OpenID document generated by buildOpenIdConfiguration()
is invalid: update buildOAuthAuthorizationServerMetadata(origin) and/or
buildOpenIdConfiguration(origin) so they omit empty-array claims (do not return
response_types_supported: [] or grant_types_supported: []), ensure
scopes_supported includes "openid" (API_SCOPES must contain "openid" for OIDC),
and when exposing OpenID configuration include required OP metadata such as
subject_types_supported and id_token_signing_alg_values_supported (and any other
mandatory OpenID Connect Discovery fields). Alternatively, if you do not intend
to act as an OpenID Provider, remove buildOpenIdConfiguration() / the
/.well-known/openid-configuration endpoint so you do not publish a
non-conformant document.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f755f6e1-6f7c-48db-9cd2-e63269ed9e6d
⛔ Files ignored due to path filters (1)
website/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (9)
website/package.jsonwebsite/src/__tests__/agent-discovery.test.tswebsite/src/__tests__/goccia-tool-schema.test.tswebsite/src/app/.well-known/mcp/server-card.json/route.tswebsite/src/components/playground.tsxwebsite/src/components/webmcp-tools.tsxwebsite/src/lib/agent-discovery.tswebsite/src/lib/goccia-api.tswebsite/src/lib/goccia-tool-schema.ts
✅ Files skipped from review due to trivial changes (1)
- website/package.json
🚧 Files skipped from review as they are similar to previous changes (3)
- website/src/app/.well-known/mcp/server-card.json/route.ts
- website/src/tests/agent-discovery.test.ts
- website/src/components/webmcp-tools.tsx
There was a problem hiding this comment.
🧹 Nitpick comments (1)
website/src/lib/goccia-tool-schema.ts (1)
64-66: AcceptunknowninvalidateGocciaToolInputto remove caller casts.Typing
inputasGocciaToolInputforces upstreamascasts on untrusted JSON. Acceptingunknownkeeps type-safety at the boundary and improves ergonomics.♻️ Proposed refactor
-export function validateGocciaToolInput( - input: GocciaToolInput, -): GocciaToolValidationResult { +export function validateGocciaToolInput( + input: unknown, +): GocciaToolValidationResult {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/src/lib/goccia-tool-schema.ts` around lines 64 - 66, Change validateGocciaToolInput signature to accept input: unknown instead of GocciaToolInput and perform the necessary runtime narrowing/validation inside the function so callers don’t need to cast untrusted JSON; update the implementation in validateGocciaToolInput (and any helper functions it calls) to validate fields and return a GocciaToolValidationResult (errors or parsed value) based on those runtime checks, and then remove upstream `as` casts at call sites that previously forced GocciaToolInput.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@website/src/lib/goccia-tool-schema.ts`:
- Around line 64-66: Change validateGocciaToolInput signature to accept input:
unknown instead of GocciaToolInput and perform the necessary runtime
narrowing/validation inside the function so callers don’t need to cast untrusted
JSON; update the implementation in validateGocciaToolInput (and any helper
functions it calls) to validate fields and return a GocciaToolValidationResult
(errors or parsed value) based on those runtime checks, and then remove upstream
`as` casts at call sites that previously forced GocciaToolInput.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9f2f3f28-bd92-48c0-b06a-af870b804b6b
📒 Files selected for processing (5)
website/src/__tests__/agent-discovery.test.tswebsite/src/__tests__/goccia-tool-schema.test.tswebsite/src/lib/agent-discovery.tswebsite/src/lib/goccia-api.tswebsite/src/lib/goccia-tool-schema.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- website/src/tests/goccia-tool-schema.test.ts
There was a problem hiding this comment.
🧹 Nitpick comments (1)
website/src/lib/goccia-api.ts (1)
594-602: Remove redundant validator error-code remapping.
payload.error.codeis already narrowed to"INVALID_INPUT" | "MISSING_CODE" | "CODE_TOO_LARGE", so the ternary adds maintenance overhead without changing behavior.♻️ Proposed simplification
return transportError( { message: payload.error.message, - code: - payload.error.code === "CODE_TOO_LARGE" - ? "CODE_TOO_LARGE" - : payload.error.code === "MISSING_CODE" - ? "MISSING_CODE" - : "INVALID_INPUT", + code: payload.error.code, }, { status }, );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@website/src/lib/goccia-api.ts` around lines 594 - 602, The ternary remapping around payload.error.code in the error object is redundant; locate the object construction that sets message: payload.error.message and code: (the ternary chain comparing payload.error.code to "CODE_TOO_LARGE" and "MISSING_CODE") and replace the conditional mapping with a direct assignment of payload.error.code (i.e., set code to payload.error.code) so the function using payload.error.code (and any types like the narrowed union) is used directly without extra branching.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@website/src/lib/goccia-api.ts`:
- Around line 594-602: The ternary remapping around payload.error.code in the
error object is redundant; locate the object construction that sets message:
payload.error.message and code: (the ternary chain comparing payload.error.code
to "CODE_TOO_LARGE" and "MISSING_CODE") and replace the conditional mapping with
a direct assignment of payload.error.code (i.e., set code to payload.error.code)
so the function using payload.error.code (and any types like the narrowed union)
is used directly without extra branching.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: affe69a5-0f74-4568-a12b-9a75f32534d0
📒 Files selected for processing (4)
website/src/__tests__/goccia-tool-schema.test.tswebsite/src/components/webmcp-tools.tsxwebsite/src/lib/goccia-api.tswebsite/src/lib/goccia-tool-schema.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- website/src/tests/goccia-tool-schema.test.ts
- website/src/components/webmcp-tools.tsx
Summary