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
20 changes: 20 additions & 0 deletions examples/mcp/mcp_elicitation/cloud/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Deploying the elicitation example to the cloud

In `mcp_agent.secrets.yaml`, set your OpenAI `api_key`.

Then, in the current directory (`cloud`), run:

```bash
uv run mcp-agent deploy elicitation --config-dir .
```

Once deployed, you should see an app ID, and a URL in the output.
You can use the URL to access the MCP via e.g. the [MCP Inspector](https://github.com/modelcontextprotocol/inspector).
Add `/sse` to the end of the url, as the MCP is exposed as a server-sent events endpoint.
Do not forget to add an authorization header with your MCP-agent API key as the bearer token.

The app ID can be used to delete the example again afterward:

```bash
uv run mcp-agent cloud app delete --id=<app-id>
```
45 changes: 45 additions & 0 deletions examples/mcp/mcp_elicitation/cloud/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import logging

from mcp.server.fastmcp import Context
from pydantic import BaseModel, Field
from mcp_agent.app import MCPApp

# Initialize logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = MCPApp(
name="elicitation_demo",
description="Demo of workflow with elicitation"
)


# mcp_context for fastmcp context
@app.tool()
async def book_table(date: str, party_size: int, app_ctx: Context) -> str:
"""Book a table with confirmation"""

# Schema must only contain primitive types (str, int, float, bool)
class ConfirmBooking(BaseModel):
confirm: bool = Field(description="Confirm booking?")
notes: str = Field(default="", description="Special requests")

app.logger.info(f"Confirming the use wants to book a table for {party_size} on {date} via elicitation")
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a typo in the log message: "Confirming the use wants" should be "Confirming the user wants".

Suggested change
app.logger.info(f"Confirming the use wants to book a table for {party_size} on {date} via elicitation")
app.logger.info(f"Confirming the user wants to book a table for {party_size} on {date} via elicitation")

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.


result = await app.context.upstream_session.elicit(
message=f"Confirm booking for {party_size} on {date}?",
requestedSchema=ConfirmBooking.model_json_schema(),
)

app.logger.info(f"Result from confirmation: {result}")

if result.action == "accept":
data = ConfirmBooking.model_validate(result.content)
if data.confirm:
return f"Booked! Notes: {data.notes or 'None'}"
return "Booking cancelled"
elif result.action == "decline":
return "Booking declined"
elif result.action == "cancel":
return "Booking cancelled"

Copy link
Contributor

Choose a reason for hiding this comment

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

Missing return statement for the function. The book_table function can reach the end without returning a value when result.action is not 'accept', 'decline', or 'cancel'. This will cause the function to return None instead of a string, violating the return type annotation and potentially causing runtime errors in calling code that expects a string. Add a default return statement like 'return "Unknown action"' at the end of the function.

Suggested change
return "Unknown action"

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

15 changes: 15 additions & 0 deletions examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
$schema: ../../schema/mcp-agent.config.schema.json
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

Confirm $schema path.

From this file’s location, ../../schema/... may not exist. Broken schema refs degrade DX.

If it lives at repo-root schema/, adjust accordingly, e.g.:

-$schema: ../../schema/mcp-agent.config.schema.json
+$schema: ../../../../schema/mcp-agent.config.schema.json

🏁 Script executed:

#!/bin/bash
# Show where the config schema actually lives
fd -a 'mcp-agent.config.schema.json' -S -HI

Length of output: 137


🏁 Script executed:

#!/bin/bash
# Search for the schema file and compute relative path from the YAML file's directory.
yaml_path="examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml"
schema_name="mcp-agent.config.schema.json"

echo "PWD: $(pwd)"
echo "Looking for $schema_name..."

# 1) try find
echo "Using find..."
find . -type f -name "$schema_name" -print 2>/dev/null || true

# 2) try fd (if available) with correct separate flags
if command -v fd >/dev/null 2>&1; then
  echo "Using fd..."
  fd -H -I -S "$schema_name" || true
fi

# 3) try rg to list files then filter
if command -v rg >/dev/null 2>&1; then
  echo "Using rg..."
  rg --files | rg -nF "$schema_name" || true
fi

# Compute relative path(s) from YAML dir to each match (if any)
echo "Computing relative path(s) from $(dirname "$yaml_path") to matches..."
matches=$(find . -type f -name "$schema_name" -print 2>/dev/null || true)
if [ -n "$matches" ]; then
  while IFS= read -r f; do
    python - <<PY
import os
yaml_dir=os.path.normpath(os.path.dirname("$yaml_path"))
schema=os.path.normpath("$f")
print("FOUND:", schema)
print("RELATIVE_PATH:", os.path.relpath(schema, yaml_dir))
PY
  done <<< "$matches"
else
  echo "No matches found."
fi

Length of output: 558


Fix $schema path in examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml.

Schema is at schema/mcp-agent.config.schema.json; correct relative path from this YAML is ../../../../schema/mcp-agent.config.schema.json.

-$schema: ../../schema/mcp-agent.config.schema.json
+$schema: ../../../../schema/mcp-agent.config.schema.json
📝 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
$schema: ../../schema/mcp-agent.config.schema.json
$schema: ../../../../schema/mcp-agent.config.schema.json
🤖 Prompt for AI Agents
In examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml around line 1, the
$schema path is incorrect; update the value from
../../schema/mcp-agent.config.schema.json to the correct relative path
../../../../schema/mcp-agent.config.schema.json by editing line 1 so it points
to schema/mcp-agent.config.schema.json four levels up.


execution_engine: asyncio
logger:
transports: [file]
level: debug
path_settings:
path_pattern: "logs/mcp-agent-{unique_id}.jsonl"
unique_id: "timestamp" # Options: "timestamp" or "session_id"
timestamp_format: "%Y%m%d_%H%M%S"

openai:
# Secrets (API keys, etc.) are stored in an mcp_agent.secrets.yaml file which can be gitignored
# default_model: "o3-mini"
default_model: "gpt-4o-mini"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
$schema: ../../schema/mcp-agent.config.schema.json
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

🧩 Analysis chain

Schema reference likely incorrect for a secrets file.

$schema points to the config schema, which may cause false validation errors. Either point to a secrets schema if it exists or remove this line.

Apply this diff to remove it pending confirmation:

-$schema: ../../schema/mcp-agent.config.schema.json

🏁 Script executed:

#!/bin/bash
# Verify if a secrets schema exists and confirm the correct relative path
fd -a 'mcp-agent.*schema.json' -S -HI

Length of output: 137


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== schema files (case-insensitive) ==="
find . -type f -iname "*schema*.json" -print || true

echo
echo "=== files with 'mcp-agent' in name ==="
find . -type f -iname "*mcp-agent*.json" -print || true

echo
echo "=== files with 'secrets' and 'schema' in name ==="
find . -type f -iname "*secrets*schema*.json" -print || true

echo
echo "=== show target example file ==="
if [ -f "examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example" ]; then
  echo "FOUND: examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example"
  sed -n '1,200p' examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example
else
  echo "MISSING: examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example"
fi

echo
echo "=== listing 'schema' directory (if any) ==="
[ -d "schema" ] && ls -la schema || echo "schema directory not present"

Length of output: 681


Remove $schema from secrets example

This secrets example references the config schema (schema/mcp-agent.config.schema.json); there is no separate secrets schema — remove the $schema line to avoid false validation errors.

File: examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example — line 1

-$schema: ../../schema/mcp-agent.config.schema.json
📝 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
$schema: ../../schema/mcp-agent.config.schema.json
🤖 Prompt for AI Agents
In examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example around line
1, the file includes a $schema reference to
../../schema/mcp-agent.config.schema.json which is a config schema (there is no
separate secrets schema); remove the entire $schema line from this secrets
example to avoid false validation errors so the example only contains secret
keys/values without schema metadata.


openai:
api_key: openai_api_key

anthropic:
api_key: anthropic_api_key
6 changes: 6 additions & 0 deletions examples/mcp/mcp_elicitation/cloud/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Core framework dependency
mcp-agent

# Additional dependencies specific to this example
anthropic
openai
Comment on lines +2 to +6
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

🧩 Analysis chain

Pin and lock dependencies for reproducible cloud deploys.

Unpinned deps can break the example at deploy time. Prefer constraints or a uv lockfile.


🌐 Web query:

What are the latest stable versions of: mcp-agent (PyPI), openai (Python), anthropic (Python)?

💡 Result:

  • mcp-agent (PyPI): 0.1.17 — uploaded Sep 5, 2025. [1]
  • openai (Python on PyPI): 1.104.2 — uploaded Sep 2, 2025. [2]
  • anthropic (Python on PyPI): 0.66.0 — uploaded Sep 3, 2025. [3]

Sources:
[1] PyPI — mcp-agent.
[2] PyPI — openai.
[3] PyPI — anthropic.


Pin dependencies for reproducible cloud deploys — examples/mcp/mcp_elicitation/cloud/requirements.txt (lines 2–6): pin mcp-agent==0.1.17 (uploaded Sep 5, 2025), openai==1.104.2 (Sep 2, 2025), anthropic==0.66.0 (Sep 3, 2025). Prefer adding a constraints file or a checked-in lockfile for reproducible deploys.

🤖 Prompt for AI Agents
In examples/mcp/mcp_elicitation/cloud/requirements.txt around lines 2 to 6, the
file lists unpinned dependencies which makes cloud deploys non-reproducible;
update the file to pin the listed packages to the recommended versions
(mcp-agent==0.1.17, openai==1.104.2, anthropic==0.66.0) or alternatively add a
constraints file (e.g., constraints.txt) or a checked-in lockfile (pip-tools
requirements.txt.lock or poetry/poetry.lock) and reference it from the
requirements so CI/deploy uses exact versions for reproducible installs.

Loading