Skip to content

fix: preserve PATHEXT for stdio mcp servers on windows#2

Merged
XXXxx7258 merged 1 commit intomasterfrom
fix/mcp-stdio-pathext
Mar 7, 2026
Merged

fix: preserve PATHEXT for stdio mcp servers on windows#2
XXXxx7258 merged 1 commit intomasterfrom
fix/mcp-stdio-pathext

Conversation

@XXXxx7258
Copy link
Copy Markdown
Owner

@XXXxx7258 XXXxx7258 commented Mar 7, 2026

Modifications / 改动点

改动 astrbot/core/agent/mcp_client.py 当:
Windows 下启动 stdio MCP 服务时,如果用户没有显式传 env.PATHEXT,AstrBot 会从父进程补上 PATHEXT,避免 uvx --from git+... 无法解析 git.exe。用户自己配置的 PATHEXT 不会被覆盖。

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

image

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

由 Sourcery 提供的摘要

确保 Windows stdio MCP 子进程从父进程继承适当的可执行文件解析设置。

错误修复:

  • 在 MCP 配置中未显式提供的情况下,为 Windows stdio MCP 服务器保留 PATHEXT 环境变量。

测试:

  • 添加单元测试,覆盖 PATHEXT 注入、环境变量合并、用户自定义 PATHEXT 保留,以及在非 Windows 环境下的 stdio MCP 配置行为。
Original summary in English

Summary by Sourcery

Ensure Windows stdio MCP subprocesses inherit appropriate executable resolution settings from the parent process.

Bug Fixes:

  • Preserve the PATHEXT environment variable for Windows stdio MCP servers when not explicitly provided in the MCP config.

Tests:

  • Add unit tests covering PATHEXT injection, env merging, user-defined PATHEXT preservation, and non-Windows behavior for stdio MCP configuration.

Copilot AI review requested due to automatic review settings March 7, 2026 06:36
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a crucial fix for Windows environments, specifically addressing how stdio MCP servers handle executable resolution. It ensures that the PATHEXT environment variable, vital for locating executables, is correctly propagated to subprocesses. By automatically supplementing PATHEXT from the parent process when it's not explicitly set, the change prevents failures in commands that rely on system executables, such as uvx attempting to find git.exe. This enhancement improves the robustness and reliability of AstrBot on Windows without overriding user-defined configurations.

Highlights

  • Windows PATHEXT Preservation: Implemented logic to preserve the PATHEXT environment variable for stdio MCP servers running on Windows.
  • Executable Resolution Fix: Solves an issue where uvx --from git+... might fail to resolve git.exe due to a missing PATHEXT.
  • Automatic PATHEXT Supplementation: AstrBot now automatically supplements PATHEXT from the parent process if it's not explicitly provided for the subprocess.
  • User Configuration Priority: Ensures that any PATHEXT explicitly configured by the user is not overwritten.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • astrbot/core/agent/mcp_client.py
    • Imported os and sys modules.
    • Added a new helper function _prepare_stdio_env to manage PATHEXT for Windows stdio subprocess configurations.
    • Integrated _prepare_stdio_env into the StdioServerParameters creation process.
  • tests/unit/test_mcp_client.py
    • Added a new test file.
    • Implemented unit tests for _prepare_stdio_env to verify its behavior in various scenarios, including adding PATHEXT on Windows, merging with existing environment variables, respecting user-defined PATHEXT, and ensuring no changes on non-Windows platforms.
Activity
  • The author provided a clear motivation and summary of changes in both English and Chinese.
  • Screenshots were included to demonstrate the functionality or test results.
  • A comprehensive checklist was completed, confirming testing, dependency management, and code safety.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Mar 7, 2026

审阅者指南

添加了一个 Windows 专用的辅助函数,用于在启动基于 stdio 的 MCP 服务器时,确保在保留/合并 PATHEXT 的同时,不覆盖用户配置;并将其接入 stdio 启动路径,同时添加了跨平台和不同环境配置下行为的单元测试。

带 PATHEXT 保留的 stdio MCP 服务器启动时序图

sequenceDiagram
    participant Agent
    participant MCPClient
    participant _prepare_stdio_env
    participant StdioServerParameters
    participant OSSubprocess

    Agent->>MCPClient: start_mcp_server(config)
    MCPClient->>MCPClient: detect_stdio_mode(cfg)
    alt stdio_mode
        MCPClient->>_prepare_stdio_env: call(cfg)
        alt platform_is_win32_and_PATHEXT_present
            _prepare_stdio_env->>_prepare_stdio_env: copy_config_and_env
            _prepare_stdio_env-->>MCPClient: cfg_with_PATHEXT
        else non_win32_or_no_PATHEXT
            _prepare_stdio_env-->>MCPClient: cfg_unmodified
        end
        MCPClient->>StdioServerParameters: create(**cfg)
        StdioServerParameters->>OSSubprocess: spawn_stdio_process(env)
        OSSubprocess-->>MCPClient: process_handle
    else non_stdio_mode
        MCPClient->>MCPClient: use_other_server_parameters
    end
    MCPClient-->>Agent: server_handle
Loading

_prepare_stdio_env 在 Windows 上合并 PATHEXT 的流程图

flowchart TD
    A[start_config_dict] --> B{sys.platform == win32}
    B -->|no| C[return_original_config]
    B -->|yes| D{PATHEXT_in_parent_env?}
    D -->|no| C
    D -->|yes| E[prepared = copy_of_config]
    E --> F["env = dict(prepared.env_or_empty)"]
    F --> G[env.setdefault PATHEXT_from_parent]
    G --> H[prepared.env = env]
    H --> I[return_prepared_config]
Loading

文件级变更

变更 详情 文件
确保 Windows 上的 stdio MCP 子进程从父进程环境继承或合并 PATHEXT,且不覆盖用户提供的值。
  • 引入 _prepare_stdio_env 辅助函数:在非 Windows 平台上为 no-op,在 Windows 上返回浅拷贝后的配置并调整 env。
  • 从父进程环境中读取 PATHEXT;如果存在,则仅在配置中的 env 尚未定义 PATHEXT 时,将其设置到子进程 env。
  • 在准备 stdio 参数时,对传入的配置和 env 映射进行拷贝,以避免修改原始配置。
  • 在构造 mcp.StdioServerParameters 之前调用 _prepare_stdio_env,用于 stdio 服务器。
astrbot/core/agent/mcp_client.py
添加单元测试,用于验证 _prepare_stdio_env 在不同平台及环境设置下的行为。
  • 测试在 Windows 上,当配置 env 中缺少 PATHEXT 时,会将 PATHEXT 添加到 env。
  • 测试在 Windows 上,现有 env 会被保留,并与 PATHEXT 进行合并。
  • 测试在配置 env 中用户自定义的 PATHEXT 不会被辅助函数覆盖。
  • 测试在非 Windows 平台上,配置保持不变,且不会注入 env。
tests/unit/test_mcp_client.py

提示与命令

与 Sourcery 交互

  • 触发一次新的审查: 在 pull request 上评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论即可。
  • 从审查评论生成 GitHub issue: 通过回复某条审查评论,请求 Sourcery 从该评论创建 issue。你也可以直接回复该评论 @sourcery-ai issue 来创建对应的 issue。
  • 生成 pull request 标题: 在 pull request 标题的任意位置写上 @sourcery-ai,即可在任意时间生成标题。你也可以在 pull request 中评论 @sourcery-ai title,在任意时间(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文的任意位置写上 @sourcery-ai summary,即可在你希望的位置生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary,在任意时间(重新)生成摘要。
  • 生成审阅者指南: 在 pull request 上评论 @sourcery-ai guide,即可在任意时间(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在 pull request 上评论 @sourcery-ai resolve,以解决所有 Sourcery 评论。当你已经处理完所有评论且不希望再看到它们时非常有用。
  • 忽略所有 Sourcery 审查: 在 pull request 上评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。当你希望从头开始一轮新的审查时尤其有用——别忘了再评论 @sourcery-ai review 来触发新的审查!

自定义你的体验

访问你的 控制面板 以:

  • 启用或禁用诸如 Sourcery 生成的 pull request 摘要、审阅者指南等审查功能。
  • 修改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

Adds a Windows-specific helper to ensure PATHEXT is preserved/merged when launching stdio-based MCP servers, and wires it into the stdio path along with unit tests covering the behavior across platforms and env configurations.

Sequence diagram for stdio MCP server startup with PATHEXT preservation

sequenceDiagram
    participant Agent
    participant MCPClient
    participant _prepare_stdio_env
    participant StdioServerParameters
    participant OSSubprocess

    Agent->>MCPClient: start_mcp_server(config)
    MCPClient->>MCPClient: detect_stdio_mode(cfg)
    alt stdio_mode
        MCPClient->>_prepare_stdio_env: call(cfg)
        alt platform_is_win32_and_PATHEXT_present
            _prepare_stdio_env->>_prepare_stdio_env: copy_config_and_env
            _prepare_stdio_env-->>MCPClient: cfg_with_PATHEXT
        else non_win32_or_no_PATHEXT
            _prepare_stdio_env-->>MCPClient: cfg_unmodified
        end
        MCPClient->>StdioServerParameters: create(**cfg)
        StdioServerParameters->>OSSubprocess: spawn_stdio_process(env)
        OSSubprocess-->>MCPClient: process_handle
    else non_stdio_mode
        MCPClient->>MCPClient: use_other_server_parameters
    end
    MCPClient-->>Agent: server_handle
Loading

Flow diagram for _prepare_stdio_env Windows PATHEXT merge logic

flowchart TD
    A[start_config_dict] --> B{sys.platform == win32}
    B -->|no| C[return_original_config]
    B -->|yes| D{PATHEXT_in_parent_env?}
    D -->|no| C
    D -->|yes| E[prepared = copy_of_config]
    E --> F["env = dict(prepared.env_or_empty)"]
    F --> G[env.setdefault PATHEXT_from_parent]
    G --> H[prepared.env = env]
    H --> I[return_prepared_config]
Loading

File-Level Changes

Change Details Files
Ensure stdio MCP subprocesses on Windows inherit or merge PATHEXT from the parent environment without overriding user-provided values.
  • Introduce a _prepare_stdio_env helper that is no-op on non-Windows platforms and returns a shallow-copied config with adjusted env on Windows.
  • Read PATHEXT from the parent process environment and, if present, set it on the child env only when the config env does not already define PATHEXT.
  • Use a copy of the incoming config and env mapping to avoid mutating the original configuration when preparing stdio parameters.
  • Invoke the _prepare_stdio_env helper before constructing mcp.StdioServerParameters for stdio servers.
astrbot/core/agent/mcp_client.py
Add unit tests to validate _prepare_stdio_env behavior under various platform and environment setups.
  • Test that PATHEXT is added to env on Windows when missing from the config env.
  • Test that existing env is preserved and merged with PATHEXT on Windows.
  • Test that a user-defined PATHEXT in the config env is not overridden by the helper.
  • Test that on non-Windows platforms the config remains unchanged and env is not injected.
tests/unit/test_mcp_client.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 2 个问题

用于 AI Agents 的提示
Please address the comments from this code review:

## 单独评论

### 评论 1
<location path="tests/unit/test_mcp_client.py" line_range="6-14" />
<code_context>
+from astrbot.core.agent import mcp_client
+
+
+def test_prepare_stdio_env_adds_pathext_on_windows(monkeypatch: pytest.MonkeyPatch):
+    monkeypatch.setattr(mcp_client.sys, "platform", "win32")
+    monkeypatch.setenv("PATHEXT", ".COM;.EXE")
+
+    cfg = {"command": "uvx", "args": ["mcp-server-fetch"]}
+
+    prepared = mcp_client._prepare_stdio_env(cfg)
+
+    assert prepared["env"]["PATHEXT"] == ".COM;.EXE"
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** 为 Windows 上未设置 PATHEXT 的情况添加一个测试,以确保返回的配置不发生变化。

当前所有 Windows 相关测试都假定 PATHEXT 已被设置。请添加一个测试(例如 `test_prepare_stdio_env_does_not_set_env_when_pathext_missing_on_windows`),在其中将 `sys.platform` 设为 `win32` 并清除 `PATHEXT`,然后断言返回的配置保持不变(不会出现新的 `env` 条目或 PATHEXT 值)。这将防止未来引入默认 PATHEXT 时产生回归问题。
</issue_to_address>

### 评论 2
<location path="tests/unit/test_mcp_client.py" line_range="3" />
<code_context>
+    }
+
+
+def test_prepare_stdio_env_preserves_user_defined_pathext(
+    monkeypatch: pytest.MonkeyPatch,
+):
+    monkeypatch.setattr(mcp_client.sys, "platform", "win32")
+    monkeypatch.setenv("PATHEXT", ".COM;.EXE")
+
+    cfg = {
+        "command": "uvx",
+        "args": ["mcp-server-fetch"],
+        "env": {"PATHEXT": ".BAT"},
+    }
+
+    prepared = mcp_client._prepare_stdio_env(cfg)
+
+    assert prepared["env"]["PATHEXT"] == ".BAT"
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** 添加一个测试,在 PATHEXT 缺失且已存在 env 字典的情况下,验证该 env 保持不变。

目前你已经覆盖了:当 PATHEXT 存在时合并 env,以及保留用户显式指定的 PATHEXT。请再补充一种情况:`sys.platform == 'win32'`,配置中已有 `env`,但父环境中没有 PATHEXT,并断言 `_prepare_stdio_env` 不会向 `env` 中注入 PATHEXT。该测试将用来记录并锁定这一行为。

```suggestion
from astrbot.core.agent import mcp_client


def test_prepare_stdio_env_does_not_inject_pathext_when_missing_in_parent_env(
    monkeypatch: pytest.MonkeyPatch,
):
    """On Windows, do not inject PATHEXT into an explicit env when parent env lacks it."""
    monkeypatch.setattr(mcp_client.sys, "platform", "win32")
    # Ensure PATHEXT is not present in the parent environment
    monkeypatch.delenv("PATHEXT", raising=False)

    cfg = {
        "command": "uvx",
        "args": ["mcp-server-fetch"],
        "env": {"HTTP_PROXY": "http://127.0.0.1:7890"},
    }

    prepared = mcp_client._prepare_stdio_env(cfg)

    # The explicit env dict should be left untouched; no PATHEXT injected
    assert prepared["env"] == {"HTTP_PROXY": "http://127.0.0.1:7890"}
```
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据反馈改进后续的评审。
Original comment in English

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tests/unit/test_mcp_client.py" line_range="6-14" />
<code_context>
+from astrbot.core.agent import mcp_client
+
+
+def test_prepare_stdio_env_adds_pathext_on_windows(monkeypatch: pytest.MonkeyPatch):
+    monkeypatch.setattr(mcp_client.sys, "platform", "win32")
+    monkeypatch.setenv("PATHEXT", ".COM;.EXE")
+
+    cfg = {"command": "uvx", "args": ["mcp-server-fetch"]}
+
+    prepared = mcp_client._prepare_stdio_env(cfg)
+
+    assert prepared["env"]["PATHEXT"] == ".COM;.EXE"
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test for the case where PATHEXT is not set on Windows to ensure the config is returned unchanged.

All current Windows tests assume PATHEXT is set. Please add a test (e.g. `test_prepare_stdio_env_does_not_set_env_when_pathext_missing_on_windows`) that sets `sys.platform` to `win32` and unsets `PATHEXT`, then asserts the returned config is unchanged (no new `env` entry or PATHEXT value). This will guard against future regressions that inject a default PATHEXT.
</issue_to_address>

### Comment 2
<location path="tests/unit/test_mcp_client.py" line_range="3" />
<code_context>
+    }
+
+
+def test_prepare_stdio_env_preserves_user_defined_pathext(
+    monkeypatch: pytest.MonkeyPatch,
+):
+    monkeypatch.setattr(mcp_client.sys, "platform", "win32")
+    monkeypatch.setenv("PATHEXT", ".COM;.EXE")
+
+    cfg = {
+        "command": "uvx",
+        "args": ["mcp-server-fetch"],
+        "env": {"PATHEXT": ".BAT"},
+    }
+
+    prepared = mcp_client._prepare_stdio_env(cfg)
+
+    assert prepared["env"]["PATHEXT"] == ".BAT"
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test where PATHEXT is missing and an existing env dict is present to verify it is left untouched.

Right now you cover merging env when PATHEXT exists and preserving a user-specified PATHEXT. Please also cover `sys.platform == 'win32'` with an existing `env` but no PATHEXT in the parent environment, and assert that `_prepare_stdio_env` does not inject PATHEXT into `env`. That test will document and lock in this behavior.

```suggestion
from astrbot.core.agent import mcp_client


def test_prepare_stdio_env_does_not_inject_pathext_when_missing_in_parent_env(
    monkeypatch: pytest.MonkeyPatch,
):
    """On Windows, do not inject PATHEXT into an explicit env when parent env lacks it."""
    monkeypatch.setattr(mcp_client.sys, "platform", "win32")
    # Ensure PATHEXT is not present in the parent environment
    monkeypatch.delenv("PATHEXT", raising=False)

    cfg = {
        "command": "uvx",
        "args": ["mcp-server-fetch"],
        "env": {"HTTP_PROXY": "http://127.0.0.1:7890"},
    }

    prepared = mcp_client._prepare_stdio_env(cfg)

    # The explicit env dict should be left untouched; no PATHEXT injected
    assert prepared["env"] == {"HTTP_PROXY": "http://127.0.0.1:7890"}
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +6 to +14
def test_prepare_stdio_env_adds_pathext_on_windows(monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(mcp_client.sys, "platform", "win32")
monkeypatch.setenv("PATHEXT", ".COM;.EXE")

cfg = {"command": "uvx", "args": ["mcp-server-fetch"]}

prepared = mcp_client._prepare_stdio_env(cfg)

assert prepared["env"]["PATHEXT"] == ".COM;.EXE"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): 为 Windows 上未设置 PATHEXT 的情况添加一个测试,以确保返回的配置不发生变化。

当前所有 Windows 相关测试都假定 PATHEXT 已被设置。请添加一个测试(例如 test_prepare_stdio_env_does_not_set_env_when_pathext_missing_on_windows),在其中将 sys.platform 设为 win32 并清除 PATHEXT,然后断言返回的配置保持不变(不会出现新的 env 条目或 PATHEXT 值)。这将防止未来引入默认 PATHEXT 时产生回归问题。

Original comment in English

suggestion (testing): Add a test for the case where PATHEXT is not set on Windows to ensure the config is returned unchanged.

All current Windows tests assume PATHEXT is set. Please add a test (e.g. test_prepare_stdio_env_does_not_set_env_when_pathext_missing_on_windows) that sets sys.platform to win32 and unsets PATHEXT, then asserts the returned config is unchanged (no new env entry or PATHEXT value). This will guard against future regressions that inject a default PATHEXT.

@@ -0,0 +1,64 @@
import pytest

from astrbot.core.agent import mcp_client
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): 添加一个测试,在 PATHEXT 缺失且已存在 env 字典的情况下,验证该 env 保持不变。

目前你已经覆盖了:当 PATHEXT 存在时合并 env,以及保留用户显式指定的 PATHEXT。请再补充一种情况:sys.platform == 'win32',配置中已有 env,但父环境中没有 PATHEXT,并断言 _prepare_stdio_env 不会向 env 中注入 PATHEXT。该测试将用来记录并锁定这一行为。

Suggested change
from astrbot.core.agent import mcp_client
from astrbot.core.agent import mcp_client
def test_prepare_stdio_env_does_not_inject_pathext_when_missing_in_parent_env(
monkeypatch: pytest.MonkeyPatch,
):
"""On Windows, do not inject PATHEXT into an explicit env when parent env lacks it."""
monkeypatch.setattr(mcp_client.sys, "platform", "win32")
# Ensure PATHEXT is not present in the parent environment
monkeypatch.delenv("PATHEXT", raising=False)
cfg = {
"command": "uvx",
"args": ["mcp-server-fetch"],
"env": {"HTTP_PROXY": "http://127.0.0.1:7890"},
}
prepared = mcp_client._prepare_stdio_env(cfg)
# The explicit env dict should be left untouched; no PATHEXT injected
assert prepared["env"] == {"HTTP_PROXY": "http://127.0.0.1:7890"}
Original comment in English

suggestion (testing): Add a test where PATHEXT is missing and an existing env dict is present to verify it is left untouched.

Right now you cover merging env when PATHEXT exists and preserving a user-specified PATHEXT. Please also cover sys.platform == 'win32' with an existing env but no PATHEXT in the parent environment, and assert that _prepare_stdio_env does not inject PATHEXT into env. That test will document and lock in this behavior.

Suggested change
from astrbot.core.agent import mcp_client
from astrbot.core.agent import mcp_client
def test_prepare_stdio_env_does_not_inject_pathext_when_missing_in_parent_env(
monkeypatch: pytest.MonkeyPatch,
):
"""On Windows, do not inject PATHEXT into an explicit env when parent env lacks it."""
monkeypatch.setattr(mcp_client.sys, "platform", "win32")
# Ensure PATHEXT is not present in the parent environment
monkeypatch.delenv("PATHEXT", raising=False)
cfg = {
"command": "uvx",
"args": ["mcp-server-fetch"],
"env": {"HTTP_PROXY": "http://127.0.0.1:7890"},
}
prepared = mcp_client._prepare_stdio_env(cfg)
# The explicit env dict should be left untouched; no PATHEXT injected
assert prepared["env"] == {"HTTP_PROXY": "http://127.0.0.1:7890"}

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a fix to ensure the PATHEXT environment variable is preserved for stdio MCP servers on Windows, which can resolve issues with executable resolution in subprocesses. The implementation is well-contained in a new _prepare_stdio_env function. This function is only called for stdio servers on Windows and correctly respects existing user-defined environment configurations. The change is accompanied by a comprehensive set of unit tests that cover various scenarios, including different platforms and pre-existing environment variables. The code is clean and the approach is sound.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Windows stdio MCP server startup issues by ensuring PATHEXT is available to the spawned subprocess when the user hasn’t explicitly provided it, preserving Windows executable resolution (e.g., git.exe) for commands like uvx --from git+....

Changes:

  • Add _prepare_stdio_env() to inject PATHEXT into stdio server env on Windows without overwriting user-provided values.
  • Apply _prepare_stdio_env() before constructing mcp.StdioServerParameters.
  • Add unit tests covering Windows/non-Windows behavior and env merge semantics.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
astrbot/core/agent/mcp_client.py Adds and uses a Windows-only env preparation step to preserve PATHEXT for stdio MCP subprocesses.
tests/unit/test_mcp_client.py Adds unit tests validating PATHEXT injection/merge behavior and non-Windows no-op behavior.

@XXXxx7258 XXXxx7258 merged commit 914c0d7 into master Mar 7, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants