feat: port CLI, TUI, and launcher from v1.5 into v2 (#1452)
Ports the CLI, TUI, and launcher from v1.5 into v2 behind a single `mcp-inspector` entrypoint (launcher → web/cli/tui). Includes the `mcp-inspector --web --dev` launcher fix (Vite alias resolution + prod-server double-start), the root `postinstall` install cascade with simplified CI, and spec/AGENTS docs (no-workspaces rationale, Development setup). Closes #1246. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
53dc4549be
commit
2488ca5e38
8 changed files with 25594 additions and 236 deletions
|
|
@ -1 +1 @@
|
|||
export { silentLogger } from "./logger.js";
|
||||
export { silentLogger, type InspectorLogger } from "./logger.js";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,39 @@
|
|||
import pino from "pino";
|
||||
import type { Bindings, LevelWithSilentOrString, LogFn } from "pino";
|
||||
|
||||
/**
|
||||
* Silent logger for use when no logger is injected. Satisfies pino.Logger,
|
||||
* does not output anything. InspectorClient uses this as the default.
|
||||
* Logging surface InspectorClient uses. Real pino loggers satisfy this;
|
||||
* the default silent logger implements it without opening a stream.
|
||||
*/
|
||||
export const silentLogger = pino({ level: "silent" });
|
||||
export interface InspectorLogger {
|
||||
level: LevelWithSilentOrString;
|
||||
fatal: LogFn;
|
||||
error: LogFn;
|
||||
warn: LogFn;
|
||||
info: LogFn;
|
||||
debug: LogFn;
|
||||
trace: LogFn;
|
||||
silent: LogFn;
|
||||
child(bindings?: Bindings): InspectorLogger;
|
||||
}
|
||||
|
||||
const noop: LogFn = () => {};
|
||||
|
||||
function createSilentLogger(): InspectorLogger {
|
||||
const logger: InspectorLogger = {
|
||||
level: "silent",
|
||||
fatal: noop,
|
||||
error: noop,
|
||||
warn: noop,
|
||||
info: noop,
|
||||
debug: noop,
|
||||
trace: noop,
|
||||
silent: noop,
|
||||
child: () => logger,
|
||||
};
|
||||
return logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default logger when none is injected. No-op at all levels; no SonicBoom stream.
|
||||
*/
|
||||
export const silentLogger: InspectorLogger = createSilentLogger();
|
||||
|
|
|
|||
|
|
@ -120,8 +120,7 @@ import {
|
|||
import { ToolCallCancelledError } from "./toolCallCancelledError.js";
|
||||
import type { AuthGuidedState, OAuthStep } from "../auth/types.js";
|
||||
import type { OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
|
||||
import type pino from "pino";
|
||||
import { silentLogger } from "../logging/logger.js";
|
||||
import { silentLogger, type InspectorLogger } from "../logging/logger.js";
|
||||
import { createFetchTracker } from "./fetchTracking.js";
|
||||
import { OAuthManager, type OAuthManagerConfig } from "./oauthManager.js";
|
||||
|
||||
|
|
@ -236,7 +235,7 @@ export class InspectorClient extends InspectorClientEventTarget {
|
|||
private receiverTaskRecords: Map<string, ReceiverTaskRecord> = new Map();
|
||||
// OAuth support (config owned by oauthManager; client delegates and uses !!oauthManager for "is OAuth configured")
|
||||
private oauthManager: OAuthManager | null = null;
|
||||
private logger: pino.Logger;
|
||||
private logger: InspectorLogger;
|
||||
private transportClientFactory: CreateTransport;
|
||||
private fetchFn?: typeof fetch;
|
||||
private effectiveAuthFetch: typeof fetch;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { existsSync, readFileSync } from "fs";
|
||||
import { resolve } from "path";
|
||||
import { getDefaultMcpConfigPath } from "../../storage/store-io.js";
|
||||
import type {
|
||||
MCPConfig,
|
||||
MCPServerConfig,
|
||||
|
|
@ -211,8 +212,26 @@ function applyOverrides(
|
|||
|
||||
export type ResolveServerConfigsMode = "single" | "multi";
|
||||
|
||||
export function hasAdHocServerOptions(options: ServerConfigOptions): boolean {
|
||||
return (
|
||||
(options.target != null && options.target.length > 0) ||
|
||||
Boolean(options.transport) ||
|
||||
Boolean(options.serverUrl?.trim())
|
||||
);
|
||||
}
|
||||
|
||||
/** When no --config and no ad-hoc target, use ~/.mcp-inspector/mcp.json (same as web). */
|
||||
export function withDefaultConfigPath(
|
||||
options: ServerConfigOptions,
|
||||
): ServerConfigOptions {
|
||||
if (options.configPath?.trim() || hasAdHocServerOptions(options)) {
|
||||
return options;
|
||||
}
|
||||
return { ...options, configPath: getDefaultMcpConfigPath() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves server config(s) from options and mode. Used by all runners.
|
||||
* Resolves server config(s) from explicit options and mode.
|
||||
* Single mode: one config (from file + overrides, or from args).
|
||||
* Multi mode: all servers from file (with optional env/cwd/headers overrides), or one from args; errors if config path + transport/serverUrl/positional.
|
||||
*/
|
||||
|
|
@ -221,10 +240,7 @@ export function resolveServerConfigs(
|
|||
mode: ResolveServerConfigsMode,
|
||||
): MCPServerConfig[] {
|
||||
const hasConfigPath = Boolean(options.configPath?.trim());
|
||||
const hasAdHoc =
|
||||
(options.target && options.target.length > 0) ||
|
||||
Boolean(options.transport) ||
|
||||
Boolean(options.serverUrl);
|
||||
const hasAdHoc = hasAdHocServerOptions(options);
|
||||
|
||||
if (mode === "single") {
|
||||
if (hasConfigPath && options.serverName) {
|
||||
|
|
@ -286,6 +302,17 @@ export function resolveServerConfigs(
|
|||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch-time resolver for CLI/TUI: applies the default catalog path when no
|
||||
* `--config` or ad-hoc target is given, then delegates to `resolveServerConfigs`.
|
||||
*/
|
||||
export function resolveLaunchServerConfigs(
|
||||
options: ServerConfigOptions,
|
||||
mode: ResolveServerConfigsMode,
|
||||
): MCPServerConfig[] {
|
||||
return resolveServerConfigs(withDefaultConfigPath(options), mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns named server configs from a config file (multi-server). Use when the caller
|
||||
* needs server names (e.g. TUI). Errors if config path is missing or if ad-hoc options
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
export {
|
||||
parseKeyValuePair,
|
||||
parseHeaderPair,
|
||||
withDefaultConfigPath,
|
||||
resolveServerConfigs,
|
||||
resolveLaunchServerConfigs,
|
||||
getNamedServerConfigs,
|
||||
type ServerConfigOptions,
|
||||
type ResolveServerConfigsMode,
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@
|
|||
* concrete `InspectorClient` since the runtime class is not yet ported.
|
||||
*/
|
||||
|
||||
import type pino from "pino";
|
||||
import { silentLogger } from "../../logging/logger.js";
|
||||
import { silentLogger, type InspectorLogger } from "../../logging/logger.js";
|
||||
import type { InspectorClientProtocol } from "../inspectorClientProtocol.js";
|
||||
import type { FetchRequestEntry } from "../types.js";
|
||||
import type {
|
||||
|
|
@ -63,7 +62,7 @@ export interface FetchRequestLogStateOptions {
|
|||
* Logger for diagnostic traces (e.g. a deferred body update arriving after
|
||||
* its entry rotated out of the log). Defaults to the silent logger.
|
||||
*/
|
||||
logger?: pino.Logger;
|
||||
logger?: InspectorLogger;
|
||||
}
|
||||
|
||||
export class FetchRequestLogState extends TypedEventTarget<FetchRequestLogStateEventMap> {
|
||||
|
|
@ -71,7 +70,7 @@ export class FetchRequestLogState extends TypedEventTarget<FetchRequestLogStateE
|
|||
private client: InspectorClientProtocol | null = null;
|
||||
private unsubscribe: (() => void) | null = null;
|
||||
private maxFetchRequests: number;
|
||||
private readonly logger: pino.Logger;
|
||||
private readonly logger: InspectorLogger;
|
||||
|
||||
constructor(
|
||||
client: InspectorClientProtocol,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import type {
|
|||
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
||||
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
||||
import type pino from "pino";
|
||||
import type { InspectorLogger } from "../logging/logger.js";
|
||||
import type { JsonValue } from "../json/jsonUtils.js";
|
||||
import type {
|
||||
OAuthNavigation,
|
||||
|
|
@ -548,7 +548,7 @@ export interface InspectorClientEnvironment {
|
|||
* - Node: pino file logger
|
||||
* - Browser: createRemoteLogger
|
||||
*/
|
||||
logger?: pino.Logger;
|
||||
logger?: InspectorLogger;
|
||||
|
||||
/**
|
||||
* OAuth environment components
|
||||
|
|
|
|||
16
core/tsconfig.json
Normal file
16
core/tsconfig.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"types": ["node"],
|
||||
"typeRoots": ["../clients/web/node_modules/@types"]
|
||||
},
|
||||
"include": [
|
||||
"mcp/**/*.ts",
|
||||
"storage/**/*.ts",
|
||||
"auth/**/*.ts",
|
||||
"json/**/*.ts",
|
||||
"logging/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules", "**/__tests__/**", "react/**"]
|
||||
}
|
||||
Loading…
Reference in a new issue