fix: add WSL path normalization for JetBrains plugin matching (#916)

* fix: add WSL path normalization for JetBrains plugin matching

When running Serena MCP server inside WSL2 with JetBrains IDE on Windows,
the plugin returns paths like `//wsl.localhost/Ubuntu-24.04/home/user/...`
while Serena expects `/home/user/...`. This causes `ServerNotFoundError`
because the paths don't match despite pointing to the same location.

This commit adds `_normalize_wsl_path()` method that converts WSL UNC
paths to standard Linux paths before comparison, enabling seamless
integration between WSL-based Claude Code and Windows-based JetBrains IDEs.

Fixes #912
This commit is contained in:
Egor authored and GitHub committed 2026-01-10 13:42:44 +01:00
1 parent b805ae99a7
commit a8cc4711b6
1 file changed
+23 -1
+23 -1
View File
@@ -4,6 +4,7 @@ Client for the Serena JetBrains Plugin
import json
import logging
import re
from pathlib import Path
from typing import Any, Optional, Self, TypeVar
@@ -74,9 +75,30 @@ class JetBrainsPluginClient(ToStringMixin):
raise ServerNotFoundError("Found no Serena service in a JetBrains IDE instance for the project at " + str(resolved_path))
@staticmethod
def _normalize_wsl_path(path_str: str) -> Path:
"""
Normalize WSL UNC paths to Linux paths for comparison.
When JetBrains IDE runs on Windows with a project opened from WSL,
it returns paths like `//wsl.localhost/Ubuntu-24.04/home/user/project`
or `//wsl$/Ubuntu/home/user/project`. This method converts such paths
to standard Linux format `/home/user/project` for proper matching.
:param path_str: Path string that may be a WSL UNC path
:return: Normalized Path object
"""
path_str = str(path_str)
# Match //wsl.localhost/<distro>/... or //wsl$/<distro>/...
match = re.match(r"^//wsl(?:\.localhost|\$)/[^/]+(.*)$", path_str, re.IGNORECASE)
if match:
return Path(match.group(1))
return Path(path_str)
def matches(self, resolved_path: Path) -> bool:
try:
return Path(self.project_root()).resolve() == resolved_path
plugin_root = self._normalize_wsl_path(self.project_root())
return plugin_root.resolve() == resolved_path
except ConnectionError:
return False