Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions examples/basic/agent_factory/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Core framework dependency
mcp-agent @ file://../../../ # Link to the local mcp-agent project root
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace file:// relative URL with an editable local path.

mcp-agent @ file://../../../ is a non‑portable/likely invalid file URL (PEP 508 expects an absolute file URL). Use an editable local path for consistency across pip/uv.

Apply:

-mcp-agent @ file://../../../  # Link to the local mcp-agent project root
+-e ../../../  # Install local mcp-agent in editable mode
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mcp-agent @ file://../../../ # Link to the local mcp-agent project root
-e ../../../ # Install local mcp-agent in editable mode
🤖 Prompt for AI Agents
In examples/basic/agent_factory/requirements.txt around line 2, replace the
non-portable PEP 508 file URL "mcp-agent @ file://../../../" with an editable
local path so pip/uv can install the local project: change the line to use pip's
editable syntax pointing to the project root (for example "-e ../../../") or an
absolute path if required by CI; ensure the comment remains if desired.


# Additional dependencies specific to this example
anthropic
openai
2 changes: 1 addition & 1 deletion examples/model_providers/mcp_basic_google_agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Before running the agent, ensure you have your Gemini Developer API or Vertex AI
- `vertexai`: Boolean flag to enable VertexAI integration (default: false)
- `project`: Google Cloud project ID (required if using VertexAI)
- `location`: Google Cloud location (required if using VertexAI)
- `default_model`: Defaults to "gemini-2.0-flash" but can be customized in your config
- `default_model`: Defaults to "gemini-2.5-flash" but can be customized in your config
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Document the new default_model more explicitly and add it to the sample config.

Good call on switching to "gemini-2.5-flash". Please also reflect this in the YAML example so users discover/override it easily.

Add to the snippet under the google section:

google:
  api_key: "your-google-api-key"
  vertexai: false
  # Include these if using VertexAI
  # project: "your-google-cloud-project"
  # location: "us-central1"
  # Optional override; falls back to gemini-2.5-flash if unset
  default_model: "gemini-2.5-flash"

Run this quick check to ensure no stale references remain to the old default:


🏁 Script executed:

#!/bin/bash
# Find any remaining mentions of gemini-2.0-flash or mixed 2-0 variants.
rg -nP --glob '!**/dist/**' '(gemini[-_.]?2[.-]0[-_.]?flash)'

Length of output: 148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Searching repository for legacy 'gemini-2.0-flash' variants (case-insensitive)..."
rg -n --hidden -uu -S '(?i)gemini[-_.]?2[.-]0[-_.]?flash' || true
echo

echo "Searching repository for new 'gemini-2.5-flash' mentions..."
rg -n --hidden -uu -S 'gemini[-_.]?2[.-]5[-_.]?flash' || true
echo

echo "Searching repository for 'default_model' occurrences..."
rg -n --hidden -uu -S 'default_model' || true
echo

echo "Printing the referenced README snippet if it exists:"
if [ -f examples/model_providers/mcp_basic_google_agent/README.md ]; then
  echo "---- README: examples/model_providers/mcp_basic_google_agent/README.md (lines 1-200) ----"
  sed -n '1,200p' examples/model_providers/mcp_basic_google_agent/README.md
else
  echo "README not found at examples/model_providers/mcp_basic_google_agent/README.md"
fi

Length of output: 27511


Document and unify Google default_model = "gemini-2.5-flash"

README already states gemini-2.5-flash — add an explicit default_model to the google sample config and replace remaining gemini-2.0-flash occurrences.

Files to update:

  • examples/model_providers/mcp_basic_google_agent/mcp_agent.config.yaml
  • examples/model_providers/mcp_basic_google_agent/mcp_agent.secrets.yaml.example
  • examples/model_providers/mcp_basic_google_agent/main.py
  • tests/workflows/llm/test_augmented_llm_google.py
  • tests/cli/fixtures/multi_provider_config.yaml
  • tests/cli/fixtures/realistic_mcp_configs/complex_integrations/mcp_agent.config.yaml
  • docs/configuration.mdx
  • docs/concepts/augmented-llms.mdx
    (also any other rg hits for "gemini-2.0-flash")

Add to the README google snippet:

google:
  api_key: "your-google-api-key"
  vertexai: false
  # Include these if using VertexAI
  # project: "your-google-cloud-project"
  # location: "us-central1"
  # Optional override; falls back to gemini-2.5-flash if unset
  default_model: "gemini-2.5-flash"
🤖 Prompt for AI Agents
In examples/model_providers/mcp_basic_google_agent/README.md around line 45, the
README mentions gemini-2.5-flash but the sample configs and code still reference
gemini-2.0-flash; add an explicit default_model entry to the google snippet and
update all occurrences to gemini-2.5-flash across the listed files.
Specifically: add default_model: "gemini-2.5-flash" to mcp_agent.config.yaml and
mcp_agent.secrets.yaml.example, update main.py to use
config.get("default_model", "gemini-2.5-flash") as the fallback, replace any
gemini-2.0-flash strings in the tests and fixtures
(tests/workflows/llm/test_augmented_llm_google.py,
tests/cli/fixtures/multi_provider_config.yaml,
tests/cli/fixtures/realistic_mcp_configs/complex_integrations/mcp_agent.config.yaml,
docs/configuration.mdx, docs/concepts/augmented-llms.mdx and any other matches)
and run tests to ensure no failing references remain.


You can provide these in one of the following ways:

Expand Down
7 changes: 7 additions & 0 deletions src/mcp_agent/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,13 @@ class GoogleSettings(BaseSettings, VertexAIMixin):
),
)

default_model: str | None = Field(
default=None,
validation_alias=AliasChoices(
"default_model", "GOOGLE_DEFAULT_MODEL", "google__default_model"
),
)

model_config = SettingsConfigDict(
env_prefix="GOOGLE_",
extra="allow",
Expand Down
18 changes: 9 additions & 9 deletions src/mcp_agent/data/artificial_analysis_llm_benchmarks.json
Original file line number Diff line number Diff line change
Expand Up @@ -8350,7 +8350,7 @@
}
},
{
"name": "gemini-2-5-pro",
"name": "gemini-2.5-pro",
"description": "Gemini 2.5 Pro (AI_Studio)",
"provider": "Google (AI_Studio)",
"context_window": 1000000,
Expand All @@ -8375,7 +8375,7 @@
}
},
{
"name": "gemini-2-5-pro",
"name": "gemini-2.5-pro",
"description": "Gemini 2.5 Pro Vertex",
"provider": "Google Vertex",
"context_window": 1000000,
Expand Down Expand Up @@ -9025,7 +9025,7 @@
}
},
{
"name": "gemini-2-5-flash-reasoning",
"name": "gemini-2.5-flash-reasoning",
"description": "Gemini 2.5 Flash (Reasoning) (AI_Studio)",
"provider": "Google (AI_Studio)",
"context_window": 1000000,
Expand All @@ -9050,7 +9050,7 @@
}
},
{
"name": "gemini-2-5-flash-reasoning",
"name": "gemini-2.5-flash-reasoning",
"description": "Gemini 2.5 Flash (Reasoning) (Vertex)",
"provider": "Google (Vertex)",
"context_window": 1000000,
Expand Down Expand Up @@ -9675,7 +9675,7 @@
}
},
{
"name": "gemini-2-5-flash",
"name": "gemini-2.5-flash",
"description": "Gemini 2.5 Flash (AI_Studio)",
"provider": "Google (AI_Studio)",
"context_window": 1000000,
Expand All @@ -9700,7 +9700,7 @@
}
},
{
"name": "gemini-2-5-flash",
"name": "gemini-2.5-flash",
"description": "Gemini 2.5 Flash (Vertex)",
"provider": "Google (Vertex)",
"context_window": 1000000,
Expand Down Expand Up @@ -12375,7 +12375,7 @@
}
},
{
"name": "gemini-2-5-flash-lite",
"name": "gemini-2.5-flash-lite",
"description": "Gemini 2.5 Flash-Lite (AI Studio)",
"provider": "Google (AI Studio)",
"context_window": 1000000,
Expand All @@ -12400,7 +12400,7 @@
}
},
{
"name": "gemini-2-5-flash-lite-reasoning",
"name": "gemini-2.5-flash-lite-reasoning",
"description": "Gemini 2.5 Flash-Lite (Reasoning) (AI\n Studio)",
"provider": "Google (AI Studio)",
"context_window": 1000000,
Expand Down Expand Up @@ -13149,4 +13149,4 @@
}
}
}
]
]
54 changes: 49 additions & 5 deletions src/mcp_agent/workflows/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ async def create_router_llm(
functions: List[Callable] | None = None,
routing_instruction: str | None = None,
name: str | None = None,
provider: SupportedRoutingProviders = "openai",
provider: SupportedLLMProviders = "openai",
model: str | ModelPreferences | None = None,
request_params: RequestParams | None = None,
context: Context | None = None,
Expand Down Expand Up @@ -185,8 +185,22 @@ async def create_router_llm(
**kwargs,
)
else:
raise ValueError(
f"Unsupported routing provider: {provider}. Currently supported providers are: ['openai', 'anthropic']. To request support, please create an issue at https://github.com/lastmile-ai/mcp-agent/issues"
factory = _llm_factory(
provider=provider,
model=model,
request_params=request_params,
context=context,
)

return await LLMRouter.create(
name=name,
llm_factory=factory,
server_names=server_names,
agents=normalized_agents,
functions=functions,
routing_instruction=routing_instruction,
context=context,
**kwargs,
)
Comment on lines +188 to 204
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Router path: llm_factory currently drops classifier instruction (behavioral regression).

LLMRouter calls llm_factory with instruction/context. Your _llm_factory returns a lambda that doesn’t accept these kwargs, triggering the TypeError fallback and creating the classifier LLM without the routing instruction. That will degrade routing quality/non‑deterministically change behavior.

Apply the fix in my comment on Lines 1037-1041 to accept and forward instruction/name.

🤖 Prompt for AI Agents
In src/mcp_agent/workflows/factory.py around lines 188 to 204, the llm_factory
produced by _llm_factory currently returns a lambda that does not accept the
instruction/name kwargs, causing LLMRouter to hit the TypeError fallback and
drop the routing/classifier instruction; update the factory so the returned
callable accepts and forwards instruction and name (or simply **kwargs) into the
underlying LLM creation call (preserving existing
provider/model/request_params/context) so that any routing_instruction or name
passed by LLMRouter is propagated to the created LLM.



Expand Down Expand Up @@ -974,9 +988,20 @@ def _llm_factory(
request_params: RequestParams | None = None,
context: Context | None = None,
) -> Callable[[Agent], AugmentedLLM]:
# Allow model to come from an explicit string, request_params.model,
# or request_params.modelPreferences (to run selection) in that order.
# Compute the chosen model by precedence:
# 1) explicit model_name from _select_provider_and_model (includes ModelPreferences)
# 2) provider default from provider_cls.get_provider_config(context)
# 3) provider hardcoded fallback
model_selector_input = (
model
or getattr(request_params, "model", None)
or getattr(request_params, "modelPreferences", None)
)
prov, model_name = _select_provider_and_model(
provider=provider,
model=model or getattr(request_params, "model", None),
model=model_selector_input,
context=context,
)
provider_cls = _get_provider_class(prov)
Expand All @@ -990,9 +1015,28 @@ def _default_params() -> RequestParams | None:
return RequestParams(modelPreferences=model)
return None

# Merge provider-selected or configured default model into RequestParams if missing.
effective_params: RequestParams | None = request_params
if effective_params is not None:
chosen_model: str | None = model_name

if not chosen_model:
cfg_obj = None
try:
cfg_obj = provider_cls.get_provider_config(context)
except Exception:
cfg_obj = None
if cfg_obj is not None:
chosen_model = getattr(cfg_obj, "default_model", None)

# If the user did not specify a model in RequestParams, but provided other
# overrides (maxTokens, temperature, etc.), fill in the model only.
if getattr(effective_params, "model", None) is None and chosen_model:
effective_params.model = chosen_model

return lambda agent: provider_cls(
agent=agent,
default_request_params=request_params or _default_params(),
default_request_params=effective_params or _default_params(),
context=context,
)
Comment on lines 1037 to 1041
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Pass instruction/name through llm_factory and avoid TypeError fallback.

Make the factory accept optional kwargs and forward instruction/name to provider_cls.

-    return lambda agent: provider_cls(
-        agent=agent,
-        default_request_params=effective_params or _default_params(),
-        context=context,
-    )
+    def _factory(agent, instruction=None, name=None, **_):
+        return provider_cls(
+            agent=agent,
+            instruction=instruction,
+            name=name,
+            default_request_params=effective_params or _default_params(),
+            context=context,
+        )
+    return _factory
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return lambda agent: provider_cls(
agent=agent,
default_request_params=request_params or _default_params(),
default_request_params=effective_params or _default_params(),
context=context,
)
def _factory(agent, instruction=None, name=None, **_):
return provider_cls(
agent=agent,
instruction=instruction,
name=name,
default_request_params=effective_params or _default_params(),
context=context,
)
return _factory
🤖 Prompt for AI Agents
In src/mcp_agent/workflows/factory.py around lines 1037 to 1041, the returned
lambda currently only accepts an agent and always calls provider_cls with fixed
args, causing issues when callers pass instruction/name (which fall back to a
TypeError). Change the factory to accept optional kwargs (e.g., def
llm_factory(agent, **kwargs):) and forward those kwargs into the provider_cls
call (provider_cls(agent=agent, default_request_params=effective_params or
_default_params(), context=context, **kwargs)) so instruction/name are passed
through and the TypeError fallback is avoided.


Expand Down
6 changes: 6 additions & 0 deletions src/mcp_agent/workflows/llm/augmented_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,12 @@ async def generate_structured(
) -> ModelT:
"""Request a structured LLM generation and return the result as a Pydantic model."""

# Provider configuration access
@classmethod
@abstractmethod
def get_provider_config(cls, context: Optional["Context"]):
"""Return the provider-specific settings object from the app context, or None."""

async def select_model(
self, request_params: RequestParams | None = None
) -> str | None:
Expand Down
4 changes: 4 additions & 0 deletions src/mcp_agent/workflows/llm/augmented_llm_anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ def __init__(self, *args, **kwargs):
use_history=True,
)

@classmethod
def get_provider_config(cls, context):
return getattr(getattr(context, "config", None), "anthropic", None)

@track_tokens()
async def generate(
self,
Expand Down
4 changes: 4 additions & 0 deletions src/mcp_agent/workflows/llm/augmented_llm_azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ def __init__(self, *args, **kwargs):
use_history=True,
)

@classmethod
def get_provider_config(cls, context):
return getattr(getattr(context, "config", None), "azure", None)

@track_tokens()
async def generate(self, message, request_params: RequestParams | None = None):
"""
Expand Down
4 changes: 4 additions & 0 deletions src/mcp_agent/workflows/llm/augmented_llm_bedrock.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ def __init__(self, *args, **kwargs):
use_history=True,
)

@classmethod
def get_provider_config(cls, context):
return getattr(getattr(context, "config", None), "bedrock", None)

@track_tokens()
async def generate(self, message, request_params: RequestParams | None = None):
"""
Expand Down
8 changes: 6 additions & 2 deletions src/mcp_agent/workflows/llm/augmented_llm_google.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def __init__(self, *args, **kwargs):
intelligencePriority=0.3,
)
# Get default model from config if available
default_model = "gemini-2.0-flash" # Fallback default
default_model = "gemini-2.5-flash" # Fallback default

if self.context.config.google:
if hasattr(self.context.config.google, "default_model"):
Expand Down Expand Up @@ -238,6 +238,10 @@ async def generate_str(

return response.text or ""

@classmethod
def get_provider_config(cls, context):
return getattr(getattr(context, "config", None), "google", None)

async def generate_structured(
self,
message,
Expand All @@ -250,7 +254,7 @@ async def generate_structured(
import json

params = self.get_request_params(request_params)
model = await self.select_model(params) or (params.model or "gemini-2.0-flash")
model = await self.select_model(params) or (params.model or "gemini-2.5-flash")

# Convert input messages and build config
messages = GoogleConverter.convert_mixed_messages_to_google(message)
Expand Down
5 changes: 5 additions & 0 deletions src/mcp_agent/workflows/llm/augmented_llm_ollama.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ def __init__(self, *args, **kwargs):

self.provider = "Ollama"

@classmethod
def get_provider_config(cls, context):
# Uses the OpenAI-compatible config (base_url, api_key) for Ollama
return getattr(getattr(context, "config", None), "openai", None)

async def generate_structured(
self,
message,
Expand Down
4 changes: 4 additions & 0 deletions src/mcp_agent/workflows/llm/augmented_llm_openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ def __init__(self, *args, **kwargs):
use_history=True,
)

@classmethod
def get_provider_config(cls, context):
return getattr(getattr(context, "config", None), "openai", None)

@classmethod
def convert_message_to_message_param(
cls, message: ChatCompletionMessage, **kwargs
Expand Down
Loading