chore: close quality-gate coverage gaps (#1689) (#1766)
Some checks failed
Run install, format, lint, build, and test on every push / build (push) Has been cancelled
Run install, format, lint, build, and test on every push / publish (push) Has been cancelled
Run install, format, lint, build, and test on every push / publish-github-container-registry (push) Has been cancelled

Closes #1689. Typecheck cli/tui src, add a core/ format+lint gate, and gate core/json + core/client coverage. See PR #1766 for the full review history.
This commit is contained in:
Cliff Hall 2026-07-24 17:20:12 -04:00 • committed by GitHub
commit 373f346e5f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 2210 additions and 467 deletions

View file

@ -1660,6 +1660,7 @@ function App({
<InfoTab
serverName={selectedServer}
serverConfig={selectedServerConfig}
serverSettings={selectedServerEntry?.settings ?? null}
serverState={currentServerState}
width={contentWidth}
height={contentHeight}

View file

@ -5,10 +5,16 @@ import type {
MCPServerConfig,
ServerState,
} from "@inspector/core/mcp/index.js";
import type { InspectorServerSettings } from "@inspector/core/mcp/types.js";
interface InfoTabProps {
serverName: string | null;
serverConfig: MCPServerConfig | null;
// HTTP headers live on the per-server settings (pair-array form), not on the
// transport `serverConfig` — `mcpConfigToServerEntries` lifts the on-disk
// `headers` map into `InspectorServerSettings.headers`. Read them here so the
// SSE / streamable-http header display reflects the real source.
serverSettings?: InspectorServerSettings | null;
serverState: ServerState | null;
width: number;
height: number;
@ -18,11 +24,24 @@ interface InfoTabProps {
export function InfoTab({
serverName,
serverConfig,
serverSettings = null,
serverState,
width,
height,
focused = false,
}: InfoTabProps) {
const headerPairs = serverSettings?.headers ?? [];
// Shared header display for the sse / streamable-http branches (identical for
// both transports — the header source is `serverSettings`, not the transport).
const headersBlock =
headerPairs.length > 0 ? (
<Box marginTop={1}>
<Text dimColor>
Headers:{" "}
{headerPairs.map(({ key, value }) => `${key}=${value}`).join(", ")}
</Text>
</Box>
) : null;
const scrollViewRef = useRef<ScrollViewRef>(null);
// Handle keyboard input for scrolling
@ -111,33 +130,13 @@ export function InfoTab({
<>
<Text dimColor>Type: sse</Text>
<Text dimColor>URL: {serverConfig.url}</Text>
{serverConfig.headers &&
Object.keys(serverConfig.headers).length > 0 && (
<Box marginTop={1}>
<Text dimColor>
Headers:{" "}
{Object.entries(serverConfig.headers)
.map(([k, v]) => `${k}=${v}`)
.join(", ")}
</Text>
</Box>
)}
{headersBlock}
</>
) : serverConfig.type === "streamable-http" ? (
<>
<Text dimColor>Type: streamable-http</Text>
<Text dimColor>URL: {serverConfig.url}</Text>
{serverConfig.headers &&
Object.keys(serverConfig.headers).length > 0 && (
<Box marginTop={1}>
<Text dimColor>
Headers:{" "}
{Object.entries(serverConfig.headers)
.map(([k, v]) => `${k}=${v}`)
.join(", ")}
</Text>
</Box>
)}
{headersBlock}
</>
) : null}
</Box>

View file

@ -34,9 +34,14 @@ function toSelectOptions(
}));
}
/** Minimal JSON Schema object shape (properties + required) */
/**
* Minimal JSON Schema object shape (properties + required). Property values are
* `unknown` so the SDK's broadly-typed `Tool["inputSchema"]` (whose `properties`
* values are the recursive JSON type) is assignable here; each value is narrowed
* to {@link JsonSchemaProperty} at the point of use below.
*/
interface JsonSchemaObject {
properties?: Record<string, JsonSchemaProperty>;
properties?: Record<string, unknown>;
required?: string[];
}
@ -60,7 +65,12 @@ export function schemaToForm(
const required = schema.required || [];
for (const [key, prop] of Object.entries(properties)) {
const property = prop as JsonSchemaProperty;
// `properties` values are `unknown` (the SDK schema admits anything), so
// guard before treating a value as a schema object — a malformed server
// schema with e.g. `properties: { foo: null }` must not throw on `.title`.
const property = (
typeof prop === "object" && prop !== null ? prop : {}
) as JsonSchemaProperty;
const baseField = {
name: key,
label: property.title || key,