Skip to content

Conversation

@chelojimenez
Copy link
Contributor

@chelojimenez chelojimenez commented Nov 5, 2025

Note

Modularizes the OAuth sequence diagram into shared components, co-locates protocol-specific action builders with state machines (including new 2025-03-26), consolidates helpers, updates types/imports, and removes the legacy facade.

  • OAuth Diagram Refactor:
    • Extracts shared diagram pieces into components/oauth/shared/ (ActorNode, CustomActionEdge, DiagramLayout, diagramBuilder, constants, utils, OAuthSequenceDiagramContent).
    • OAuthSequenceDiagram now selects protocol-specific actions via builders and renders via shared content; default registrationStrategy set to "dcr".
  • State Machines:
    • Adds buildActions_2025_11_25, buildActions_2025_06_18, and buildActions_2025_03_26 co-located with their state machines for visualization parity.
    • Consolidates common logic into state-machines/shared/helpers.ts and shared types.ts.
    • Implements 2025-03-26 protocol variant and aligns types (OAuthFlowState, steps) across versions.
  • Types/Imports Cleanup:
    • Updates imports to lib/oauth/state-machines/* (e.g., OAuthFlowState, OAuthProtocolVersion), replaces legacy OauthFlowStateJune2025 usages.
    • Removes legacy facade client/src/lib/debug-oauth-state-machine.ts.
  • UI Integrations:
    • OAuthFlowTab and ProtocolVersionSelector updated to new types/factory and state init; diagram wired to selected protocol/registration strategy.

Written by Cursor Bugbot for commit 4876853. This will update automatically on new commits. Configure here.

@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. enhancement New feature or request labels Nov 5, 2025
export function buildActions_2025_03_26(
flowState: OAuthFlowState,
registrationStrategy: "dcr" | "preregistered",
): Action[] {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Dead Code: Invalid CIMD Registration Path

The function signature accepts registrationStrategy: "dcr" | "preregistered" but the function body checks for registrationStrategy === "cimd" at line 100. According to the type system, the 2025-03-26 protocol only supports "dcr" and "preregistered" strategies (RegistrationStrategy2025_03_26 = "dcr" | "preregistered"), not "cimd". This means the CIMD branch (lines 100-183) will never execute, making it dead code. The function should not check for "cimd" since it's not a valid value for this protocol version.

Fix in Cursor Fix in Web

export function buildActions_2025_06_18(
flowState: OAuthFlowState,
registrationStrategy: "dcr" | "preregistered",
): Action[] {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Dead Code: Invalid CIMD Check in Registration Flow

The function signature accepts registrationStrategy: "dcr" | "preregistered" but the function body checks for registrationStrategy === "cimd" at line 100. According to the type system, the 2025-06-18 protocol only supports "dcr" and "preregistered" strategies (RegistrationStrategy2025_06_18 = "dcr" | "preregistered"), not "cimd". This means the CIMD branch (lines 100-183) will never execute, making it dead code. The function should not check for "cimd" since it's not a valid value for this protocol version.

Fix in Cursor Fix in Web

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

The OAuth sequence diagram was refactored from a monolithic ReactFlow implementation to a composition-based design. OAuthSequenceDiagram now renders OAuthSequenceDiagramContent and selects protocol-specific action builders (buildActions_2025_11_25, buildActions_2025_06_18, buildActions_2025_03_26). New UI pieces—ActorNode, CustomActionEdge, DiagramLayout—plus shared types, constants, a diagramBuilder, and helpers (proxyFetch, PKCE, preregistered credential loading, etc.) provide layout and status logic. State-machine modules now export DiagramAction builders for each protocol. The component prop type changed to OAuthFlowState and the default registrationStrategy in the public path was updated to "dcr".


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5844a1b and 4876853.

📒 Files selected for processing (13)
  • client/src/components/OAuthFlowTab.tsx (3 hunks)
  • client/src/components/OAuthSequenceDiagram.tsx (1 hunks)
  • client/src/components/oauth/ProtocolVersionSelector.tsx (1 hunks)
  • client/src/components/oauth/shared/DiagramLayout.tsx (1 hunks)
  • client/src/components/oauth/shared/diagramBuilder.ts (1 hunks)
  • client/src/components/oauth/shared/utils.ts (1 hunks)
  • client/src/lib/debug-oauth-state-machine.ts (0 hunks)
  • client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts (4 hunks)
  • client/src/lib/oauth/state-machines/debug-oauth-2025-06-18.ts (4 hunks)
  • client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts (4 hunks)
  • client/src/lib/oauth/state-machines/shared/helpers.ts (1 hunks)
  • client/src/lib/oauth/state-machines/shared/types.ts (1 hunks)
  • client/src/lib/oauth/state-machines/types.ts (0 hunks)

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
client/src/components/oauth/shared/DiagramLayout.tsx (1)

75-79: Replace magic numbers with the shared layout constants

The zoom math re-embeds the ACTION_SPACING and SEGMENT_HEIGHT / 2 values, so any future tweak to the layout constants will desynchronize viewport targeting. Import the shared constants and compute this expression from them to keep the animation aligned with the rendered diagram.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a075dc9 and a967ce1.

📒 Files selected for processing (13)
  • client/src/components/OAuthSequenceDiagram.tsx (1 hunks)
  • client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts (1 hunks)
  • client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts (1 hunks)
  • client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts (1 hunks)
  • client/src/components/oauth/shared/ActorNode.tsx (1 hunks)
  • client/src/components/oauth/shared/CustomActionEdge.tsx (1 hunks)
  • client/src/components/oauth/shared/DiagramLayout.tsx (1 hunks)
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx (1 hunks)
  • client/src/components/oauth/shared/constants.ts (1 hunks)
  • client/src/components/oauth/shared/diagramBuilder.ts (1 hunks)
  • client/src/components/oauth/shared/index.ts (1 hunks)
  • client/src/components/oauth/shared/types.ts (1 hunks)
  • client/src/components/oauth/shared/utils.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Prefer interfaces for defining object shapes
Constrain generics with appropriate type bounds
Use type guards to narrow unknown or union types before usage
Enforce import ordering consistently

**/*.{ts,tsx}: Prefer named exports in TypeScript modules
Use 2-space indentation
Declare types and interfaces using PascalCase

Files:

  • client/src/components/oauth/shared/constants.ts
  • client/src/components/oauth/shared/diagramBuilder.ts
  • client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts
  • client/src/components/oauth/shared/CustomActionEdge.tsx
  • client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts
  • client/src/components/oauth/shared/utils.ts
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts
  • client/src/components/oauth/shared/DiagramLayout.tsx
  • client/src/components/oauth/shared/types.ts
  • client/src/components/oauth/shared/index.ts
  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/components/oauth/shared/ActorNode.tsx
client/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (client/CLAUDE.md)

Implement strict TypeScript types: strict prop types, event types, state interfaces, and utility types

In client code, use the @/ alias for imports

Files:

  • client/src/components/oauth/shared/constants.ts
  • client/src/components/oauth/shared/diagramBuilder.ts
  • client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts
  • client/src/components/oauth/shared/CustomActionEdge.tsx
  • client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts
  • client/src/components/oauth/shared/utils.ts
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts
  • client/src/components/oauth/shared/DiagramLayout.tsx
  • client/src/components/oauth/shared/types.ts
  • client/src/components/oauth/shared/index.ts
  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/components/oauth/shared/ActorNode.tsx
client/src/{app,components,hooks}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (client/CLAUDE.md)

Use React hooks for local state: apply useState/useReducer patterns, create custom hooks, and always clean up effects

Files:

  • client/src/components/oauth/shared/constants.ts
  • client/src/components/oauth/shared/diagramBuilder.ts
  • client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts
  • client/src/components/oauth/shared/CustomActionEdge.tsx
  • client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts
  • client/src/components/oauth/shared/utils.ts
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts
  • client/src/components/oauth/shared/DiagramLayout.tsx
  • client/src/components/oauth/shared/types.ts
  • client/src/components/oauth/shared/index.ts
  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/components/oauth/shared/ActorNode.tsx
client/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Follow consistent React component structure in the frontend

Files:

  • client/src/components/oauth/shared/CustomActionEdge.tsx
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/shared/DiagramLayout.tsx
  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/components/oauth/shared/ActorNode.tsx
client/src/{app,components}/**/*.tsx

📄 CodeRabbit inference engine (client/CLAUDE.md)

client/src/{app,components}/**/*.tsx: Use React functional components with React.FC typing for all UI components and pages
Define explicit Props interfaces for components, including proper children prop handling
Type event handlers with React-provided types (e.g., React.MouseEvent, FormEvent)
Follow React 19 patterns: hooks-centric components, Suspense and Error Boundaries where appropriate, and concurrent features
Maintain component isolation: avoid excessive prop drilling, use Context wisely, favor composition, and optimize renders
Build responsive layouts using the established Tailwind breakpoint system, grids, flex, and container queries
Ensure accessibility: proper ARIA attributes, keyboard navigation, focus management, and screen reader support

Files:

  • client/src/components/oauth/shared/CustomActionEdge.tsx
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/shared/DiagramLayout.tsx
  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/components/oauth/shared/ActorNode.tsx
client/src/components/**/*.tsx

📄 CodeRabbit inference engine (client/CLAUDE.md)

Use Radix UI primitives for dialogs, dropdowns, form controls, and tooltips

React components in client/src/components should be functional and saved as PascalCase.tsx files

Files:

  • client/src/components/oauth/shared/CustomActionEdge.tsx
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/shared/DiagramLayout.tsx
  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/components/oauth/shared/ActorNode.tsx
🧠 Learnings (6)
📚 Learning: 2025-10-19T23:06:33.450Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: client/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:06:33.450Z
Learning: Applies to client/src/{components/servers,hooks/mcp,lib/api}/**/*.{ts,tsx} : Implement authentication setup: OAuth configuration, token management, scopes, and refresh handling

Applied to files:

  • client/src/components/oauth/shared/constants.ts
  • client/src/components/oauth/shared/diagramBuilder.ts
  • client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts
  • client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts
  • client/src/components/oauth/shared/types.ts
  • client/src/components/oauth/shared/index.ts
📚 Learning: 2025-10-19T23:06:33.450Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: client/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:06:33.450Z
Learning: Applies to client/src/{lib/api,hooks/llm}/**/*.{ts,tsx} : Implement Anthropic Claude integration: authentication flow, request formatting, stream processing, and rate limiting

Applied to files:

  • client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts
  • client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts
  • client/src/components/oauth/shared/index.ts
📚 Learning: 2025-10-19T23:06:33.450Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: client/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:06:33.450Z
Learning: Applies to client/src/{app,components}/**/*.tsx : Follow React 19 patterns: hooks-centric components, Suspense and Error Boundaries where appropriate, and concurrent features

Applied to files:

  • client/src/components/oauth/shared/CustomActionEdge.tsx
  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/shared/ActorNode.tsx
📚 Learning: 2025-10-19T23:05:54.474Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-19T23:05:54.474Z
Learning: Applies to client/src/**/*.tsx : Follow consistent React component structure in the frontend

Applied to files:

  • client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx
  • client/src/components/oauth/shared/ActorNode.tsx
📚 Learning: 2025-10-19T23:06:33.450Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: client/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:06:33.450Z
Learning: Applies to client/src/**/*.{ts,tsx} : Implement strict TypeScript types: strict prop types, event types, state interfaces, and utility types

Applied to files:

  • client/src/components/oauth/shared/types.ts
  • client/src/components/oauth/shared/index.ts
📚 Learning: 2025-10-19T23:07:40.722Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-19T23:07:40.722Z
Learning: Applies to shared/**/*.{ts,tsx} : Place shared types and utilities in the shared/ directory for reuse by client and server

Applied to files:

  • client/src/components/oauth/shared/types.ts
  • client/src/components/oauth/shared/index.ts
🧬 Code graph analysis (10)
client/src/components/oauth/shared/diagramBuilder.ts (3)
client/src/components/oauth/shared/types.ts (2)
  • Action (27-34)
  • ActorNodeData (6-16)
client/src/components/oauth/shared/constants.ts (4)
  • ACTION_SPACING (17-17)
  • SEGMENT_HEIGHT (19-19)
  • ACTOR_X_POSITIONS (10-15)
  • ACTORS (2-7)
client/src/components/oauth/shared/utils.ts (1)
  • getActionStatus (5-22)
client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts (1)
client/src/components/oauth/shared/types.ts (1)
  • Action (27-34)
client/src/components/oauth/shared/CustomActionEdge.tsx (2)
client/src/components/oauth/shared/index.ts (1)
  • CustomActionEdge (6-6)
client/src/components/oauth/shared/types.ts (1)
  • ActionEdgeData (19-24)
client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts (1)
client/src/components/oauth/shared/types.ts (1)
  • Action (27-34)
client/src/components/oauth/shared/utils.ts (1)
client/src/components/oauth/shared/types.ts (1)
  • NodeStatus (3-3)
client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx (3)
client/src/components/oauth/shared/types.ts (1)
  • Action (27-34)
client/src/components/oauth/shared/diagramBuilder.ts (1)
  • buildNodesAndEdges (12-215)
client/src/components/oauth/shared/DiagramLayout.tsx (1)
  • DiagramLayout (29-117)
client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts (1)
client/src/components/oauth/shared/types.ts (1)
  • Action (27-34)
client/src/components/oauth/shared/DiagramLayout.tsx (2)
client/src/components/oauth/shared/ActorNode.tsx (1)
  • ActorNode (7-142)
client/src/components/oauth/shared/CustomActionEdge.tsx (1)
  • CustomActionEdge (12-66)
client/src/components/OAuthSequenceDiagram.tsx (5)
client/src/lib/oauth/state-machines/types.ts (2)
  • OAuthFlowState (32-124)
  • OAuthProtocolVersion (163-163)
client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts (1)
  • buildActions_2025_11_25 (4-386)
client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts (1)
  • buildActions_2025_06_18 (4-386)
client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts (1)
  • buildActions_2025_03_26 (4-386)
client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx (1)
  • OAuthSequenceDiagramContent (29-37)
client/src/components/oauth/shared/ActorNode.tsx (1)
client/src/components/oauth/shared/types.ts (1)
  • ActorNodeData (6-16)
🔍 Remote MCP Context7

Now let me search for OAuth 2.0 best practices related to PKCE, DCR, and protocol versioning:Perfect! I've gathered relevant context. Let me now compile the findings for the PR review.

Summary of Relevant Context for PR #803 Review

Based on research into React Flow patterns, OAuth 2.0 best practices, and API versioning strategies, here are key insights applicable to this PR:

OAuth 2.0 Implementation Compliance

MCP clients MUST implement PKCE according to OAuth 2.1 Section 7.5.2, and both authorization servers and MCP clients SHOULD support the OAuth 2.0 Dynamic Client Registration Protocol (RFC7591). The PR implements all three registration strategies (CIMD, DCR, and preregistered), which aligns with the specification requirements for flexible client authentication.

Both DCR and static registration require PKCE as an extra layer of security, and the PR's implementation of PKCE generation steps in all action builders validates this security requirement.

Protocol Versioning Strategy

The PR's date-based versioning approach (2025-11-25, 2025-06-18, 2025-03-26) with useMemo routing based on protocolVersion follows established API versioning practices. When designing APIs that support versioning, design depends on context and goals, with general steps including choosing a versioning method that suits the service and clients, implementing backward compatibility techniques, and testing and monitoring.

When making backward compatible API changes, increment the minor number; when making backward incompatible changes, increment the major number and reset the minor number. The date-based versioning scheme provides clear historical tracking.

React Component Composition Pattern

The refactoring from a monolithic React Flow component to a composition-based architecture with separate action builders aligns with React Flow best practices. The PR extracts rendering logic into OAuthSequenceDiagramContent, creating custom node and edge components (ActorNode, CustomActionEdge), which mirrors patterns shown in the React Flow documentation for building maintainable, reusable diagram components.

Type System Design

MCP clients MUST implement Resource Indicators for OAuth 2.0 as defined in RFC 8707, with the resource parameter MUST be included in both authorization requests and token requests and MUST identify the target resource. The PR's updated OAuthFlowState type (replacing OauthFlowStateJune2025) should ensure proper resource tracking across all protocol versions.

Backward Compatibility Considerations

Backward-compatible changes include adding optional query parameters, adding optional header or form parameters, and adding new optional fields in JSON or XML data structures. The PR's public API change (flowState type update) should be validated against existing consumers to ensure no breaking changes., [::web_search::]

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: prettier-and-build

Comment on lines 4 to 7
export function buildActions_2025_03_26(
flowState: OAuthFlowState,
registrationStrategy: "dcr" | "preregistered",
): Action[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Widen the registrationStrategy union.

The signature excludes "cimd", yet the body handles it and the caller passes it. With strict TypeScript, this is a compile-time error ("cimd" is not assignable to "dcr" | "preregistered"). Broaden the union so the function type matches its usage.

 export function buildActions_2025_03_26(
   flowState: OAuthFlowState,
-  registrationStrategy: "dcr" | "preregistered",
+  registrationStrategy: "cimd" | "dcr" | "preregistered",
 ): Action[] {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function buildActions_2025_03_26(
flowState: OAuthFlowState,
registrationStrategy: "dcr" | "preregistered",
): Action[] {
export function buildActions_2025_03_26(
flowState: OAuthFlowState,
registrationStrategy: "cimd" | "dcr" | "preregistered",
): Action[] {
🤖 Prompt for AI Agents
In client/src/components/oauth/diagrams/actions/actions_2025_03_26.ts around
lines 4 to 7, the function parameter registrationStrategy is typed as "dcr" |
"preregistered" but the body and callers also use "cimd", causing a TypeScript
error; update the declaration to include "cimd" (e.g. "dcr" | "preregistered" |
"cimd") or replace the union with a shared RegistrationStrategy type/enum used
by callers so the function signature matches actual usage.

Comment on lines 4 to 7
export function buildActions_2025_06_18(
flowState: OAuthFlowState,
registrationStrategy: "dcr" | "preregistered",
): Action[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Align the function signature with supported strategies.

Here too, the function narrows registrationStrategy to "dcr" | "preregistered" even though the implementation (and callers) expect "cimd" as well, leading to a TypeScript error. Expand the union to keep the type contract honest.

 export function buildActions_2025_06_18(
   flowState: OAuthFlowState,
-  registrationStrategy: "dcr" | "preregistered",
+  registrationStrategy: "cimd" | "dcr" | "preregistered",
 ): Action[] {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function buildActions_2025_06_18(
flowState: OAuthFlowState,
registrationStrategy: "dcr" | "preregistered",
): Action[] {
export function buildActions_2025_06_18(
flowState: OAuthFlowState,
registrationStrategy: "cimd" | "dcr" | "preregistered",
): Action[] {
🤖 Prompt for AI Agents
In client/src/components/oauth/diagrams/actions/actions_2025_06_18.ts around
lines 4 to 7, the function signature currently narrows registrationStrategy to
"dcr" | "preregistered" but callers and implementation also use "cimd"; update
the union type to include "cimd" (i.e., "dcr" | "preregistered" | "cimd") so the
type matches usage and removes the TypeScript error, and run a quick grep to
ensure any related overloads or callers remain consistent with the new union.

Comment on lines 274 to 282
? [
{
label: "code_challenge",
value:
flowState.codeChallenge?.substring(0, 12) + "..." || "S256",
},
{ label: "resource", value: flowState.serverUrl || "" },
]
: undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix the code_challenge fallback value

When flowState.codeChallenge is still unset, the expression flowState.codeChallenge?.substring(0, 12) + "..." evaluates to the string "undefined...", which is truthy and blocks the intended "S256" fallback. Users will therefore see "undefined..." in the diagram. Guard explicitly before appending the ellipsis so the fallback is applied correctly.

                 {
                   label: "code_challenge",
-                  value:
-                    flowState.codeChallenge?.substring(0, 12) + "..." || "S256",
+                  value: flowState.codeChallenge
+                    ? `${flowState.codeChallenge.substring(0, 12)}...`
+                    : "S256",
                 },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
? [
{
label: "code_challenge",
value:
flowState.codeChallenge?.substring(0, 12) + "..." || "S256",
},
{ label: "resource", value: flowState.serverUrl || "" },
]
: undefined,
? [
{
label: "code_challenge",
value: flowState.codeChallenge
? `${flowState.codeChallenge.substring(0, 12)}...`
: "S256",
},
{ label: "resource", value: flowState.serverUrl || "" },
]
: undefined,
🤖 Prompt for AI Agents
In client/src/components/oauth/diagrams/actions/actions_2025_11_25.ts around
lines 274-282, the expression flowState.codeChallenge?.substring(0, 12) + "..."
can produce "undefined..." because the optional chaining returns undefined then
string concatenation coerces it; change the expression to explicitly guard
before appending the ellipsis so the fallback "S256" is used when codeChallenge
is unset (e.g. use a conditional that checks flowState.codeChallenge and only
does substring + "..." when present, otherwise return "S256").

const {
flowState,
registrationStrategy = "cimd",
registrationStrategy = "dcr",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Default Registration Strategy Mismatch with Protocol Version

The default value for registrationStrategy was changed from "cimd" to "dcr", which is inconsistent with the default protocol version "2025-11-25". According to the factory's getDefaultRegistrationStrategy function, the default for "2025-11-25" should be "cimd", not "dcr". This breaks the expected behavior where the component defaults align with the protocol version's recommended registration strategy.

Fix in Cursor Fix in Web

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts (1)

51-58: Consolidate the duplicated DiagramAction type.
This interface is re-declared here and in the 2025-03-26 / 2025-06-18 builders with identical fields. Please hoist it into a shared module (e.g., client/src/components/oauth/shared/types.ts) and import it where needed to avoid drift.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a967ce1 and 5844a1b.

📒 Files selected for processing (5)
  • client/src/components/OAuthSequenceDiagram.tsx (1 hunks)
  • client/src/components/oauth/shared/utils.ts (1 hunks)
  • client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts (1 hunks)
  • client/src/lib/oauth/state-machines/debug-oauth-2025-06-18.ts (1 hunks)
  • client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Prefer interfaces for defining object shapes
Constrain generics with appropriate type bounds
Use type guards to narrow unknown or union types before usage
Enforce import ordering consistently

**/*.{ts,tsx}: Prefer named exports in TypeScript modules
Use 2-space indentation
Declare types and interfaces using PascalCase

Files:

  • client/src/lib/oauth/state-machines/debug-oauth-2025-06-18.ts
  • client/src/components/oauth/shared/utils.ts
  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts
  • client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts
client/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (client/CLAUDE.md)

Implement strict TypeScript types: strict prop types, event types, state interfaces, and utility types

In client code, use the @/ alias for imports

Files:

  • client/src/lib/oauth/state-machines/debug-oauth-2025-06-18.ts
  • client/src/components/oauth/shared/utils.ts
  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts
  • client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts
client/src/{stores/servers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (client/CLAUDE.md)

Persist configuration: local storage, export/import, sync, and backup/restore options

Files:

  • client/src/lib/oauth/state-machines/debug-oauth-2025-06-18.ts
  • client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts
  • client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts
client/src/{app,components,hooks}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (client/CLAUDE.md)

Use React hooks for local state: apply useState/useReducer patterns, create custom hooks, and always clean up effects

Files:

  • client/src/components/oauth/shared/utils.ts
  • client/src/components/OAuthSequenceDiagram.tsx
client/src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Follow consistent React component structure in the frontend

Files:

  • client/src/components/OAuthSequenceDiagram.tsx
client/src/{app,components}/**/*.tsx

📄 CodeRabbit inference engine (client/CLAUDE.md)

client/src/{app,components}/**/*.tsx: Use React functional components with React.FC typing for all UI components and pages
Define explicit Props interfaces for components, including proper children prop handling
Type event handlers with React-provided types (e.g., React.MouseEvent, FormEvent)
Follow React 19 patterns: hooks-centric components, Suspense and Error Boundaries where appropriate, and concurrent features
Maintain component isolation: avoid excessive prop drilling, use Context wisely, favor composition, and optimize renders
Build responsive layouts using the established Tailwind breakpoint system, grids, flex, and container queries
Ensure accessibility: proper ARIA attributes, keyboard navigation, focus management, and screen reader support

Files:

  • client/src/components/OAuthSequenceDiagram.tsx
client/src/components/**/*.tsx

📄 CodeRabbit inference engine (client/CLAUDE.md)

Use Radix UI primitives for dialogs, dropdowns, form controls, and tooltips

React components in client/src/components should be functional and saved as PascalCase.tsx files

Files:

  • client/src/components/OAuthSequenceDiagram.tsx
🧠 Learnings (4)
📚 Learning: 2025-10-19T23:06:33.450Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: client/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:06:33.450Z
Learning: Applies to client/src/{lib/api,hooks/llm}/**/*.{ts,tsx} : Implement Anthropic Claude integration: authentication flow, request formatting, stream processing, and rate limiting

Applied to files:

  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts
  • client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts
📚 Learning: 2025-10-19T23:06:33.450Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: client/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:06:33.450Z
Learning: Applies to client/src/{components/servers,hooks/mcp,lib/api}/**/*.{ts,tsx} : Implement authentication setup: OAuth configuration, token management, scopes, and refresh handling

Applied to files:

  • client/src/components/OAuthSequenceDiagram.tsx
  • client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts
📚 Learning: 2025-10-19T23:06:33.450Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: client/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:06:33.450Z
Learning: Applies to client/src/{app,components}/**/*.tsx : Follow React 19 patterns: hooks-centric components, Suspense and Error Boundaries where appropriate, and concurrent features

Applied to files:

  • client/src/components/OAuthSequenceDiagram.tsx
📚 Learning: 2025-10-19T23:06:33.450Z
Learnt from: CR
Repo: MCPJam/inspector PR: 0
File: client/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:06:33.450Z
Learning: Applies to client/src/{hooks/llm,components/chat}/**/*.{ts,tsx} : Handle response streaming: token processing, UI updates, cancellation, and error states

Applied to files:

  • client/src/components/OAuthSequenceDiagram.tsx
🧬 Code graph analysis (5)
client/src/lib/oauth/state-machines/debug-oauth-2025-06-18.ts (1)
client/src/lib/oauth/state-machines/types.ts (1)
  • OAuthFlowState (32-124)
client/src/components/oauth/shared/utils.ts (1)
client/src/components/oauth/shared/types.ts (1)
  • NodeStatus (3-3)
client/src/components/OAuthSequenceDiagram.tsx (5)
client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts (2)
  • OAuthFlowState (22-22)
  • buildActions_2025_03_26 (66-313)
client/src/lib/oauth/state-machines/debug-oauth-2025-06-18.ts (2)
  • OAuthFlowState (21-21)
  • buildActions_2025_06_18 (65-363)
client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts (2)
  • OAuthFlowState (22-22)
  • buildActions_2025_11_25 (66-448)
client/src/lib/oauth/state-machines/types.ts (2)
  • OAuthFlowState (32-124)
  • OAuthProtocolVersion (163-163)
client/src/components/oauth/shared/OAuthSequenceDiagramContent.tsx (1)
  • OAuthSequenceDiagramContent (29-37)
client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts (1)
client/src/lib/oauth/state-machines/types.ts (1)
  • OAuthFlowState (32-124)
client/src/lib/oauth/state-machines/debug-oauth-2025-03-26.ts (3)
client/src/lib/oauth/state-machines/debug-oauth-2025-06-18.ts (2)
  • DiagramAction (51-58)
  • OAuthFlowState (21-21)
client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts (2)
  • DiagramAction (52-59)
  • OAuthFlowState (22-22)
client/src/lib/oauth/state-machines/types.ts (1)
  • OAuthFlowState (32-124)
🔍 Remote MCP Context7

Additional facts relevant to reviewing DiagramLayout auto-zoom and viewport code

  • The Context7 resolver selected the Xyflow / React Flow library entry: /xyflow/xyflow. Reason: exact name match and high trust/coverage.
  • Xyflow's React API exposes programmatic viewport controls used by DiagramLayout: useReactFlow provides getViewport, setViewport, fitView, fitBounds, zoomTo, getZoom, setCenter, and coordinate conversion helpers. These support animated transitions and options (padding, minZoom/maxZoom, duration) which align with DiagramLayout's setCenter/zoom usage and debounce behavior.

Sources:

  • Resolver output: /xyflow/xyflow (selection) —
  • Docs/example for useReactFlow and viewport methods —
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: prettier-and-build

Comment on lines 25 to 27
registrationStrategy = "dcr",
protocolVersion = "2025-11-25",
}: OAuthSequenceDiagramProps) => {
const reactFlowInstance = useReactFlow();

const { nodes, edges } = useMemo(() => {
const currentStep = flowState.currentStep;

// Define actions in the sequence (matches MCP OAuth spec)
const actions = [
// For 2025-03-26: Start directly with discovery (no initial MCP request)
// Other protocols: Show initial unauthorized request that triggers OAuth
...(protocolVersion === "2025-03-26"
? []
: [
{
id: "request_without_token",
label: "MCP request without token",
description:
"Client makes initial request without authorization",
from: "client",
to: "mcpServer",
details: flowState.serverUrl
? [
{ label: "POST", value: flowState.serverUrl },
{ label: "method", value: "initialize" },
]
: undefined,
},
]),
// For 2025-03-26: Skip RFC9728 steps, go directly to auth server discovery
...(protocolVersion === "2025-03-26"
? []
: [
{
id: "received_401_unauthorized",
label: "HTTP 401 Unauthorized with WWW-Authenticate header",
description: "Server returns 401 with WWW-Authenticate header",
from: "mcpServer",
to: "client",
details: flowState.resourceMetadataUrl
? [{ label: "Note", value: "Extract resource_metadata URL" }]
: undefined,
},
{
id: "request_resource_metadata",
label: "Request Protected Resource Metadata",
description: "Client requests metadata from well-known URI",
from: "client",
to: "mcpServer",
details: flowState.resourceMetadataUrl
? [
{
label: "GET",
value: new URL(flowState.resourceMetadataUrl).pathname,
},
]
: undefined,
},
{
id: "received_resource_metadata",
label: "Return metadata",
description: "Server returns OAuth protected resource metadata",
from: "mcpServer",
to: "client",
details: flowState.resourceMetadata?.authorization_servers
? [
{
label: "Auth Server",
value:
flowState.resourceMetadata.authorization_servers[0],
},
]
: undefined,
},
]),
{
id: "request_authorization_server_metadata",
label:
protocolVersion === "2025-03-26"
? "GET /.well-known/oauth-authorization-server from MCP base URL"
: protocolVersion === "2025-11-25"
? "GET Authorization server metadata endpoint"
: "GET /.well-known/oauth-authorization-server",
description:
protocolVersion === "2025-03-26"
? "Direct discovery from MCP server base URL with fallback to /authorize, /token, /register"
: protocolVersion === "2025-11-25"
? "Try OAuth path insertion, OIDC path insertion, OIDC path appending"
: "Try RFC8414 path, then RFC8414 root (no OIDC support)",
from: "client",
to: "authServer",
details: flowState.authorizationServerUrl
? [
{ label: "URL", value: flowState.authorizationServerUrl },
{ label: "Protocol", value: protocolVersion },
]
: undefined,
},
{
id: "received_authorization_server_metadata",
label: "Authorization server metadata response",
description: "Authorization Server returns metadata",
from: "authServer",
to: "client",
details: flowState.authorizationServerMetadata
? [
{
label: "Token",
value: new URL(
flowState.authorizationServerMetadata.token_endpoint,
).pathname,
},
{
label: "Auth",
value: new URL(
flowState.authorizationServerMetadata.authorization_endpoint,
).pathname,
},
]
: undefined,
},
// Client registration steps - conditionally included based on strategy
...(registrationStrategy === "cimd"
? [
{
id: "cimd_prepare",
label: "Client uses HTTPS URL as client_id",
description:
"Client prepares to use URL-based client identification",
from: "client",
to: "client",
details: flowState.clientId
? [
{
label: "client_id (URL)",
value: flowState.clientId.includes("http")
? flowState.clientId
: "https://www.mcpjam.com/.well-known/oauth/client-metadata.json",
},
{
label: "Method",
value: "Client ID Metadata Document (CIMD)",
},
]
: [
{
label: "Note",
value: "HTTPS URL points to metadata document",
},
],
},
{
id: "cimd_fetch_request",
label: "Fetch metadata from client_id URL",
description:
"Authorization Server fetches client metadata from the URL",
from: "authServer",
to: "client",
details: [
{
label: "Action",
value: "GET client_id URL",
},
{
label: "Note",
value:
"Server initiates metadata fetch during authorization",
},
],
},
{
id: "cimd_metadata_response",
label: "JSON metadata document",
description:
"Client hosting returns metadata with redirect_uris and client info",
from: "client",
to: "authServer",
details: [
{
label: "Content-Type",
value: "application/json",
},
{
label: "Contains",
value: "client_id, client_name, redirect_uris, etc.",
},
],
},
{
id: "received_client_credentials",
label: "Validate metadata and redirect_uris",
description: "Authorization Server validates fetched metadata",
from: "authServer",
to: "authServer",
details: [
{
label: "Validates",
value: "client_id matches URL, redirect_uris are valid",
},
{
label: "Security",
value: "SSRF protection, domain trust policies",
},
],
},
]
: registrationStrategy === "dcr"
? [
{
id: "request_client_registration",
label: `POST /register (${protocolVersion})`,
description:
"Client registers dynamically with Authorization Server",
from: "client",
to: "authServer",
details: [
{
label: "Note",
value: "Dynamic client registration (DCR)",
},
],
},
{
id: "received_client_credentials",
label: "Client Credentials",
description:
"Authorization Server returns client ID and credentials",
from: "authServer",
to: "client",
details: flowState.clientId
? [
{
label: "client_id",
value: flowState.clientId.substring(0, 20) + "...",
},
]
: undefined,
},
]
: [
{
id: "received_client_credentials",
label: `Use Pre-registered Client (${protocolVersion})`,
description:
"Client uses pre-configured credentials (skipped DCR)",
from: "client",
to: "client",
details: flowState.clientId
? [
{
label: "client_id",
value: flowState.clientId.substring(0, 20) + "...",
},
{
label: "Note",
value: "Pre-registered (no DCR needed)",
},
]
: [
{
label: "Note",
value: "Pre-registered client credentials",
},
],
},
]),
{
id: "generate_pkce_parameters",
label:
protocolVersion === "2025-11-25"
? "Generate PKCE (REQUIRED)\nInclude resource parameter"
: protocolVersion === "2025-03-26"
? "Generate PKCE (REQUIRED)\nInclude resource parameter"
: "Generate PKCE parameters",
description:
protocolVersion === "2025-11-25"
? "Client generates code verifier and challenge (REQUIRED), includes resource parameter"
: protocolVersion === "2025-03-26"
? "Client generates code verifier and challenge (REQUIRED), includes resource parameter"
: "Client generates code verifier and challenge (recommended), includes resource parameter",
from: "client",
to: "client",
details: flowState.codeChallenge
? [
{
label: "code_challenge",
value: flowState.codeChallenge.substring(0, 15) + "...",
},
{
label: "method",
value: flowState.codeChallengeMethod || "S256",
},
{ label: "resource", value: flowState.serverUrl || "—" },
{ label: "Protocol", value: protocolVersion },
]
: undefined,
},
{
id: "authorization_request",
label: "Open browser with authorization URL",
description:
"Client opens browser with authorization URL + code_challenge + resource",
from: "client",
to: "browser",
details: flowState.authorizationUrl
? [
{
label: "code_challenge",
value:
flowState.codeChallenge?.substring(0, 12) + "..." || "S256",
},
{ label: "resource", value: flowState.serverUrl || "" },
]
: undefined,
},
{
id: "browser_to_auth_server",
label: "Authorization request with resource parameter",
description: "Browser navigates to authorization endpoint",
from: "browser",
to: "authServer",
details: flowState.authorizationUrl
? [{ label: "Note", value: "User authorizes in browser" }]
: undefined,
},
{
id: "auth_redirect_to_browser",
label: "Redirect to callback with authorization code",
description:
"Authorization Server redirects browser back to callback URL",
from: "authServer",
to: "browser",
details: flowState.authorizationCode
? [
{
label: "code",
value: flowState.authorizationCode.substring(0, 20) + "...",
},
]
: undefined,
},
{
id: "received_authorization_code",
label: "Authorization code callback",
description:
"Browser redirects back to client with authorization code",
from: "browser",
to: "client",
details: flowState.authorizationCode
? [
{
label: "code",
value: flowState.authorizationCode.substring(0, 20) + "...",
},
]
: undefined,
},
{
id: "token_request",
label: "Token request + code_verifier + resource",
description: "Client exchanges authorization code for access token",
from: "client",
to: "authServer",
details: flowState.codeVerifier
? [
{ label: "grant_type", value: "authorization_code" },
{ label: "resource", value: flowState.serverUrl || "" },
]
: undefined,
},
{
id: "received_access_token",
label: "Access token (+ refresh token)",
description: "Authorization Server returns access token",
from: "authServer",
to: "client",
details: flowState.accessToken
? [
{ label: "token_type", value: flowState.tokenType || "Bearer" },
{
label: "expires_in",
value: flowState.expiresIn?.toString() || "3600",
},
]
: undefined,
},
{
id: "authenticated_mcp_request",
label: "MCP request with access token",
description: "Client makes authenticated request to MCP server",
from: "client",
to: "mcpServer",
details: flowState.accessToken
? [
{ label: "POST", value: "tools/list" },
{
label: "Authorization",
value:
"Bearer " + flowState.accessToken.substring(0, 15) + "...",
},
]
: undefined,
},
{
id: "complete",
label: "MCP response",
description: "MCP Server returns successful response",
from: "mcpServer",
to: "client",
details: flowState.accessToken
? [
{ label: "Status", value: "200 OK" },
{ label: "Content", value: "tools, resources, prompts" },
]
: undefined,
},
];

// Calculate total height needed for segments
const totalActions = actions.length;
// Total segment height: space for all actions + a final buffer
const totalSegmentHeight = totalActions * ACTION_SPACING + 100;

// Create segments for each actor (order: Browser, Client, MCP Server, Auth Server)
const browserSegments: ActorNodeData["segments"] = [];
const clientSegments: ActorNodeData["segments"] = [];
const mcpServerSegments: ActorNodeData["segments"] = [];
const authServerSegments: ActorNodeData["segments"] = [];

let currentY = 0;

actions.forEach((action, index) => {
const actionY = index * ACTION_SPACING;

// Add line segments before the action
if (currentY < actionY) {
browserSegments.push({
id: `browser-line-${index}`,
type: "line",
height: actionY - currentY,
});
clientSegments.push({
id: `client-line-${index}`,
type: "line",
height: actionY - currentY,
});
mcpServerSegments.push({
id: `mcp-line-${index}`,
type: "line",
height: actionY - currentY,
});
authServerSegments.push({
id: `auth-line-${index}`,
type: "line",
height: actionY - currentY,
});
currentY = actionY;
}

// Add box segments for the actors involved in this action
if (action.from === "browser" || action.to === "browser") {
browserSegments.push({
id: `browser-box-${action.id}`,
type: "box",
height: SEGMENT_HEIGHT,
handleId: action.id,
});
} else {
browserSegments.push({
id: `browser-line-action-${index}`,
type: "line",
height: SEGMENT_HEIGHT,
});
}

if (action.from === "client" || action.to === "client") {
clientSegments.push({
id: `client-box-${action.id}`,
type: "box",
height: SEGMENT_HEIGHT,
handleId: action.id,
});
} else {
clientSegments.push({
id: `client-line-action-${index}`,
type: "line",
height: SEGMENT_HEIGHT,
});
}

if (action.from === "mcpServer" || action.to === "mcpServer") {
mcpServerSegments.push({
id: `mcp-box-${action.id}`,
type: "box",
height: SEGMENT_HEIGHT,
handleId: action.id,
});
} else {
mcpServerSegments.push({
id: `mcp-line-action-${index}`,
type: "line",
height: SEGMENT_HEIGHT,
});
}

if (action.from === "authServer" || action.to === "authServer") {
authServerSegments.push({
id: `auth-box-${action.id}`,
type: "box",
height: SEGMENT_HEIGHT,
handleId: action.id,
});
} else {
authServerSegments.push({
id: `auth-line-action-${index}`,
type: "line",
height: SEGMENT_HEIGHT,
});
}

currentY += SEGMENT_HEIGHT;
});

// Add final line segments to reach the same total height for all actors
const remainingHeight = totalSegmentHeight - currentY;
if (remainingHeight > 0) {
browserSegments.push({
id: "browser-line-end",
type: "line",
height: remainingHeight,
});
clientSegments.push({
id: "client-line-end",
type: "line",
height: remainingHeight,
});
mcpServerSegments.push({
id: "mcp-line-end",
type: "line",
height: remainingHeight,
});
authServerSegments.push({
id: "auth-line-end",
type: "line",
height: remainingHeight,
});
}

// Create actor nodes (left to right: Browser, Client, MCP Server, Auth Server)
const nodes: Node[] = [
{
id: "actor-browser",
type: "actor",
position: { x: ACTOR_X_POSITIONS.browser, y: 0 },
data: {
label: ACTORS.browser.label,
color: ACTORS.browser.color,
totalHeight: totalSegmentHeight,
segments: browserSegments,
},
draggable: false,
},
{
id: "actor-client",
type: "actor",
position: { x: ACTOR_X_POSITIONS.client, y: 0 },
data: {
label: ACTORS.client.label,
color: ACTORS.client.color,
totalHeight: totalSegmentHeight,
segments: clientSegments,
},
draggable: false,
},
{
id: "actor-mcpServer",
type: "actor",
position: { x: ACTOR_X_POSITIONS.mcpServer, y: 0 },
data: {
label: ACTORS.mcpServer.label,
color: ACTORS.mcpServer.color,
totalHeight: totalSegmentHeight,
segments: mcpServerSegments,
},
draggable: false,
},
{
id: "actor-authServer",
type: "actor",
position: { x: ACTOR_X_POSITIONS.authServer, y: 0 },
data: {
label: ACTORS.authServer.label,
color: ACTORS.authServer.color,
totalHeight: totalSegmentHeight,
segments: authServerSegments,
},
draggable: false,
},
];

// Create action edges
const edges: Edge[] = actions.map((action, index) => {
const status = getActionStatus(action.id, currentStep, actions);
const isComplete = status === "complete";
const isCurrent = status === "current";
const isPending = status === "pending";

// Determine arrow color based on status
const arrowColor = isComplete
? "#10b981"
: isCurrent
? "#3b82f6"
: "#d1d5db";

// Determine handle positions based on flow direction
const sourceX =
ACTOR_X_POSITIONS[action.from as keyof typeof ACTOR_X_POSITIONS];
const targetX =
ACTOR_X_POSITIONS[action.to as keyof typeof ACTOR_X_POSITIONS];
const isLeftToRight = sourceX < targetX;

return {
id: `edge-${action.id}`,
source: `actor-${action.from}`,
target: `actor-${action.to}`,
sourceHandle: isLeftToRight
? `${action.id}-right-source`
: `${action.id}-left-source`,
targetHandle: isLeftToRight
? `${action.id}-left-target`
: `${action.id}-right-target`,
type: "actionEdge",
data: {
label: action.label,
description: action.description,
status,
details: action.details,
},
animated: isCurrent, // Only animate current step
markerEnd: {
type: "arrowclosed" as const,
color: arrowColor,
width: 12,
height: 12,
},
style: {
stroke: arrowColor,
strokeWidth: isCurrent ? 3 : isComplete ? 2 : 1.5,
strokeDasharray: isCurrent ? "5,5" : undefined, // Only current step is dashed
opacity: isPending ? 0.4 : 1, // Dim pending edges
},
};
});

return { nodes, edges };
}, [flowState, registrationStrategy, protocolVersion]);

// Auto-zoom to current step
useEffect(() => {
if (!reactFlowInstance || !flowState.currentStep) {
return;
}

// Small delay to ensure nodes are rendered
const timer = setTimeout(() => {
// If reset to idle, zoom back to the top
if (flowState.currentStep === "idle") {
// Zoom to the top of the diagram
// Center around the middle actors (Client and MCP Server)
reactFlowInstance.setCenter(550, 200, {
zoom: 0.8,
duration: 800,
});
return;
}

// Don't zoom when flow is complete - let user stay at current position
if (flowState.currentStep === "complete") {
return;
}

// Find the edge that has "current" status (the next step to execute)
const currentEdge = edges.find((e) => e.data?.status === "current");

if (currentEdge) {
// Get source and target actor positions
const sourceNode = nodes.find((n) => n.id === currentEdge.source);
const targetNode = nodes.find((n) => n.id === currentEdge.target);

if (sourceNode && targetNode) {
// Find the action index to calculate Y position
const actionIndex = edges.findIndex((e) => e.id === currentEdge.id);

// Calculate positions
// Actor nodes have a header (~52px) + some padding (~50px)
// Each action segment is ACTION_SPACING (180) apart
const headerOffset = 102;
const actionY = headerOffset + actionIndex * 180 + 40; // 40 is half of SEGMENT_HEIGHT
const centerX =
(sourceNode.position.x + targetNode.position.x) / 2 + 70; // +70 to account for node width
const centerY = actionY;

// Zoom into the current step with animation
reactFlowInstance.setCenter(centerX, centerY, {
zoom: 1.2,
duration: 800,
});
}
}
}, 100);

return () => clearTimeout(timer);
}, [flowState.currentStep, edges, nodes, reactFlowInstance]);

return (
<div className="w-full h-full">
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
minZoom={0.4}
maxZoom={2}
defaultViewport={{ x: 0, y: 0, zoom: 0.8 }}
proOptions={{ hideAttribution: true }}
nodesDraggable={false}
nodesConnectable={false}
elementsSelectable={false}
panOnScroll={true}
zoomOnScroll={true}
zoomOnPinch={true}
panOnDrag={true}
>
<Background />
<Controls />
</ReactFlow>
</div>
);
},
);

DiagramContent.displayName = "DiagramContent";

// Wrapper component with ReactFlowProvider
export const OAuthSequenceDiagram = memo((props: OAuthSequenceDiagramProps) => {
return (
<ReactFlowProvider>
<DiagramContent {...props} />
</ReactFlowProvider>
);
} = props;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Default registration strategy now diverges from the state machine.
The diagram defaults to "dcr", but createDebugOAuthStateMachine (client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts, Line 635) still defaults to "cimd". When no strategy is passed, the visualization shows the DCR branch while the underlying flow continues down the CIMD path—yielding incorrect diagrams. Align these defaults (either revert this prop default to "cimd" or update the state machine default to match) before shipping.

Apply this diff if you choose to restore the previous default on the component side:

-    registrationStrategy = "dcr",
+    registrationStrategy = "cimd",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
registrationStrategy = "dcr",
protocolVersion = "2025-11-25",
}: OAuthSequenceDiagramProps) => {
const reactFlowInstance = useReactFlow();
const { nodes, edges } = useMemo(() => {
const currentStep = flowState.currentStep;
// Define actions in the sequence (matches MCP OAuth spec)
const actions = [
// For 2025-03-26: Start directly with discovery (no initial MCP request)
// Other protocols: Show initial unauthorized request that triggers OAuth
...(protocolVersion === "2025-03-26"
? []
: [
{
id: "request_without_token",
label: "MCP request without token",
description:
"Client makes initial request without authorization",
from: "client",
to: "mcpServer",
details: flowState.serverUrl
? [
{ label: "POST", value: flowState.serverUrl },
{ label: "method", value: "initialize" },
]
: undefined,
},
]),
// For 2025-03-26: Skip RFC9728 steps, go directly to auth server discovery
...(protocolVersion === "2025-03-26"
? []
: [
{
id: "received_401_unauthorized",
label: "HTTP 401 Unauthorized with WWW-Authenticate header",
description: "Server returns 401 with WWW-Authenticate header",
from: "mcpServer",
to: "client",
details: flowState.resourceMetadataUrl
? [{ label: "Note", value: "Extract resource_metadata URL" }]
: undefined,
},
{
id: "request_resource_metadata",
label: "Request Protected Resource Metadata",
description: "Client requests metadata from well-known URI",
from: "client",
to: "mcpServer",
details: flowState.resourceMetadataUrl
? [
{
label: "GET",
value: new URL(flowState.resourceMetadataUrl).pathname,
},
]
: undefined,
},
{
id: "received_resource_metadata",
label: "Return metadata",
description: "Server returns OAuth protected resource metadata",
from: "mcpServer",
to: "client",
details: flowState.resourceMetadata?.authorization_servers
? [
{
label: "Auth Server",
value:
flowState.resourceMetadata.authorization_servers[0],
},
]
: undefined,
},
]),
{
id: "request_authorization_server_metadata",
label:
protocolVersion === "2025-03-26"
? "GET /.well-known/oauth-authorization-server from MCP base URL"
: protocolVersion === "2025-11-25"
? "GET Authorization server metadata endpoint"
: "GET /.well-known/oauth-authorization-server",
description:
protocolVersion === "2025-03-26"
? "Direct discovery from MCP server base URL with fallback to /authorize, /token, /register"
: protocolVersion === "2025-11-25"
? "Try OAuth path insertion, OIDC path insertion, OIDC path appending"
: "Try RFC8414 path, then RFC8414 root (no OIDC support)",
from: "client",
to: "authServer",
details: flowState.authorizationServerUrl
? [
{ label: "URL", value: flowState.authorizationServerUrl },
{ label: "Protocol", value: protocolVersion },
]
: undefined,
},
{
id: "received_authorization_server_metadata",
label: "Authorization server metadata response",
description: "Authorization Server returns metadata",
from: "authServer",
to: "client",
details: flowState.authorizationServerMetadata
? [
{
label: "Token",
value: new URL(
flowState.authorizationServerMetadata.token_endpoint,
).pathname,
},
{
label: "Auth",
value: new URL(
flowState.authorizationServerMetadata.authorization_endpoint,
).pathname,
},
]
: undefined,
},
// Client registration steps - conditionally included based on strategy
...(registrationStrategy === "cimd"
? [
{
id: "cimd_prepare",
label: "Client uses HTTPS URL as client_id",
description:
"Client prepares to use URL-based client identification",
from: "client",
to: "client",
details: flowState.clientId
? [
{
label: "client_id (URL)",
value: flowState.clientId.includes("http")
? flowState.clientId
: "https://www.mcpjam.com/.well-known/oauth/client-metadata.json",
},
{
label: "Method",
value: "Client ID Metadata Document (CIMD)",
},
]
: [
{
label: "Note",
value: "HTTPS URL points to metadata document",
},
],
},
{
id: "cimd_fetch_request",
label: "Fetch metadata from client_id URL",
description:
"Authorization Server fetches client metadata from the URL",
from: "authServer",
to: "client",
details: [
{
label: "Action",
value: "GET client_id URL",
},
{
label: "Note",
value:
"Server initiates metadata fetch during authorization",
},
],
},
{
id: "cimd_metadata_response",
label: "JSON metadata document",
description:
"Client hosting returns metadata with redirect_uris and client info",
from: "client",
to: "authServer",
details: [
{
label: "Content-Type",
value: "application/json",
},
{
label: "Contains",
value: "client_id, client_name, redirect_uris, etc.",
},
],
},
{
id: "received_client_credentials",
label: "Validate metadata and redirect_uris",
description: "Authorization Server validates fetched metadata",
from: "authServer",
to: "authServer",
details: [
{
label: "Validates",
value: "client_id matches URL, redirect_uris are valid",
},
{
label: "Security",
value: "SSRF protection, domain trust policies",
},
],
},
]
: registrationStrategy === "dcr"
? [
{
id: "request_client_registration",
label: `POST /register (${protocolVersion})`,
description:
"Client registers dynamically with Authorization Server",
from: "client",
to: "authServer",
details: [
{
label: "Note",
value: "Dynamic client registration (DCR)",
},
],
},
{
id: "received_client_credentials",
label: "Client Credentials",
description:
"Authorization Server returns client ID and credentials",
from: "authServer",
to: "client",
details: flowState.clientId
? [
{
label: "client_id",
value: flowState.clientId.substring(0, 20) + "...",
},
]
: undefined,
},
]
: [
{
id: "received_client_credentials",
label: `Use Pre-registered Client (${protocolVersion})`,
description:
"Client uses pre-configured credentials (skipped DCR)",
from: "client",
to: "client",
details: flowState.clientId
? [
{
label: "client_id",
value: flowState.clientId.substring(0, 20) + "...",
},
{
label: "Note",
value: "Pre-registered (no DCR needed)",
},
]
: [
{
label: "Note",
value: "Pre-registered client credentials",
},
],
},
]),
{
id: "generate_pkce_parameters",
label:
protocolVersion === "2025-11-25"
? "Generate PKCE (REQUIRED)\nInclude resource parameter"
: protocolVersion === "2025-03-26"
? "Generate PKCE (REQUIRED)\nInclude resource parameter"
: "Generate PKCE parameters",
description:
protocolVersion === "2025-11-25"
? "Client generates code verifier and challenge (REQUIRED), includes resource parameter"
: protocolVersion === "2025-03-26"
? "Client generates code verifier and challenge (REQUIRED), includes resource parameter"
: "Client generates code verifier and challenge (recommended), includes resource parameter",
from: "client",
to: "client",
details: flowState.codeChallenge
? [
{
label: "code_challenge",
value: flowState.codeChallenge.substring(0, 15) + "...",
},
{
label: "method",
value: flowState.codeChallengeMethod || "S256",
},
{ label: "resource", value: flowState.serverUrl || "—" },
{ label: "Protocol", value: protocolVersion },
]
: undefined,
},
{
id: "authorization_request",
label: "Open browser with authorization URL",
description:
"Client opens browser with authorization URL + code_challenge + resource",
from: "client",
to: "browser",
details: flowState.authorizationUrl
? [
{
label: "code_challenge",
value:
flowState.codeChallenge?.substring(0, 12) + "..." || "S256",
},
{ label: "resource", value: flowState.serverUrl || "" },
]
: undefined,
},
{
id: "browser_to_auth_server",
label: "Authorization request with resource parameter",
description: "Browser navigates to authorization endpoint",
from: "browser",
to: "authServer",
details: flowState.authorizationUrl
? [{ label: "Note", value: "User authorizes in browser" }]
: undefined,
},
{
id: "auth_redirect_to_browser",
label: "Redirect to callback with authorization code",
description:
"Authorization Server redirects browser back to callback URL",
from: "authServer",
to: "browser",
details: flowState.authorizationCode
? [
{
label: "code",
value: flowState.authorizationCode.substring(0, 20) + "...",
},
]
: undefined,
},
{
id: "received_authorization_code",
label: "Authorization code callback",
description:
"Browser redirects back to client with authorization code",
from: "browser",
to: "client",
details: flowState.authorizationCode
? [
{
label: "code",
value: flowState.authorizationCode.substring(0, 20) + "...",
},
]
: undefined,
},
{
id: "token_request",
label: "Token request + code_verifier + resource",
description: "Client exchanges authorization code for access token",
from: "client",
to: "authServer",
details: flowState.codeVerifier
? [
{ label: "grant_type", value: "authorization_code" },
{ label: "resource", value: flowState.serverUrl || "" },
]
: undefined,
},
{
id: "received_access_token",
label: "Access token (+ refresh token)",
description: "Authorization Server returns access token",
from: "authServer",
to: "client",
details: flowState.accessToken
? [
{ label: "token_type", value: flowState.tokenType || "Bearer" },
{
label: "expires_in",
value: flowState.expiresIn?.toString() || "3600",
},
]
: undefined,
},
{
id: "authenticated_mcp_request",
label: "MCP request with access token",
description: "Client makes authenticated request to MCP server",
from: "client",
to: "mcpServer",
details: flowState.accessToken
? [
{ label: "POST", value: "tools/list" },
{
label: "Authorization",
value:
"Bearer " + flowState.accessToken.substring(0, 15) + "...",
},
]
: undefined,
},
{
id: "complete",
label: "MCP response",
description: "MCP Server returns successful response",
from: "mcpServer",
to: "client",
details: flowState.accessToken
? [
{ label: "Status", value: "200 OK" },
{ label: "Content", value: "tools, resources, prompts" },
]
: undefined,
},
];
// Calculate total height needed for segments
const totalActions = actions.length;
// Total segment height: space for all actions + a final buffer
const totalSegmentHeight = totalActions * ACTION_SPACING + 100;
// Create segments for each actor (order: Browser, Client, MCP Server, Auth Server)
const browserSegments: ActorNodeData["segments"] = [];
const clientSegments: ActorNodeData["segments"] = [];
const mcpServerSegments: ActorNodeData["segments"] = [];
const authServerSegments: ActorNodeData["segments"] = [];
let currentY = 0;
actions.forEach((action, index) => {
const actionY = index * ACTION_SPACING;
// Add line segments before the action
if (currentY < actionY) {
browserSegments.push({
id: `browser-line-${index}`,
type: "line",
height: actionY - currentY,
});
clientSegments.push({
id: `client-line-${index}`,
type: "line",
height: actionY - currentY,
});
mcpServerSegments.push({
id: `mcp-line-${index}`,
type: "line",
height: actionY - currentY,
});
authServerSegments.push({
id: `auth-line-${index}`,
type: "line",
height: actionY - currentY,
});
currentY = actionY;
}
// Add box segments for the actors involved in this action
if (action.from === "browser" || action.to === "browser") {
browserSegments.push({
id: `browser-box-${action.id}`,
type: "box",
height: SEGMENT_HEIGHT,
handleId: action.id,
});
} else {
browserSegments.push({
id: `browser-line-action-${index}`,
type: "line",
height: SEGMENT_HEIGHT,
});
}
if (action.from === "client" || action.to === "client") {
clientSegments.push({
id: `client-box-${action.id}`,
type: "box",
height: SEGMENT_HEIGHT,
handleId: action.id,
});
} else {
clientSegments.push({
id: `client-line-action-${index}`,
type: "line",
height: SEGMENT_HEIGHT,
});
}
if (action.from === "mcpServer" || action.to === "mcpServer") {
mcpServerSegments.push({
id: `mcp-box-${action.id}`,
type: "box",
height: SEGMENT_HEIGHT,
handleId: action.id,
});
} else {
mcpServerSegments.push({
id: `mcp-line-action-${index}`,
type: "line",
height: SEGMENT_HEIGHT,
});
}
if (action.from === "authServer" || action.to === "authServer") {
authServerSegments.push({
id: `auth-box-${action.id}`,
type: "box",
height: SEGMENT_HEIGHT,
handleId: action.id,
});
} else {
authServerSegments.push({
id: `auth-line-action-${index}`,
type: "line",
height: SEGMENT_HEIGHT,
});
}
currentY += SEGMENT_HEIGHT;
});
// Add final line segments to reach the same total height for all actors
const remainingHeight = totalSegmentHeight - currentY;
if (remainingHeight > 0) {
browserSegments.push({
id: "browser-line-end",
type: "line",
height: remainingHeight,
});
clientSegments.push({
id: "client-line-end",
type: "line",
height: remainingHeight,
});
mcpServerSegments.push({
id: "mcp-line-end",
type: "line",
height: remainingHeight,
});
authServerSegments.push({
id: "auth-line-end",
type: "line",
height: remainingHeight,
});
}
// Create actor nodes (left to right: Browser, Client, MCP Server, Auth Server)
const nodes: Node[] = [
{
id: "actor-browser",
type: "actor",
position: { x: ACTOR_X_POSITIONS.browser, y: 0 },
data: {
label: ACTORS.browser.label,
color: ACTORS.browser.color,
totalHeight: totalSegmentHeight,
segments: browserSegments,
},
draggable: false,
},
{
id: "actor-client",
type: "actor",
position: { x: ACTOR_X_POSITIONS.client, y: 0 },
data: {
label: ACTORS.client.label,
color: ACTORS.client.color,
totalHeight: totalSegmentHeight,
segments: clientSegments,
},
draggable: false,
},
{
id: "actor-mcpServer",
type: "actor",
position: { x: ACTOR_X_POSITIONS.mcpServer, y: 0 },
data: {
label: ACTORS.mcpServer.label,
color: ACTORS.mcpServer.color,
totalHeight: totalSegmentHeight,
segments: mcpServerSegments,
},
draggable: false,
},
{
id: "actor-authServer",
type: "actor",
position: { x: ACTOR_X_POSITIONS.authServer, y: 0 },
data: {
label: ACTORS.authServer.label,
color: ACTORS.authServer.color,
totalHeight: totalSegmentHeight,
segments: authServerSegments,
},
draggable: false,
},
];
// Create action edges
const edges: Edge[] = actions.map((action, index) => {
const status = getActionStatus(action.id, currentStep, actions);
const isComplete = status === "complete";
const isCurrent = status === "current";
const isPending = status === "pending";
// Determine arrow color based on status
const arrowColor = isComplete
? "#10b981"
: isCurrent
? "#3b82f6"
: "#d1d5db";
// Determine handle positions based on flow direction
const sourceX =
ACTOR_X_POSITIONS[action.from as keyof typeof ACTOR_X_POSITIONS];
const targetX =
ACTOR_X_POSITIONS[action.to as keyof typeof ACTOR_X_POSITIONS];
const isLeftToRight = sourceX < targetX;
return {
id: `edge-${action.id}`,
source: `actor-${action.from}`,
target: `actor-${action.to}`,
sourceHandle: isLeftToRight
? `${action.id}-right-source`
: `${action.id}-left-source`,
targetHandle: isLeftToRight
? `${action.id}-left-target`
: `${action.id}-right-target`,
type: "actionEdge",
data: {
label: action.label,
description: action.description,
status,
details: action.details,
},
animated: isCurrent, // Only animate current step
markerEnd: {
type: "arrowclosed" as const,
color: arrowColor,
width: 12,
height: 12,
},
style: {
stroke: arrowColor,
strokeWidth: isCurrent ? 3 : isComplete ? 2 : 1.5,
strokeDasharray: isCurrent ? "5,5" : undefined, // Only current step is dashed
opacity: isPending ? 0.4 : 1, // Dim pending edges
},
};
});
return { nodes, edges };
}, [flowState, registrationStrategy, protocolVersion]);
// Auto-zoom to current step
useEffect(() => {
if (!reactFlowInstance || !flowState.currentStep) {
return;
}
// Small delay to ensure nodes are rendered
const timer = setTimeout(() => {
// If reset to idle, zoom back to the top
if (flowState.currentStep === "idle") {
// Zoom to the top of the diagram
// Center around the middle actors (Client and MCP Server)
reactFlowInstance.setCenter(550, 200, {
zoom: 0.8,
duration: 800,
});
return;
}
// Don't zoom when flow is complete - let user stay at current position
if (flowState.currentStep === "complete") {
return;
}
// Find the edge that has "current" status (the next step to execute)
const currentEdge = edges.find((e) => e.data?.status === "current");
if (currentEdge) {
// Get source and target actor positions
const sourceNode = nodes.find((n) => n.id === currentEdge.source);
const targetNode = nodes.find((n) => n.id === currentEdge.target);
if (sourceNode && targetNode) {
// Find the action index to calculate Y position
const actionIndex = edges.findIndex((e) => e.id === currentEdge.id);
// Calculate positions
// Actor nodes have a header (~52px) + some padding (~50px)
// Each action segment is ACTION_SPACING (180) apart
const headerOffset = 102;
const actionY = headerOffset + actionIndex * 180 + 40; // 40 is half of SEGMENT_HEIGHT
const centerX =
(sourceNode.position.x + targetNode.position.x) / 2 + 70; // +70 to account for node width
const centerY = actionY;
// Zoom into the current step with animation
reactFlowInstance.setCenter(centerX, centerY, {
zoom: 1.2,
duration: 800,
});
}
}
}, 100);
return () => clearTimeout(timer);
}, [flowState.currentStep, edges, nodes, reactFlowInstance]);
return (
<div className="w-full h-full">
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
minZoom={0.4}
maxZoom={2}
defaultViewport={{ x: 0, y: 0, zoom: 0.8 }}
proOptions={{ hideAttribution: true }}
nodesDraggable={false}
nodesConnectable={false}
elementsSelectable={false}
panOnScroll={true}
zoomOnScroll={true}
zoomOnPinch={true}
panOnDrag={true}
>
<Background />
<Controls />
</ReactFlow>
</div>
);
},
);
DiagramContent.displayName = "DiagramContent";
// Wrapper component with ReactFlowProvider
export const OAuthSequenceDiagram = memo((props: OAuthSequenceDiagramProps) => {
return (
<ReactFlowProvider>
<DiagramContent {...props} />
</ReactFlowProvider>
);
} = props;
registrationStrategy = "cimd",
protocolVersion = "2025-11-25",
} = props;
🤖 Prompt for AI Agents
In client/src/components/OAuthSequenceDiagram.tsx around lines 25 to 27, the
component default registrationStrategy is set to "dcr" which conflicts with the
state machine default "cimd" (see
client/src/lib/oauth/state-machines/debug-oauth-2025-11-25.ts line 635), causing
diagrams to diverge from actual flows; fix by making the defaults consistent —
either change this component default back to "cimd" or update the state machine
default to "dcr" so both match, and ensure any tests or usages that rely on
implicit defaults are updated accordingly.

@chelojimenez chelojimenez merged commit c04dbbc into main Nov 5, 2025
3 checks passed
khandrew1 pushed a commit to khandrew1/inspector that referenced this pull request Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants