Skip to content

feat (mcp-conf): Project-level MCP configuration with merge/override strategy#2349

Open
asanisimov wants to merge 2 commits into
MoonshotAI:mainfrom
asanisimov:feat/overwriting-project-mcp-conf
Open

feat (mcp-conf): Project-level MCP configuration with merge/override strategy#2349
asanisimov wants to merge 2 commits into
MoonshotAI:mainfrom
asanisimov:feat/overwriting-project-mcp-conf

Conversation

@asanisimov
Copy link
Copy Markdown

@asanisimov asanisimov commented May 23, 2026

Related Issue

#1365

We've encountered similar limitations on our projects and, for now, have decided to maintain changes in our fork and rebase them ourselves. We'd appreciate the community's PR review and are open to improvements.

Description

This PR introduces project-level MCP configuration and a configurable merge strategy for combining MCP configs from multiple sources.

What changed

  • Project-level MCP config: kimi-cli now auto-discovers .kimi/mcp.json inside the working directory. If it exists, it is treated as the project-level MCP config.
  • Merge strategy: a new mcp.merge_strategy config field controls how configs from different sources are combined.
  • Unified collection logic: all entry points (CLI, ACP server, web worker) now use the same collect_file_mcp_configs() helper so behavior is consistent across UIs.
  • Help text updated: --mcp-config-file now documents the automatic project-level fallback.

Source priority (lowest → highest)

  1. Global ~/.kimi/mcp.json
  2. Project <work_dir>/.kimi/mcp.json
  3. Explicit --mcp-config-file paths
  4. Raw --mcp-config JSON strings

merge_strategy

Strategy Behavior
override (default) Use only the highest-priority source that is defined. Explicit inputs beat project config, which beats global config.
merge Return all available layers in priority order. Later layers override duplicate server names when the toolset merges them.

Configuration examples

Project-level config (my-project/.kimi/mcp.json):

{
  "mcpServers": {
    "project-docs": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project/docs"]
    }
  }
}

Global config (~/.kimi/mcp.json):

  {
    "mcpServers": {
      "filesystem": {
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem"]
      }
    }
  }

Config file (~/.kimi/config.toml):

 [mcp]
  merge_strategy = "override"   # or "merge"

Behavior examples

Scenario A — override (default): project isolates its own servers

You have a global filesystem server, but inside my-project you only want project-docs.

• ~/.kimi/mcp.json defines filesystem
• my-project/.kimi/mcp.json defines project-docs
• Running kimi --work-dir my-project loads only project-docs

Scenario B — merge: combine global and project servers

  [mcp]
  merge_strategy = "merge"

With the same files as above, both filesystem and project-docs are available. If a server name collides, the project config wins.

Scenario C — explicit --mcp-config-file wins

kimi --mcp-config-file ./explicit.json

In override mode, ./explicit.json is the only config loaded, even if a project .kimi/mcp.json exists.

Coverage

The feature is active in:
• CLI (interactive shell, --print, one-shot mode)
• ACP server (IDE integrations via the ACP protocol)
• Web worker (web UI sessions)

Tests

─────

Added tests/cli/test_project_mcp_config.py with 14 tests covering:
• get_project_mcp_config_file discovery
• collect_file_mcp_configs for both merge and override strategies
• Duplicate-name handling in merge mode
• Fallback chains (project → global, explicit → project, etc.)
• CLI integration via CliRunner
• ACP server integration (async)
Existing tests/core/test_plan_flag.py patches were updated to match the new import paths.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked the related issue, if any.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have run make gen-changelog to update the changelog.
  • I have run make gen-docs to update the user documentation.

Open in Devin Review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe2ba8e679

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

path=default_mcp_file,
)
# Load MCP config files according to merge_strategy.
work_dir = session.dir
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use project root when loading web worker MCP configs

The web worker now calls collect_file_mcp_configs() with session.dir, which points to the session storage directory under ~/.kimi/sessions/..., not the user’s project workspace. As a result, project-level MCP config discovery (<work_dir>/.kimi/mcp.json) never finds the project file in web sessions, so web mode silently falls back to global/default MCP config and ignores project-specific servers. This breaks the new project-level MCP behavior for the web workflow.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

path=default_mcp_file,
)
# Load MCP config files according to merge_strategy.
work_dir = session.dir
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.

🔴 Web worker uses session storage directory instead of project working directory for MCP config discovery

In src/kimi_cli/web/runner/worker.py:34, work_dir = session.dir assigns the session's internal storage directory (e.g., ~/.kimi/sessions/<hash>/<session_id>/) to work_dir. This is then passed to collect_file_mcp_configs(strategy, work_dir=work_dir) which looks for .kimi/mcp.json inside work_dir. Since the session storage directory will never contain a .kimi/mcp.json project config, the project-level MCP config discovery will always fail silently in the web worker. The correct directory is the project working directory, accessible via session.work_dir (a KaosPath). Other call sites use session.work_dir.unsafe_to_local_path() or Path(str(session.work_dir)) for this purpose (see src/kimi_cli/web/api/sessions.py:480 and src/kimi_cli/web/api/sessions.py:959).

Suggested change
work_dir = session.dir
work_dir = session.work_dir.unsafe_to_local_path()
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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