-
Notifications
You must be signed in to change notification settings - Fork 772
Example of elicitation for MCP cloud #493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a cloud-deployable MCP elicitation example: a new MCP app with a booking tool, config and secrets templates, requirements, and README guidance for deploying, accessing via SSE with Authorization, and deleting the app. The tool elicits a ConfirmBooking schema and branches on accept/decline/cancel. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User as User / MCP Inspector
participant Agent as MCP Agent
participant App as MCP App (elicitation_demo)
participant LLM as Upstream Model
User->>Agent: HTTP(S) request to /sse (Authorization: Bearer <API_KEY>)
Agent->>App: Invoke tool book_table(date, party_size)
App->>LLM: elicit(ConfirmBooking schema)
LLM-->>App: result { action, content? }
alt action == "accept"
App->>App: validate content as ConfirmBooking
alt confirm == true
App-->>Agent: "Booked! Notes: {notes|None}"
else confirm == false
App-->>Agent: "Booking cancelled"
end
else action == "decline"
App-->>Agent: "Booking declined"
else action == "cancel"
App-->>Agent: "Booking cancelled"
end
Agent-->>User: Streamed response over SSE
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal). Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
return "Booking declined" | ||
elif result.action == "cancel": | ||
return "Booking cancelled" | ||
|
There was a problem hiding this comment.
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.
return "Unknown action" |
Spotted by Diamond
Is this helpful? React 👍 or 👎 to let us know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (8)
examples/mcp/mcp_elicitation/cloud/requirements.txt (1)
5-6
: Make Anthropic optional (or document why both providers are needed).If the example only uses the OpenAI provider, drop
anthropic
to reduce cold start and attack surface. If you intend to show both, note that in README.examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example (1)
3-7
: Add a cautionary header about copying and not committing real secrets.A brief comment helps users use the
.example
safely.+## Copy this file to `mcp_agent.secrets.yaml` and NEVER commit real keys. +## Values are example placeholders. openai: api_key: openai_api_keyexamples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml (1)
7-10
: Ensure log path is writable in cloud.
logs/...
may not exist. Either ensure directory creation or use a tmp path.- path_pattern: "logs/mcp-agent-{unique_id}.jsonl" + path_pattern: "/tmp/mcp-agent-{unique_id}.jsonl"If the file transport auto-creates dirs, ignore this.
examples/mcp/mcp_elicitation/cloud/README.md (2)
3-3
: Include the copy step for the secrets file.Users need to create
mcp_agent.secrets.yaml
from the example.-In `mcp_agent.secrets.yaml`, set your OpenAI `api_key`. +Copy `mcp_agent.secrets.yaml.example` to `mcp_agent.secrets.yaml`, then set your OpenAI `api_key`.
11-15
: Clarify how to auth and add a concrete curl example-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. +Add `/sse` to the end of the URL; the MCP is exposed as a Server‑Sent Events endpoint. +Include `Authorization: Bearer <MCP_AGENT_API_KEY>` (e.g. `mcp_sk_...` or `KEY_ID:SECRET` for some providers). Example: + +```bash +curl -N \ + -H "Accept: text/event-stream" \ + -H "Authorization: Bearer $MCP_AGENT_API_KEY" \ + "<APP_URL>/sse" +```examples/mcp/mcp_elicitation/cloud/main.py (3)
37-37
: Nit: log message typo.“use” → “user”.
- 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")
39-44
: Use request-scoped context and guard against missing upstream session.Prefer
app_ctx.upstream_session
over globalapp.context.*
. Add a friendly error if missing.- result = await app.context.upstream_session.elicit( + if not app_ctx.upstream_session: + raise RuntimeError("No upstream session available for elicitation; ensure this tool is invoked via an upstream client (e.g., Inspector).") + result = await app_ctx.upstream_session.elicit( message=f"Confirm booking for {party_size} on {date}?", requestedSchema=ConfirmBooking.model_json_schema(), )
46-55
: Optional: handle unexpected actions defensively.Future protocol changes won’t cause silent fallthrough.
elif result.action == "cancel": return "Booking cancelled" + else: + raise ValueError(f"Unexpected elicitation action: {result.action}")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
examples/mcp/mcp_elicitation/cloud/README.md
(1 hunks)examples/mcp/mcp_elicitation/cloud/main.py
(1 hunks)examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml
(1 hunks)examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example
(1 hunks)examples/mcp/mcp_elicitation/cloud/requirements.txt
(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-22T18:59:49.368Z
Learnt from: CR
PR: lastmile-ai/mcp-agent#0
File: examples/usecases/reliable_conversation/CLAUDE.md:0-0
Timestamp: 2025-07-22T18:59:49.368Z
Learning: Applies to examples/usecases/reliable_conversation/examples/reliable_conversation/src/utils/config.py : Configuration values such as quality_threshold, max_refinement_attempts, consolidation_interval, and evaluator_model_provider must be loaded from mcp_agent.config.yaml.
Applied to files:
examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml
📚 Learning: 2025-07-22T18:59:49.368Z
Learnt from: CR
PR: lastmile-ai/mcp-agent#0
File: examples/usecases/reliable_conversation/CLAUDE.md:0-0
Timestamp: 2025-07-22T18:59:49.368Z
Learning: Applies to examples/usecases/reliable_conversation/examples/reliable_conversation/src/**/*.py : Use mcp-agent's Agent abstraction for ALL LLM interactions, including quality evaluation, to ensure consistent tool access, logging, and error handling.
Applied to files:
examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml
examples/mcp/mcp_elicitation/cloud/requirements.txt
🧬 Code graph analysis (1)
examples/mcp/mcp_elicitation/cloud/main.py (5)
src/mcp_agent/core/context.py (2)
mcp
(102-103)Context
(57-103)src/mcp_agent/server/app_server.py (2)
app
(134-136)create_mcp_server_for_app
(312-1290)src/mcp_agent/executor/workflow.py (1)
WorkflowResult
(55-61)src/mcp_agent/app.py (1)
logger
(193-210)src/mcp_agent/executor/temporal/session_proxy.py (1)
elicit
(291-307)
🪛 GitHub Actions: Pull Request Checks
examples/mcp/mcp_elicitation/cloud/main.py
[error] 1-1: Ruff: F401 - 'asyncio' imported but unused.
[error] 3-3: Ruff: F401 - 'sys' imported but unused.
[error] 5-5: Ruff: F401 - 'FastMCP' imported but unused.
[error] 7-7: Ruff: F401 - 'AcceptedElicitation' imported but unused.
[error] 8-8: Ruff: F401 - 'DeclinedElicitation' imported but unused.
[error] 9-9: Ruff: F401 - 'CancelledElicitation' imported but unused.
[error] 13-13: Ruff: F401 - 'create_mcp_server_for_app' imported but unused.
[error] 14-14: Ruff: F401 - 'Workflow' imported but unused.
[error] 14-14: Ruff: F401 - 'WorkflowResult' imported but unused.
[error] 15-15: Ruff: F401 - 'workflow' imported but unused.
🔇 Additional comments (1)
examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml (1)
12-15
: Provider alignment.Config defaults to OpenAI; ensure
openai
is present (it is) and note Anthropic in README only if also configured (to avoid confusion with the secrets template).
@@ -0,0 +1,15 @@ | |||
$schema: ../../schema/mcp-agent.config.schema.json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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.
$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.
@@ -0,0 +1,7 @@ | |||
$schema: ../../schema/mcp-agent.config.schema.json |
There was a problem hiding this comment.
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.
$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.
mcp-agent | ||
|
||
# Additional dependencies specific to this example | ||
anthropic | ||
openai |
There was a problem hiding this comment.
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.
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") |
There was a problem hiding this comment.
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"
.
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
Is this helpful? React 👍 or 👎 to let us know.
Minimal example that can be run on the cloud with instructions how to use it
Summary by CodeRabbit
New Features
Documentation
Chores