Skip to content

docs(examples): add hosted-MCP variant to ADK, LangChain, OpenAI Agents#99

Merged
jiashuoz merged 3 commits into
mainfrom
feat/hosted-mcp-examples
May 22, 2026
Merged

docs(examples): add hosted-MCP variant to ADK, LangChain, OpenAI Agents#99
jiashuoz merged 3 commits into
mainfrom
feat/hosted-mcp-examples

Conversation

@jiashuoz
Copy link
Copy Markdown
Member

Summary

Each framework example in mcp/examples/ now ships two scripts:

File Transport When to use
agent.py stdio (npx -y @e2a/mcp-server) Local dev with a Node toolchain
agent_hosted.py Streamable HTTP (https://mcp.e2a.dev/mcp) Serverless deploys (Cloud Run, Lambda, Vercel); zero Node dependency

The hosted variant is specifically required for Cloud Run deployments — Cloud Run doesn't support stdio MCP servers, so an ADK agent deployed there literally can't run agent.py. Same pressure on Lambda and similar runtimes that aren't friendly to long-lived stdio children.

What changed

New files (each ~50 LOC, mirrors the existing stdio shape):

  • mcp/examples/adk/agent_hosted.pyMcpToolset(StreamableHTTPConnectionParams(url, headers, timeout))
  • mcp/examples/langchain/agent_hosted.pyMultiServerMCPClient({"e2a": {"transport": "streamable_http", "url", "headers"}})
  • mcp/examples/openai-agents/agent_hosted.pyasync with MCPServerStreamableHttp(params={"url", "headers"})

README updates:

  • Per-example READMEs: add a "two transport options" section, document run instructions for both, drop the stale "all 11 e2a tools" claim (we ship 18).
  • Top-level mcp/examples/README.md: transport matrix + stdio-vs-hosted explainer.

Verification

Smoke against the live hosted endpoint with a real API key:

$ curl ... initialize → HTTP 200, session id obtained
$ curl ... tools/list → 18 tools returned (full set: approve_pending_message,
  create_agent, delete_agent, delete_domain, get_attachment_data,
  get_message, get_pending_message, list_agents, list_domains,
  list_messages, list_pending_messages, register_domain,
  reject_pending_message, reply_to_message, send_email, update_agent,
  verify_domain, whoami)
$ curl ... tools/call list_messages WITH agent_email → succeeds
$ curl ... tools/call list_messages WITHOUT agent_email (multi-agent acct)
   → correctly errors "agentEmail is required" per PR #98 single-agent
   prefetch design (kicks in only when listAgents returns exactly 1)

Framework adapter API shapes verified against actual source, not docs:

Notes

  • Multi-agent accounts: the hosted endpoint's session-init prefetch (PR feat(mcp): single-agent default at session init #98) is structurally a no-op when listAgents returns >1. Documented in the per-example READMEs as "pass agent_email per tool call or wait for a future grant-binding feature." Filed as a follow-up if/when multi-agent OAuth users surface friction.
  • This PR is the codebase companion to google/adk-docs#1793 — same hosted-MCP story shipped on adk.dev's integration page.

🤖 Generated with Claude Code

jiashuoz and others added 3 commits May 21, 2026 17:35
Each framework example now ships two scripts that exercise the same
e2a tool surface:

  agent.py         — stdio: npx -y @e2a/mcp-server, local Node child
  agent_hosted.py  — Streamable HTTP: https://mcp.e2a.dev/mcp + Bearer

The hosted variant is the right choice when deploying to serverless
runtimes (Cloud Run, Lambda, Vercel) where spawning a stdio child
process per request is awkward or impossible — Cloud Run in particular
doesn't host stdio MCP servers at all, so an ADK agent deployed there
literally can't use agent.py.

Verified against the live hosted endpoint:
- MCP initialize handshake: 200, session id assigned
- tools/list: returns all 18 tools, matches the registry
- tools/call list_messages with explicit agent_email: succeeds
- tools/call list_messages without agent_email on a multi-agent
  account: correctly returns "agentEmail is required" (the PR #98
  single-agent prefetch is structurally a no-op when listAgents
  returns >1; a future grant-binding slice would address that)

API shapes verified against actual source, not docs:
- ADK Python: StreamableHTTPConnectionParams(url, headers, timeout)
  (google/adk-python src/google/adk/tools/mcp_tool/mcp_session_manager.py)
- LangChain: transport="streamable_http" + url + headers
  (langchain-ai/langchain-mcp-adapters sessions.py)
- OpenAI Agents: MCPServerStreamableHttp(params={url, headers})
  (openai/openai-agents-python src/agents/mcp/server.py)

Also corrects stale tool counts ("all 11 e2a tools" → drop the count;
we ship 18) across each per-framework README. Top-level
mcp/examples/README.md gets a transport matrix and a stdio-vs-hosted
explainer.
…2.0 + mcp

google-adk 2.0 stopped re-exporting McpToolset from
google.adk.tools.mcp_tool's package __init__ — only the deep path
google.adk.tools.mcp_tool.mcp_toolset.McpToolset still works.

Bumped requirement to google-adk>=2.0 (was >=1.0) so we don't claim
support for a version where the example doesn't import, and added
mcp>=1.0 as an explicit dep: google-adk 2.0 declared mcp as optional,
but the toolset module imports it unconditionally
(`from mcp import SamplingCapability` at mcp_toolset.py:33), so without
it both agent.py and agent_hosted.py ImportError before they run.

Caught during the build+run smoke for the hosted-variant rollout:
neither agent.py nor agent_hosted.py imported on a fresh
google-adk 2.0 install. The same fix applies to both since they
share the broken import line. With this commit:

  $ python -c "import agent_hosted; print(agent_hosted.root_agent)"
  → imports clean

  $ python -c "...await McpToolset.get_tools(...)..." against the
    hosted endpoint
  → returns all 18 e2a tools

LangChain and OpenAI Agents examples were unaffected — those import
their MCP classes from already-deep paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three findings from the review pass on PR #99:

1. (Low) openai-agents floor was wildly stale: >=0.0.13. The hosted
   variant uses MCPServerStreamableHttp which first shipped in
   v0.0.15 (feat: Streamable HTTP support #643, 2025-05-14). A user
   who pinned the minimum would ImportError before any of our code
   runs — same failure class as the McpToolset/google-adk 2.0
   regression already in this branch. Bumped to >=0.0.15 (verified
   against the v0.0.15 src/agents/mcp/__init__.py snapshot, which
   exports both MCPServerStreamableHttp and MCPServerStreamableHttpParams).

2. (Nit) Inconsistent timeouts across hosted variants:
     ADK             timeout=30
     LangChain       (adapter default, ~undocumented)
     OpenAI Agents   5s default (tight for cold serverless backends)
   Aligned all three at 30s:
     LangChain  → "timeout": timedelta(seconds=30)
     OpenAI     → client_session_timeout_seconds=30
   Both fields verified against the actual library source (already
   in this branch's PR description). ADK already at 30s.

3. (Nit) "wait for a future grant-binding feature" appeared 3x across
   per-example READMEs. Forward-promising language for an unscheduled
   slice. Tightened to just "pass agent_email per tool call" — drops
   the implicit promise without dropping useful information.

Re-smoked all three hosted variants after the changes: each
returns 18 tools against mcp.e2a.dev/mcp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jiashuoz jiashuoz merged commit acf7778 into main May 22, 2026
10 checks passed
@jiashuoz jiashuoz deleted the feat/hosted-mcp-examples branch May 22, 2026 00:49
jiashuoz added a commit that referenced this pull request May 22, 2026
Prep for publishing to the official MCP Registry (registry.modelcontextprotocol.io).

Two artifacts:

1. mcp/package.json: add `mcpName: "io.github.mnexa-ai/mcp-server"`.
   This is the verification handshake the Registry's publish step
   uses — it confirms the npm package belongs to the publisher
   claiming the registry name. The convention `io.github.OWNER/NAME`
   is required for GitHub-based auth at publish time. Lowercased
   per the Registry's namespacing rules (our GitHub org is
   "Mnexa-AI"; the registry name is "io.github.mnexa-ai/...").

   Also bumps version 0.3.0 → 0.3.1. Two fixes merged since the
   0.3.0 tag — single-agent prefetch (#98) and hosted-MCP example
   variants (#99) — warrant a publish.

2. mcp/server.json: the Registry's canonical server descriptor.
   Lists both transports in one entry:
     - packages[].npm: stdio via @e2a/mcp-server 0.3.1 with the
       three env vars (E2A_API_KEY required + secret, optional
       E2A_AGENT_EMAIL, optional E2A_BASE_URL).
     - remotes[]: streamable-http at https://mcp.e2a.dev/mcp with
       an `Authorization: Bearer {e2a_api_key}` header that
       resolves a registry variable.

   Validated against schema 2025-12-11 — fits maxLength=100 on
   description, all required fields present.

Publish flow (NOT in this PR — requires a maintainer to run):

  1. Merge this PR to main.
  2. Tag mcp-v0.3.1 and push. publish-mcp.yml fires and publishes
     @e2a/mcp-server 0.3.1 to npm with the mcpName field baked in.
  3. brew install mcp-publisher
  4. mcp-publisher login github   (interactive)
  5. cd mcp && mcp-publisher publish

Step 5 reads server.json from the cwd, verifies that the npm
package at @e2a/mcp-server@0.3.1 has the matching mcpName field,
then writes the listing to registry.modelcontextprotocol.io.

After the listing lands, other catalogs (mcp.directory, Glama,
smithery) that cross-reference the Registry will auto-pick us up
on their next sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jiashuoz added a commit that referenced this pull request May 22, 2026
Prep for publishing to the official MCP Registry (registry.modelcontextprotocol.io).

Two artifacts:

1. mcp/package.json: add `mcpName: "io.github.mnexa-ai/mcp-server"`.
   This is the verification handshake the Registry's publish step
   uses — it confirms the npm package belongs to the publisher
   claiming the registry name. The convention `io.github.OWNER/NAME`
   is required for GitHub-based auth at publish time. Lowercased
   per the Registry's namespacing rules (our GitHub org is
   "Mnexa-AI"; the registry name is "io.github.mnexa-ai/...").

   Also bumps version 0.3.0 → 0.3.1. Two fixes merged since the
   0.3.0 tag — single-agent prefetch (#98) and hosted-MCP example
   variants (#99) — warrant a publish.

2. mcp/server.json: the Registry's canonical server descriptor.
   Lists both transports in one entry:
     - packages[].npm: stdio via @e2a/mcp-server 0.3.1 with the
       three env vars (E2A_API_KEY required + secret, optional
       E2A_AGENT_EMAIL, optional E2A_BASE_URL).
     - remotes[]: streamable-http at https://mcp.e2a.dev/mcp with
       an `Authorization: Bearer {e2a_api_key}` header that
       resolves a registry variable.

   Validated against schema 2025-12-11 — fits maxLength=100 on
   description, all required fields present.

Publish flow (NOT in this PR — requires a maintainer to run):

  1. Merge this PR to main.
  2. Tag mcp-v0.3.1 and push. publish-mcp.yml fires and publishes
     @e2a/mcp-server 0.3.1 to npm with the mcpName field baked in.
  3. brew install mcp-publisher
  4. mcp-publisher login github   (interactive)
  5. cd mcp && mcp-publisher publish

Step 5 reads server.json from the cwd, verifies that the npm
package at @e2a/mcp-server@0.3.1 has the matching mcpName field,
then writes the listing to registry.modelcontextprotocol.io.

After the listing lands, other catalogs (mcp.directory, Glama,
smithery) that cross-reference the Registry will auto-pick us up
on their next sync.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant