Skip to content

fix: Update VSCode manager to use mcp.json with correct structure - #300

Merged
JoJoJoJoJoJoJo merged 6 commits into
mainfrom
copilot/update-vscode-config-file
Jan 15, 2026
Merged

fix: Update VSCode manager to use mcp.json with correct structure#300
JoJoJoJoJoJoJo merged 6 commits into
mainfrom
copilot/update-vscode-config-file

Conversation

Copilot AI commented Jan 15, 2026

Copy link
Copy Markdown
Contributor

User description

VSCode's MCP configuration was incorrectly targeting settings.json with config wrapped under an mcp key. Per VS Code MCP docs, it should use a dedicated mcp.json file with servers at root level.

Changes

  • Config paths: Changed from settings.json to mcp.json for all platforms:

    • macOS: ~/Library/Application Support/Code/User/mcp.json
    • Windows: %APPDATA%/Code/User/mcp.json
    • Linux: ~/.config/Code/User/mcp.json
  • Config structure: Removed mcp wrapper in _load_config() and _save_config():

    # Before
    {"mcp": {"servers": {...}}}
    
    # After  
    {"servers": {...}, "inputs": []}
  • Added test coverage: 18 tests for VSCode manager including platform-specific paths, config structure validation, and CRUD operations

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • astral.sh
    • Triggering command: /usr/bin/curl curl -LsSf REDACTED tests/test_run.py (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Problem

The VS Code client manager in mcpm is currently configured to edit settings.json when it should be editing mcp.json according to the VS Code MCP documentation.

Additionally, the configuration structure is incorrect - the mcp root key should be removed since mcp.json expects servers as the root key.

Changes Required

Update src/mcpm/clients/managers/vscode.py to:

  1. Change config file paths from settings.json to mcp.json:

    • macOS: ~/Library/Application Support/Code/User/mcp.json
    • Windows: %APPDATA%/Code/User/mcp.json
    • Linux: ~/.config/Code/User/mcp.json
  2. Update config structure to match the mcp.json schema:

    • Remove the mcp root key wrapping
    • Have servers directly at the root level
    • Support inputs array at root level (empty by default)
  3. Update _load_config() method:

    • Remove logic that wraps/unwraps mcp key
    • Return config with servers at root level
    • Handle the simpler structure: {"servers": {}, "inputs": []}
  4. Update _save_config() method:

    • Remove logic that nests config under mcp key
    • Save config directly with servers at root
    • Preserve inputs array if it exists

Expected Result

After the fix, the config file structure should be:

{
  "servers": {
    "mcpm_profile_work": {
      "type": "stdio",
      "command": "mcpm",
      "args": ["profile", "run", "work"]
    }
  },
  "inputs": []
}

Located in ~/Library/Application Support/Code/User/mcp.json (on macOS) instead of settings.json.

References

This pull request was created from Copilot chat.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.


PR Type

Bug fix, Tests


Description

  • Changed VSCode config file from settings.json to mcp.json per VS Code MCP docs

  • Removed mcp root key wrapper, moved servers to root level

  • Updated _load_config() and _save_config() to handle new structure

  • Added comprehensive test suite with 18 tests for VSCode manager functionality


Diagram Walkthrough

flowchart LR
  A["settings.json<br/>with mcp wrapper"] -->|"Update config path"| B["mcp.json<br/>at root level"]
  C["Old structure<br/>mcp.servers"] -->|"Flatten structure"| D["New structure<br/>servers at root"]
  E["_load_config<br/>_save_config"] -->|"Refactor methods"| F["Handle new<br/>mcp.json format"]
  G["No tests"] -->|"Add coverage"| H["18 new tests<br/>for VSCode manager"]
Loading

File Walkthrough

Relevant files
Bug fix
vscode.py
Update VSCode config to use mcp.json with correct structure

src/mcpm/clients/managers/vscode.py

  • Changed config file paths from settings.json to mcp.json for all
    platforms (Windows, macOS, Linux)
  • Removed mcp root key wrapping in _load_config() method, now returns
    config with servers at root level
  • Updated _save_config() to save config directly without nesting under
    mcp key
  • Added support for inputs array at root level per VS Code MCP
    specification
  • Simplified config structure handling and improved docstrings
+25/-27 
Tests
test_vscode.py
Add comprehensive test suite for VSCode manager                   

tests/test_clients/test_vscode.py

  • Added 18 comprehensive tests for VSCodeManager covering
    platform-specific config paths (macOS, Windows, Linux)
  • Tests validate correct config structure with servers at root level and
    inputs array
  • Added tests for CRUD operations: add_server(), get_server(),
    remove_server(), list_servers()
  • Added tests for format conversion methods to_client_format() and
    from_client_format()
  • Included edge case tests for empty configs, invalid JSON, missing
    files, and config migration compatibility
+336/-0 

@coderabbitai

coderabbitai Bot commented Jan 15, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI and others added 4 commits January 15, 2026 03:07
…ucture

- Change config file paths from settings.json to mcp.json
  - macOS: ~/Library/Application Support/Code/User/mcp.json
  - Windows: %APPDATA%/Code/User/mcp.json
  - Linux: ~/.config/Code/User/mcp.json
- Remove mcp root key wrapping in _load_config and _save_config
- Support servers and inputs at root level per VS Code docs
- Add comprehensive test suite for VSCode manager

Fixes #295

Co-authored-by: JoJoJoJoJoJoJo <23650418+JoJoJoJoJoJoJo@users.noreply.github.com>
Use tempfile.gettempdir() instead of hardcoded /tmp/ path for Windows compatibility

Co-authored-by: JoJoJoJoJoJoJo <23650418+JoJoJoJoJoJoJo@users.noreply.github.com>
Remove redundant import from method body

Co-authored-by: JoJoJoJoJoJoJo <23650418+JoJoJoJoJoJoJo@users.noreply.github.com>
- Update _load_config docstring to reflect full return structure
- Capitalize MCP consistently in test comments

Co-authored-by: JoJoJoJoJoJoJo <23650418+JoJoJoJoJoJoJo@users.noreply.github.com>
Copilot AI changed the title [WIP] Update VS Code client manager to edit mcp.json fix: Update VSCode manager to use mcp.json with correct structure Jan 15, 2026
Copilot AI requested a review from JoJoJoJoJoJoJo January 15, 2026 03:14
@JoJoJoJoJoJoJo
JoJoJoJoJoJoJo marked this pull request as ready for review January 15, 2026 03:29
Copilot AI review requested due to automatic review settings January 15, 2026 03:29
@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Stack trace exposed: _save_config() calls traceback.print_exc() which can expose internal stack traces to
end-users/console output rather than restricting detailed diagnostics to secure internal
logs.

Referred Code
except Exception as e:
    logger.error(f"Error saving client config: {str(e)}")
    traceback.print_exc()

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit context: Configuration read/write operations only emit basic warnings/errors without user identity,
action outcome context, or an auditable event record, which may be insufficient if these
operations are considered critical in production.

Referred Code
logger.warning(f"Client config file not found at: {self.config_path}")
return empty_config

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Unhandled IO errors: _load_config() only handles json.JSONDecodeError and may still raise on
filesystem/permission errors (e.g., OSError, PermissionError), which reduces graceful
degradation for common edge cases.

Referred Code
try:
    with open(self.config_path, "r", encoding="utf-8") as f:
        config = json.load(f)
        # Ensure servers section exists
        if self.configure_key_name not in config:
            config[self.configure_key_name] = {}
        # Ensure inputs array exists
        if "inputs" not in config:
            config["inputs"] = []
        return config
except json.JSONDecodeError:
    logger.error(f"Error parsing client config file: {self.config_path}")

return empty_config

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Unstructured error logs: Logging is plain-text f-strings (and includes exception text) rather than structured
logging, and may inadvertently include sensitive local paths or error details depending on
runtime exceptions.

Referred Code
    logger.warning(f"Client config file not found at: {self.config_path}")
    return empty_config

try:
    with open(self.config_path, "r", encoding="utf-8") as f:
        config = json.load(f)
        # Ensure servers section exists
        if self.configure_key_name not in config:
            config[self.configure_key_name] = {}
        # Ensure inputs array exists
        if "inputs" not in config:
            config["inputs"] = []
        return config
except json.JSONDecodeError:
    logger.error(f"Error parsing client config file: {self.config_path}")

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Config not validated: Loaded JSON content is minimally normalized (keys ensured) but not validated for expected
types/shapes (e.g., ensuring servers is a dict and inputs is a list), which could lead to
unsafe or unexpected behavior with malformed external files.

Referred Code
# Ensure servers section exists
if self.configure_key_name not in config:
    config[self.configure_key_name] = {}
# Ensure inputs array exists
if "inputs" not in config:
    config["inputs"] = []
return config

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Implement migration for existing VSCode configurations

Implement a one-time migration to move existing user configurations from the old
settings.json to the new mcp.json file. This prevents data loss caused by the
breaking change in configuration location and format.

Examples:

src/mcpm/clients/managers/vscode.py [36-56]
    def _load_config(self) -> Dict[str, Any]:
        """Load client configuration file

        {
            "servers": {
                "server_name": {
                    ...
                }
            },
            "inputs": []

 ... (clipped 11 lines)

Solution Walkthrough:

Before:

class VSCodeManager(JSONClientManager):
    def __init__(self, ...):
        # ...
        # self.config_path is set to '.../mcp.json'
        # ...

    def _load_config(self):
        # Creates an empty config if 'mcp.json' does not exist.
        # It does not check for the old 'settings.json'.
        if not os.path.exists(self.config_path):
            return {"servers": {}, "inputs": []}

        # Loads config from 'mcp.json'
        with open(self.config_path, "r") as f:
            config = json.load(f)
        return config

After:

class VSCodeManager(JSONClientManager):
    def __init__(self, ...):
        # ...
        self.config_path = '.../mcp.json'
        self._migrate_config_if_needed()

    def _migrate_config_if_needed(self):
        # If new config doesn't exist, check for old one
        if os.path.exists(self.config_path):
            return

        old_path = self.config_path.replace("mcp.json", "settings.json")
        if os.path.exists(old_path):
            with open(old_path, "r") as f:
                old_config = json.load(f)
            if "mcp" in old_config and "servers" in old_config["mcp"]:
                new_config = {"servers": old_config["mcp"]["servers"], "inputs": []}
                # Save migrated config to the new 'mcp.json' path
                self._save_config(new_config)
Suggestion importance[1-10]: 10

__

Why: This suggestion correctly identifies a critical flaw in the PR that would cause data loss for existing users, and proposes a necessary migration path to ensure a seamless transition.

High
Possible issue
Validate loaded config type

In _load_config, validate that the loaded JSON from the config file is a
dictionary. If not, log a warning and return a default empty configuration to
prevent potential runtime errors.

src/mcpm/clients/managers/vscode.py [59-67]

 with open(self.config_path, "r", encoding="utf-8") as f:
-    config = json.load(f)
+    loaded = json.load(f)
+    if not isinstance(loaded, dict):
+        logger.warning(f"Unexpected config format, expected dict but got {type(loaded).__name__}")
+        return empty_config
+    config = loaded
     # Ensure servers section exists
     if self.configure_key_name not in config:
         config[self.configure_key_name] = {}
     # Ensure inputs array exists
     if "inputs" not in config:
         config["inputs"] = []
     return config
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: This is a good defensive programming suggestion that improves the robustness of _load_config by handling cases where the config file contains valid JSON that is not a dictionary, preventing potential AttributeError or TypeError exceptions.

Low
General
Guard directory creation calls

In _save_config, before calling os.makedirs, check if the directory path derived
from self.config_path is non-empty. This prevents errors when
config_path_override is a bare filename.

src/mcpm/clients/managers/vscode.py [83-84]

-# Create directory if it doesn't exist
-os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
+dir_path = os.path.dirname(self.config_path)
+if dir_path:
+    os.makedirs(dir_path, exist_ok=True)
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies a potential edge case where os.path.dirname on a bare filename returns an empty string, which would cause os.makedirs to incorrectly try creating the current directory. This improves the robustness of the file saving logic.

Low
Avoid modifying loaded configuration in-place

In _load_config, avoid modifying the loaded configuration in-place. Create a
copy of the config dictionary before adding default keys like servers and inputs
to prevent unexpected side effects.

src/mcpm/clients/managers/vscode.py [58-71]

 try:
     with open(self.config_path, "r", encoding="utf-8") as f:
-        config = json.load(f)
-        # Ensure servers section exists
-        if self.configure_key_name not in config:
-            config[self.configure_key_name] = {}
-        # Ensure inputs array exists
-        if "inputs" not in config:
-            config["inputs"] = []
-        return config
+        loaded_config = json.load(f)
+
+    # Create a new config from the loaded one to avoid mutation
+    config = loaded_config.copy()
+
+    # Ensure servers section exists
+    if self.configure_key_name not in config:
+        config[self.configure_key_name] = {}
+    # Ensure inputs array exists
+    if "inputs" not in config:
+        config["inputs"] = []
+    return config
 except json.JSONDecodeError:
     logger.error(f"Error parsing client config file: {self.config_path}")
 
 return empty_config
  • Apply / Chat
Suggestion importance[1-10]: 4

__

Why: The suggestion correctly identifies that modifying the loaded config in-place is a potential source of side effects. Creating a copy before modification is a good practice for robustness, even if no immediate bug is present.

Low
  • More

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes the VSCode MCP configuration to use the correct file location (mcp.json) and structure as specified in the VS Code MCP documentation, replacing the previous incorrect implementation that targeted settings.json with a nested mcp wrapper.

Changes:

  • Updated config file paths from settings.json to mcp.json across all platforms (macOS, Windows, Linux)
  • Modified config structure to have servers at root level instead of nested under an mcp key
  • Added comprehensive test suite with 18 tests covering platform-specific paths, config structure validation, and CRUD operations

Reviewed changes

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

File Description
src/mcpm/clients/managers/vscode.py Updated config paths to mcp.json and restructured _load_config() and _save_config() methods to use servers at root level with inputs array
tests/test_clients/test_vscode.py Added comprehensive test coverage for VSCode manager including platform-specific path tests, config structure validation, and server CRUD operations

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/mcpm/clients/managers/vscode.py
Comment thread tests/test_clients/test_vscode.py
Comment thread tests/test_clients/test_vscode.py
Comment thread tests/test_clients/test_vscode.py
@JoJoJoJoJoJoJo
JoJoJoJoJoJoJo enabled auto-merge (squash) January 15, 2026 05:27
@JoJoJoJoJoJoJo
JoJoJoJoJoJoJo merged commit a1adc20 into main Jan 15, 2026
14 checks passed
@JoJoJoJoJoJoJo
JoJoJoJoJoJoJo deleted the copilot/update-vscode-config-file branch January 15, 2026 05:29
mcpm-semantic-release Bot pushed a commit that referenced this pull request Jan 15, 2026
# [2.13.0](v2.12.1...v2.13.0) (2026-01-15)

### Bug Fixes

* Update VSCode manager to use mcp.json with correct structure ([#300](#300)) ([a1adc20](a1adc20)), closes [#295](#295)

### Features

* Add MCP manifest for jotform-mcp-server ([#297](#297)) ([99564ab](99564ab))
* Add MCP manifest for ProfessionalWiki-MediaWiki-MCP-Server ([#293](#293)) ([eabf191](eabf191)), closes [#299](#299)
@mcpm-semantic-release

Copy link
Copy Markdown

🎉 This PR is included in version 2.13.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants