Skip to content

Conversation

roman-van-der-krogt
Copy link
Contributor

@roman-van-der-krogt roman-van-der-krogt commented Sep 16, 2025

Minimal example that can be run on the cloud with instructions how to use it

Summary by CodeRabbit

  • New Features

    • Added an elicitation-based booking example app for cloud deployment with confirm/decline/cancel flow.
  • Documentation

    • Added cloud deployment guide: API key setup, deploy command, app ID/URL output, MCP Inspector access, SSE endpoint usage, Authorization header, and app deletion steps.
  • Chores

    • Added configuration with asyncio engine, logging settings, and default model.
    • Added example secrets template for OpenAI/Anthropic keys.
    • Added requirements file including mcp-agent, openai, and anthropic.

Copy link

coderabbitai bot commented Sep 16, 2025

Note

Other AI code review bot(s) detected

CodeRabbit 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.

Walkthrough

Adds 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

Cohort / File(s) Summary
Cloud elicitation app
examples/mcp/mcp_elicitation/cloud/main.py
New MCPApp example implementing a booking workflow. Adds tool book_table(date: str, party_size: int, app_ctx: Context) -> str that elicits a ConfirmBooking schema and handles accept/decline/cancel outcomes; initializes logging and app metadata.
Cloud deployment docs
examples/mcp/mcp_elicitation/cloud/README.md
New instructions for cloud deployment: set API key in mcp_agent.secrets.yaml, deploy via uv run mcp-agent deploy elicitation --config-dir ., access via MCP Inspector or append /sse for SSE with Authorization: Bearer <API_KEY>, and delete app with uv run mcp-agent cloud app delete --id=<app-id>.
Agent configuration
examples/mcp/mcp_elicitation/cloud/mcp_agent.config.yaml
Adds config referencing schema, sets execution_engine: asyncio, file logger with timestamped JSONL path pattern, and openai.default_model: gpt-4o-mini (comments about secrets and alternative model).
Secrets template
examples/mcp/mcp_elicitation/cloud/mcp_agent.secrets.yaml.example
Adds example secrets YAML with placeholders for openai.api_key and anthropic.api_key (schema reference included).
Dependencies
examples/mcp/mcp_elicitation/cloud/requirements.txt
Adds mcp-agent plus example-specific dependencies anthropic and openai, with comments separating core vs additional.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • saqadri
  • andrew-lastmile
  • rholinshead

Poem

I thump my paws—deploy, deploy!
Cloud lights blink, a booking toy.
SSE streams and keys in place,
Confirm or cancel, save the space.
Logs hum softly—dinner's on its way! 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Example of elicitation for MCP cloud" is concise, directly reflects the primary change (adding a minimal elicitation example and cloud deployment instructions), and is specific enough for a teammate to understand the main purpose of the PR at a glance.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/cloud-elicitation

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 82d46c9 and 952f0d6.

📒 Files selected for processing (1)
  • examples/mcp/mcp_elicitation/cloud/main.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/mcp/mcp_elicitation/cloud/main.py

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.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

Copy link
Collaborator

@saqadri saqadri left a comment

Choose a reason for hiding this comment

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

Awesome!

Copy link

@coderabbitai coderabbitai bot left a 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_key
examples/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 global app.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

📥 Commits

Reviewing files that changed from the base of the PR and between 4e15a7e and 82d46c9.

📒 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
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.

@@ -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.

Comment on lines +2 to +6
mcp-agent

# Additional dependencies specific to this example
anthropic
openai
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.

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.

@roman-van-der-krogt roman-van-der-krogt merged commit f10f6ea into main Sep 17, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants