Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions aider/coders/agent_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,8 @@
from datetime import datetime
from pathlib import Path

from litellm import experimental_mcp_client

from aider import urls, utils

# Import the change tracker
from aider.change_tracker import ChangeTracker

# Import similarity functions for tool usage analysis
from aider.helpers.similarity import (
cosine_similarity,
create_bigram_vector,
Expand All @@ -30,7 +24,7 @@

# Import skills helper for skills
from aider.helpers.skills import SkillsManager
from aider.mcp.server import LocalServer
from aider.mcp_support.server import LocalServer
from aider.repo import ANY_GIT_ERROR

# Import tool modules for registry
Expand Down Expand Up @@ -77,6 +71,25 @@
from .editblock_coder import do_replace, find_original_update_blocks, find_similar_lines


class _ExperimentalMCPClientProxy:
"""Lazy proxy to defer importing litellm.experimental_mcp_client."""

_client = None

def _get_client(self):
if self._client is None:
from litellm import experimental_mcp_client as client

self._client = client
return self._client

def __getattr__(self, name):
return getattr(self._get_client(), name)


experimental_mcp_client = _ExperimentalMCPClientProxy()


class AgentCoder(Coder):
"""Mode where the LLM autonomously manages which files are in context."""

Expand Down
22 changes: 20 additions & 2 deletions aider/coders/base_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from typing import List

import httpx
from litellm import experimental_mcp_client
from litellm.types.utils import ModelResponse
from prompt_toolkit.patch_stdout import patch_stdout
from rich.console import Console
Expand All @@ -42,7 +41,7 @@
from aider.io import ConfirmGroup, InputOutput
from aider.linter import Linter
from aider.llm import litellm
from aider.mcp.server import LocalServer
from aider.mcp_support.server import LocalServer
from aider.models import RETRY_TIMEOUT
from aider.reasoning_tags import (
REASONING_TAG,
Expand All @@ -61,6 +60,25 @@
from .chat_chunks import ChatChunks


class _ExperimentalMCPClientProxy:
"""Lazy proxy to defer importing litellm.experimental_mcp_client."""

_client = None

def _get_client(self):
if self._client is None:
from litellm import experimental_mcp_client as client

self._client = client
return self._client

def __getattr__(self, name):
return getattr(self._get_client(), name)


experimental_mcp_client = _ExperimentalMCPClientProxy()


class UnknownEditFormat(ValueError):
def __init__(self, edit_format, valid_formats):
self.edit_format = edit_format
Expand Down
2 changes: 1 addition & 1 deletion aider/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
from aider.history import ChatSummary
from aider.io import InputOutput
from aider.llm import litellm # noqa: F401; properly init litellm on launch
from aider.mcp import load_mcp_servers
from aider.mcp_support import load_mcp_servers
from aider.models import ModelSettings
from aider.onboarding import offer_openrouter_oauth, select_default_model
from aider.repo import ANY_GIT_ERROR, GitRepo
Expand Down
31 changes: 19 additions & 12 deletions aider/mcp/__init__.py → aider/mcp_support/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import json
from pathlib import Path

from aider.mcp.server import HttpStreamingServer, McpServer, SseServer

def _create_server_from_config(server_config, transport):
from .server import HttpStreamingServer, McpServer, SseServer

if transport == "stdio":
return McpServer(server_config)
if transport == "http":
return HttpStreamingServer(server_config)
if transport == "sse":
return SseServer(server_config)
return None


def _parse_mcp_servers_from_json_string(json_string, io, verbose=False, mcp_transport="stdio"):
Expand All @@ -21,12 +31,9 @@ def _parse_mcp_servers_from_json_string(json_string, io, verbose=False, mcp_tran
# Create a server config with name included
server_config["name"] = name
transport = server_config.get("transport", mcp_transport)
if transport == "stdio":
servers.append(McpServer(server_config))
elif transport == "http":
servers.append(HttpStreamingServer(server_config))
elif transport == "sse":
servers.append(SseServer(server_config))
server = _create_server_from_config(server_config, transport)
if server:
servers.append(server)

if verbose:
io.tool_output(f"Loaded {len(servers)} MCP servers from JSON string")
Expand Down Expand Up @@ -120,10 +127,9 @@ def _parse_mcp_servers_from_file(file_path, io, verbose=False, mcp_transport="st
# Create a server config with name included
server_config["name"] = name
transport = server_config.get("transport", mcp_transport)
if transport == "stdio":
servers.append(McpServer(server_config))
elif transport == "http":
servers.append(HttpStreamingServer(server_config))
server = _create_server_from_config(server_config, transport)
if server:
servers.append(server)

if verbose:
io.tool_output(f"Loaded {len(servers)} MCP servers from {file_path}")
Expand Down Expand Up @@ -169,6 +175,7 @@ def load_mcp_servers(mcp_servers, mcp_servers_file, io, verbose=False, mcp_trans
# and maybe it is actually prompt_toolkit's fault
# but this hack works swimmingly because ???
# so sure! why not
servers = [McpServer(json.loads('{"aider_default": {}}'))]
default_server = _create_server_from_config(json.loads('{"aider_default": {}}'), "stdio")
servers = [default_server] if default_server else []

return servers
File renamed without changes.
Loading