fix(vscode): strip markdown links from non-JSON MCP/generic tool output

McpTool's formattedOutput() only fences output when it parses as JSON;
non-JSON output (the common case for a tool returning prose or
markdown) is fed straight into the real Markdown renderer, which does
parse [label](url) into a link, hiding the URL half. toolText() was
treating all non-bash tool output the same as bash's (never stripped),
which reintroduced the exact mismatch this PR fixes for JSON-shaped
output on plain-text results. Now mirrors McpTool's own JSON.parse-or-
fallback branching: JSON output stays raw (rendered fenced, literal),
non-JSON output gets the same link stripping as text/reasoning chunks.

(cherry picked from commit e33a1a7ebc)
This commit is contained in:
Sylwester Liljegren
2026-07-10 15:52:20 +02:00
committed by marius-kilocode
parent fb44bb8dc3
commit 064be73fef
@@ -272,10 +272,27 @@ export const MessageList: Component<MessageListProps> = (props) => {
if (state.title) chunks.push(state.title)
collectStrings(state.input, chunks)
collectStrings(state.metadata, chunks)
if (typeof state.output === "string" && state.output) chunks.push(state.output)
if (typeof state.output === "string" && state.output) chunks.push(mcpOutputText(state.output))
return chunks
}
// Mirrors McpTool's formattedOutput(): if `output` parses as JSON, the
// renderer pretty-prints it inside a fenced ```json block, so it's shown
// literally, same as bash. If it isn't valid JSON — the common case for a
// tool returning prose or markdown — the renderer feeds the raw string
// straight into the real Markdown component, which *does* parse
// `[label](url)` into an actual link, hiding the URL half. Strip it there
// the same as text/reasoning chunks, or a non-JSON tool result reintroduces
// the exact mismatch this rewrite otherwise fixes.
function mcpOutputText(output: string): string {
try {
JSON.parse(output)
return output
} catch {
return stripMarkdownLinkUrls(output)
}
}
function bashText(state: Extract<ToolState, { status: "completed" }>) {
const input = state.input as { command?: string; description?: string } | undefined
const metadata = state.metadata as { command?: string; description?: string } | undefined