diff --git a/specification/v2_ux.md b/specification/v2_ux.md index d695604b..df050840 100644 --- a/specification/v2_ux.md +++ b/specification/v2_ux.md @@ -1,7 +1,7 @@ # Inspector V2 UX - Specification ### [Brief](README.md) | [V1 Problems](v1_problems.md) | [V2 Scope](v2_scope.md) | [V2 Tech Stack](v2_web_client.md) | V2 UX -#### Overview | [Features](v2_ux_features.md) | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) +#### Overview | [Features](v2_ux_features.md) | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) | [Interfaces](v2_ux_interfaces.md) ## Table of Contents * [Design Principles](#design-principles) diff --git a/specification/v2_ux_components.md b/specification/v2_ux_components.md index 19d33d8e..72f03c76 100644 --- a/specification/v2_ux_components.md +++ b/specification/v2_ux_components.md @@ -1,7 +1,7 @@ # Inspector V2 UX - Component Development ### [Brief](README.md) | [V1 Problems](v1_problems.md) | [V2 Scope](v2_scope.md) | [V2 Tech Stack](v2_web_client.md) | V2 UX -#### [Overview](v2_ux.md) | [Features](v2_ux_features.md) | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | Components +#### [Overview](v2_ux.md) | [Features](v2_ux_features.md) | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | Components | [Interfaces](v2_ux_interfaces.md) We are developing React components with Mantine, Zustand, and Storybook using a pattern called "Presentational Components" that emphasizes separation of concerns and testability. diff --git a/specification/v2_ux_features.md b/specification/v2_ux_features.md index e919f571..94fa518f 100644 --- a/specification/v2_ux_features.md +++ b/specification/v2_ux_features.md @@ -1,7 +1,7 @@ # Inspector V2 UX - Feature Screens ### [Brief](README.md) | [V1 Problems](v1_problems.md) | [V2 Scope](v2_scope.md) | [V2 Tech Stack](v2_web_client.md) | V2 UX -#### [Overview](v2_ux.md) | Features | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) +#### [Overview](v2_ux.md) | Features | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) | [Interfaces](v2_ux_interfaces.md) --- diff --git a/specification/v2_ux_handlers.md b/specification/v2_ux_handlers.md index 0b32bc73..af57e172 100644 --- a/specification/v2_ux_handlers.md +++ b/specification/v2_ux_handlers.md @@ -1,7 +1,7 @@ # Inspector V2 UX - Handlers & Patterns ### [Brief](README.md) | [V1 Problems](v1_problems.md) | [V2 Scope](v2_scope.md) | [V2 Tech Stack](v2_web_client.md) | V2 UX -#### [Overview](v2_ux.md) | [Features](v2_ux_features.md) | Handlers | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) +#### [Overview](v2_ux.md) | [Features](v2_ux_features.md) | Handlers | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) | [Interfaces](v2_ux_interfaces.md) --- diff --git a/specification/v2_ux_interfaces.md b/specification/v2_ux_interfaces.md new file mode 100644 index 00000000..76063ee8 --- /dev/null +++ b/specification/v2_ux_interfaces.md @@ -0,0 +1,923 @@ +# Inspector V2 UX - Component Interfaces + +### [Brief](README.md) | [V1 Problems](v1_problems.md) | [V2 Scope](v2_scope.md) | [V2 Tech Stack](v2_web_client.md) | V2 UX +#### [Overview](v2_ux.md) | [Features](v2_ux_features.md) | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) | Interfaces + +## Summary + +The Inspector V2 web client's React components were created iteratively from text +descriptions, ASCII wireframes, mockup screenshots, and hand-tweaked refinements. +Their current prop interfaces were derived from those informal sources plus +intuitive gap-filling during implementation. As a result, the component layer is +visually polished and internally consistent, but the data shapes it consumes are +ad hoc — they do not yet line up with the authoritative object definitions that +the Inspector core will actually hand down at runtime. + +Those authoritative object definitions come from the Model Context Protocol +schema (see +[modelcontextprotocol/schema 2025-11-25](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2025-11-25/schema.json)). +Tools, Prompts, Resources, ResourceTemplates, Messages, ServerCapabilities, Roots, +LoggingMessage notifications, ProgressNotifications, ElicitRequests, +CreateMessageRequests (sampling), and every other MCP primitive our UI surfaces +has a canonical shape in that schema. Wherever a component currently accepts a +local, inferred type for one of those primitives, it must instead accept the +corresponding MCP schema type (or an explicit superset/wrapper type defined in +`core/`). + +In addition to MCP schema objects, components receive two other categories of +props: + +1. **Callbacks** — handlers invoked when the user interacts with the UI + (connect, disconnect, callTool, readResource, subscribe, setLogLevel, respond + to elicitation, approve sampling, etc.). These are provided by the Inspector + core's hook layer and passed down as props. +2. **Application state** — UI-facing state that is not part of the MCP schema + but is needed to render correctly: connection status, pending request lists, + history entries, selection state, loading flags, error strings, form drafts, + etc. Shapes for these are owned by the web client, but where they wrap MCP + objects, they should embed the schema types verbatim rather than + re-declaring them. + +### Dumb component principle + +Every component in `clients/web/src/components/` is a **dumb component**. It: + +- Renders the data passed in via props. +- Executes the callbacks passed in via props in response to user interaction. +- Holds internal state *only* where needed for presentation or local + interaction (open/closed accordions, text in an uncommitted form field, + current tab index, hover state, etc.). +- Does **not** fetch data, manage MCP transport, persist anything to storage, + or know about global application state. + +All communication with MCP servers, transport lifecycle management, request +correlation, history recording, log buffering, subscription tracking, and +persistence is owned by the **Inspector core system**. The core lives in this +repo under `core/` and is modeled after the v1.5 architecture — specifically the +React hooks published on the +[v1.5/main branch of modelcontextprotocol/inspector](https://github.com/modelcontextprotocol/inspector/tree/v1.5/main). +Those hooks (`useConnection`, `useMcpClient`, `useServerCapabilities`, etc.) +produce the exact data and callbacks that the upper-layer screen/view +components will destructure and pass down into the component tree as props. + +### Goals of this plan + +1. **Inventory** every component currently under + `clients/web/src/components/` grouped by its folder (`elements/`, `groups/`, + `screens/`, `views/`). +2. **Identify MCP schema touch points** — for each component, list the MCP + schema types its props should reference. +3. **Propose a new prop interface** — for each component, document the current + props, the target props (schema types + callbacks + app state), and any + internal display/logic refactors that will be required to consume the new + shapes. +4. **Map callbacks to core hooks** — note which Inspector core hook is expected + to provide each callback and each piece of application state, so the + wiring layer (screens and views) has a clear contract to fulfill. + +This document is a **plan only**. No component code is modified by producing +it. Implementation will happen in follow-up PRs, one component family at a +time, with Storybook stories updated in lockstep so each component can be +exercised in isolation against realistic MCP schema fixtures. + +### Document conventions + +For each component, the plan records: + +- **Location** — folder path under `clients/web/src/components/`. +- **Purpose** — one-line description of what the component renders. +- **Current props** — the interface as it exists today. +- **MCP schema touch points** — which MCP types the props should align to. +- **Target props** — the proposed new interface. +- **Callbacks → core hook** — which Inspector core hook supplies each callback. +- **Internal refactors** — display/logic changes implied by the new shape. + +--- + +## Section 1 — Elements (`clients/web/src/components/elements/`) + +> Small, focused presentational primitives. Each renders a single MCP concept +> (a badge, an indicator, a button, a viewer) and is composed by higher-level +> group and screen components. + + + +### AnnotationBadge + +- **Location** — `elements/AnnotationBadge/AnnotationBadge.tsx` +- **Purpose** — Single colored badge representing one MCP annotation facet (audience, readOnly, destructive, longRun, priority). +- **Current props** — `label: string`; `variant?: "audience" | "readOnly" | "destructive" | "longRun" | "priority" | "default"`. +- **MCP schema touch points** — `Annotations` object (used by `Tool.annotations` as `ToolAnnotations`, and by `Resource`/`ResourceTemplate`/content blocks). Relevant fields: `audience`, `priority`, and `ToolAnnotations.readOnlyHint`/`destructiveHint`/`idempotentHint`/`openWorldHint`. +- **Target props** — `facet: "audience" | "priority" | "readOnlyHint" | "destructiveHint" | "idempotentHint" | "openWorldHint" | "longRunHint"`; `value: Role[] | number | boolean`. Keeps the badge a pure mapping from one annotation facet+value to a styled label; the owning group component (e.g. `ToolCard`) destructures an `Annotations`/`ToolAnnotations` object and renders one `AnnotationBadge` per populated field. +- **Callbacks → core hook** — None. +- **Internal refactors** — Move the facet→label formatting (e.g. `"audience: user, assistant"`, `"priority: 0.8"`, `"read-only"`) into the component so callers only pass the raw schema value. Drop the standalone `label` prop. + +### CapabilityItem + +- **Location** — `elements/CapabilityItem/CapabilityItem.tsx` +- **Purpose** — Single row in a server-capabilities list: check/cross icon plus capability name and optional count. +- **Current props** — `name: string`; `supported: boolean`; `count?: number`. +- **MCP schema touch points** — `ServerCapabilities` (keys `tools`, `resources`, `prompts`, `logging`, `completions`, `experimental`) plus the paginated `ListToolsResult` / `ListResourcesResult` / `ListPromptsResult` for the count. +- **Target props** — Shape stays similar, but semantics pin `name` to a `keyof ServerCapabilities` and `count` to the length of the corresponding list result. Proposed: `capability: keyof ServerCapabilities`; `supported: boolean`; `count?: number`. +- **Callbacks → core hook** — None. `supported` is derived from `useServerCapabilities` in the wiring layer; `count` from `useMcpClient` list results. +- **Internal refactors** — Map `capability` key to its display label inside the component (`tools → "Tools"`, etc.). + +### ConnectionToggle + +- **Location** — `elements/ConnectionToggle/ConnectionToggle.tsx` +- **Purpose** — Large on/off switch that connects or disconnects a configured server. +- **Current props** — `checked: boolean`; `loading: boolean`; `disabled: boolean`; `onChange: (checked: boolean) => void`. +- **MCP schema touch points** — None — purely presentational, but `checked`/`loading` are derived from `ConnectionStatus` application state (not MCP schema). +- **Target props** — `status: ConnectionStatus` (core-owned enum: `"disconnected" | "connecting" | "connected" | "failed"`); `disabled?: boolean`; `onConnect: () => void`; `onDisconnect: () => void`. +- **Callbacks → core hook** — `onConnect`, `onDisconnect` → `useConnection` (v1.5 `useConnection` exposes `connect`/`disconnect`). +- **Internal refactors** — Derive `checked`/`loading` from `status` internally; split the single `onChange` into explicit `onConnect`/`onDisconnect` so the wiring layer can pass hook callbacks directly without a boolean adapter. + +### ContentViewer + +- **Location** — `elements/ContentViewer/ContentViewer.tsx` +- **Purpose** — Renders a single content block (text, JSON-formatted text, image, or audio) with an optional copy overlay. +- **Current props** — `type: "text" | "json" | "image" | "audio"`; `content: string`; `mimeType?: string`; `copyable?: boolean`. +- **MCP schema touch points** — `ContentBlock` union: `TextContent`, `ImageContent`, `AudioContent`, `EmbeddedResource`, `ResourceLink`. Also `BlobResourceContents` / `TextResourceContents` for embedded resources. +- **Target props** — `block: ContentBlock`; `copyable?: boolean`. The component discriminates on `block.type` (`"text" | "image" | "audio" | "resource" | "resource_link"`) and reads `text`, `data` + `mimeType`, or nested `resource` fields from the schema object directly. +- **Callbacks → core hook** — None. +- **Internal refactors** — Replace the ad hoc `"json"` pseudo-type with a heuristic (or explicit flag) applied to `TextContent.text` whose `mimeType` is `application/json`. Add a branch for `EmbeddedResource` and `ResourceLink`. Drop the separate `content`/`mimeType` scalar props. + +### CopyButton + +- **Location** — `elements/CopyButton/CopyButton.tsx` +- **Purpose** — Thin wrapper around Mantine `CopyButton` + `ActionIcon` that copies a string to the clipboard with a tooltip. +- **Current props** — `value: string`. +- **MCP schema touch points** — None — purely presentational. +- **Target props** — Unchanged: `value: string`. +- **Callbacks → core hook** — None. +- **Internal refactors** — None. + +### InlineError + +- **Location** — `elements/InlineError/InlineError.tsx` +- **Purpose** — Red alert with a message, optional expandable details, retry counter, and doc link. +- **Current props** — `message: string`; `details?: string`; `retryCount?: number`; `maxRetries?: number`; `docLink?: string`. +- **MCP schema touch points** — `JSONRPCError.error` (`code: number`, `message: string`, `data?: unknown`) is the canonical MCP error shape; any tool result with `isError: true` also surfaces here via its embedded `TextContent`. +- **Target props** — `error: JSONRPCError["error"] | { message: string; data?: unknown }`; `retryCount?: number`; `maxRetries?: number`; `docLink?: string`. +- **Callbacks → core hook** — None. Retry counters come from `useConnection` / request-layer state in the wiring layer. +- **Internal refactors** — Derive `message` from `error.message` and `details` from a pretty-printed `error.data` (or `error.code`) instead of taking them as separate scalar props. + +### ListChangedIndicator + +- **Location** — `elements/ListChangedIndicator/ListChangedIndicator.tsx` +- **Purpose** — "List updated" pill with a dot and Refresh button, shown when the server emits a list-changed notification. +- **Current props** — `visible: boolean`; `onRefresh: () => void`. +- **MCP schema touch points** — `ToolListChangedNotification`, `ResourceListChangedNotification`, `PromptListChangedNotification`, `RootsListChangedNotification` — all parameterless notifications; the component only needs a boolean "one or more are pending" signal. +- **Target props** — Unchanged: `visible: boolean`; `onRefresh: () => void`. +- **Callbacks → core hook** — `onRefresh` → `useMcpClient` (re-invokes `listTools` / `listResources` / `listPrompts` / `listRoots` depending on the screen). `visible` comes from core notification-tracking state. +- **Internal refactors** — None. + +### ListToggle + +- **Location** — `elements/ListToggle/ListToggle.tsx` +- **Purpose** — Icon button that toggles a list between compact and expanded rendering. +- **Current props** — `compact: boolean`; `onToggle: () => void`. +- **MCP schema touch points** — None — purely presentational UI state. +- **Target props** — Unchanged. +- **Callbacks → core hook** — None. `compact` is local UI state held by the owning screen/group. +- **Internal refactors** — None. + +### LogEntry + +- **Location** — `elements/LogEntry/LogEntry.tsx` +- **Purpose** — Single row in the log stream: timestamp, level badge, optional logger name, message. +- **Current props** — `timestamp: string`; `level: LogLevel`; `message: string`; `logger?: string`. +- **MCP schema touch points** — `LoggingMessageNotification.params` (`level: LoggingLevel`, `logger?: string`, `data: unknown`). Timestamp is not part of the MCP notification — it is recorded by core when the notification arrives. +- **Target props** — `entry: { receivedAt: string; params: LoggingMessageNotification["params"] }` — a core-owned wrapper type that embeds the MCP params verbatim and adds the client-side receive time. +- **Callbacks → core hook** — None. Log buffer is owned by core (`useLoggingNotifications` or equivalent) and entries are passed down as props. +- **Internal refactors** — Accept `params.data` (`unknown`) and render it via a string coercion / JSON stringify instead of a pre-formatted `message`. Pull `level` and `logger` off `params`. Remove the local `LogLevel` alias in favor of the schema's `LoggingLevel`. + +### LogLevelBadge + +- **Location** — `elements/LogLevelBadge/LogLevelBadge.tsx` +- **Purpose** — Colored badge for a single MCP log level. +- **Current props** — `level: LogLevel` (local union re-exported from `LogEntry`). +- **MCP schema touch points** — `LoggingLevel` (`"debug" | "info" | "notice" | "warning" | "error" | "critical" | "alert" | "emergency"`). +- **Target props** — `level: LoggingLevel` (imported from the MCP schema types in `core/`). +- **Callbacks → core hook** — None. +- **Internal refactors** — Swap the local `LogLevel` import for the schema `LoggingLevel` type. No visual changes. + +### MessageBubble + +- **Location** — `elements/MessageBubble/MessageBubble.tsx` +- **Purpose** — One message in a sampling `CreateMessageRequest` preview or assistant/user transcript, with text and optional image/audio content. +- **Current props** — `index: number`; `role: "user" | "assistant"`; `content: string`; `imageContent?: { data: string; mimeType: string }`; `audioContent?: { data: string; mimeType: string }`. +- **MCP schema touch points** — `SamplingMessage` (`role: Role`, `content: TextContent | ImageContent | AudioContent`). Also `PromptMessage` for prompt rendering, which uses `ContentBlock`. +- **Target props** — `index: number`; `message: SamplingMessage` (or `PromptMessage` when used in the prompts screen — both share the `role` + content-block shape). +- **Callbacks → core hook** — None. +- **Internal refactors** — Discriminate on `message.content.type` instead of taking three parallel content props. Delegate content rendering to `ContentViewer` for consistency. + +### ProgressDisplay + +- **Location** — `elements/ProgressDisplay/ProgressDisplay.tsx` +- **Purpose** — Progress bar with an optional description and elapsed-time caption. +- **Current props** — `progress: number` (0–100); `description?: string`; `elapsed?: string`. +- **MCP schema touch points** — `ProgressNotification.params` (`progressToken`, `progress: number`, `total?: number`, `message?: string`). +- **Target props** — `params: ProgressNotification["params"]`; `elapsed?: string` (client-computed from the time the request was issued). +- **Callbacks → core hook** — None. Progress state is aggregated by core (`useMcpClient` / request tracker) keyed by `progressToken`. +- **Internal refactors** — Compute the displayed percentage from `progress`/`total` (fall back to raw `progress` if `total` is missing). Read caption text from `message` instead of `description`. + +### ServerStatusIndicator + +- **Location** — `elements/ServerStatusIndicator/ServerStatusIndicator.tsx` +- **Purpose** — Colored dot + text label showing current connection state for a server, with optional latency and retry count. +- **Current props** — `status: "connected" | "connecting" | "disconnected" | "failed"`; `latencyMs?: number`; `retryCount?: number`. +- **MCP schema touch points** — None — purely application state. (Server identity lives in `Implementation`, but the indicator itself only reflects transport status.) +- **Target props** — `status: ConnectionStatus` (core-owned enum matching the four states above); `latencyMs?: number`; `retryCount?: number`. +- **Callbacks → core hook** — None. All three props come from `useConnection`. +- **Internal refactors** — None beyond importing `ConnectionStatus` from `core/` once defined. + +### SubscribeButton + +- **Location** — `elements/SubscribeButton/SubscribeButton.tsx` +- **Purpose** — Toggle button to subscribe/unsubscribe from a single MCP resource. +- **Current props** — `subscribed: boolean`; `onToggle: () => void`. +- **MCP schema touch points** — `SubscribeRequest.params.uri` and `UnsubscribeRequest.params.uri` — but the URI is held by the parent row; the button itself only needs the current subscription boolean. +- **Target props** — `subscribed: boolean`; `onSubscribe: () => void`; `onUnsubscribe: () => void` (split for parity with `ConnectionToggle`). Alternatively keep a single `onToggle` if the wiring layer prefers that. +- **Callbacks → core hook** — `onSubscribe` / `onUnsubscribe` → `useMcpClient` (wraps `client.subscribeResource` / `client.unsubscribeResource`); `subscribed` derived from a core-owned subscription set. +- **Internal refactors** — Optional split of `onToggle` into the two explicit callbacks; otherwise none. + +### TaskStatusBadge + +- **Location** — `elements/TaskStatusBadge/TaskStatusBadge.tsx` +- **Purpose** — Colored badge for the current lifecycle state of a long-running task. +- **Current props** — `status: TaskStatus` (imported from `groups/TaskCard/TaskCard`: `"waiting" | "running" | "completed" | "failed" | "cancelled"`). +- **MCP schema touch points** — The 2025-11-25 MCP schema does not define a first-class "task" primitive; task state is an Inspector-side aggregation over in-flight requests, cancellations (`CancelledNotification`), progress (`ProgressNotification`), and final results/errors. So the type is core-owned application state, not schema. +- **Target props** — `status: TaskStatus` where `TaskStatus` is moved out of `TaskCard` into a core-owned type (e.g. `core/src/tasks/types.ts`) so both this badge and `TaskCard` import it from the same place. +- **Callbacks → core hook** — None. Status comes from a core task-tracking hook (e.g. `useTasks`) in the wiring layer. +- **Internal refactors** — Update the import path for `TaskStatus` to the core module; no visual changes. + +### TransportBadge + +- **Location** — `elements/TransportBadge/TransportBadge.tsx` +- **Purpose** — Small outline badge labeling a server's transport (`STDIO` or `HTTP`). +- **Current props** — `transport: "stdio" | "http"`. +- **MCP schema touch points** — None — transport is not in the MCP wire schema; it is described by core-owned server-config types (stdio command/args vs. streamable HTTP URL, matching v1.5's `StdioServerParameters` and streamable-HTTP transport options). +- **Target props** — `transport: TransportKind` where `TransportKind = "stdio" | "streamable-http" | "sse"` is owned by `core/` (aligning with v1.5's supported transports). +- **Callbacks → core hook** — None. Value comes from the server-config record exposed by the wiring layer. +- **Internal refactors** — Extend the display-label map to cover `streamable-http` (e.g. `"HTTP"`) and `sse` (e.g. `"SSE"`) so the badge can render every transport core supports. + + + +--- + +## Section 2 — Groups (`clients/web/src/components/groups/`) + +> Composite components that combine elements into a functional panel, form, +> list item, or control cluster. Most of the MCP-schema-shaped data flows +> through this layer. + + + +### ElicitationFormPanel + +- **Location**: `groups/ElicitationFormPanel/` +- **Purpose**: Full-panel form rendering an `elicitation/create` request with schema-driven fields, trust warning, and submit/cancel actions. +- **Current props**: `message`, `schema: JsonSchema`, `values`, `serverName`, `onChange`, `onSubmit`, `onCancel`. +- **MCP schema touch points**: `ElicitRequest.params` (`message`, `requestedSchema`), `PrimitiveSchemaDefinition`, `ElicitResult` (`action`, `content`). +- **Target props**: `request: ElicitRequest` (or `{ message; requestedSchema }`), `serverName: string`, `values: Record`, `onChange`, `onSubmit(result: ElicitResult)`, `onCancel()`. +- **Callbacks → core hook**: `onSubmit`/`onCancel` from likely `useElicitation` (pending `ElicitRequest` queue). +- **Internal refactors**: Constrain to `PrimitiveSchemaDefinition` record instead of freeform `JsonSchema`; emit `{action:'accept'|'decline'|'cancel', content}`. + +### ElicitationUrlPanel + +- **Location**: `groups/ElicitationUrlPanel/` +- **Purpose**: Full-panel display of a URL-mode elicitation (copy URL, open externally, wait for completion). +- **Current props**: `message`, `url`, `elicitationId`, `isWaiting`, `onCopyUrl`, `onOpenInBrowser`, `onCancel`. +- **MCP schema touch points**: URL-mode elicitation is NOT in MCP 2025-11-25 — Inspector-owned extension of `ElicitRequest`. +- **Target props**: `request: InspectorUrlElicitRequest` (`requestId`, `message`, `url`), `isWaiting`, `onCopyUrl`, `onOpenInBrowser`, `onCancel`. +- **Callbacks → core hook**: likely `useElicitation` (URL variant). +- **Internal refactors**: Replace scalar props with wrapper object. + +### ExperimentalFeaturesPanel + +- **Location**: `groups/ExperimentalFeaturesPanel/` +- **Purpose**: Displays server/client experimental capabilities and a raw JSON-RPC tester with headers and request history. +- **Current props**: `serverCapabilities`, `clientCapabilities`, `requestJson`, `responseJson`, `customHeaders`, `requestHistory`, many handlers. +- **MCP schema touch points**: `ServerCapabilities.experimental`, `ClientCapabilities.experimental` (freeform `{[k]: object}`); `JSONRPCRequest`/`JSONRPCResponse`/`JSONRPCError`. `RequestHistoryItem` is Inspector-owned. +- **Target props**: `serverExperimental: ServerCapabilities['experimental']`, `clientExperimental: ClientCapabilities['experimental']`, `requestDraft: string`, `response?: JSONRPCResponse | JSONRPCError`, `customHeaders: HeaderPair[]`, `history: InspectorRequestHistoryItem[]`, handlers unchanged. +- **Callbacks → core hook**: `onSendRequest`/`onTestCapability` from likely `useMcpClient`; `onToggleClientCapability` from likely `useClientCapabilities`; history from `useHistory`. +- **Internal refactors**: Iterate over the freeform capability record rather than an inferred `{name,description,methods}` list. + +### HistoryControls + +- **Location**: `groups/HistoryControls/` +- **Purpose**: Search + method filter sidebar for the history screen. +- **Current props**: `searchText`, `methodFilter`, `onSearchChange`, `onMethodFilterChange`. +- **MCP schema touch points**: Method filter values are MCP `Request.method` literals. +- **Target props**: `searchText`, `methodFilter?: RequestMethod`, `availableMethods: RequestMethod[]`, `onSearchChange`, `onMethodFilterChange`. +- **Callbacks → core hook**: likely `useHistory`. +- **Internal refactors**: Type the method filter as a union of MCP method strings. + +### HistoryEntry + +- **Location**: `groups/HistoryEntry/` +- **Purpose**: Collapsible card for a single historical MCP request/response with replay and pin. +- **Current props**: `timestamp`, `method`, `target?`, `status`, `durationMs`, `parameters`, `response`, `childEntries`, `isPinned`, `isListExpanded`, `onReplay`, `onTogglePin`. +- **MCP schema touch points**: Wraps an MCP `Request`/`Result` pair; parameters → `Request.params`, response → `Result | JSONRPCError`. Child entries are nested server→client calls (sampling/elicitation/roots). +- **Target props**: `entry: InspectorHistoryEntry` (embeds `request: JSONRPCRequest`, `response?: JSONRPCResponse | JSONRPCError`, `startedAt`, `durationMs`, `childEntries`, `isPinned`), `isListExpanded`, `onReplay`, `onTogglePin`. +- **Callbacks → core hook**: likely `useHistory`. +- **Internal refactors**: Derive `method`/`target`/`status` from the embedded JSON-RPC objects rather than flat scalars. + +### HistoryListPanel + +- **Location**: `groups/HistoryListPanel/` +- **Purpose**: Scrollable list of pinned + regular history entries with toolbar. +- **Current props**: `entries`, `pinnedEntries`, `searchText`, `methodFilter?`, `onClearAll`, `onExport`. +- **MCP schema touch points**: Same `InspectorHistoryEntry` wrapper as above. +- **Target props**: `entries: InspectorHistoryEntry[]`, `pinnedEntries: InspectorHistoryEntry[]`, `searchText`, `methodFilter?`, `onClearAll`, `onExport`, `onReplay(entryId)`, `onTogglePin(entryId)`. +- **Callbacks → core hook**: likely `useHistory`. +- **Internal refactors**: Pass entry id + handlers down instead of pre-bound callbacks on each entry. + +### ImportServerJsonPanel + +- **Location**: `groups/ImportServerJsonPanel/` +- **Purpose**: Form for pasting/validating an MCP registry `server.json` and configuring env vars before adding. +- **Current props**: `jsonContent`, `validationResults`, `packages?`, `selectedPackageIndex`, `envVars`, `serverName`, handlers. +- **MCP schema touch points**: `server.json` is MCP **registry** spec, not the runtime schema — Inspector/registry-owned. +- **Target props**: `draft: InspectorServerJsonDraft` (raw text + parsed `RegistryServerJson` + `selectedPackageIndex` + env overrides + name override), `validation: ValidationResult[]`, handlers unchanged. +- **Callbacks → core hook**: likely `useServerRegistry` / `useServers`. +- **Internal refactors**: Collapse scattered scalar props into a single draft object. + +### InlineElicitationRequest + +- **Location**: `groups/InlineElicitationRequest/` +- **Purpose**: Compact inline card for a pending elicitation (form or URL mode) in request queues. +- **Current props**: `mode`, `message`, `queuePosition`, `schema?`, `values?`, `url?`, `isWaiting?`, handlers. +- **MCP schema touch points**: `ElicitRequest` (form); URL variant is Inspector-owned. +- **Target props**: `request: ElicitRequest | InspectorUrlElicitRequest`, `queuePosition`, `values?`, `isWaiting?`, handlers. +- **Callbacks → core hook**: likely `useElicitation`. +- **Internal refactors**: Discriminate on `request` shape rather than a separate `mode` prop. + +### InlineSamplingRequest + +- **Location**: `groups/InlineSamplingRequest/` +- **Purpose**: Compact inline card for a pending `sampling/createMessage` request. +- **Current props**: `queuePosition`, `modelHints?`, `messagePreview`, `responseText`, `onAutoRespond`, `onEditAndSend`, `onReject`, `onViewDetails`. +- **MCP schema touch points**: `CreateMessageRequest` (`messages`, `modelPreferences.hints[].name`, etc.), `CreateMessageResult`. +- **Target props**: `request: CreateMessageRequest`, `queuePosition`, `draftResult?: CreateMessageResult`, handlers. +- **Callbacks → core hook**: likely `useSampling`. +- **Internal refactors**: Derive `modelHints` and `messagePreview` from the embedded request. + +### LogControls + +- **Location**: `groups/LogControls/` +- **Purpose**: Sidebar for setting active log level, filtering text, and toggling visible levels. +- **Current props**: `currentLevel`, `filterText`, `visibleLevels`, `onSetLevel`, `onFilterChange`, `onToggleLevel`, `onToggleAllLevels`. +- **MCP schema touch points**: `LoggingLevel` union, `SetLevelRequest.params.level`. +- **Target props**: `currentLevel: LoggingLevel`, `filterText`, `visibleLevels: Record`, handlers typed with `LoggingLevel`. +- **Callbacks → core hook**: `onSetLevel` from likely `useLogs` (issues `logging/setLevel`); visibility is client state from `useLogs` or screen. +- **Internal refactors**: Replace string-typed levels with `LoggingLevel` throughout. + +### LogStreamPanel + +- **Location**: `groups/LogStreamPanel/` +- **Purpose**: Scrollable stream of log entries with auto-scroll, clear, export, copy-all. +- **Current props**: `entries: LogEntryProps[]`, `filterText`, `visibleLevels`, `autoScroll`, handlers. +- **MCP schema touch points**: `LoggingMessageNotification.params` (`level`, `logger?`, `data`). +- **Target props**: `entries: InspectorLogEntry[]` (wraps `LoggingMessageNotification['params']` + timestamp), `filterText`, `visibleLevels: Record`, `autoScroll`, handlers. +- **Callbacks → core hook**: likely `useLogs` (buffers `notifications/message`). +- **Internal refactors**: Adapt `LogEntry` to render `LoggingMessageNotification.params` directly. + +### PendingClientRequests + +- **Location**: `groups/PendingClientRequests/` +- **Purpose**: Alert wrapper showing a pending-request count and rendering children (sampling/elicitation cards). +- **Current props**: `count`, `children`. +- **MCP schema touch points**: None directly; children render `CreateMessageRequest`/`ElicitRequest` inline cards. +- **Target props**: Unchanged; optionally `requests: InspectorPendingRequest[]` if the wrapper needs to render its own list. +- **Callbacks → core hook**: N/A (children own their handlers). +- **Internal refactors**: None. + +### PromptArgumentsForm + +- **Location**: `groups/PromptArgumentsForm/` +- **Purpose**: Form for filling a prompt's declared arguments before issuing `prompts/get`. +- **Current props**: `name`, `description?`, `arguments`, `argumentValues`, `onArgumentChange`, `onGetPrompt`. +- **MCP schema touch points**: `Prompt`, `PromptArgument` (`name`, `description`, `required`), `GetPromptRequest.params`. +- **Target props**: `prompt: Prompt`, `argumentValues: Record`, `onArgumentChange`, `onGetPrompt(args: GetPromptRequest['params']['arguments'])`. +- **Callbacks → core hook**: `onGetPrompt` from likely `usePrompts`. +- **Internal refactors**: Read `prompt.arguments` directly; display `prompt.title ?? prompt.name`. + +### PromptControls + +- **Location**: `groups/PromptControls/` +- **Purpose**: Searchable prompts list sidebar with list-changed indicator. +- **Current props**: `prompts: PromptItem[]`, `listChanged`, `onRefreshList`, `onSelectPrompt`. +- **MCP schema touch points**: `Prompt`, `ListPromptsResult`, `PromptListChangedNotification`. +- **Target props**: `prompts: Prompt[]`, `selectedName?: string`, `listChanged`, `onRefreshList()`, `onSelectPrompt(name)`. +- **Callbacks → core hook**: likely `usePrompts`. +- **Internal refactors**: Replace local `PromptItem` with schema `Prompt`; lift `selected` out of item. + +### PromptListItem + +- **Location**: `groups/PromptListItem/` +- **Purpose**: Single selectable row in the prompts list. +- **Current props**: `name`, `description?`, `selected`, `onClick`. +- **MCP schema touch points**: `Prompt`. +- **Target props**: `prompt: Prompt`, `selected`, `onClick()`. +- **Callbacks → core hook**: selection via `usePrompts`. +- **Internal refactors**: Render `prompt.title ?? prompt.name` + `description` from the schema object. + +### PromptMessagesDisplay + +- **Location**: `groups/PromptMessagesDisplay/` +- **Purpose**: Renders the assembled `GetPromptResult` message list as bubbles. +- **Current props**: `messages: PromptMessage[]` (flat `content`/`imageContent`/`audioContent`), `onCopyAll?`. +- **MCP schema touch points**: `GetPromptResult.messages: PromptMessage[]`, where `content` is `TextContent | ImageContent | AudioContent | EmbeddedResource | ResourceLink`. +- **Target props**: `messages: PromptMessage[]` (schema type), `onCopyAll?`. +- **Callbacks → core hook**: `onCopyAll` is UI-local; selected prompt content from `usePrompts`. +- **Internal refactors**: Handle full discriminated union of content blocks; delegate rendering to a content-block element. + +### ResourceControls + +- **Location**: `groups/ResourceControls/` +- **Purpose**: Accordion sidebar listing resources, templates, and subscriptions with search. +- **Current props**: `resources`, `templates`, `subscriptions`, `listChanged`, `onRefreshList`, `onSelectUri`, `onSelectTemplate`, `onUnsubscribeResource`. +- **MCP schema touch points**: `Resource`, `ResourceTemplate`, `ListResourcesResult`, `ListResourceTemplatesResult`, `ResourceListChangedNotification`, `ResourceUpdatedNotification`. +- **Target props**: `resources: Resource[]`, `templates: ResourceTemplate[]`, `subscriptions: InspectorResourceSubscription[]`, `selectedUri?`, `selectedTemplate?`, `listChanged`, handlers. +- **Callbacks → core hook**: likely `useResources`. +- **Internal refactors**: Replace inferred item types with schema types; lift `selected` out. + +### ResourceListItem + +- **Location**: `groups/ResourceListItem/` +- **Purpose**: Single selectable row in the resources or templates list. +- **Current props**: `name`, `uri`, `annotations?`, `selected`, `onClick`. +- **MCP schema touch points**: `Resource` / `ResourceTemplate` with `Annotations` (`audience`, `priority`). +- **Target props**: `resource: Resource | ResourceTemplate`, `selected`, `onClick()`. +- **Callbacks → core hook**: selection via `useResources`. +- **Internal refactors**: Actually render the annotations currently received but unused; use `title ?? name`. + +### ResourcePreviewPanel + +- **Location**: `groups/ResourcePreviewPanel/` +- **Purpose**: Panel showing content returned by `resources/read` with subscribe/refresh actions. +- **Current props**: `uri`, `mimeType`, `annotations?`, `content: string`, `lastUpdated?`, `isSubscribed`, `onRefresh`, `onSubscribe`, `onUnsubscribe`. +- **MCP schema touch points**: `ReadResourceResult.contents[]` (`TextResourceContents | BlobResourceContents`), parent `Resource`. +- **Target props**: `resource: Resource`, `contents: (TextResourceContents | BlobResourceContents)[]`, `lastUpdated?`, `isSubscribed`, handlers. +- **Callbacks → core hook**: likely `useResources`. +- **Internal refactors**: Handle blob vs text and iterate over `contents[]` instead of a single string. + +### ResourceSubscribedItem + +- **Location**: `groups/ResourceSubscribedItem/` +- **Purpose**: Row in subscriptions accordion for a subscribed resource. +- **Current props**: `name`, `lastUpdated?`, `onUnsubscribe`. +- **MCP schema touch points**: `Resource` + Inspector subscription state (`lastUpdated` from `notifications/resources/updated`). +- **Target props**: `subscription: InspectorResourceSubscription` (`{ resource: Resource; lastUpdated? }`), `onUnsubscribe(uri)`. +- **Callbacks → core hook**: likely `useResources`. +- **Internal refactors**: Take the wrapper, not flat scalars. + +### ResourceTemplatePanel + +- **Location**: `groups/ResourceTemplatePanel/` +- **Purpose**: Panel expanding a `ResourceTemplate` with per-variable inputs to produce a concrete URI and read it. +- **Current props**: `name`, `title?`, `uriTemplate`, `description?`, `annotations?`, `onReadResource`. +- **MCP schema touch points**: `ResourceTemplate` (`uriTemplate`, `name`, `title`, `description`, `mimeType`, `annotations`). +- **Target props**: `template: ResourceTemplate`, `onReadResource(uri)`. +- **Callbacks → core hook**: likely `useResources`. +- **Internal refactors**: Destructure a single schema object; keep local variable-values state. + +### RootsTable + +- **Location**: `groups/RootsTable/` +- **Purpose**: Configures the client-exposed filesystem roots list. +- **Current props**: `roots: RootEntry[]`, `newRootName`, `newRootPath`, handlers. +- **MCP schema touch points**: `Root` (`uri: string (file://...)`, `name?`), `ListRootsResult`, `RootsListChangedNotification`. +- **Target props**: `roots: Root[]`, `newRootDraft: { name: string; uri: string }`, handlers. +- **Callbacks → core hook**: likely `useRoots`. +- **Internal refactors**: Use schema `Root`; replace `path` field with `uri`. + +### SamplingRequestPanel + +- **Location**: `groups/SamplingRequestPanel/` +- **Purpose**: Full review panel for an incoming `sampling/createMessage` request — messages, model preferences, parameters, tools, draft response. +- **Current props**: `messages`, `modelHints?`, `cost/speed/intelligencePriority?`, `maxTokens?`, `stopSequences?`, `temperature?`, `includeContext?`, `tools?`, `toolChoice?`, `responseText`, `modelUsed`, `stopReason`, handlers. +- **MCP schema touch points**: `CreateMessageRequest.params` (`messages: SamplingMessage[]`, `modelPreferences: ModelPreferences`, `systemPrompt`, `includeContext`, `temperature`, `maxTokens`, `stopSequences`, `metadata`), `CreateMessageResult` (`role`, `content`, `model`, `stopReason`). `tools`/`toolChoice` are NOT in 2025-11-25 `CreateMessageRequest` — Inspector extension or drop. +- **Target props**: `request: CreateMessageRequest`, `draftResult: CreateMessageResult`, `onResultChange`, `onAutoRespond`, `onSend`, `onReject`. +- **Callbacks → core hook**: likely `useSampling`. +- **Internal refactors**: Destructure all preferences/parameters from the embedded request; drop or fence off non-schema `tools`/`toolChoice`. + +### SchemaForm + +- **Location**: `groups/SchemaForm/` +- **Purpose**: Generic JSON Schema → Mantine form renderer used by tool calls, elicitation, and structured prompt inputs. +- **Current props**: `schema: JsonSchema` (local), `values`, `onChange`, `disabled?`. +- **MCP schema touch points**: JSON Schema as appearing in `Tool.inputSchema`, `Tool.outputSchema`, and `ElicitRequest.params.requestedSchema` (restricted to `PrimitiveSchemaDefinition`). +- **Target props**: `schema: JSONSchema` (shared `core/` type, not Inspector-local `JsonSchema`), `values: Record`, `onChange`, `disabled?`. +- **Callbacks → core hook**: `onChange` is UI-local; committed values forwarded via consumer's hook (`useTools`/`useElicitation`/etc.). +- **Internal refactors**: Replace local `JsonSchema` with shared type; add `$ref`/`allOf`/nullable/format-aware widgets. + +### ServerAddMenu + +- **Location**: `groups/ServerAddMenu/` +- **Purpose**: Dropdown to add a server manually or import config/`server.json`. +- **Current props**: `onAddManually`, `onImportConfig`, `onImportServerJson`. +- **MCP schema touch points**: None — Inspector-core-owned. +- **Target props**: Unchanged. +- **Callbacks → core hook**: likely `useServers` (and `useServerRegistry` for import). +- **Internal refactors**: None. + +### ServerCard + +- **Location**: `groups/ServerCard/` +- **Purpose**: Card for a configured server with status, transport, connection toggle, actions, and test-client-features menu. +- **Current props**: `name`, `version?`, `transport`, `connectionMode`, `command`, `status`, `retryCount?`, `error?`, `canTestClientFeatures`, `activeServer?`, many handlers. +- **MCP schema touch points**: `Implementation` (server `name`, `version`) from `InitializeResult.serverInfo`. Transport/command/mode/status are Inspector-core-owned (connection lifecycle). +- **Target props**: `config: InspectorServerConfig`, `info?: Implementation`, `connection: InspectorConnectionState` (`status`, `retryCount`, `error`), `canTestClientFeatures`, `activeServer?`, handlers unchanged. +- **Callbacks → core hook**: `onToggleConnection`/`onSetActiveServer` from likely `useConnection`; `onEdit`/`onClone`/`onRemove` from `useServers`; test handlers from `useSampling`/`useElicitation`/`useRoots`. +- **Internal refactors**: Replace flat scalar props with grouped objects; **move the auto-connect `useEffect` out** — dumb components must not self-dispatch side effects. + +### ServerInfoContent + +- **Location**: `groups/ServerInfoContent/` +- **Purpose**: Modal content showing server identity, capabilities, instructions, OAuth. +- **Current props**: `name`, `version`, `protocolVersion`, `transport`, `serverCapabilities`, `clientCapabilities`, `instructions?`, `oauthDetails?`. +- **MCP schema touch points**: `InitializeResult` (`serverInfo: Implementation`, `protocolVersion`, `capabilities: ServerCapabilities`, `instructions?`), `ClientCapabilities`. +- **Target props**: `initializeResult: InitializeResult`, `clientCapabilities: ClientCapabilities`, `transport: InspectorTransportType`, `oauth?: InspectorOAuthDetails`. +- **Callbacks → core hook**: read-only; data from likely `useConnection` / `useServerCapabilities`. +- **Internal refactors**: Derive capability list by iterating the `ServerCapabilities` record rather than a pre-built `CapabilityInfo[]`. + +### ServerListControls + +- **Location**: `groups/ServerListControls/` +- **Purpose**: Top-right toolbar with compact-list toggle and add-server menu. +- **Current props**: `compact`, `serverCount`, `onToggleList`, plus `AddServerMenuProps`. +- **MCP schema touch points**: None (Inspector-core-owned). +- **Target props**: Unchanged. +- **Callbacks → core hook**: likely `useServers` (+ `useServerRegistry`). +- **Internal refactors**: None. + +### ServerSettingsForm + +- **Location**: `groups/ServerSettingsForm/` +- **Purpose**: Per-server settings — connection mode, headers, metadata, timeouts, OAuth. +- **Current props**: `connectionMode`, `headers`, `metadata`, `connectionTimeout`, `requestTimeout`, `oauthClient*`, many handlers. +- **MCP schema touch points**: `Request._meta` passthrough is the only schema-level tie-in; the rest is Inspector-core-owned. +- **Target props**: `settings: InspectorServerSettings`, `onSettingsChange(settings)` (or keep granular setters). +- **Callbacks → core hook**: likely `useServers`. +- **Internal refactors**: Collapse props into a settings object; keep internal `KeyValueRows`. + +### TaskCard + +- **Location**: `groups/TaskCard/` +- **Purpose**: Expandable card for a long-running task with progress and cancel. +- **Current props**: `taskId`, `status`, `method`, `target?`, `progress?`, `progressDescription?`, `startedAt?`, `completedAt?`, `lastUpdated?`, `elapsed?`, `ttl?`, `error?`, `isListExpanded`, `onCancel`. +- **MCP schema touch points**: `ProgressNotification.params` (`progressToken`, `progress`, `total`, `message`); formal `tasks/*` types are NOT in MCP 2025-11-25 base schema — treat the task envelope as Inspector-owned wrapping a `progressToken`-tracked MCP request. +- **Target props**: `task: InspectorTask` (embeds originating `Request`, latest `ProgressNotification`, `status`, timestamps, `ttl`), `isListExpanded`, `onCancel(taskId)`. +- **Callbacks → core hook**: likely `useTasks` (issues `notifications/cancelled`). +- **Internal refactors**: Replace flat scalars with the wrapper; derive display fields. + +### TaskControls + +- **Location**: `groups/TaskControls/` +- **Purpose**: Sidebar search + status filter + refresh/clear for tasks. +- **Current props**: `searchText`, `statusFilter?`, handlers. +- **MCP schema touch points**: Statuses Inspector-owned. +- **Target props**: Unchanged; statuses typed as `InspectorTaskStatus`. +- **Callbacks → core hook**: likely `useTasks`. +- **Internal refactors**: None beyond typing. + +### TaskListPanel + +- **Location**: `groups/TaskListPanel/` +- **Purpose**: List of active and completed tasks. +- **Current props**: `tasks: TaskCardProps[]`, `searchText`, `statusFilter?`. +- **MCP schema touch points**: Same `InspectorTask` wrapper as TaskCard. +- **Target props**: `tasks: InspectorTask[]`, `searchText`, `statusFilter?`, `onCancel(taskId)`. +- **Callbacks → core hook**: likely `useTasks`. +- **Internal refactors**: Pass `onCancel` through to each `TaskCard`; stop spreading prop objects. + +### ToolControls + +- **Location**: `groups/ToolControls/` +- **Purpose**: Searchable tool list sidebar with list-changed indicator. +- **Current props**: `tools: ToolListItemProps[]`, `listChanged`, `onRefreshList`, `onSelectTool`. +- **MCP schema touch points**: `Tool`, `ListToolsResult`, `ToolListChangedNotification`. +- **Target props**: `tools: Tool[]`, `selectedName?`, `listChanged`, `onRefreshList`, `onSelectTool`. +- **Callbacks → core hook**: likely `useTools`. +- **Internal refactors**: Consume schema `Tool[]` directly. + +### ToolDetailPanel + +- **Location**: `groups/ToolDetailPanel/` +- **Purpose**: Form for invoking a selected tool — annotations, progress, execute/cancel. +- **Current props**: `name`, `title?`, `description?`, `annotations?`, `schema: JsonSchema`, `formValues`, `isExecuting`, `progress?`, handlers. +- **MCP schema touch points**: `Tool` (`name`, `title`, `description`, `inputSchema`, `annotations: ToolAnnotations`), `ToolAnnotations` (`title`, `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`), `CallToolRequest`, `ProgressNotification`. +- **Target props**: `tool: Tool`, `formValues: Record`, `isExecuting`, `progress?: ProgressNotification['params']`, `onFormChange`, `onExecute(args)`, `onCancel()`. +- **Callbacks → core hook**: likely `useTools` (wraps `tools/call` with progress token). +- **Internal refactors**: Rename local annotation flags to schema `*Hint` names; read `inputSchema` from `tool`. + +### ToolListItem + +- **Location**: `groups/ToolListItem/` +- **Purpose**: Row in the tool list. +- **Current props**: `name`, `title?`, `selected`, `onClick`. +- **MCP schema touch points**: `Tool`. +- **Target props**: `tool: Tool`, `selected`, `onClick()`. +- **Callbacks → core hook**: selection via `useTools`. +- **Internal refactors**: None beyond type swap. + +### ToolResultPanel + +- **Location**: `groups/ToolResultPanel/` +- **Purpose**: Displays the `CallToolResult` content blocks. +- **Current props**: `content: ResultContentItem[]`, `onClear`. +- **MCP schema touch points**: `CallToolResult` (`content: ContentBlock[]`, `structuredContent?`, `isError?`). `ContentBlock = TextContent | ImageContent | AudioContent | ResourceLink | EmbeddedResource`. +- **Target props**: `result?: CallToolResult`, `onClear()`. +- **Callbacks → core hook**: `onClear` UI-local; result from `useTools`. +- **Internal refactors**: Handle full `ContentBlock` union (incl. `resource_link`, embedded resources), surface `isError`, optionally render `structuredContent`. + +### ViewHeader + +- **Location**: `groups/ViewHeader/` +- **Purpose**: Top app header — unconnected (brand + theme) or connected (server name, tabs, disconnect). +- **Current props**: discriminated union on `connected`: `serverName`, `status`, `latencyMs`, tabs, handlers. +- **MCP schema touch points**: `Implementation.name` for `serverName`; status/latency are Inspector connection state. +- **Target props**: Connected: `serverInfo: Implementation`, `connection: InspectorConnectionState`, `activeTab`, `availableTabs`, `onTabChange`, `onDisconnect`, `onToggleTheme`. Unconnected: unchanged. +- **Callbacks → core hook**: `onDisconnect` from likely `useConnection`; `onTabChange` from screen/view router; `onToggleTheme` from UI theme store. +- **Internal refactors**: Replace flat header scalars with grouped objects. + + + +--- + +## Section 3 — Screens (`clients/web/src/components/screens/`) + +> Top-level per-feature screens (Tools, Prompts, Resources, Tasks, Logging, +> History, ServerList). Screens are the seam between the Inspector core hook +> layer and the dumb component tree — they destructure hook output and pass it +> down as props. + + + +Screens are dumb containers: they own local UI state (search text, filter +toggles, active selection, compact mode) and destructure Inspector core hook +output into props for the group components below. They do **not** call MCP +themselves — every callback passed down must originate in a core hook. + +### ToolsScreen + +- **Location**: `screens/ToolsScreen/ToolsScreen.tsx` +- **Purpose**: Sidebar tool list + detail panel + last-call result panel. +- **Current props**: `tools: ToolListItemProps[]`, `selectedTool?: ToolDetailPanelProps`, `result?: ToolResultPanelProps`, `listChanged: boolean`, `onRefreshList`, `onSelectTool`. +- **MCP schema touch points**: `Tool`, `ListToolsResult`, `CallToolRequest.params`, `CallToolResult`, `ToolListChangedNotification`. +- **Target props**: + - `tools: Tool[]` — raw MCP `Tool[]` from `ListToolsResult.tools`. + - `selectedToolName?: string` — selection is screen-local; detail derived from `tools`. + - `callState?: { status: 'idle' | 'pending' | 'ok' | 'error'; request?: CallToolRequest['params']; result?: CallToolResult; error?: string }`. + - `listChanged: boolean` — driven by `notifications/tools/list_changed`. + - `onRefreshList: () => void`, `onSelectTool: (name: string) => void`, `onCallTool: (name: string, args: Record) => void`. +- **Callbacks → core hook**: `useTools` (likely) provides `tools`, `listChanged`, `refreshTools`, `callTool`, `lastCallResult`; backed by `useMcpClient` for the underlying `client.request`. +- **Internal refactors**: + - Stop flattening `Tool` into `ToolListItemProps` at the screen boundary — pass `Tool` down and let `ToolListItem` project fields. + - Derive the selected tool from `tools.find(t => t.name === selectedToolName)` instead of receiving a pre-built `ToolDetailPanelProps`. + - Replace the separate `result` prop with a unified `callState` so pending/error UI can be rendered by `ToolResultPanel`. + +### PromptsScreen + +- **Location**: `screens/PromptsScreen/PromptsScreen.tsx` +- **Purpose**: Sidebar prompt list + argument form + rendered messages. +- **Current props**: `prompts: PromptItem[]`, `selectedPrompt?: SelectedPrompt`, `messages?: PromptMessagesDisplayProps`, `listChanged`, `onRefreshList`, `onSelectPrompt`, `onArgumentChange`, `onGetPrompt`. +- **MCP schema touch points**: `Prompt`, `PromptArgument`, `ListPromptsResult`, `GetPromptRequest.params`, `GetPromptResult`, `PromptMessage`, `PromptListChangedNotification`. +- **Target props**: + - `prompts: Prompt[]` — raw MCP `Prompt[]`. + - `selectedPromptName?: string`; detail derived internally. + - `argumentValues: Record` — uncommitted form state, held in screen or lifted to a core draft store. + - `getPromptState?: { status: 'idle' | 'pending' | 'ok' | 'error'; result?: GetPromptResult; error?: string }` — replaces the bare `messages` prop. + - `listChanged: boolean`. + - `onRefreshList`, `onSelectPrompt(name)`, `onArgumentChange(name, value)`, `onGetPrompt()`. +- **Callbacks → core hook**: `usePrompts` (likely) provides `prompts`, `listChanged`, `refreshPrompts`, `getPrompt`, `lastGetPromptResult`; backed by `useMcpClient`. +- **Internal refactors**: + - Drop `PromptItem`/`SelectedPrompt` wrapper types; consume `Prompt` directly. + - `PromptMessage[]` flows into `PromptMessagesDisplay` from `GetPromptResult.messages` verbatim. + +### ResourcesScreen + +- **Location**: `screens/ResourcesScreen/ResourcesScreen.tsx` +- **Purpose**: Sidebar resources/templates/subscriptions + preview + template panel. +- **Current props**: `resources: ResourceItem[]`, `templates: TemplateListItem[]`, `subscriptions: SubscriptionItem[]`, `selectedResource?`, `selectedTemplate?`, `listChanged`, plus `onRefreshList`, `onSelectUri`, `onSelectTemplate`, `onReadResource`, `onSubscribeResource`, `onUnsubscribeResource`. +- **MCP schema touch points**: `Resource`, `ResourceTemplate`, `ListResourcesResult`, `ListResourceTemplatesResult`, `ReadResourceRequest.params`, `ReadResourceResult`, `TextResourceContents`, `BlobResourceContents`, `SubscribeRequest.params`, `UnsubscribeRequest.params`, `ResourceUpdatedNotification`, `ResourceListChangedNotification`, `Annotations`. +- **Target props**: + - `resources: Resource[]`, `templates: ResourceTemplate[]`. + - `subscriptions: Array<{ uri: string; lastUpdated?: string }>` — app state wrapping the URIs tracked by core. + - `selectedResourceUri?: string`, `selectedTemplateUriTemplate?: string`. + - `readState?: { status; uri: string; result?: ReadResourceResult; error?: string }`. + - `listChanged: boolean`. + - `onRefreshList`, `onSelectUri(uri)`, `onSelectTemplate(uriTemplate)`, `onReadResource(uri)`, `onSubscribeResource(uri)`, `onUnsubscribeResource(uri)`. +- **Callbacks → core hook**: `useResources` (likely) owns `resources`, `resourceTemplates`, `readResource`, `subscribe`/`unsubscribe`, `subscriptions`, and forwards `notifications/resources/updated` + `list_changed`. +- **Internal refactors**: + - Replace the ad-hoc `SelectedResource` (with inlined `content: string`) with `ReadResourceResult` whose `contents` is a union of `TextResourceContents | BlobResourceContents` — preview panel must branch on type. + - Pass `Annotations` through unmodified rather than the reduced `{ audience?: string; priority?: number }`. + +### HistoryScreen + +- **Location**: `screens/HistoryScreen/HistoryScreen.tsx` +- **Purpose**: Search/filter controls + scrollable list of all JSON-RPC requests and responses. +- **Current props**: `entries: HistoryEntryProps[]`, `pinnedEntries: HistoryEntryProps[]`, `onClearAll`, `onExport`. +- **MCP schema touch points**: `JSONRPCRequest`, `JSONRPCResponse`, `JSONRPCNotification`, `JSONRPCError`, `RequestId` — entries wrap these, not transform them. +- **Target props**: + - `entries: HistoryEntry[]` where `HistoryEntry = { id: string; timestamp: string; direction: 'outgoing' | 'incoming'; message: JSONRPCRequest | JSONRPCResponse | JSONRPCNotification | JSONRPCError; pinned: boolean; durationMs?: number }`. + - `onClearAll`, `onExport`, `onTogglePin(id)`, `onCopy(id)`. + - Local state `searchText` / `methodFilter` stays in screen. +- **Callbacks → core hook**: `useHistory` (likely) — buffers every message seen by `useMcpClient`'s transport and exposes `entries`, `clear`, `export`, `togglePin`. +- **Internal refactors**: collapse `entries` + `pinnedEntries` into one list with a `pinned` flag; `HistoryListPanel` handles grouping. + +### LoggingScreen + +- **Location**: `screens/LoggingScreen/LoggingScreen.tsx` +- **Purpose**: Server log-level control + filter/visibility controls + streaming log panel. +- **Current props**: `entries: LogEntryProps[]`, `currentLevel: string`, `onSetLevel`, `onClear`, `onExport`, `autoScroll`, `onToggleAutoScroll`, `onCopyAll`. +- **MCP schema touch points**: `LoggingMessageNotification.params` (`LoggingLevel`, `logger?`, `data: unknown`), `SetLevelRequest.params.level`. +- **Target props**: + - `entries: Array`. + - `currentLevel: LoggingLevel`. + - `onSetLevel(level: LoggingLevel)`, `onClear`, `onExport`, `onCopyAll`, `autoScroll`, `onToggleAutoScroll`. + - `filterText` and `visibleLevels` stay screen-local. +- **Callbacks → core hook**: `useLogs` (likely) — subscribes to `notifications/message`, buffers entries, exposes `entries`, `currentLevel`, `setLevel` (wraps `logging/setLevel`). + +### TasksScreen + +- **Location**: `screens/TasksScreen/TasksScreen.tsx` +- **Purpose**: Search/status filter + list of long-running / progress-tracked requests. +- **Current props**: `tasks: TaskCardProps[]`, `onRefresh`, `onClearHistory`. +- **MCP schema touch points**: `ProgressNotification.params` (`progressToken`, `progress`, `total?`, `message?`), `CancelledNotification.params`, `RequestId`, plus the originating request (`CallToolRequest`, `ReadResourceRequest`, etc.) and its eventual result/error. +- **Target props**: + - `tasks: Task[]` where `Task = { id: RequestId; progressToken?: ProgressToken; method: string; params: unknown; status: 'pending' | 'progress' | 'done' | 'error' | 'cancelled'; progress?: ProgressNotification['params']; result?: unknown; error?: JSONRPCError['error']; startedAt: string; endedAt?: string }`. + - `onRefresh`, `onClearHistory`, `onCancel(id: RequestId)`. + - Local state `searchText` / `statusFilter` stays in screen. +- **Callbacks → core hook**: `useTasks` (likely, new in v2) — correlates outbound requests with `notifications/progress`, `notifications/cancelled`, and terminal responses via the transport owned by `useMcpClient`. + +### ServerListScreen + +- **Location**: `screens/ServerListScreen/ServerListScreen.tsx` +- **Purpose**: Grid of configured servers with controls for add/import and compact toggle. +- **Current props**: `servers: ServerCardProps[]`, `onAddManually`, `onImportConfig`, `onImportServerJson`. +- **MCP schema touch points**: `Implementation` (server `name`/`version`), `ServerCapabilities`, `InitializeResult` — identity and capability surface reported on initialize. Transport config (`command`, `args`, `env`, `url`, `headers`) is **not** MCP schema; it is Inspector core app state. +- **Target props**: + - `servers: ServerEntry[]` where `ServerEntry = { id: string; config: ServerTransportConfig; connection: { status: 'disconnected' | 'connecting' | 'connected' | 'error'; error?: string; initializeResult?: InitializeResult } }`. + - `activeServerId?: string` — may be lifted to core if it drives routing; currently screen-local. + - `onAddManually`, `onImportConfig`, `onImportServerJson`, `onConnect(id)`, `onDisconnect(id)`, `onSetActiveServer(id)`, `onEditServer(id)`, `onRemoveServer(id)`. +- **Callbacks → core hook**: `useServers` (likely) owns the persisted config list; `useConnection` (v1.5, `client/src/lib/hooks/useConnection.ts`) owns per-server transport lifecycle and exposes `connectionStatus`, `serverCapabilities`, `connect`, `disconnect`. `ServerListScreen` composes both via a parent view. +- **Internal refactors**: + - Stop flattening each server into a loose `ServerCardProps`; pass `ServerEntry` and let `ServerCard` read `config` / `connection` fields. + - `activeServer` state may migrate to `useServers` once it gates which screen renders; until then, keep `useState` local. + + + +--- + +## Section 4 — Views (`clients/web/src/components/views/`) + +> Outer shell components that decide which screen to render based on +> connection state (`ConnectedView`, `UnconnectedView`). They receive the full +> Inspector core context and route to the appropriate screen. + + +### ConnectedView + +- **Location**: `views/ConnectedView/ConnectedView.tsx` +- **Purpose**: Outer `AppShell` wrapper shown once a server session is live; renders `ViewHeader` in connected mode and slots the active screen into the main region via `children`. +- **Current props**: + - `serverName: string` + - `status: "connected" | "connecting" | "failed"` + - `latencyMs?: number` + - `activeTab: string` + - `availableTabs: string[]` + - `onTabChange: (tab: string) => void` + - `onDisconnect: () => void` + - `onToggleTheme: () => void` + - `children: ReactNode` +- **MCP schema touch points**: + - `Implementation` (server identity → `serverName`) from `InitializeResult.serverInfo`. + - `ServerCapabilities` from `InitializeResult.capabilities` — drives which tabs are available (tools/prompts/resources/logging/completions). + - `InitializeResult` as a whole is the natural handshake object to accept instead of loose strings. +- **Target props**: + - `serverInfo: Implementation` + - `capabilities: ServerCapabilities` + - `connectionStatus: "connected" | "connecting" | "failed"` (app state, owned by core) + - `latencyMs?: number` (app state) + - `activeTab: InspectorTab` (app state; enum derived from capabilities) + - `availableTabs: InspectorTab[]` (app state; derived from `capabilities`) + - `onTabChange: (tab: InspectorTab) => void` + - `onDisconnect: () => void` + - `onToggleTheme: () => void` + - `children: ReactNode` +- **Callbacks → core hook**: + - `onDisconnect` → `useConnection` (disconnect action). + - `onTabChange` → local UI state in the wiring layer (not an MCP call); likely `useInspectorNavigation` or screen-level state. + - `onToggleTheme` → app-level theme store, not a core hook. + - `connectionStatus`, `latencyMs`, `serverInfo`, `capabilities` → likely `useConnection` / `useMcpClient` / `useServerCapabilities`. +- **Internal refactors**: + - Replace flat `serverName` with `serverInfo.name` lookup; forward full `serverInfo` to `ViewHeader` once that group is updated. + - Compute/validate `availableTabs` against `capabilities` rather than accepting an arbitrary string list; narrow `activeTab`/`availableTabs` to an `InspectorTab` union. + - No transport or fetching logic; remains a pure shell routing children. + +### UnconnectedView + +- **Location**: `views/UnconnectedView/UnconnectedView.tsx` +- **Purpose**: Outer `AppShell` wrapper shown when no MCP session is active; renders `ViewHeader` in disconnected mode and slots the server-list / connect screen into the main region via `children`. +- **Current props**: + - `children: ReactNode` + - `onToggleTheme: () => void` +- **MCP schema touch points**: + - None directly — no handshake has occurred. The view is intentionally MCP-schema-free and only hosts the connect flow. +- **Target props**: + - `children: ReactNode` + - `onToggleTheme: () => void` + - (Optional future) `connectionStatus: "disconnected" | "connecting" | "failed"` if the header needs to surface retry state in this shell. +- **Callbacks → core hook**: + - `onToggleTheme` → app-level theme store, not a core hook. + - Any connect action rendered inside `children` (e.g. from `ServerListScreen`) → `useConnection` (connect action), not owned by this view. +- **Internal refactors**: + - None required today; keep the shell minimal and let the embedded `ServerListScreen` own all connect/form state. + - Rename internal `HomeLayoutProps` to `UnconnectedViewProps` for consistency with the component name when the refactor lands. + + +--- + +## Appendix — Inspector core hooks (v1.5 reference) + +This section will briefly catalog the v1.5 hooks that the wiring layer will +adopt or adapt, with a pointer to where each lives in the v1.5 source tree. +Filled in alongside the Screens and Views sections since those are the +components that consume hook output directly. + + + +Authoritative source: [`modelcontextprotocol/inspector` v1.5/main, `client/src/lib/hooks`](https://github.com/modelcontextprotocol/inspector/tree/main/client/src/lib/hooks) (v1.5 monorepo bundles most primitive-specific logic inside `client/src/App.tsx`; hooks marked "likely" will be extracted cleanly in v2 core). + +- **`useConnection`** — confirmed in v1.5 at `client/src/lib/hooks/useConnection.ts`. Owns MCP transport lifecycle (stdio / SSE / streamable HTTP), performs `initialize`, tracks `connectionStatus`, exposes `makeRequest`, `handleCompletion`, `sendNotification`, and surfaces `serverCapabilities`. Produces: `InitializeResult`, `ServerCapabilities`, `Implementation`, `JSONRPCRequest`/`JSONRPCResponse` flow. +- **`useMcpClient`** (likely) — thin wrapper over the MCP SDK `Client` that returns the underlying client, `request`, and `notification` handles. Produces: every `ClientRequest` / `ServerRequest` / `ServerNotification` union member. +- **`useServerCapabilities`** (likely) — memoized accessor over `InitializeResult.capabilities`; drives which tabs/screens render. Produces: `ServerCapabilities`. +- **`useTools`** (likely) — lists tools, listens for `notifications/tools/list_changed`, calls tools. Produces: `Tool[]`, `ListToolsResult`, `CallToolResult`. +- **`usePrompts`** (likely) — lists prompts, listens for `notifications/prompts/list_changed`, gets prompts. Produces: `Prompt[]`, `ListPromptsResult`, `GetPromptResult`, `PromptMessage[]`. +- **`useResources`** (likely) — lists resources + templates, reads resources, manages subscriptions, listens for `notifications/resources/updated` and `list_changed`. Produces: `Resource[]`, `ResourceTemplate[]`, `ReadResourceResult`, `TextResourceContents | BlobResourceContents`, subscription set. +- **`useLogs`** (likely) — subscribes to `notifications/message`, buffers entries, wraps `logging/setLevel`. Produces: `LoggingMessageNotification['params'][]`, `LoggingLevel`. +- **`useHistory`** (likely) — transport-level buffer of every inbound/outbound JSON-RPC frame. Produces: `JSONRPCRequest | JSONRPCResponse | JSONRPCNotification | JSONRPCError` entries with direction and timestamp. +- **`useTasks`** (likely, new in v2) — correlates outbound requests with `notifications/progress` and `notifications/cancelled` to model long-running operations. Produces: task records keyed by `RequestId` / `ProgressToken`, wrapping `ProgressNotification.params` and terminal result/error. +- **`useServers`** (likely, v2-only) — persisted list of configured server entries (transport config + last-known identity) independent of any live connection. Produces: `ServerEntry[]` (app state; not MCP schema). +- **`useCompletionState`** — confirmed in v1.5 at `client/src/lib/hooks/useCompletionState.ts`. Manages argument-completion dropdown state against `completion/complete`. Produces: `CompleteResult` fragments. +- **`useElicitation`** (likely) — handles incoming `elicitation/create` server→client requests and exposes pending prompts + `respond` callback. Produces: `ElicitRequest.params`, `ElicitResult`. +- **`useSampling`** (likely) — handles incoming `sampling/createMessage` server→client requests and exposes pending prompts + `approve`/`reject`. Produces: `CreateMessageRequest.params`, `CreateMessageResult`. +- **`useRoots`** (likely) — client-side roots registry answering `roots/list` requests from the server. Produces: `Root[]`. + +Non-MCP utility hooks present in v1.5 (`useToast`, `useCopy`, `useTheme`, `useDraggablePane`) are orthogonal to the schema contract and will be adopted as-is or replaced by Mantine equivalents. + + + +--- + +## Appendix B — Inspector core return types: raw MCP vs. wrappers + +### Summary answer +The v1.5/main inspector core returns a deliberate mix: **raw MCP SDK types for primitive lists and individual message payloads**, and **Inspector-owned wrapper types only where the MCP schema has no equivalent concept** (history entries, fetch logs, stderr logs, invocation caches, transport/server configs). The handshake is never surfaced as an `InitializeResult` object — it is decomposed into discrete reactive fields (`capabilities`, `serverInfo`, `instructions`) on the `useInspectorClient` result. + +### Handshake (`InitializeResult`) +`InitializeResult` is not imported or re-exported anywhere in `core/` or `clients/web/src/App.tsx`. The `Client` from `@modelcontextprotocol/sdk/client/index.js` is owned by `InspectorClient` and its initialize result is split at the class boundary. `useInspectorClient` exposes the pieces as separate reactive fields, all raw SDK types: + +- `core/react/useInspectorClient.ts:11-19` — `UseInspectorClientResult` has `status: ConnectionStatus`, `capabilities?: ServerCapabilities`, `serverInfo?: Implementation`, `instructions?: string`, `appRendererClient: AppRendererClient | null`, plus `connect` / `disconnect`. +- `core/react/useInspectorClient.ts:30-38` — state is fed from `inspectorClient.getCapabilities()`, `getServerInfo()`, `getInstructions()` and updated via `capabilitiesChange` / `serverInfoChange` / `instructionsChange` events. +- `clients/web/src/App.tsx:584-588` — web consumer destructures `capabilities: serverCapabilities, serverInfo: serverImplementation` from the hook. + +### Primitive lists (Tools / Prompts / Resources / ResourceTemplates) +All hooks return raw SDK arrays directly — no wrapping: + +- `core/react/useManagedTools.ts:4,8-11` — `tools: Tool[]`, `refresh: () => Promise` (`Tool` imported from `@modelcontextprotocol/sdk/types.js`). +- `core/react/useManagedPrompts.ts:4,8-11` — `prompts: Prompt[]`. +- `core/react/useManagedResources.ts:4,8-11` — `resources: Resource[]`. +- `core/react/useManagedResourceTemplates.ts` — `resourceTemplates: ResourceTemplate[]` (same pattern). +- `core/react/usePagedTools.ts:11-15` — `tools: Tool[]` plus a `loadPage(cursor?)` returning `LoadPageResult` (a core-owned `{ tools, nextCursor }` page shape defined in `core/mcp/state/pagedToolsState.ts`). + +Tabs receive these as `Tool[]` / `Prompt[]` / `Resource[]` props (`clients/web/src/components/ToolsTab.tsx`, `PromptsTab.tsx`, `ResourcesTab.tsx`) — no wrapper layer between hook and component. + +### Notifications & streams (logs, progress, sampling, elicitation, roots) +Server notifications are raw SDK `ServerNotification` values, but they reach the UI *inside* a history wrapper (`MessageEntry`). `clients/web/src/App.tsx:174` holds `useState` and `App.tsx:675-676` derives it from the message log by filtering and casting `msg.message as ServerNotification`. Progress, sampling/createMessage, elicit, and roots/list are all delivered through the same `MessageEntry` stream — the payload itself is the raw JSON-RPC message from the SDK (`clients/web/src/lib/notificationTypes.ts` just re-exports the SDK union schema). + +### Inspector-owned wrapper types +Defined in `core/mcp/types.ts`: + +- **`MessageEntry`** (`types.ts:61-72`) — `{ id, timestamp, direction: "request"|"response"|"notification", message: JSONRPCRequest|JSONRPCNotification|JSONRPCResultResponse|JSONRPCErrorResponse, response?, duration? }`. The UI-history wrapper around raw JSON-RPC payloads. Consumed via `useMessageLog` (`core/react/useMessageLog.ts:7-9`). +- **`FetchRequestEntry`** (`types.ts:76-91`) — `{ id, timestamp, method, url, requestHeaders, requestBody?, responseStatus?, responseStatusText?, responseHeaders?, responseBody?, duration?, error?, category: "auth"|"transport" }`. Non-MCP transport-layer log used by `useFetchRequestLog`. +- **`StderrLogEntry`** (`types.ts:44-47`) — `{ timestamp, message }`. Stdio stderr buffer used by `useStderrLog`. +- **`ResourceReadInvocation` / `ResourceTemplateReadInvocation` / `PromptGetInvocation` / `ToolCallInvocation`** (`types.ts:167-214`) — invocation caches pairing request params + a raw SDK result (`ReadResourceResult`, `GetPromptResult`, `CallToolResult`) with `timestamp`, `success`, `error`, `metadata`. +- **`ConnectionStatus`** (`types.ts:38-42`) — `"disconnected"|"connecting"|"connected"|"error"` string union. +- **`ServerState`** (`types.ts:143-153`) — aggregated snapshot `{ status, error, capabilities?, serverInfo?, instructions?, resources, prompts, tools, stderrLogs }`. Used by non-React consumers (CLI/TUI); React hooks split this across individual hooks. +- **`MCPServerConfig`** (`types.ts:2-32`) — discriminated union `StdioServerConfig | SseServerConfig | StreamableHttpServerConfig`, plus `MCPConfig` (`{ mcpServers: Record }`) and `ServerType`. These describe how the inspector connects to a server and are entirely inspector-owned (not MCP schema). + +Notably there are **no** wrapper types for pending requests, sampling approvals, elicitation dialogs, or roots as first-class shapes — those flows are coordinated through the raw SDK request handlers inside `InspectorClient` with UI state living locally in `App.tsx`. + +### Implications for v2 dumb components +- Accept raw SDK types directly as props wherever v1.5 does: `Tool`, `Prompt`, `Resource`, `ResourceTemplate`, `ServerCapabilities`, `Implementation`, `ReadResourceResult`, `GetPromptResult`, `CallToolResult`, `LoggingMessageNotification`, `Root`. No need to re-wrap. +- Treat the handshake as three independent props (`serverInfo`, `capabilities`, `instructions`) rather than an `InitializeResult` object — matches both v1.5 hook shape and React's reactive-granularity preference. If v2 wants whole-object ergonomics, derive an `InitializeResult` view in the hook layer, not in components. +- Inspector-owned wrappers that v2 `core/` must define (and that dumb components should consume): `MessageEntry` (history/pending-request display), `FetchRequestEntry`, `StderrLogEntry`, `ConnectionStatus`, the `MCPServerConfig` discriminated union, and the invocation cache types (`ToolCallInvocation`, `PromptGetInvocation`, `ResourceReadInvocation`, `ResourceTemplateReadInvocation`). +- "Server" in the inspector sense is a config entry (`MCPServerConfig` in `core/mcp/types.ts`), not an MCP concept — v2 `ServerCard` etc. should take this inspector-owned type plus a separate `ConnectionStatus`, never an SDK type. +- Notifications for UI history should stay as `MessageEntry` (with the raw `ServerNotification` union inside `.message`) rather than introducing a parallel `NotificationEntry` wrapper — v1.5 intentionally unifies request/response/notification under one timestamped envelope and filters by predicate at the view layer (`App.tsx:146-147,675-676`). + +Source paths (v1.5/main, SHA `632e967`): `core/react/useInspectorClient.ts`, `core/react/useManaged{Tools,Prompts,Resources,ResourceTemplates}.ts`, `core/react/usePaged{Tools,...}.ts`, `core/react/{useMessageLog,useStderrLog,useFetchRequestLog}.ts`, `core/mcp/types.ts`, `clients/web/src/App.tsx`, `clients/web/src/lib/notificationTypes.ts`. diff --git a/specification/v2_ux_storybook.md b/specification/v2_ux_storybook.md index 2b077446..a2c196bd 100644 --- a/specification/v2_ux_storybook.md +++ b/specification/v2_ux_storybook.md @@ -1,7 +1,7 @@ # Inspector V2 UX - Storybook Component Plan ### [Brief](README.md) | [V1 Problems](v1_problems.md) | [V2 Scope](v2_scope.md) | [V2 Tech Stack](v2_web_client.md) | V2 UX -#### [Overview](v2_ux.md) | [Features](v2_ux_features.md) | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) | Storybook +#### [Overview](v2_ux.md) | [Features](v2_ux_features.md) | [Handlers](v2_ux_handlers.md) | [Screenshots](v2_screenshots.md) | [Components](v2_ux_components.md) | [Interfaces](v2_ux_interfaces.md) | Storybook ---