Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import {
SSEClientTransport,
type SSEClientTransportOptions,
} from "@modelcontextprotocol/sdk/client/sse.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import type { FetchLike, Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import { loadUndiciRuntimeDeps } from "../infra/net/undici-runtime.js";
import { logDebug } from "../logger.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { OpenClawStdioClientTransport } from "./mcp-stdio-transport.js";
import { resolveMcpTransportConfig } from "./mcp-transport-config.js";
export type ResolvedMcpTransport = {
transport: Transport;
description: string;
transportType: "stdio" | "sse" | "streamable-http";
connectionTimeoutMs: number;
detachStderr?: () => void;
};
function attachStderrLogging(serverName: string, transport: OpenClawStdioClientTransport) {
const stderr = transport.stderr;
if (!stderr || typeof stderr.on !== "function") {
return undefined;
}
const onData = (chunk: Buffer | string) => {
const message =
normalizeOptionalString(typeof chunk === "string" ? chunk : String(chunk)) ?? "";
if (!message) {
return;
}
for (const line of message.split(/\r?\n/)) {
const trimmed = line.trim();
if (trimmed) {
logDebug(`bundle-mcp:${serverName}: ${trimmed}`);
}
}
};
stderr.on("data", onData);
return () => {
if (typeof stderr.off === "function") {
stderr.off("data", onData);
} else if (typeof stderr.removeListener === "function") {
stderr.removeListener("data", onData);
}
};
}
type SseEventSourceFetch = NonNullable<
NonNullable<SSEClientTransportOptions["eventSourceInit"]>["fetch"]
>;
const fetchWithUndici: FetchLike = async (url, init) =>
(await loadUndiciRuntimeDeps().fetch(
url,
init as Parameters<ReturnType<typeof loadUndiciRuntimeDeps>["fetch"]>[1],
)) as unknown as Response;
function buildSseEventSourceFetch(headers: Record<string, string>): SseEventSourceFetch {
return (url: string | URL, init?: RequestInit) => {
const sdkHeaders: Record<string, string> = {};
if (init?.headers) {
if (init.headers instanceof Headers) {
init.headers.forEach((value, key) => {
sdkHeaders[key] = value;
});
} else {
Object.assign(sdkHeaders, init.headers);
}
}
return fetchWithUndici(url, {
...(init as RequestInit),
headers: { ...sdkHeaders, ...headers },
}) as ReturnType<SseEventSourceFetch>;
};
}
export function resolveMcpTransport(
serverName: string,
rawServer: unknown,
): ResolvedMcpTransport | null {
const resolved = resolveMcpTransportConfig(serverName, rawServer);
if (!resolved) {
return null;
}
if (resolved.kind === "stdio") {
const transport = new OpenClawStdioClientTransport({
command: resolved.command,
args: resolved.args,
env: resolved.env,
cwd: resolved.cwd,
stderr: "pipe",
});
return {
transport,
description: resolved.description,
transportType: "stdio",
connectionTimeoutMs: resolved.connectionTimeoutMs,
detachStderr: attachStderrLogging(serverName, transport),
};
}
if (resolved.transportType === "streamable-http") {
return {
transport: new StreamableHTTPClientTransport(new URL(resolved.url), {
requestInit: resolved.headers ? { headers: resolved.headers } : undefined,
}),
description: resolved.description,
transportType: "streamable-http",
connectionTimeoutMs: resolved.connectionTimeoutMs,
};
}
const headers: Record<string, string> = {
...resolved.headers,
};
const hasHeaders = Object.keys(headers).length > 0;
return {
transport: new SSEClientTransport(new URL(resolved.url), {
requestInit: hasHeaders ? { headers } : undefined,
fetch: fetchWithUndici,
eventSourceInit: { fetch: buildSseEventSourceFetch(headers) },
}),
description: resolved.description,
transportType: "sse",
connectionTimeoutMs: resolved.connectionTimeoutMs,
};
}
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland