Skip to content

fix: replace fastmcp update_config_file with encoding-safe implementation#178

Merged
ichoosetoaccept merged 1 commit intomainfrom
02-18-fix-replace-fastmcp-update_config_file-with-encoding-safe-implementation
Feb 18, 2026
Merged

fix: replace fastmcp update_config_file with encoding-safe implementation#178
ichoosetoaccept merged 1 commit intomainfrom
02-18-fix-replace-fastmcp-update_config_file-with-encoding-safe-implementation

Conversation

@ichoosetoaccept
Copy link
Member

@ichoosetoaccept ichoosetoaccept commented Feb 18, 2026

Summary

Replace fastmcp's update_config_file() with our own encoding-safe implementation in the install module.

Problem

CI was failing across all platforms (Ubuntu, macOS, Windows) and both dependency resolutions (highest and lowest-direct). The root cause: fastmcp's update_config_file() internally calls Path.read_text() and Path.write_text() without specifying encoding=. Our CI sets PYTHONWARNDEFAULTENCODING=1, which in Python 3.14 promotes this to an EncodingWarning exception — caught by _write_config_file's broad except Exception handler, making all config-writing tests fail.

Fix

  • Replaced the update_config_file() call with a simple read → merge → write using json.loads/json.dumps, always passing encoding="utf-8".
  • Removed the update_config_file import from fastmcp (only StdioMCPServer is still used).
  • Updated two tests that mocked the now-removed update_config_file to instead trigger real filesystem errors (making a path a directory so write_text fails).

Test plan

All 461 tests pass locally. CI should now pass on all matrix combinations.

Copy link
Member Author

ichoosetoaccept commented Feb 18, 2026

@greptile-apps
Copy link

greptile-apps bot commented Feb 18, 2026

Greptile Summary

Replaces fastmcp's update_config_file() with an in-house JSON config merge in _write_config_file(). The fastmcp function omitted explicit encoding= on file I/O, triggering EncodingWarning errors in CI under PYTHONWARNDEFAULTENCODING=1. The new implementation reads existing config (if present), merges in the server entry via setdefault + assignment, and writes back with encoding="utf-8" throughout.

  • Removed update_config_file import from fastmcp.mcp_config; only StdioMCPServer is still used
  • New implementation correctly handles missing files, empty files, and preserves existing config entries
  • Tests updated to use filesystem-based error triggers instead of mocking the removed function
  • Output format now uses indent=2 pretty-printing, which is a minor improvement over the previous behavior

Confidence Score: 5/5

  • This PR is safe to merge — it's a straightforward replacement of an upstream utility with an equivalent encoding-safe implementation.
  • The change is small and well-scoped: a single function body rewritten with the same semantics, well-documented rationale, and tests updated to match. All edge cases (missing file, empty file, existing entries, write errors) are covered by existing tests.
  • No files require special attention.

Important Files Changed

Filename Overview
src/codereviewbuddy/install.py Replaces fastmcp's update_config_file() with an encoding-safe inline implementation that reads, merges, and writes JSON config with explicit UTF-8 encoding. One minor style note on a dense walrus-operator line.
tests/test_install.py Removes mocked update_config_file side-effects in error tests, replacing them with filesystem-based error triggers (creating directories where files are expected). Tests are now more realistic and less coupled to the fastmcp dependency.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["_write_config_file(config_path, server_config)"] --> B{config_path exists?}
    B -- Yes --> C["Read file with encoding='utf-8'"]
    C --> D{Content non-empty?}
    D -- Yes --> E["json.loads(raw)"]
    D -- No --> F["config = {}"]
    B -- No --> F
    E --> G["config.setdefault('mcpServers', {})"]
    F --> G
    G --> H["config['mcpServers'][SERVER_NAME] = server_config.model_dump()"]
    H --> I["write_text(json.dumps(config), encoding='utf-8')"]
    I --> J["return True ✅"]
    E -- JSONDecodeError --> K["except Exception → return False ❌"]
    I -- OSError --> K
Loading

Last reviewed commit: 7323bab

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link
Member Author

ichoosetoaccept commented Feb 18, 2026

Merge activity

  • Feb 18, 9:47 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Feb 18, 9:47 AM UTC: @ichoosetoaccept merged this pull request with Graphite.

@ichoosetoaccept ichoosetoaccept merged commit 3cb8b83 into main Feb 18, 2026
12 checks passed
@ichoosetoaccept ichoosetoaccept deleted the 02-18-fix-replace-fastmcp-update_config_file-with-encoding-safe-implementation branch February 18, 2026 09:47
ichoosetoaccept added a commit that referenced this pull request Feb 18, 2026
…m deeplink (#181)

## Summary

Address two Greptile review findings from PR #178 (merged before comments were visible due to stacked PR limitations).

## Changes

1. **Check stderr for Claude Code CLI detection** — Some CLI tools (including Node.js-based CLIs) print version info to stderr rather than stdout. `_find_claude_command` now checks both `result.stdout` and `result.stderr` for the "Claude Code" string. Applied to both the PATH lookup and the known-locations fallback.

2. **Exclude empty `env` from Cursor deeplink** — `model_dump_json(exclude_none=True)` still serialized `"env": {}` into the base64 payload when no env vars were provided. Added `exclude_defaults=True` to omit the empty dict, keeping the deeplink payload clean and consistent with `mcp-json` output.

## Tests added

- `test_found_via_stderr` — verifies Claude Code detection when version string is only in stderr
- `test_deeplink_excludes_empty_env` — decodes the base64 deeplink config and asserts `env` key is absent when no env vars provided
- Updated `test_not_claude_code` to also set `stderr=""` for completeness

## Related

Filed #180 for the codereviewbuddy bug where `list_review_comments` missed these inline Greptile threads entirely.
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.

1 participant