diff --git a/backend/packages/harness/deerflow/mcp/tools.py b/backend/packages/harness/deerflow/mcp/tools.py index 9f7d4bc5f..148f82b49 100644 --- a/backend/packages/harness/deerflow/mcp/tools.py +++ b/backend/packages/harness/deerflow/mcp/tools.py @@ -70,7 +70,10 @@ def _local_path_from_uri(uri: str, *, base_dir: Path | None = None) -> Path | No """ if not uri: return None - parsed = urlparse(uri) + try: + parsed = urlparse(uri) + except ValueError: + return None if parsed.scheme == "file": raw = unquote(parsed.path) elif parsed.scheme == "": diff --git a/backend/tests/test_mcp_file_migration.py b/backend/tests/test_mcp_file_migration.py index 615008b63..235be193e 100644 --- a/backend/tests/test_mcp_file_migration.py +++ b/backend/tests/test_mcp_file_migration.py @@ -46,6 +46,9 @@ class TestLocalPathFromUri: assert mcp_tools._local_path_from_uri("https://example.com/a.png") is None assert mcp_tools._local_path_from_uri("data:image/png;base64,AAAA") is None + def test_malformed_uri_is_ignored(self): + assert mcp_tools._local_path_from_uri("//[::1/foo.png") is None + def test_relative_path_is_ignored_without_base_dir(self): assert mcp_tools._local_path_from_uri("relative/path.txt") is None @@ -192,6 +195,14 @@ class TestRewriteLocalPathsInText: assert result == text + def test_malformed_path_like_text_is_left_untouched(self, paths: Paths): + text = "Saved at //[::1/foo.png" + + with _patch_paths(paths): + result = mcp_tools._rewrite_local_paths_in_text(text, thread_id="t1", user_id="u1") + + assert result == text + def test_playwright_markdown_path_is_rewritten_twice_without_copy(self, paths: Paths): workspace = paths.sandbox_work_dir("t1", user_id="u1") _workspace_file(paths, ".playwright-mcp/page.png", content=b"png") @@ -508,6 +519,15 @@ class TestConvertCallToolResultRewrites: assert content[0]["type"] == "text" assert content[0]["text"] == "hello" + def test_malformed_path_like_text_result_does_not_raise(self, paths: Paths): + result = CallToolResult(content=[TextContent(type="text", text="Saved at //[::1/foo.png")], isError=False) + + with _patch_paths(paths): + content, _ = mcp_tools._convert_call_tool_result(result, thread_id="t1", user_id="u1") + + assert content[0]["type"] == "text" + assert content[0]["text"] == "Saved at //[::1/foo.png" + def test_image_content_passthrough(self, paths: Paths): from mcp.types import ImageContent