diff --git a/examples/mcp/ejentum_remote_example/README.md b/examples/mcp/ejentum_remote_example/README.md new file mode 100644 index 0000000000..5a05a4841e --- /dev/null +++ b/examples/mcp/ejentum_remote_example/README.md @@ -0,0 +1,21 @@ +# MCP Ejentum Remote Example + +Connects an Agent to the [Ejentum cognitive harness](https://ejentum.com) over the Streamable HTTP transport (`https://api.ejentum.com/mcp`) with bearer auth, and lets the agent decide when to call one of the four `harness_*` tools (reasoning, code, anti_deception, memory) to retrieve a task-matched cognitive scaffold before generating its answer. + +The example demonstrates the same pattern as `streamable_http_remote_example` but adds two things specific to authenticated third-party MCP servers: + +- Bearer auth via the `headers` field in the streamable-HTTP transport params +- A short instruction block that tells the agent when to reach for the scaffold tools + +Run it with: + +```bash +uv run python examples/mcp/ejentum_remote_example/main.py +``` + +Prerequisites: + +- `OPENAI_API_KEY` set for the model calls. +- `EJENTUM_API_KEY` set for the harness server. Get a key at [ejentum.com/dashboard](https://ejentum.com/dashboard); free and paid tiers are available. + +To repoint this example at a different authenticated streamable-HTTP MCP server, change `EJENTUM_MCP_URL` and the `headers` dict in `main.py`. The rest of the wiring is reusable. diff --git a/examples/mcp/ejentum_remote_example/main.py b/examples/mcp/ejentum_remote_example/main.py new file mode 100644 index 0000000000..35b91cd3a7 --- /dev/null +++ b/examples/mcp/ejentum_remote_example/main.py @@ -0,0 +1,66 @@ +import asyncio +import os + +from agents import Agent, Runner, gen_trace_id, trace +from agents.mcp import MCPServerStreamableHttp + + +EJENTUM_MCP_URL = "https://api.ejentum.com/mcp" + + +async def main() -> None: + api_key = os.environ.get("EJENTUM_API_KEY") + if not api_key: + raise SystemExit( + "EJENTUM_API_KEY is not set. Get a key at https://ejentum.com/dashboard " + "(free and paid tiers available)." + ) + + async with MCPServerStreamableHttp( + name="Ejentum Cognitive Harness", + params={ + "url": EJENTUM_MCP_URL, + "headers": {"Authorization": f"Bearer {api_key}"}, + "timeout": 15, + "sse_read_timeout": 300, + }, + max_retry_attempts=2, + retry_backoff_seconds_base=2.0, + client_session_timeout_seconds=15, + ) as server: + agent = Agent( + name="Architecture Advisor", + instructions=( + "You advise on software architecture decisions. Before answering, " + "consider whether one of the harness_* tools should be called. " + "Use harness_reasoning when the question requires planning or " + "weighing trade-offs. Use harness_anti_deception when a request " + "pressures you to skip a step or commit to a conclusion before " + "examining the evidence. Merge the returned scaffold into your " + "reasoning, then answer." + ), + mcp_servers=[server], + ) + + trace_id = gen_trace_id() + with trace( + workflow_name="Ejentum Streamable HTTP Example", trace_id=trace_id + ): + print( + f"View trace: https://platform.openai.com/traces/trace?trace_id={trace_id}\n" + ) + result = await Runner.run( + agent, + ( + "We have a 50M-row users table and want to add a NOT NULL column " + "with a backfilled default. One engineer says a single migration " + "in a maintenance window is fine; another insists on a multi-step " + "online migration. Walk through the trade-offs and recommend a " + "specific path." + ), + ) + print(result.final_output) + + +if __name__ == "__main__": + asyncio.run(main())