python: add emem geospatial memory MCP example for Streamable HTTP - #14228
python: add emem geospatial memory MCP example for Streamable HTTP#14228kumari-jaya wants to merge 4 commits into
Conversation
Demonstrates using MCPStreamableHttpPlugin to connect to emem (https://emem.dev/mcp), a public no-auth Streamable HTTP MCP server providing Ed25519-signed Earth observation facts. The example shows a three-step verification chain: 1. emem_locate — resolve a place name to a canonical cell64 address 2. emem_recall — read signed facts (elevation, AQI, flood extent, etc.) 3. Report the emem:fact: receipt for offline verification No API key or signup is needed for emem reads (Apache 2.0).
There was a problem hiding this comment.
Automated Code Review
Reviewers: 5 | Confidence: 93%
✓ Correctness
This is a straightforward new sample file that closely follows the existing agent_with_http_mcp_plugin.py pattern. The MCPStreamableHttpPlugin API usage is correct (name, url, description all match the constructor signature). The ChatCompletionAgent setup and get_response call pattern are correct. Thread reuse across the loop is intentional for multi-step conversation context. The only issue is the missing copyright header that all other files in this directory include.
✓ Security Reliability
This new sample file follows the exact same pattern as the existing
agent_with_http_mcp_plugin.py. TheMCPStreamableHttpPluginis used correctly with valid parameters (name,url,description). Resource cleanup is properly handled viaasync withcontext manager (which callsconnect()/close()withAsyncExitStack), andthread.delete()is guarded withif thread. Thesampling_auto_approvedefaults toFalse(safe default), so the remote MCP server cannot issue sampling requests. TheEMEM_MCP_URLenvironment variable override is user-controlled input on the runner's own machine, consistent with howOPENAI_API_KEYand similar env vars are used across samples. No security or reliability issues found.
✓ Test Coverage
This PR adds a new MCP sample file (em_mcp_geospatial_agent.py) with no corresponding tests. However, this is consistent with the established repo pattern: MCP sample files are demonstration code excluded from pytest discovery via testpaths='tests' in pyproject.toml. The closest existing analog (agent_with_http_mcp_plugin.py) also has no tests. The underlying MCPStreamableHttpPlugin class is already well-tested in tests/unit/connectors/mcp/test_mcp.py. Since this sample requires a live external service (em.dev) and a valid OPENAI_API_KEY, adding automated tests would be impractical without extensive mocking. No test coverage gap exists beyond what the repo already accepts for all MCP samples.
✓ Failure Modes
This is a new sample file that follows the exact same patterns as the existing
agent_with_http_mcp_plugin.pysample. The async context manager properly handles MCP plugin cleanup via__aenter__/__aexit__(connect/close). The thread lifecycle is correct — shared across queries intentionally for multi-step verification, with delete after the loop. Theawaitternary on line 66 parses safely as(await thread.delete()) if thread else None(confirmed via AST). No silent failures, swallowed exceptions, resource leaks, or operational failure modes were found.
✓ Design Approach
I found one design inconsistency in the new sample: although the PR describes this as three example queries and says it follows the existing Streamable HTTP sample pattern, the implementation reuses a single chat thread across all prompts. That makes the second and third prompts context-dependent on the first exchange instead of exercising the MCP workflow as standalone examples.
Suggestions
- Create and clean up a fresh ChatHistoryAgentThread for each entry in USER_INPUTS so each example query is independent, matching the pattern in python/samples/concepts/mcp/agent_with_http_mcp_plugin.py:43-56.
Automated review by kumari-jaya's agents
There was a problem hiding this comment.
Pull request overview
Adds a new Python sample under python/samples/concepts/mcp/ demonstrating how to use MCPStreamableHttpPlugin (Streamable HTTP transport) with the public emem MCP server to retrieve signed, verifiable geospatial facts.
Changes:
- Introduces
emem_mcp_geospatial_agent.py, aChatCompletionAgentsample that connects tohttps://emem.dev/mcp(withEMEM_MCP_URLoverride) and runs multiple geospatial queries. - Demonstrates a multi-step “locate → recall → receipt” flow intended to surface verifiable
emem:fact:receipts.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| """Semantic Kernel + emem MCP example — multi-step verification: locate, recall, verify. | ||
|
|
||
| Connects a Microsoft Semantic Kernel agent to the emem MCP server over | ||
| Streamable HTTP and runs a multi-step verification chain for South Mumbai: | ||
| resolve the place, recall elevation, then verify the receipt/fact CID. | ||
|
|
||
| Install: | ||
| pip install semantic-kernel | ||
|
|
||
| Usage: | ||
| export OPENAI_API_KEY="sk-..." | ||
| python emem_mcp_geospatial_agent.py | ||
|
|
||
| The agent will resolve South Mumbai, recall its elevation, then verify | ||
| the receipt/fact CID, showing each step in the chain. | ||
| """ |
| url=EMEM_MCP_URL, | ||
| ) as emem_plugin: | ||
| agent = ChatCompletionAgent( | ||
| service=OpenAIChatCompletion(ai_model_id="gpt-4o"), |
| "You are a geospatial verification agent grounded in emem's signed Earth memory. " | ||
| "For every place query: " | ||
| "1. Call emem_locate to resolve the place to a canonical cell64 address. " | ||
| "2. Call emem_recall to read signed facts (air quality, elevation, flood extent, etc.). " | ||
| "3. Report the emem:fact: receipt so the user can verify it offline. " | ||
| "Always cite the fact_cid from the receipt." |
| thread: ChatHistoryAgentThread | None = None | ||
|
|
||
| for user_input in USER_INPUTS: | ||
| print(f"\n# User: {user_input}") | ||
| response = await agent.get_response(messages=user_input, thread=thread) | ||
| print(f"# {response.name}: {response}") | ||
| thread = response.thread | ||
|
|
||
| await thread.delete() if thread else None |
|
@microsoft-github-policy-service agree |
|
Thanks for the Copilot review — addressed all four points:
|
Description
Adds a sample showing how to use
MCPStreamableHttpPluginwith emem — a public, no-auth, Streamable HTTP MCP server providing Ed25519-signed Earth observation facts for any place on Earth.emem (emem.dev) is a good fit for an MCP sample because:
MCPStreamableHttpPluginpath, as opposed to stdio or SSE)pip install semantic-kernelSample walkthrough
The agent runs three example queries:
fact_cidreceiptEach response includes an
emem:fact:token that can be verified offline without calling emem again.Checklist
agent_with_http_mcp_plugin.pyMCPStreamableHttpPlugin(Streamable HTTP transport)ChatCompletionAgent+OpenAIChatCompletionhttps://emem.dev/mcpEMEM_MCP_URLenv var override supportedTesting