[logging] inspector: consume backend InternalLogContext in authorize wrapper#1931
[logging] inspector: consume backend InternalLogContext in authorize wrapper#1931
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Internal previewPreview URL: https://mcp-inspector-pr-1931.up.railway.app |
3793c66 to
4c560c9
Compare
10298d1 to
b74394b
Compare
4c560c9 to
837a168
Compare
837a168 to
9fcab59
Compare
9fcab59 to
d48002d
Compare
d48002d to
95f0834
Compare
ba938fd to
6feebad
Compare
95f0834 to
683f70a
Compare
683f70a to
fb0967b
Compare
…wrapper Updates authorizeServer and authorizeBatch to take c: Context as the first argument, strip internalLogContext from the response, and merge it into requestLogContext via setRequestLogContext. All call sites updated (servers.ts, conformance.ts, chat-v2.ts, evals.ts, and the internal createAuthorizedManager/withEphemeralConnection). No typed events are added in this PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fb0967b to
a324b93
Compare
WalkthroughAuthorization functions now accept a Hono Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
mcpjam-inspector/server/routes/web/__tests__/auth-manager.test.ts (1)
24-27: Test coverage gap: the new stripping/merging behavior is never exercised.
mockContext.var.requestLogContextisundefined, sosetRequestLogContextshort-circuits at itsif (!current) returnguard, and none of the fixtures include aninternalLogContextfield. The tests confirm the new signature compiles but say nothing about the actual contract of this PR — that backendinternalLogContextis (a) merged into the request log context and (b) absent from the returned result.Consider seeding
requestLogContextand adding a fixture withinternalLogContextso a regression to the wrapper would actually fail a test:🧪 Proposed additional coverage
it("strips internalLogContext from results and merges it into requestLogContext", async () => { const setSpy = vi.fn(); const ctx = { var: { requestLogContext: { authType: "signedIn" } }, set: setSpy, } as unknown as Context; global.fetch = vi.fn(async () => new Response( JSON.stringify({ results: { "server-1": { ok: true, role: "member", accessLevel: "workspace_member", permissions: { chatOnly: false }, serverConfig: { transportType: "http", url: "https://server-1.example.com/mcp", headers: {}, useOAuth: false, }, internalLogContext: { authType: "signedIn", workspaceRole: "owner", workspaceId: "workspace-1", }, }, }, }), { status: 200, headers: { "Content-Type": "application/json" } }, ), ) as typeof fetch; await createAuthorizedManager(ctx, "bearer-token", "workspace-1", ["server-1"], 10_000); expect(setSpy).toHaveBeenCalledWith( "requestLogContext", expect.objectContaining({ workspaceRole: "owner", workspaceId: "workspace-1" }), ); });Also applies to: 90-144
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcpjam-inspector/server/routes/web/__tests__/auth-manager.test.ts` around lines 24 - 27, The tests never exercise the new strip/merge behavior because mockContext.var.requestLogContext is undefined; seed requestLogContext and add a fixture containing internalLogContext so the merge and removal are exercised. Specifically, create a ctx with var.requestLogContext (e.g., { authType: "signedIn" }) and a set spy, stub global.fetch to return a JSON payload under results that includes an internalLogContext for a server, call createAuthorizedManager(...) with that ctx and server id, then assert ctx.set was called with "requestLogContext" containing the merged fields (workspaceRole, workspaceId) and that the returned/observed server result no longer contains internalLogContext. Use the existing mocks (mockContext / setSpy) and the createAuthorizedManager call to locate where to add this test.mcpjam-inspector/server/routes/web/auth.ts (2)
304-330: Two small type cleanups while you're here.
- Line 328:
Omit<ConvexAuthorizeResponse, "internalLogContext">["serverConfig"]is a no-op —serverConfigis not the omitted key, so this is identical toConvexAuthorizeResponse["serverConfig"]. The added complexity hints at a guard that isn't actually doing anything.- Lines 313–330:
ConvexBatchAuthorizeSuccessstill publicly carriesinternalLogContext?, even thoughauthorizeBatchis now contractually obliged to strip it before returning. Consumers ofConvexBatchAuthorizeResponsemay reasonably (and incorrectly) believe the field can surface on a result. Mirroring theClientSafeAuthorizeResponsepattern would close the loop.♻️ Proposed cleanup
-export type ConvexBatchAuthorizeSuccess = { +type ConvexBatchAuthorizeSuccessWithInternal = { ok: true; role: "owner" | "admin" | "member"; accessLevel: "workspace_member" | "shared_chat"; oauthAccessToken?: string | null; permissions: { chatOnly: boolean; }; - serverConfig: Omit<ConvexAuthorizeResponse, "internalLogContext">["serverConfig"]; + serverConfig: ConvexAuthorizeResponse["serverConfig"]; internalLogContext?: InternalLogContext; }; + +export type ConvexBatchAuthorizeSuccess = Omit< + ConvexBatchAuthorizeSuccessWithInternal, + "internalLogContext" +>;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcpjam-inspector/server/routes/web/auth.ts` around lines 304 - 330, Update the ConvexBatchAuthorizeSuccess type to mirror the ClientSafeAuthorizeResponse pattern by removing the optional internalLogContext property (it should not be exposed to clients) and simplify the serverConfig type: replace Omit<ConvexAuthorizeResponse, "internalLogContext">["serverConfig"] with ConvexAuthorizeResponse["serverConfig"] (since omitting internalLogContext does not affect the serverConfig property); ensure you only modify the ConvexBatchAuthorizeSuccess declaration and leave AuthorizedServerConfigHolder and ClientSafeAuthorizeResponse as-is.
245-285: Import canonical log-context types to prevent type inconsistencies.The local
InternalLogContextre-declares string-literal unions forauthType,workspaceRole,accessLevel,serverTransport, andsurface. The canonical definitions inutils/log-events.tsdiverge:AuthTypeincludes"system"and"unknown"in addition to"signedIn"and"guest", but the local type omits them. This narrows the accepted values, creating a type safety gap—code assigning"system"toauthTypewould pass local type-checking but fail when the result flows intoPartial<RequestLogContext>. Importing and using the canonical types makes this constraint explicit and maintainable.♻️ Proposed type unification
-import type { RequestLogContext } from "../../utils/log-events.js"; +import type { + RequestLogContext, + AuthType, + WorkspaceRole, + AccessLevel, + ServerTransport, + Surface, +} from "../../utils/log-events.js"; … type InternalLogContext = { - authType: "signedIn" | "guest"; + authType: AuthType; userId?: string | null; … - workspaceRole?: "owner" | "admin" | "member" | "guest" | "editor" | "chat" | null; - accessLevel?: "workspace_member" | "shared_chat" | null; + workspaceRole?: WorkspaceRole | null; + accessLevel?: AccessLevel | null; serverId?: string | null; - serverTransport?: "stdio" | "http" | null; + serverTransport?: ServerTransport | null; chatboxId?: string | null; - surface?: "preview" | "share_link" | null; + surface?: Surface | null; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcpjam-inspector/server/routes/web/auth.ts` around lines 245 - 285, The InternalLogContext type redeclares string-literal unions that diverge from the canonical types in utils/log-events.ts; update mapInternalToRequestContext and replace the local InternalLogContext declaration by importing and using the canonical types (e.g., AuthType, WorkspaceRole, AccessLevel, ServerTransport, Surface, etc.) from utils/log-events.ts so the fields (authType, workspaceRole, accessLevel, serverTransport, surface) use those imported types and keep optional/null semantics compatible with Partial<RequestLogContext>.mcpjam-inspector/server/routes/web/conformance.ts (1)
43-44: PreferContextfromhonooveranyfor the new helper parameters.
authorizeServeris now strictly typed as(c: Context, …), so widening these helpers toc: anydiscards the type guarantees the rest ofauth.tscarefully restored. A one-line import change keeps the surface honest.♻️ Proposed typing tightening
+import type { Context } from "hono"; … async function resolveHostedHttpConfig( - c: any, + c: Context, bearerToken: string, body: Record<string, unknown>, ): Promise<{ … async function resolveHostedServerConfig( - c: any, + c: Context, bearerToken: string, body: Record<string, unknown>, ): Promise<MCPAppsConformanceConfig> {Also applies to: 127-128
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcpjam-inspector/server/routes/web/conformance.ts` around lines 43 - 44, The helper functions (e.g., resolveHostedHttpConfig) currently accept c: any which discards the stricter auth types; change their parameter types to Context from hono by adding an import like `import { Context } from "hono"` and update the function signatures (e.g., async function resolveHostedHttpConfig(c: Context, ...) ) and any other helper(s) in this file that use c: any (including the one around lines 127-128) so they match authorizeServer's `(c: Context, ...)` typing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@mcpjam-inspector/server/routes/web/auth.ts`:
- Around line 505-519: The loop in authorizeBatch merges each result's
InternalLogContext into the request-level log via setRequestLogContext(c,
mapInternalToRequestContext(internalLogContext)), causing per-server fields to
be overwritten when multiple servers are authorized; update the loop that
iterates Object.entries(raw.results) to detect multi-result batches and, when
results.length > 1, strip per-server fields (serverId, serverTransport,
chatboxId) from internalLogContext before calling mapInternalToRequestContext
and setRequestLogContext so only workspace-level context is merged (leave
strippedResults population and client-safe result extraction unchanged).
---
Nitpick comments:
In `@mcpjam-inspector/server/routes/web/__tests__/auth-manager.test.ts`:
- Around line 24-27: The tests never exercise the new strip/merge behavior
because mockContext.var.requestLogContext is undefined; seed requestLogContext
and add a fixture containing internalLogContext so the merge and removal are
exercised. Specifically, create a ctx with var.requestLogContext (e.g., {
authType: "signedIn" }) and a set spy, stub global.fetch to return a JSON
payload under results that includes an internalLogContext for a server, call
createAuthorizedManager(...) with that ctx and server id, then assert ctx.set
was called with "requestLogContext" containing the merged fields (workspaceRole,
workspaceId) and that the returned/observed server result no longer contains
internalLogContext. Use the existing mocks (mockContext / setSpy) and the
createAuthorizedManager call to locate where to add this test.
In `@mcpjam-inspector/server/routes/web/auth.ts`:
- Around line 304-330: Update the ConvexBatchAuthorizeSuccess type to mirror the
ClientSafeAuthorizeResponse pattern by removing the optional internalLogContext
property (it should not be exposed to clients) and simplify the serverConfig
type: replace Omit<ConvexAuthorizeResponse,
"internalLogContext">["serverConfig"] with
ConvexAuthorizeResponse["serverConfig"] (since omitting internalLogContext does
not affect the serverConfig property); ensure you only modify the
ConvexBatchAuthorizeSuccess declaration and leave AuthorizedServerConfigHolder
and ClientSafeAuthorizeResponse as-is.
- Around line 245-285: The InternalLogContext type redeclares string-literal
unions that diverge from the canonical types in utils/log-events.ts; update
mapInternalToRequestContext and replace the local InternalLogContext declaration
by importing and using the canonical types (e.g., AuthType, WorkspaceRole,
AccessLevel, ServerTransport, Surface, etc.) from utils/log-events.ts so the
fields (authType, workspaceRole, accessLevel, serverTransport, surface) use
those imported types and keep optional/null semantics compatible with
Partial<RequestLogContext>.
In `@mcpjam-inspector/server/routes/web/conformance.ts`:
- Around line 43-44: The helper functions (e.g., resolveHostedHttpConfig)
currently accept c: any which discards the stricter auth types; change their
parameter types to Context from hono by adding an import like `import { Context
} from "hono"` and update the function signatures (e.g., async function
resolveHostedHttpConfig(c: Context, ...) ) and any other helper(s) in this file
that use c: any (including the one around lines 127-128) so they match
authorizeServer's `(c: Context, ...)` typing.
🪄 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: e368c1d4-0612-4dba-b912-479aa0d38e20
📒 Files selected for processing (6)
mcpjam-inspector/server/routes/web/__tests__/auth-manager.test.tsmcpjam-inspector/server/routes/web/auth.tsmcpjam-inspector/server/routes/web/chat-v2.tsmcpjam-inspector/server/routes/web/conformance.tsmcpjam-inspector/server/routes/web/evals.tsmcpjam-inspector/server/routes/web/servers.ts
…atch Per-server fields (serverId, serverTransport, chatboxId) were being overwritten on each iteration of the batch results loop, leaving the request log envelope attributed to whichever server iterated last. Now we set workspace-level fields (auth/user/org/workspace/accessLevel/ surface) once from the first successful result, and only set per-server fields when the batch contains exactly one server. Multi-server batches null those fields at the request envelope; per-server attribution belongs on per-server child events. Addresses CodeRabbit review feedback on PR #1931. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (4)
mcpjam-inspector/server/routes/web/__tests__/authorize-batch.test.ts (2)
186-222: Security invariant test — exactly the right guard.Asserting
internalLogContext === undefinedon every returned successful entry is the defining check for this PR's "must never reach the browser" promise. Consider an additional assertion thatObject.values(result.results).length > 0purely to defend against a fetch-mock regression silently producing an emptyresultsobject (a passing test for the wrong reason).♻️ Optional belt-and-braces
+ expect(Object.values(result.results).length).toBeGreaterThan(0); for (const entry of Object.values(result.results)) { expect((entry as Record<string, unknown>).internalLogContext).toBeUndefined(); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcpjam-inspector/server/routes/web/__tests__/authorize-batch.test.ts` around lines 186 - 222, Add a guard assertion to the test that the batch actually contains results before checking for stripped fields: after calling authorizeBatch(c, "bearer", "ws-1", [...]) assert that Object.values(result.results).length > 0 (or expect(Object.keys(result.results).length).toBeGreaterThan(0)) before the loop that verifies internalLogContext is undefined, referencing the existing result variable and result.results to prevent a false positive if fetch was mocked to return an empty results object.
31-40: Mock context plays its part — though a brittle understudy.The
Proxygettrap blindly indexest[p as string], which fine for the string keys this file uses but will misbehave if any code path inadvertently touches aSymbol(e.g.,Symbol.toPrimitive). SinceauthorizeBatchonly readsc.var.requestLogContextviasetRequestLogContext, the current shape is sufficient — just worth keeping in mind if future tests expand the surface area exercised throughc.♻️ Optional hardening
- const c = { - var: new Proxy(vars, { get: (t, p) => t[p as string] }), - set: (key: string, value: unknown) => { - vars[key] = value; - }, - } as unknown as Context; + const c = { + var: new Proxy(vars, { + get: (t, p) => (typeof p === "string" ? t[p] : undefined), + }), + get: (key: string) => vars[key], + set: (key: string, value: unknown) => { + vars[key] = value; + }, + } as unknown as Context;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcpjam-inspector/server/routes/web/__tests__/authorize-batch.test.ts` around lines 31 - 40, The Proxy get trap in makeContext naively does t[p as string], which will break if a Symbol property (e.g., Symbol.toPrimitive) is accessed; update the get trap implementation in makeContext to only treat string/property keys by checking typeof p === 'string' (or using String(p) safely) and return undefined (or Reflect.get) for Symbol keys so c.var and setRequestLogContext continue to work and future symbol accesses don't crash the test.mcpjam-inspector/server/routes/web/auth.ts (2)
328-328: TheOmithere is a no-op disguised as intent.
Omit<ConvexAuthorizeResponse, "internalLogContext">["serverConfig"]is structurally identical toConvexAuthorizeResponse["serverConfig"]— theOmitstrips a sibling key from the outer object, but you immediately index intoserverConfig, which never containedinternalLogContextto begin with. Simplify for clarity.♻️ Suggested simplification
- serverConfig: Omit<ConvexAuthorizeResponse, "internalLogContext">["serverConfig"]; + serverConfig: ConvexAuthorizeResponse["serverConfig"];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcpjam-inspector/server/routes/web/auth.ts` at line 328, The type expression using Omit is misleading and a no-op: replace the type "Omit<ConvexAuthorizeResponse, \"internalLogContext\">[\"serverConfig\"]" with the simpler "ConvexAuthorizeResponse[\"serverConfig\"]" wherever the serverConfig type is declared (the symbol named serverConfig in this file) to improve clarity and remove the redundant Omit usage.
788-789: Mixedc: anyandc: Context— let's not leave the type coverage half-built.This PR rightly tightens
authorizeServer,authorizeBatch, andcreateAuthorizedManagerto takec: Context, butwithEphemeralConnection(line 789),handleRoute(line 708),requireGuestId(line 167), andcreateGuestEphemeralManager(line 180) still acceptc: any. They're now passingcdirectly into strongly-typed callees, so swapping these signatures toContext(orContext<{ Variables: { requestLogContext?: RequestLogContext; guestId?: string } }>) would catch shape drift earlier without behavioral risk. Optional, but feels like the right moment to harmonize.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcpjam-inspector/server/routes/web/auth.ts` around lines 788 - 789, The functions withEphemeralConnection, handleRoute, requireGuestId, and createGuestEphemeralManager currently accept c: any; update their signatures to use the proper Context type to match the other authorized helpers — e.g., change c: any to Context or the more specific Context<{ Variables: { requestLogContext?: RequestLogContext; guestId?: string } }> so callers pass a consistently-typed context into authorizeServer/authorizeBatch/createAuthorizedManager; also add any needed imports for Context and RequestLogContext and adjust generics on withEphemeralConnection<S, T> if required to preserve existing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@mcpjam-inspector/server/routes/web/__tests__/authorize-batch.test.ts`:
- Around line 186-222: Add a guard assertion to the test that the batch actually
contains results before checking for stripped fields: after calling
authorizeBatch(c, "bearer", "ws-1", [...]) assert that
Object.values(result.results).length > 0 (or
expect(Object.keys(result.results).length).toBeGreaterThan(0)) before the loop
that verifies internalLogContext is undefined, referencing the existing result
variable and result.results to prevent a false positive if fetch was mocked to
return an empty results object.
- Around line 31-40: The Proxy get trap in makeContext naively does t[p as
string], which will break if a Symbol property (e.g., Symbol.toPrimitive) is
accessed; update the get trap implementation in makeContext to only treat
string/property keys by checking typeof p === 'string' (or using String(p)
safely) and return undefined (or Reflect.get) for Symbol keys so c.var and
setRequestLogContext continue to work and future symbol accesses don't crash the
test.
In `@mcpjam-inspector/server/routes/web/auth.ts`:
- Line 328: The type expression using Omit is misleading and a no-op: replace
the type "Omit<ConvexAuthorizeResponse,
\"internalLogContext\">[\"serverConfig\"]" with the simpler
"ConvexAuthorizeResponse[\"serverConfig\"]" wherever the serverConfig type is
declared (the symbol named serverConfig in this file) to improve clarity and
remove the redundant Omit usage.
- Around line 788-789: The functions withEphemeralConnection, handleRoute,
requireGuestId, and createGuestEphemeralManager currently accept c: any; update
their signatures to use the proper Context type to match the other authorized
helpers — e.g., change c: any to Context or the more specific Context<{
Variables: { requestLogContext?: RequestLogContext; guestId?: string } }> so
callers pass a consistently-typed context into
authorizeServer/authorizeBatch/createAuthorizedManager; also add any needed
imports for Context and RequestLogContext and adjust generics on
withEphemeralConnection<S, T> if required to preserve existing behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3fb42c75-f694-4872-a715-dd983b1a8794
📒 Files selected for processing (2)
mcpjam-inspector/server/routes/web/__tests__/authorize-batch.test.tsmcpjam-inspector/server/routes/web/auth.ts

Summary
Adds a security-safe wrapper around
authorizeServerandauthorizeBatchthat strips the optionalinternalLogContextfield (returned by the backend authorize endpoint) from the Convex response and merges it intoc.var.requestLogContext. This ensures backend-private identity context flows into Axiom events without ever reaching the browser. The signature of both functions now takesc: Contextas the first argument so the log context can be side-effected without callers having to handle it.Changes
server/routes/web/auth.ts— addedInternalLogContexttype,ClientSafeAuthorizeResponseexport,mapInternalToRequestContexthelper; updatedauthorizeServer,authorizeBatch,createAuthorizedManagerto takec: Contextas first arg and strip/mergeinternalLogContext;withEphemeralConnectionpassesctocreateAuthorizedManagerserver/routes/web/servers.ts— updated 2authorizeServercall sitesserver/routes/web/conformance.ts— updatedresolveHostedHttpConfigandresolveHostedServerConfighelpers to takec: any, updated 3 call sitesserver/routes/web/chat-v2.ts— updatedcreateAuthorizedManagercall siteserver/routes/web/evals.ts— updatedcreateAuthorizedManagercall siteserver/middleware/request-log-context.ts— fixed TS assertion on spreadserver/routes/web/__tests__/auth-manager.test.ts— updated existing tests to pass mock context as first argOut of scope
logger.warn/errorcallsitesTest plan
Automated
auth-manager.test.ts3 existing tests updated and passing with new signatureManual
/api/web/servers/validate; confirm nointernalLogContextkey appears in the JSON response bodyinternalLogContext, confirmc.var.requestLogContext.workspaceRoleis populated after a hosted requestRisk and rollback
authorizeServer/authorizeBatchsignatures; all call sites updated in this PRCross-repo dependencies
logging-inspector-typed-foundation)logging-inspector-route-conversions-wave-1)