Redact MCP debug request logs (#842)

This commit is contained in:
João Sousa Andrade
2026-05-10 09:33:29 +00:00
committed by GitHub
parent 17073fe8ff
commit b8c77bf0e3
3 changed files with 85 additions and 3 deletions
@@ -41,6 +41,52 @@ describe("paseo daemon bootstrap", () => {
}
});
test("redacts Agent MCP debug request credentials and bodies", async () => {
const logLines: string[] = [];
const logger = pino(
{ level: "debug" },
{
write: (line: string) => {
logLines.push(line);
},
},
);
const daemonHandle = await createTestPaseoDaemon({
logger,
mcpDebug: true,
});
try {
const response = await fetch(`http://127.0.0.1:${daemonHandle.port}/mcp/agents`, {
method: "POST",
headers: {
Authorization: "Bearer secret-debug-token",
"Content-Type": "application/json",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "tools/call",
params: {
apiKey: "secret-body-token",
},
}),
});
expect(response.status).toBe(400);
const logs = logLines.join("\n");
expect(logs).toContain("Agent MCP request");
expect(logs).toContain("[redacted]");
expect(logs).toContain('"method":"tools/call"');
expect(logs).toContain('"hasParams":true');
expect(logs).not.toContain("secret-debug-token");
expect(logs).not.toContain("secret-body-token");
expect(logs).not.toContain("apiKey");
} finally {
await daemonHandle.close();
}
});
test("fails fast when OpenAI speech provider is configured without credentials", async () => {
const paseoHomeRoot = await mkdtemp(path.join(os.tmpdir(), "paseo-openai-config-"));
const paseoHome = path.join(paseoHomeRoot, ".paseo");
+37 -2
View File
@@ -141,6 +141,9 @@ import { createRequireBearerMiddleware, type DaemonAuthConfig } from "./auth.js"
type AgentMcpTransportMap = Map<string, StreamableHTTPServerTransport>;
const MAX_MCP_DEBUG_BATCH_ITEMS = 10;
const REDACTED_LOG_VALUE = "[redacted]";
function formatHostForHttpUrl(host: string): string {
return host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
}
@@ -155,6 +158,38 @@ function createAgentMcpBaseUrl(listenTarget: ListenTarget | null): string | null
).toString();
}
function summarizeAgentMcpDebugMessage(body: unknown): Record<string, unknown> {
if (!body || typeof body !== "object" || Array.isArray(body)) {
return {
type: body === null ? "null" : typeof body,
};
}
const record = body as Record<string, unknown>;
const method = typeof record.method === "string" ? record.method : undefined;
return {
type: "object",
...(typeof record.jsonrpc === "string" ? { jsonrpc: record.jsonrpc } : {}),
...(method ? { method } : {}),
hasId: Object.prototype.hasOwnProperty.call(record, "id"),
hasParams: Object.prototype.hasOwnProperty.call(record, "params"),
};
}
function summarizeAgentMcpDebugBody(body: unknown): Record<string, unknown> {
if (!Array.isArray(body)) {
return summarizeAgentMcpDebugMessage(body);
}
const messages = body.slice(0, MAX_MCP_DEBUG_BATCH_ITEMS).map(summarizeAgentMcpDebugMessage);
return {
type: "batch",
count: body.length,
messages,
...(body.length > messages.length ? { omitted: body.length - messages.length } : {}),
};
}
export type PaseoOpenAIConfig = OpenAiSpeechProviderConfig;
export type PaseoLocalSpeechConfig = LocalSpeechProviderConfig;
@@ -671,8 +706,8 @@ export async function createPaseoDaemon(
method: req.method,
url: req.originalUrl,
sessionId: req.header("mcp-session-id"),
authorization: req.header("authorization"),
body: req.body,
authorization: req.header("authorization") ? REDACTED_LOG_VALUE : undefined,
body: summarizeAgentMcpDebugBody(req.body),
},
"Agent MCP request",
);
@@ -18,6 +18,7 @@ interface TestPaseoDaemonOptions {
corsAllowedOrigins?: string[];
listen?: string;
logger?: Parameters<typeof createPaseoDaemon>[1];
mcpDebug?: boolean;
relayEnabled?: boolean;
relayEndpoint?: string;
agentClients?: Partial<Record<AgentProvider, AgentClient>>;
@@ -152,7 +153,7 @@ async function prepareTestDaemonConfig(
hostnames: true,
mcpEnabled: true,
staticDir,
mcpDebug: false,
mcpDebug: options.mcpDebug ?? false,
agentClients: options.agentClients ?? createTestAgentClients(),
agentStoragePath: path.join(paseoHome, "agents"),
relayEnabled: options.relayEnabled ?? false,