Phase 2: Refactor Server/Settings/ViewShell cluster to MCP SDK types

ServerCard: Replace flat scalar props (name, version, transport, status,
error) with grouped objects (config: MCPServerConfig, info?: Implementation,
connection: ConnectionState). Remove auto-connect useEffect — dumb
components must not self-dispatch side effects. Derive transport and
command/url from config.

ServerInfoContent: Replace flat props with initializeResult: InitializeResult
and clientCapabilities: ClientCapabilities from MCP SDK. Derive capability
lists by iterating the ServerCapabilities record.

ServerSettingsForm: Collapse flat setting props (connectionMode, headers,
metadata, timeouts, oauth*) into settings: InspectorServerSettings. Add
InspectorServerSettings type to core/mcp/types.ts.

ImportServerJsonPanel: Replace scattered scalar props (jsonContent,
selectedPackageIndex, serverName) with draft: InspectorServerJsonDraft.

ViewHeader: Replace serverName: string with serverInfo: Implementation.
Use ConnectionStatus from core types.

ConnectedView: Update to pass serverInfo: Implementation instead of
serverName. Use ConnectionStatus type.

Update all stories for ServerCard, ServerInfoContent, ServerSettingsForm,
ImportServerJsonPanel, ViewHeader, ServerListScreen, ConnectedView, and
UnconnectedView.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cliffhall 2026-04-21 15:22:08 -04:00
commit 771a67ee20
2 changed files with 562 additions and 539 deletions

View file

@ -1,7 +1,16 @@
import type { InspectorServerSettings } from "@inspector/core/mcp/types.js";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { fn } from "storybook/test";
import { ServerSettingsForm } from "./ServerSettingsForm";
const defaultSettings: InspectorServerSettings = {
connectionMode: "proxy",
headers: [],
metadata: [],
connectionTimeout: 30000,
requestTimeout: 60000,
};
const meta: Meta<typeof ServerSettingsForm> = {
title: "Groups/ServerSettingsForm",
component: ServerSettingsForm,
@ -25,55 +34,51 @@ type Story = StoryObj<typeof ServerSettingsForm>;
export const DefaultSettings: Story = {
args: {
connectionMode: "proxy",
headers: [],
metadata: [],
connectionTimeout: 30000,
requestTimeout: 60000,
settings: defaultSettings,
},
};
export const WithHeaders: Story = {
args: {
connectionMode: "proxy",
headers: [
{ key: "Authorization", value: "Bearer token-abc-123" },
{ key: "X-Custom-Header", value: "custom-value" },
],
metadata: [],
connectionTimeout: 30000,
requestTimeout: 60000,
settings: {
...defaultSettings,
headers: [
{ key: "Authorization", value: "Bearer token-abc-123" },
{ key: "X-Custom-Header", value: "custom-value" },
],
},
},
};
export const WithOAuth: Story = {
args: {
connectionMode: "direct",
headers: [],
metadata: [],
connectionTimeout: 30000,
requestTimeout: 60000,
oauthClientId: "my-client-id",
oauthClientSecret: "super-secret-value",
oauthScopes: "read write admin",
settings: {
...defaultSettings,
connectionMode: "direct",
oauthClientId: "my-client-id",
oauthClientSecret: "super-secret-value",
oauthScopes: "read write admin",
},
},
};
export const AllConfigured: Story = {
args: {
connectionMode: "proxy",
headers: [
{ key: "Authorization", value: "Bearer token-abc-123" },
{ key: "X-Request-Id", value: "req-456" },
],
metadata: [
{ key: "userId", value: "user-789" },
{ key: "sessionId", value: "session-012" },
],
connectionTimeout: 15000,
requestTimeout: 45000,
oauthClientId: "my-client-id",
oauthClientSecret: "super-secret-value",
oauthScopes: "read write",
settings: {
connectionMode: "proxy",
headers: [
{ key: "Authorization", value: "Bearer token-abc-123" },
{ key: "X-Request-Id", value: "req-456" },
],
metadata: [
{ key: "userId", value: "user-789" },
{ key: "sessionId", value: "session-012" },
],
connectionTimeout: 15000,
requestTimeout: 45000,
oauthClientId: "my-client-id",
oauthClientSecret: "super-secret-value",
oauthScopes: "read write",
},
},
};

View file

@ -9,11 +9,7 @@ import {
Text,
TextInput,
} from "@mantine/core";
export interface KeyValuePair {
key: string;
value: string;
}
import type { InspectorServerSettings } from "@inspector/core/mcp/types.js";
export type ServerSettingsSection =
| "connectionMode"
@ -23,14 +19,7 @@ export type ServerSettingsSection =
| "oauth";
export interface ServerSettingsFormProps {
connectionMode: "proxy" | "direct";
headers: KeyValuePair[];
metadata: KeyValuePair[];
connectionTimeout: number;
requestTimeout: number;
oauthClientId?: string;
oauthClientSecret?: string;
oauthScopes?: string;
settings: InspectorServerSettings;
expandedSections: ServerSettingsSection[];
onExpandedSectionsChange: (sections: ServerSettingsSection[]) => void;
onConnectionModeChange: (mode: string) => void;
@ -75,7 +64,7 @@ function KeyValueRows({
onChange,
onRemove,
}: {
items: KeyValuePair[];
items: { key: string; value: string }[];
onChange: (index: number, key: string, value: string) => void;
onRemove: (index: number) => void;
}) {
@ -105,14 +94,7 @@ function KeyValueRows({
}
export function ServerSettingsForm({
connectionMode,
headers,
metadata,
connectionTimeout,
requestTimeout,
oauthClientId,
oauthClientSecret,
oauthScopes,
settings,
expandedSections,
onExpandedSectionsChange,
onConnectionModeChange,
@ -145,12 +127,12 @@ export function ServerSettingsForm({
<Accordion.Panel>
<Select
data={CONNECTION_MODE_OPTIONS}
value={connectionMode}
value={settings.connectionMode}
onChange={(value) => {
if (value) onConnectionModeChange(value);
}}
description={
connectionMode === "proxy"
settings.connectionMode === "proxy"
? "Route through inspector proxy (required for STDIO)"
: undefined
}
@ -168,11 +150,11 @@ export function ServerSettingsForm({
</HintText>
<AddButton onClick={onAddHeader}>+ Add Header</AddButton>
</Group>
{headers.length === 0 ? (
{settings.headers.length === 0 ? (
<EmptyHint>No custom headers configured</EmptyHint>
) : (
<KeyValueRows
items={headers}
items={settings.headers}
onChange={onHeaderChange}
onRemove={onRemoveHeader}
/>
@ -191,11 +173,11 @@ export function ServerSettingsForm({
</HintText>
<AddButton onClick={onAddMetadata}>+ Add Metadata</AddButton>
</Group>
{metadata.length === 0 ? (
{settings.metadata.length === 0 ? (
<EmptyHint>No request metadata configured</EmptyHint>
) : (
<KeyValueRows
items={metadata}
items={settings.metadata}
onChange={onMetadataChange}
onRemove={onRemoveMetadata}
/>
@ -211,13 +193,13 @@ export function ServerSettingsForm({
<NumberInput
label="Connection Timeout"
suffix=" ms"
value={connectionTimeout}
value={settings.connectionTimeout}
onChange={handleTimeoutChange("connectionTimeout")}
/>
<NumberInput
label="Request Timeout"
suffix=" ms"
value={requestTimeout}
value={settings.requestTimeout}
onChange={handleTimeoutChange("requestTimeout")}
/>
</Group>
@ -234,12 +216,12 @@ export function ServerSettingsForm({
</HintText>
<TextInput
label="Client ID"
value={oauthClientId ?? ""}
value={settings.oauthClientId ?? ""}
onChange={(e) => onOAuthChange("clientId", e.currentTarget.value)}
/>
<TextInput
label="Client Secret"
value={oauthClientSecret ?? ""}
value={settings.oauthClientSecret ?? ""}
type="password"
onChange={(e) =>
onOAuthChange("clientSecret", e.currentTarget.value)
@ -247,7 +229,7 @@ export function ServerSettingsForm({
/>
<TextInput
label="Scopes"
value={oauthScopes ?? ""}
value={settings.oauthScopes ?? ""}
onChange={(e) => onOAuthChange("scopes", e.currentTarget.value)}
/>
</Stack>