refactor: satisfy oxlint rules

This commit is contained in:
Peter Steinberger 2026-04-18 19:33:14 +01:00
parent efed4d4383
commit 9bfc604e01
No known key found for this signature in database
34 changed files with 163 additions and 173 deletions

View File

@ -5,68 +5,62 @@
* and print only the markdown headlines.
*/
import { createRuntime, createServerProxy, type CallResult } from "../src/index.js";
import { createRuntime, createServerProxy, type CallResult } from '../src/index.js';
async function main(): Promise<void> {
const apiKey = process.env.CONTEXT7_API_KEY;
const context7Definition = {
name: "context7",
description: "Context7 documentation MCP",
command: {
kind: "http" as const,
url: new URL("https://mcp.context7.com/mcp"),
headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined,
},
};
// Inline definitions can also live in config/mcporter.json if you prefer shared config.
const apiKey = process.env.CONTEXT7_API_KEY;
const context7Definition = {
name: 'context7',
description: 'Context7 documentation MCP',
command: {
kind: 'http' as const,
url: new URL('https://mcp.context7.com/mcp'),
headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined,
},
};
// Inline definitions can also live in config/mcporter.json if you prefer shared config.
const mcpRuntime = await createRuntime({ servers: [context7Definition] });
try {
const context7 = createServerProxy(mcpRuntime, "context7") as Record<string, unknown>;
const resolveLibraryId = context7.resolveLibraryId as (
args: unknown,
) => Promise<CallResult>;
const getLibraryDocs = context7.getLibraryDocs as (
args: unknown,
) => Promise<CallResult>;
const mcpRuntime = await createRuntime({ servers: [context7Definition] });
try {
const context7 = createServerProxy(mcpRuntime, 'context7') as Record<string, unknown>;
const resolveLibraryId = context7.resolveLibraryId as (args: unknown) => Promise<CallResult>;
const getLibraryDocs = context7.getLibraryDocs as (args: unknown) => Promise<CallResult>;
const resolved = await resolveLibraryId("react");
const contextId = extractContext7LibraryId(resolved);
if (!contextId) {
throw new Error("Unable to resolve React documentation ID from Context7.");
}
const resolved = await resolveLibraryId('react');
const contextId = extractContext7LibraryId(resolved);
if (!contextId) {
throw new Error('Unable to resolve React documentation ID from Context7.');
}
const docs = await getLibraryDocs(contextId);
const docs = await getLibraryDocs(contextId);
const markdown = docs.markdown() ?? docs.text() ?? "";
const headlines = markdown
.split("\n")
.filter((line) => /^#+\s/.test(line))
.join("\n");
const markdown = docs.markdown() ?? docs.text() ?? '';
const headlines = markdown
.split('\n')
.filter((line) => /^#+\s/.test(line))
.join('\n');
console.log("# Headlines for React");
console.log(headlines || "(no headlines found)");
} finally {
await mcpRuntime.close();
}
console.log('# Headlines for React');
console.log(headlines || '(no headlines found)');
} finally {
await mcpRuntime.close();
}
}
main().catch((error) => {
console.error(error);
process.exit(1);
console.error(error);
process.exit(1);
});
function extractContext7LibraryId(result: CallResult): string | null {
const json = result.json<
{ candidates?: Array<{ context7CompatibleLibraryID?: string }> } | undefined
>();
if (json && json.candidates) {
for (const candidate of json.candidates) {
if (candidate?.context7CompatibleLibraryID) {
return candidate.context7CompatibleLibraryID;
}
}
}
const textMatch = result.text()?.match(/Context7-compatible library ID:\s*([^\s]+)/);
return textMatch?.[1] ?? null;
const json = result.json<{ candidates?: Array<{ context7CompatibleLibraryID?: string }> } | undefined>();
if (json && json.candidates) {
for (const candidate of json.candidates) {
if (candidate?.context7CompatibleLibraryID) {
return candidate.context7CompatibleLibraryID;
}
}
}
const textMatch = result.text()?.match(/Context7-compatible library ID:\s*([^\s]+)/);
return textMatch?.[1] ?? null;
}

View File

@ -28,7 +28,7 @@ function walkMarkdownFiles(dir: string, base: string = dir): string[] {
files.push(relative(base, fullPath));
}
}
return files.sort((a, b) => a.localeCompare(b));
return files.toSorted((a, b) => a.localeCompare(b));
}
function extractMetadata(fullPath: string): {

View File

@ -80,7 +80,7 @@ export async function handleAuth(runtime: Runtime, args: string[]): Promise<void
process.exitCode = 1;
return;
}
throw new Error(`Failed to authorize '${target}': ${message}`);
throw new Error(`Failed to authorize '${target}': ${message}`, { cause: error });
}
}
}

View File

@ -284,7 +284,7 @@ function handleArgsFlag(context: FlagHandlerContext): number {
try {
decoded = JSON.parse(raw);
} catch (error) {
throw new Error(`Unable to parse --args: ${(error as Error).message}`);
throw new Error(`Unable to parse --args: ${(error as Error).message}`, { cause: error });
}
if (decoded === null || typeof decoded !== 'object' || Array.isArray(decoded)) {
throw new Error('Unable to parse --args: --args must be a JSON object.');

View File

@ -25,7 +25,7 @@ import { dimText, redText, yellowText } from './terminal.js';
import { resolveCallTimeout, withTimeout } from './timeouts.js';
import { loadToolMetadata } from './tool-cache.js';
type Runtime = Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>;
type Runtime = Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>;
interface ResolvedCallTarget {
server: string;
@ -199,7 +199,7 @@ export function printCallHelp(): void {
}
async function maybeDescribeServer(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
server: string,
tool: string,
outputFormat: OutputFormat
@ -266,7 +266,7 @@ function resolveCallTarget(
}
async function enforceSchemaStringTypes(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
server: string,
tool: string,
args: Record<string, unknown>,
@ -325,7 +325,7 @@ function schemaAllowsString(descriptor: unknown): boolean {
}
async function hydratePositionalArguments(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
server: string,
tool: string,
namedArgs: Record<string, unknown>,
@ -375,7 +375,7 @@ async function hydratePositionalArguments(
type ToolResolution = IdentifierResolution;
async function inferSingleToolName(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
server: string
): Promise<string | undefined> {
const tools = await loadToolMetadata(runtime, server, { includeSchema: false });
@ -391,7 +391,7 @@ async function inferSingleToolName(
}
async function invokeWithAutoCorrection(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
server: string,
tool: string,
args: Record<string, unknown>,
@ -402,7 +402,7 @@ async function invokeWithAutoCorrection(
}
async function attemptCall(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
server: string,
tool: string,
args: Record<string, unknown>,
@ -417,7 +417,8 @@ async function attemptCall(
const timeoutDisplay = `${timeoutMs}ms`;
await runtime.close(server).catch(() => {});
throw new Error(
`Call to ${server}.${tool} timed out after ${timeoutDisplay}. Override MCPORTER_CALL_TIMEOUT or pass --timeout to adjust.`
`Call to ${server}.${tool} timed out after ${timeoutDisplay}. Override MCPORTER_CALL_TIMEOUT or pass --timeout to adjust.`,
{ cause: error }
);
}
@ -451,7 +452,7 @@ async function attemptCall(
}
async function maybeResolveToolName(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
server: string,
attemptedTool: string,
error: unknown

View File

@ -202,7 +202,7 @@ function parseTransport(value: string | undefined): 'http' | 'sse' | 'stdio' {
}
function parseKeyValue(input: string | undefined, target: Record<string, string>, flagName: string): void {
if (!input || !input.includes('=')) {
if (!input?.includes('=')) {
throw new CliUsageError(`${flagName} requires KEY=value.`);
}
const [key, ...rest] = input.split('=');

View File

@ -26,8 +26,8 @@ export function cloneConfig(config: RawConfig): RawConfig {
export async function loadOrCreateConfig(loadOptions: LoadConfigOptions): Promise<{ config: RawConfig; path: string }> {
try {
const { config, path } = await loadRawConfig(loadOptions);
return { config, path };
const { config, path: configPath } = await loadRawConfig(loadOptions);
return { config, path: configPath };
} catch (error) {
if (isErrno(error, 'ENOENT')) {
const rootDir = loadOptions.rootDir ?? process.cwd();

View File

@ -182,7 +182,7 @@ function getServerDefinition(runtime: Runtime, selector: string): ServerDefiniti
return runtime.getDefinition(resolved);
}
if (error instanceof Error) {
throw new Error(error.message);
throw new Error(error.message, { cause: error });
}
throw error;
}

View File

@ -66,7 +66,7 @@ export function extractEphemeralServerFlags(
if (token === '--env') {
const value = args[index + 1];
if (!value || !value.includes('=')) {
if (!value?.includes('=')) {
throw new Error("Flag '--env' requires KEY=value.");
}
const [key, ...rest] = value.split('=');

View File

@ -46,7 +46,7 @@ async function bundleWithRolldown({
runtimeKind: 'node' | 'bun';
minify: boolean;
}): Promise<string> {
let rolldownImpl: typeof import('rolldown')['rolldown'];
let rolldownImpl: (typeof import('rolldown'))['rolldown'];
try {
({ rolldown: rolldownImpl } = await import('rolldown'));
} catch (error) {
@ -56,7 +56,7 @@ async function bundleWithRolldown({
error.message = `${message}\n\n${error.message}`;
throw error;
}
throw new Error(message);
throw new Error(message, { cause: error });
}
const absTarget = path.resolve(targetPath);
await fs.mkdir(path.dirname(absTarget), { recursive: true });

View File

@ -167,8 +167,7 @@ function deriveNameFromUrl(url: URL): string | undefined {
return last;
}
}
const segments = url.pathname.split('/').filter(Boolean);
const firstSegment = segments[0];
const firstSegment = url.pathname.split('/').find(Boolean);
if (firstSegment) {
return firstSegment.replace(/[^a-zA-Z0-9-_]/g, '-');
}

View File

@ -79,11 +79,12 @@ export function renderTemplate({
flagExtras: [{ text: '--raw <json>' }],
}),
}));
const renderedTools = toolDocs.map((entry) => ({
...renderToolCommand(entry.tool, timeoutMs, serverName, entry.doc),
doc: entry.doc,
tool: entry.tool,
}));
const renderedTools = toolDocs.map((entry) =>
Object.assign(renderToolCommand(entry.tool, timeoutMs, serverName, entry.doc), {
doc: entry.doc,
tool: entry.tool,
})
);
const toolHelp = renderedTools.map((entry) => ({
name: entry.commandName,
description: entry.tool.tool.description ?? '',

View File

@ -20,6 +20,26 @@ export interface GeneratedOption {
formatHint?: string;
}
function resolveSchemaType(value: unknown): GeneratedOption['type'] | undefined {
if (value === 'integer') {
return 'number';
}
if (value === 'string' || value === 'number' || value === 'boolean' || value === 'array' || value === 'object') {
return value;
}
return undefined;
}
function resolveArrayItemType(value: unknown): GeneratedOption['arrayItemType'] | undefined {
if (value === 'integer') {
return 'number';
}
if (value === 'string' || value === 'number' || value === 'boolean') {
return value;
}
return undefined;
}
export function buildToolMetadata(tool: ServerToolInfo): ToolMetadata {
const methodName = toProxyMethodName(tool.name);
const properties = extractOptions(tool);
@ -230,25 +250,16 @@ export function inferType(descriptor: unknown): GeneratedOption['type'] {
return 'unknown';
}
const type = (descriptor as Record<string, unknown>).type;
const resolveType = (value: unknown): GeneratedOption['type'] | undefined => {
if (value === 'integer') {
return 'number';
}
if (value === 'string' || value === 'number' || value === 'boolean' || value === 'array' || value === 'object') {
return value;
}
return undefined;
};
if (Array.isArray(type)) {
for (const entry of type) {
const resolved = resolveType(entry);
const resolved = resolveSchemaType(entry);
if (resolved) {
return resolved;
}
}
return 'unknown';
}
const resolved = resolveType(type);
const resolved = resolveSchemaType(type);
if (resolved) {
return resolved;
}
@ -265,25 +276,16 @@ export function inferArrayItemType(descriptor: unknown): GeneratedOption['arrayI
}
const items = record.items as Record<string, unknown>;
const itemType = items.type;
const resolveItemType = (value: unknown): GeneratedOption['arrayItemType'] | undefined => {
if (value === 'integer') {
return 'number';
}
if (value === 'string' || value === 'number' || value === 'boolean') {
return value;
}
return undefined;
};
if (Array.isArray(itemType)) {
for (const entry of itemType) {
const resolved = resolveItemType(entry);
const resolved = resolveArrayItemType(entry);
if (resolved) {
return resolved;
}
}
return 'unknown';
}
const resolved = resolveItemType(itemType);
const resolved = resolveArrayItemType(itemType);
if (resolved) {
return resolved;
}

View File

@ -86,7 +86,7 @@ export function extractListFlags(args: string[]): {
type ListOutputFormat = 'text' | 'json';
export async function handleList(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
args: string[]
): Promise<void> {
const flags = extractListFlags(args);
@ -341,7 +341,6 @@ export async function handleList(
const durationMs = Date.now() - startedAt;
printSingleServerHeader(definition, undefined, durationMs, transportSummary, sourcePath);
const message = error instanceof Error ? error.message : 'Failed to load tool list.';
const timeoutMs = flags.timeoutMs ?? LIST_TIMEOUT_MS;
const authCommand = buildAuthCommandHint(definition);
const advice = classifyListError(error, definition.name, timeoutMs, { authCommand });
console.warn(` Tools: <timed out after ${timeoutMs}ms>`);
@ -390,7 +389,7 @@ export function printListHelp(): void {
}
function resolveServerDefinition(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
name: string
): { definition: ServerDefinition; name: string } | undefined {
try {
@ -423,7 +422,7 @@ function resolveServerDefinition(
}
function suggestServerName(
runtime: Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>,
runtime: Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>,
attempted: string
) {
const definitions = runtime.getDefinitions();

View File

@ -33,7 +33,7 @@ export interface ListJsonServerEntry {
}
export function printSingleServerHeader(
definition: ReturnType<Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>['getDefinition']>,
definition: ReturnType<Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>['getDefinition']>,
toolCount: number | undefined,
durationMs: number | undefined,
transportSummary: string,
@ -70,7 +70,7 @@ export function printSingleServerHeader(
}
export function printToolDetail(
definition: ReturnType<Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>['getDefinition']>,
definition: ReturnType<Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>['getDefinition']>,
metadata: ToolMetadata,
includeSchema: boolean,
requiredOnly: boolean
@ -107,7 +107,7 @@ export function printToolDetail(
}
function buildExampleOptions(
definition: ReturnType<Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>['getDefinition']>
definition: ReturnType<Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>['getDefinition']>
): { selector?: string; wrapExpression?: boolean } | undefined {
if (definition.source?.kind !== 'local' || definition.source.path !== '<adhoc>') {
return undefined;
@ -150,7 +150,7 @@ export function buildJsonListEntry(
description: result.server.description,
transport: formatTransportSummary(
result.server as ReturnType<
Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>['getDefinition']
Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>['getDefinition']
>
),
source: result.server.source,
@ -164,7 +164,7 @@ export function buildJsonListEntry(
};
}
const authCommand = buildAuthCommandHint(
result.server as ReturnType<Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>['getDefinition']>
result.server as ReturnType<Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>['getDefinition']>
);
const advice = classifyListError(result.error, result.server.name, timeoutSeconds, { authCommand });
return {
@ -173,7 +173,9 @@ export function buildJsonListEntry(
durationMs: result.durationMs,
description: result.server.description,
transport: formatTransportSummary(
result.server as ReturnType<Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>['getDefinition']>
result.server as ReturnType<
Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>['getDefinition']
>
),
source: result.server.source,
sources: options.includeSources ? result.server.sources : undefined,
@ -193,7 +195,7 @@ export function createUnknownResult(server: ServerDefinition): ListSummaryResult
}
export function buildAuthCommandHint(
definition: ReturnType<Awaited<ReturnType<typeof import('../runtime.js')['createRuntime']>>['getDefinition']>
definition: ReturnType<Awaited<ReturnType<(typeof import('../runtime.js'))['createRuntime']>>['getDefinition']>
): string {
if (definition.source?.kind === 'local' && definition.source.path === '<adhoc>') {
if (definition.command.kind === 'http') {

View File

@ -346,5 +346,5 @@ function normalizeLayers(
): Array<{ path: string; mtimeMs: number | null }> {
return layers
.map((entry) => ({ path: path.resolve(entry.path), mtimeMs: entry.mtimeMs ?? null }))
.sort((a, b) => a.path.localeCompare(b.path));
.toSorted((a, b) => a.path.localeCompare(b.path));
}

View File

@ -68,7 +68,7 @@ export function resolveEnvPlaceholders(value: string): string {
});
if (missing.size > 0) {
const names = [...missing].sort().join(', ');
const names = [...missing].toSorted().join(', ');
throw new Error(`Environment variable(s) ${names} must be set for MCP header substitution.`);
}

View File

@ -2,13 +2,7 @@ export type { CommandSpec, ServerDefinition } from './config.js';
export { loadServerDefinitions } from './config.js';
export type { CallResult, ConnectionIssue, ImageContent } from './result-utils.js';
export { createCallResult, describeConnectionIssue, wrapCallResult } from './result-utils.js';
export type {
CallOptions,
ListToolsOptions,
Runtime,
RuntimeLogger,
ServerToolInfo,
} from './runtime.js';
export type { CallOptions, ListToolsOptions, Runtime, RuntimeLogger, ServerToolInfo } from './runtime.js';
export { callOnce, createRuntime } from './runtime.js';
export type { ServerProxyOptions } from './server-proxy.js';
export { createServerProxy } from './server-proxy.js';

View File

@ -15,7 +15,7 @@ export function materializeHeaders(
resolved[key] = resolveEnvPlaceholders(value);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to resolve header '${key}' for server '${serverName}': ${message}`);
throw new Error(`Failed to resolve header '${key}' for server '${serverName}': ${message}`, { cause: error });
}
}

View File

@ -122,7 +122,7 @@ class McpRuntime implements Runtime {
// listServers returns configured names sorted alphabetically for stable CLI output.
listServers(): string[] {
return [...this.definitions.keys()].sort((a, b) => a.localeCompare(b));
return [...this.definitions.keys()].toSorted((a, b) => a.localeCompare(b));
}
// getDefinitions exposes raw server metadata to consumers such as the CLI.

View File

@ -73,6 +73,8 @@ if (STDIO_TRACE_ENABLED) {
console.log('[mcporter] STDIO trace logging enabled (set MCPORTER_STDIO_TRACE=0 to disable).');
}
function ignoreEmitterError(): void {}
function destroyStream(stream: unknown): void {
if (!stream || typeof stream !== 'object') {
return;
@ -85,9 +87,8 @@ function destroyStream(stream: unknown): void {
end?: () => void;
unref?: () => void;
};
const swallowError = () => {};
try {
emitter.on?.('error', swallowError);
emitter.on?.('error', ignoreEmitterError);
} catch {
// ignore
}
@ -107,12 +108,12 @@ function destroyStream(stream: unknown): void {
// ignore
}
try {
emitter.off?.('error', swallowError);
emitter.off?.('error', ignoreEmitterError);
} catch {
// ignore
}
try {
emitter.removeListener?.('error', swallowError);
emitter.removeListener?.('error', ignoreEmitterError);
} catch {
// ignore
}
@ -130,9 +131,8 @@ function waitForChildClose(child: MaybeChildProcess | undefined, timeoutMs: numb
}
return new Promise((resolve) => {
let settled = false;
const swallowProcessError = () => {};
try {
child.on?.('error', swallowProcessError);
child.on?.('error', ignoreEmitterError);
} catch {
// ignore
}
@ -149,7 +149,7 @@ function waitForChildClose(child: MaybeChildProcess | undefined, timeoutMs: numb
child.removeListener('close', finish);
child.removeListener('error', finish);
try {
child.removeListener?.('error', swallowProcessError);
child.removeListener?.('error', ignoreEmitterError);
} catch {
// ignore
}
@ -393,9 +393,8 @@ function patchStdioStart(): void {
meta.stderrChunks.push(chunk.toString('utf8'));
}
};
const swallowError = () => {};
(targetStream as NodeJS.EventEmitter).on('data', handleChunk);
(targetStream as NodeJS.EventEmitter).on('error', swallowError);
(targetStream as NodeJS.EventEmitter).on('error', ignoreEmitterError);
meta.listeners.push({
stream: targetStream as NodeJS.EventEmitter & {
removeListener?: (event: string, listener: (...args: unknown[]) => void) => void;
@ -408,7 +407,7 @@ function patchStdioStart(): void {
removeListener?: (event: string, listener: (...args: unknown[]) => void) => void;
},
event: 'error',
handler: swallowError,
handler: ignoreEmitterError,
});
}
@ -426,9 +425,8 @@ function patchStdioStart(): void {
meta.stdoutChunks.push(chunk.toString('utf8'));
}
};
const swallowStdoutError = () => {};
stdoutStream.on('data', handleStdout);
stdoutStream.on('error', swallowStdoutError);
stdoutStream.on('error', ignoreEmitterError);
meta.listeners.push({
stream: stdoutStream,
event: 'data',
@ -437,7 +435,7 @@ function patchStdioStart(): void {
meta.listeners.push({
stream: stdoutStream,
event: 'error',
handler: swallowStdoutError,
handler: ignoreEmitterError,
});
}

View File

@ -281,11 +281,11 @@ export function createServerProxy(
}
const base: ServerProxy = {
call: async (toolName: string, options?: ToolCallOptions) => {
const result = await runtime.callTool(serverName, toolName, options ?? {});
call: async (toolName: string, callOptions?: ToolCallOptions) => {
const result = await runtime.callTool(serverName, toolName, callOptions ?? {});
return createCallResult(result);
},
listTools: (options) => runtime.listTools(serverName, options),
listTools: (listOptions) => runtime.listTools(serverName, listOptions),
};
return new Proxy(base as ServerProxy & Record<string | symbol, unknown>, {

View File

@ -20,7 +20,7 @@ describe('handleAuth retry logic', () => {
registerDefinition: vi.fn(),
getDefinition: vi.fn().mockReturnValue(baseDefinition),
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
await expect(handleAuth(runtime, ['adhoc-server'])).resolves.toBeUndefined();
expect(listTools).toHaveBeenCalledTimes(2);
@ -33,7 +33,7 @@ describe('handleAuth retry logic', () => {
registerDefinition: vi.fn(),
getDefinition: vi.fn().mockReturnValue(baseDefinition),
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
await expect(handleAuth(runtime, ['adhoc-server'])).rejects.toThrow(/Failed to authorize/);
expect(listTools).toHaveBeenCalledTimes(2);

View File

@ -22,7 +22,7 @@ const createRuntimeDouble = () => {
getDefinition,
getDefinitions: () => Array.from(definitions.values()),
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
return { runtime, listTools };
};
@ -59,7 +59,7 @@ describe('mcporter auth ad-hoc support', () => {
registerDefinition,
listTools,
getDefinition: () => definition,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
await handleAuth(runtime, ['https://mcp.vercel.com']);
@ -78,7 +78,7 @@ describe('mcporter auth ad-hoc support', () => {
registerDefinition: vi.fn(),
listTools: vi.fn().mockRejectedValue(new Error('fetch failed: connect ECONNREFUSED 127.0.0.1:9000')),
getDefinition: () => definition,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});

View File

@ -10,7 +10,7 @@ describe('CLI call error reporting', () => {
const runtime = {
callTool,
close: vi.fn().mockResolvedValue(undefined),
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
@ -31,7 +31,7 @@ describe('CLI call error reporting', () => {
const runtime = {
callTool,
close: vi.fn().mockResolvedValue(undefined),
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});

View File

@ -196,7 +196,7 @@ describe('CLI call execution behavior', () => {
callTool,
listTools,
close: vi.fn().mockResolvedValue(undefined),
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -220,7 +220,7 @@ describe('CLI call execution behavior', () => {
callTool,
listTools,
close: vi.fn().mockResolvedValue(undefined),
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
@ -311,7 +311,7 @@ function createRuntimeStub(
>,
options: { definitions?: ServerDefinition[] } = {}
): {
runtime: Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
runtime: Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
callTool: ReturnType<typeof vi.fn>;
listTools: ReturnType<typeof vi.fn>;
} {
@ -343,6 +343,6 @@ function createRuntimeStub(
listTools,
callTool,
close,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
return { runtime, callTool, listTools };
}

View File

@ -659,12 +659,12 @@ await new Promise((resolve) => {
expect(stats.isFile()).toBe(true);
const { stdout } = await new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
execFile(binaryPath, [], { env: process.env }, (error, stdout, stderr) => {
execFile(binaryPath, [], { env: process.env }, (error, childStdout, childStderr) => {
if (error) {
reject(error);
return;
}
resolve({ stdout, stderr });
resolve({ stdout: childStdout, stderr: childStderr });
});
});
expect(stdout).toContain('echo - Return the provided text');

View File

@ -52,7 +52,7 @@ describe('CLI list classification and routing', () => {
return Promise.resolve([]);
}
},
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
@ -99,7 +99,7 @@ describe('CLI list classification and routing', () => {
}),
getDefinitions: () => Array.from(definitions.values()),
listTools: vi.fn().mockRejectedValue(new Error('SSE error: Non-200 status code (401)')),
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -130,7 +130,7 @@ describe('CLI list classification and routing', () => {
registerDefinition,
getDefinition: () => definition,
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
await handleList(runtime, ['https://mcp.vercel.com']);
@ -153,7 +153,7 @@ describe('CLI list classification and routing', () => {
registerDefinition,
getDefinition: () => definition,
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
await handleList(runtime, ['https://www.shadcn.io/api/mcp.getComponents']);
@ -175,7 +175,7 @@ describe('CLI list classification and routing', () => {
registerDefinition: vi.fn(),
getDefinition: () => definition,
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
await handleList(runtime, ['shadcn.io/api/mcp.getComponents']);
@ -195,7 +195,7 @@ describe('CLI list classification and routing', () => {
const runtime = {
getDefinitions: () => [definition],
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
await handleList(runtime, []);
@ -223,7 +223,7 @@ describe('CLI list classification and routing', () => {
},
listTools,
registerDefinition,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -250,7 +250,7 @@ describe('CLI list classification and routing', () => {
getDefinition,
getDefinitions: () => [definition],
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -274,7 +274,7 @@ describe('CLI list classification and routing', () => {
},
getDefinitions: () => [definition],
listTools,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});

View File

@ -66,7 +66,7 @@ describe('CLI list flag parsing', () => {
new Promise((resolve) => {
setTimeout(() => resolve([{ name: 'ok' }]), 50);
}),
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});

View File

@ -41,7 +41,7 @@ describe('CLI list formatting', () => {
command: { kind: 'http', url: new URL('https://example.com/mcp') },
}),
listTools: listToolsSpy,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -94,7 +94,7 @@ describe('CLI list formatting', () => {
}
return Promise.reject(new Error('HTTP error 500: upstream unavailable'));
},
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
await handleList(runtime, ['--json']);
const payload = JSON.parse(logSpy.mock.calls.at(-1)?.[0] ?? '{}');
@ -133,7 +133,7 @@ describe('CLI list formatting', () => {
getDefinitions: () => [definition],
getDefinition: () => definition,
registerDefinition: vi.fn(),
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -156,7 +156,7 @@ describe('CLI list formatting', () => {
const runtime = {
getDefinition: () => linearDefinition,
listTools: listToolsSpy,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -183,7 +183,7 @@ describe('CLI list formatting', () => {
const runtime = {
getDefinition: () => linearDefinition,
listTools: listToolsSpy,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -224,7 +224,7 @@ describe('CLI list formatting', () => {
const runtime = {
getDefinition: () => linearDefinition,
listTools: listToolsSpy,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -247,7 +247,7 @@ describe('CLI list formatting', () => {
const runtime = {
getDefinition: () => linearDefinition,
listTools: listToolsSpy,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
@ -306,7 +306,7 @@ describe('CLI list formatting', () => {
const runtime = {
getDefinition: () => linearDefinition,
listTools: listToolsSpy,
} as unknown as Awaited<ReturnType<typeof import('../src/runtime.js')['createRuntime']>>;
} as unknown as Awaited<ReturnType<(typeof import('../src/runtime.js'))['createRuntime']>>;
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
const nowSpy = vi.spyOn(Date, 'now').mockReturnValue(1_700_000_000_000);

View File

@ -197,7 +197,7 @@ async function writeMetadataFixture(kind: ArtifactKind): Promise<string> {
kind: 'http' as const,
url: 'https://mcp.vercel.com',
headers: {
// biome-ignore lint/suspicious/noTemplateCurlyInString: metadata preserves env-placeholder format
// Metadata preserves env-placeholder format.
Authorization: 'Bearer ${VERCEL_TOKEN}',
},
},

View File

@ -79,7 +79,7 @@ describe('config imports', () => {
});
const homeDir = ensureFakeHomeDir();
const names = servers.map((server) => server.name).sort();
const names = servers.map((server) => server.name).toSorted();
expect(names).toEqual([
'claude-home',
'claude-local',

View File

@ -95,7 +95,7 @@ describe('loadServerDefinitions with layered configs', () => {
);
const servers = await loadServerDefinitions({ rootDir: projectDir });
const names = servers.map((server) => server.name).sort();
const names = servers.map((server) => server.name).toSorted();
expect(names).toEqual(['fromHome', 'fromProject', 'overrideMe']);
const merged = Object.fromEntries(servers.map((server) => [server.name, server]));

View File

@ -271,9 +271,9 @@ describe('stdio transport environment', () => {
cwd: '/repo',
},
env: {
// biome-ignore lint/suspicious/noTemplateCurlyInString: placeholders resolve against process env at runtime
// Placeholders resolve against process env at runtime.
OBSIDIAN_API_KEY: '${OBSIDIAN_API_KEY}',
// biome-ignore lint/suspicious/noTemplateCurlyInString: placeholders resolve against process env at runtime
// Placeholders resolve against process env at runtime.
OBSIDIAN_BASE_URL: '${OBSIDIAN_BASE_URL:-https://127.0.0.1:27124}',
EMPTY_VAR: '',
},