Skip to content
Merged
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
157 changes: 47 additions & 110 deletions schema/mcp-agent.config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,18 @@
"default": false,
"title": "Vertexai",
"type": "boolean"
},
"default_model": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Default Model"
}
},
"title": "GoogleSettings",
Expand Down Expand Up @@ -774,95 +786,6 @@
"title": "MCPSettings",
"type": "object"
},
"OTelConsoleExporterSettings": {
Copy link
Member

Choose a reason for hiding this comment

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

Unrelated, but I suppose we can also clean up the fallback handling for the deprecated settings now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes will do

"additionalProperties": true,
"properties": {
"type": {
"const": "console",
"default": "console",
"title": "Type",
"type": "string"
}
},
"title": "OTelConsoleExporterSettings",
"type": "object"
},
"OTelFileExporterSettings": {
"additionalProperties": true,
"properties": {
"type": {
"const": "file",
"default": "file",
"title": "Type",
"type": "string"
},
"path": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Path"
},
"path_settings": {
"anyOf": [
{
"$ref": "#/$defs/TracePathSettings"
},
{
"type": "null"
}
],
"default": null
}
},
"title": "OTelFileExporterSettings",
"type": "object"
},
"OTelOTLPExporterSettings": {
"additionalProperties": true,
"properties": {
"type": {
"const": "otlp",
"default": "otlp",
"title": "Type",
"type": "string"
},
"endpoint": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Endpoint"
},
"headers": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"title": "Headers"
}
},
"title": "OTelOTLPExporterSettings",
"type": "object"
},
"OpenAISettings": {
"additionalProperties": true,
"description": "Settings for using OpenAI models in the MCP Agent application.",
Expand Down Expand Up @@ -956,28 +879,16 @@
"exporters": {
"default": [],
"items": {
"discriminator": {
"mapping": {
"console": "#/$defs/OTelConsoleExporterSettings",
"file": "#/$defs/OTelFileExporterSettings",
"otlp": "#/$defs/OTelOTLPExporterSettings"
},
"propertyName": "type"
},
"oneOf": [
{
"$ref": "#/$defs/OTelConsoleExporterSettings"
},
{
"$ref": "#/$defs/OTelFileExporterSettings"
},
{
"$ref": "#/$defs/OTelOTLPExporterSettings"
}
]
"enum": [
"console",
"file",
"otlp"
],
"type": "string"
},
"title": "Exporters",
"type": "array"
"type": "array",
"description": "List of exporters to use (can enable multiple simultaneously)"
},
"service_name": {
"default": "mcp-agent",
Expand Down Expand Up @@ -1024,7 +935,7 @@
}
],
"default": null,
"description": "Deprecated single OTLP settings. Prefer exporters list with type \"otlp\"."
"description": "OTLP settings for OpenTelemetry tracing. Required if using otlp exporter."
},
"path": {
"anyOf": [
Expand Down Expand Up @@ -1268,6 +1179,32 @@
"additionalProperties": true,
"description": "Configuration schema for MCP Agent applications",
"properties": {
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Name",
"description": "The name of the MCP application"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Description",
"description": "The description of the MCP application"
},
"mcp": {
"anyOf": [
{
Expand Down
12 changes: 8 additions & 4 deletions src/mcp_agent/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,6 @@ def __init__(
initialize_model_selector: Initializes the built-in ModelSelector to help with model selection. Defaults to False.
"""
self.mcp = mcp
self.name = name or (mcp.name if mcp else None)
self.description = description or (
mcp.instructions if mcp else "MCP Agent Application"
)

# We use these to initialize the context in initialize()
if settings is None:
Expand All @@ -114,6 +110,14 @@ def __init__(
else:
self._config = settings

self.name = name or self._config.name or (mcp.name if mcp else None)

self.description = (
description
or self._config.description
or (mcp.instructions if mcp else "MCP Agent Application")
)

# We initialize the task and decorator registries at construction time
# (prior to initializing the context) to ensure that they are available
# for any decorators that are applied to the workflow or task methods.
Expand Down
101 changes: 86 additions & 15 deletions src/mcp_agent/cli/cloud/commands/deploy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
create_git_tag,
sanitize_git_ref_component,
)
from mcp_agent.config import get_settings

from .wrangler_wrapper import wrangler_deploy

Expand All @@ -57,11 +58,22 @@ def deploy_config(
"-d",
help="Description of the MCP App being deployed.",
),
config_dir: Path = typer.Option(
Path(""),
config_dir: Optional[Path] = typer.Option(
None,
"--config-dir",
"-c",
help="Path to the directory containing the app config and app files.",
help="Path to the directory containing the app config and app files."
" If relative, it is resolved against --working-dir.",
readable=True,
dir_okay=True,
file_okay=False,
resolve_path=False,
),
working_dir: Path = typer.Option(
Path("."),
"--working-dir",
"-w",
help="Working directory to resolve config and bundle files from. Defaults to the current directory.",
exists=True,
readable=True,
dir_okay=True,
Expand Down Expand Up @@ -126,12 +138,45 @@ def deploy_config(
Returns:
Newly-deployed MCP App ID
"""
# Show help if no app_name is provided
if app_name is None:
typer.echo(ctx.get_help())
raise typer.Exit()

try:
if config_dir is None:
resolved_config_dir = working_dir
elif config_dir.is_absolute():
resolved_config_dir = config_dir
else:
resolved_config_dir = working_dir / config_dir

if not resolved_config_dir.exists() or not resolved_config_dir.is_dir():
raise CLIError(
f"Configuration directory '{resolved_config_dir}' does not exist or is not a directory.",
retriable=False,
)

config_dir = resolved_config_dir

config_file, secrets_file, deployed_secrets_file = get_config_files(config_dir)

default_app_name, default_app_description = _get_app_info_from_config(
config_file
)

if app_name is None:
if default_app_name:
print_info(
f"No app name provided. Using '{default_app_name}' from configuration."
)
app_name = default_app_name
else:
app_name = "default"
print_info("No app name provided. Using 'default' as app name.")

if app_description is None:
if default_app_description:
print_info(
"No app description provided. Using description from configuration."
)
app_description = default_app_description

Comment on lines +157 to +179
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix fallback: use directory name when config has no name (test blocker)

Current code defaults to "default" when CLI name and config name are missing; tests expect config_dir.name. Apply this change.

-        if app_name is None:
-            if default_app_name:
-                print_info(
-                    f"No app name provided. Using '{default_app_name}' from configuration."
-                )
-                app_name = default_app_name
-            else:
-                app_name = "default"
-                print_info("No app name provided. Using 'default' as app name.")
+        if app_name is None:
+            if default_app_name:
+                print_info(
+                    f"No app name provided. Using '{default_app_name}' from configuration."
+                )
+                app_name = default_app_name
+            else:
+                # Fallback: use directory name when config does not define one
+                app_name = config_dir.name
+                print_info(
+                    f"No app name provided. Using directory name '{app_name}' as app name."
+                )

After this change, test_deploy_defaults_to_directory_name_when_config_missing_name should pass.

Also applies to: 163-172


🏁 Script executed:

#!/usr/bin/env bash
set -eux

# Print lines 130-230 for context in main.py
sed -n '130,230p' src/mcp_agent/cli/cloud/commands/deploy/main.py || true

# Search for the specific test
rg -n "test_deploy_defaults_to_directory_name_when_config_missing_name" -C3 -g "*.py" . || true

Length of output: 4743


Fix fallback: use directory name when config has no name

File: src/mcp_agent/cli/cloud/commands/deploy/main.py
Replace the "default" fallback under if app_name is None with config_dir.name so the test passes:

-        if app_name is None:
-            if default_app_name:
-                print_info(
-                    f"No app name provided. Using '{default_app_name}' from configuration."
-                )
-                app_name = default_app_name
-            else:
-                app_name = "default"
-                print_info("No app name provided. Using 'default' as app name.")
+        if app_name is None:
+            if default_app_name:
+                print_info(
+                    f"No app name provided. Using '{default_app_name}' from configuration."
+                )
+                app_name = default_app_name
+            else:
+                # Fallback: use directory name when config does not define one
+                app_name = config_dir.name
+                print_info(
+                    f"No app name provided. Using directory name '{app_name}' as app name."
+                )

After this change, test_deploy_defaults_to_directory_name_when_config_missing_name will pass.

📝 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
config_file, secrets_file, deployed_secrets_file = get_config_files(config_dir)
default_app_name, default_app_description = _get_app_info_from_config(
config_file
)
if app_name is None:
if default_app_name:
print_info(
f"No app name provided. Using '{default_app_name}' from configuration."
)
app_name = default_app_name
else:
app_name = "default"
print_info("No app name provided. Using 'default' as app name.")
if app_description is None:
if default_app_description:
print_info(
"No app description provided. Using description from configuration."
)
app_description = default_app_description
if app_name is None:
if default_app_name:
print_info(
f"No app name provided. Using '{default_app_name}' from configuration."
)
app_name = default_app_name
else:
# Fallback: use directory name when config does not define one
app_name = config_dir.name
print_info(
f"No app name provided. Using directory name '{app_name}' as app name."
)
🤖 Prompt for AI Agents
In src/mcp_agent/cli/cloud/commands/deploy/main.py around lines 157 to 179, the
fallback that sets app_name to the literal "default" when no app name is
provided should be replaced to use the directory name; change the assignment to
set app_name = config_dir.name and update the accompanying print_info message to
reflect using the config directory name instead of the string "default".

provided_key = api_key
effective_api_url = api_url or settings.API_BASE_URL
effective_api_key = (
Expand Down Expand Up @@ -174,7 +219,8 @@ def deploy_config(
)
if not non_interactive:
use_existing = typer.confirm(
f"Do you want deploy an update to the existing app ID: {app_id}?"
f"Do you want deploy an update to the existing app ID: {app_id}?",
default=True,
)
if use_existing:
print_info(f"Will deploy an update to app ID: {app_id}")
Expand All @@ -195,9 +241,6 @@ def deploy_config(
except Exception as e:
raise CLIError(f"Error checking or creating app: {str(e)}") from e

# Validate config directory and required files
config_file, secrets_file, deployed_secrets_file = get_config_files(config_dir)

# If a deployed secrets file already exists, determine if it should be used or overwritten
if deployed_secrets_file:
if secrets_file:
Expand All @@ -209,10 +252,11 @@ def deploy_config(
"--non-interactive specified, using existing deployed secrets file without changes."
)
else:
update = typer.confirm(
f"Do you want to update the existing '{MCP_DEPLOYED_SECRETS_FILENAME}' by re-processing '{MCP_SECRETS_FILENAME}'?"
reuse = typer.confirm(
f"Do you want to reuse the previously deployed secrets in '{MCP_DEPLOYED_SECRETS_FILENAME}'?",
default=True,
)
if update:
if not reuse:
print_info(
f"Will update existing '{MCP_DEPLOYED_SECRETS_FILENAME}' by re-processing '{MCP_SECRETS_FILENAME}'."
)
Expand Down Expand Up @@ -443,3 +487,30 @@ def get_config_files(config_dir: Path) -> tuple[Path, Optional[Path], Optional[P
deployed_secrets_file = deployed_secrets_path

return config_file, secrets_file, deployed_secrets_file


def _get_app_info_from_config(config_file: Path) -> Optional[tuple[str, str]]:
"""Return a default deployment name sourced from configuration if available."""

try:
loaded_settings = get_settings(
config_path=str(config_file),
set_global=False,
)
except Exception:
return None, None

app_name = (
loaded_settings.name
if isinstance(loaded_settings.name, str) and loaded_settings.name.strip()
else None
)

app_description = (
loaded_settings.description
if isinstance(loaded_settings.description, str)
and loaded_settings.description.strip()
else None
)

return app_name, app_description
6 changes: 6 additions & 0 deletions src/mcp_agent/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,12 @@ class Settings(BaseSettings):
nested_model_default_partial_update=True,
) # Customize the behavior of settings here

name: str | None = None
"""The name of the MCP application"""

description: str | None = None
"""The description of the MCP application"""

mcp: MCPSettings | None = Field(default_factory=MCPSettings)
"""MCP config, such as MCP servers"""

Expand Down
Loading
Loading