Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions 6_mcp/community_contributions/eddy_mmaitsimwale/date_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from datetime import datetime, timezone
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("date_time_server")

@mcp.tool()
async def get_current_date() -> str:
"""Return today's date in ISO format (UTC)."""
return datetime.now(timezone.utc).date().isoformat()

@mcp.tool()
async def get_current_datetime() -> str:
"""Return current date-time in ISO format (UTC)."""
return datetime.now(timezone.utc).isoformat()

if __name__ == "__main__":
mcp.run(transport="stdio")
296 changes: 296 additions & 0 deletions 6_mcp/community_contributions/eddy_mmaitsimwale/mcp_Exercise.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Week 6 MCP Exercise (`6_mcp`)\n",
"\n",
"This notebook follows the Week 6 MCP exercises and keeps to the same toolchain:\n",
"1. Build your own MCP server (date/time tool)\n",
"2. Use it via OpenAI Agents SDK (`MCPServerStdio`)\n",
"3. Build a custom MCP client\n",
"4. Use native OpenAI tool calling (without Agents SDK)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Concept Consolidation (Week 6)\n",
"\n",
"- MCP server creation with `FastMCP`, exposing tools/resources over stdio.\n",
"- MCP server usage via `MCPServerStdio` inside OpenAI Agents SDK.\n",
"- Direct MCP client usage via `mcp.ClientSession` (`list_tools`, `call_tool`, `read_resource`).\n",
"- Wrapping MCP tools into OpenAI-compatible function tools for native chat completions.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1) Imports and Environment\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import json\n",
"from pathlib import Path\n",
"\n",
"from dotenv import load_dotenv\n",
"\n",
"from agents import Agent, Runner, trace\n",
"from agents.mcp import MCPServerStdio\n",
"\n",
"import mcp\n",
"from mcp.client.stdio import stdio_client\n",
"from mcp import StdioServerParameters\n",
"\n",
"from openai import OpenAI\n",
"\n",
"load_dotenv(override=True)\n",
"\n",
"if not os.getenv('OPENAI_API_KEY') and not os.getenv('OR_API_KEY'):\n",
" raise ValueError('Set OPENAI_API_KEY or OR_API_KEY in .env')\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2) Confirm the Local MCP Server File\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"server_file = Path('6_mcp/community_contributions/eddy_mmaitsimwale/date_server.py')\n",
"print('Exists:', server_file.exists())\n",
"print('Path:', server_file)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3) Use the MCP Server with OpenAI Agents SDK\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"date_params = {\n",
" 'command': 'uv',\n",
" 'args': ['run', '6_mcp/community_contributions/eddy_mmaitsimwale/date_server.py']\n",
"}\n",
"\n",
"async with MCPServerStdio(params=date_params, client_session_timeout_seconds=30) as server:\n",
" tools = await server.list_tools()\n",
" tools\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"instructions = 'You answer date/time questions by using your MCP tools.'\n",
"request = \"What is today's date in UTC?\"\n",
"model = 'gpt-4.1-mini'\n",
"\n",
"async with MCPServerStdio(params=date_params, client_session_timeout_seconds=30) as mcp_server:\n",
" agent = Agent(\n",
" name='date_assistant',\n",
" instructions=instructions,\n",
" model=model,\n",
" mcp_servers=[mcp_server],\n",
" )\n",
" with trace('mcp_date_agent'):\n",
" result = await Runner.run(agent, request)\n",
"\n",
"print(result.final_output)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4) Build a Custom MCP Client\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"params = StdioServerParameters(\n",
" command='uv',\n",
" args=['run', '6_mcp/community_contributions/eddy_mmaitsimwale/date_server.py'],\n",
" env=None,\n",
")\n",
"\n",
"async def list_date_tools():\n",
" async with stdio_client(params) as streams:\n",
" async with mcp.ClientSession(*streams) as session:\n",
" await session.initialize()\n",
" tools_result = await session.list_tools()\n",
" return tools_result.tools\n",
"\n",
"async def call_date_tool(tool_name, tool_args=None):\n",
" async with stdio_client(params) as streams:\n",
" async with mcp.ClientSession(*streams) as session:\n",
" await session.initialize()\n",
" result = await session.call_tool(tool_name, tool_args or {})\n",
" return result\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tools = await list_date_tools()\n",
"for t in tools:\n",
" print(t.name, '-', t.description)\n",
"\n",
"raw_result = await call_date_tool('get_current_date', {})\n",
"print(raw_result)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5) Native OpenAI Tool Calling (No Agents SDK)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"openai_api_key = os.getenv('OPENAI_API_KEY') or os.getenv('OR_API_KEY')\n",
"base_url = os.getenv('OR_BASE_URL') if os.getenv('OR_API_KEY') else None\n",
"\n",
"client = OpenAI(api_key=openai_api_key, base_url=base_url)\n",
"model_name = 'gpt-4.1-mini' if not base_url else 'openai/gpt-4.1-mini'\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Convert MCP tools to OpenAI function schema\n",
"openai_tools = []\n",
"for t in tools:\n",
" schema = {**t.inputSchema, 'additionalProperties': False}\n",
" openai_tools.append(\n",
" {\n",
" 'type': 'function',\n",
" 'function': {\n",
" 'name': t.name,\n",
" 'description': t.description or '',\n",
" 'parameters': schema,\n",
" },\n",
" }\n",
" )\n",
"\n",
"messages = [\n",
" {'role': 'system', 'content': 'You are a date assistant. Use available tools when needed.'},\n",
" {'role': 'user', 'content': 'Please tell me current UTC date and datetime.'},\n",
"]\n",
"\n",
"response = client.chat.completions.create(\n",
" model=model_name,\n",
" messages=messages,\n",
" tools=openai_tools,\n",
")\n",
"\n",
"first = response.choices[0].message\n",
"print('Finish reason:', response.choices[0].finish_reason)\n",
"print('Tool calls:', first.tool_calls)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Handle any tool call(s), then send tool results back to model\n",
"if first.tool_calls:\n",
" messages.append(first.model_dump(exclude_none=True))\n",
"\n",
" for call in first.tool_calls:\n",
" fn_name = call.function.name\n",
" fn_args = json.loads(call.function.arguments or '{}')\n",
" tool_result = await call_date_tool(fn_name, fn_args)\n",
"\n",
" # collect text payload from MCP result content\n",
" text_payload = ''\n",
" if hasattr(tool_result, 'content') and tool_result.content:\n",
" parts = []\n",
" for item in tool_result.content:\n",
" if getattr(item, 'type', None) == 'text':\n",
" parts.append(getattr(item, 'text', ''))\n",
" text_payload = '\\n'.join(parts).strip()\n",
"\n",
" messages.append(\n",
" {\n",
" 'role': 'tool',\n",
" 'tool_call_id': call.id,\n",
" 'content': text_payload or str(tool_result),\n",
" }\n",
" )\n",
"\n",
" final = client.chat.completions.create(\n",
" model=model_name,\n",
" messages=messages,\n",
" )\n",
" print(final.choices[0].message.content)\n",
"else:\n",
" print(first.content)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6) Notes\n",
"\n",
"- This exercise follows the exact Week 6 direction: own MCP server + own MCP client + native OpenAI tool loop.\n",
"- If `uv run .../date_server.py` fails, make sure MCP dependencies are installed in your environment.\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
76 changes: 76 additions & 0 deletions allegiance_arena_agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
ARENA_AGENT_NAME=EddyTheArchitect
ARENA_ENDPOINT=https://alliance.abdull.dev/mcp
ARENA_POLL_INTERVAL_SECONDS=1.0
ARENA_MAX_ROUNDS=10
ARENA_MEMORY_PATH=allegiance_arena_agent/state.json
ARENA_LOG_LEVEL=INFO
ARENA_LOG_GAME_STATE_EVERY_TICKS=5
ARENA_LOG_GAME_STATE_PAYLOAD=false

# Deterministic controls
ARENA_TRUST_DECAY=0.92
ARENA_ABSTAIN_THRESHOLD=-0.10
ARENA_MAX_DIRECT_MESSAGES_PER_DIPLOMACY=3
ARENA_FAST_START_ROUNDS=3
ARENA_FAST_START_EXTRA_DIRECT_MESSAGES=2
ARENA_SIMULATION_RUNS=60
ARENA_SIMULATION_MONTE_CARLO=true
ARENA_RISK_PENALTY_WEIGHT=0.55
ARENA_AVOID_LEADER_WHEN_BEHIND=true
ARENA_LEADER_GAP_ACTIVATION=8.0
ARENA_LEADER_TARGET_PENALTY_WEIGHT=0.9
ARENA_CATCHUP_MIN_EV=0.35
ARENA_CATCHUP_EV_DELTA_MAX=0.6
ARENA_ISOLATION_SUPPORT_BONUS_WEIGHT=1.1
ARENA_PROFILE_CONFIDENCE_FLOOR=0.3
ARENA_MIN_PRIMARY_PACTS=2
ARENA_MIN_BACKUP_PACTS=1

# MCP networking
ARENA_MCP_TIMEOUT_SECONDS=8.0
ARENA_MCP_MAX_RETRIES=3
ARENA_MCP_RETRY_BACKOFF_SECONDS=0.5

# API keys
GROQ_API_KEY=your_groq_api_key_here
ANTHROPIC_API_KEY=
OPENROUTER_API_KEY=your_openrouter_api_key_here
OPENROUTER_SITE_URL=
OPENROUTER_APP_NAME=allegiance-arena-agent

# Flexible LLM timeouts (seconds)
ARENA_TIMEOUT_STRATEGY_SECONDS=5.0
ARENA_TIMEOUT_OPPONENT_SECONDS=5.5
ARENA_TIMEOUT_MESSAGING_SECONDS=3.5
ARENA_TIMEOUT_FALLBACK_STRATEGY_SECONDS=3.0
ARENA_TIMEOUT_REALTIME_BACKUP_SECONDS=1.8

# Phase multipliers
ARENA_TIMEOUT_MULTIPLIER_SETUP=1.2
ARENA_TIMEOUT_MULTIPLIER_LOBBY=1.2
ARENA_TIMEOUT_MULTIPLIER_DIPLOMACY=1.0
ARENA_TIMEOUT_MULTIPLIER_VOTING=0.9
ARENA_TIMEOUT_MULTIPLIER_RESULTS=1.1
ARENA_TIMEOUT_MULTIPLIER_UNKNOWN=1.0

# Model routing (provider + model string)
ARENA_MODEL_STRATEGY_PRIMARY_PROVIDER=anthropic
ARENA_MODEL_STRATEGY_PRIMARY_MODEL=claude-3-5-haiku-latest
ARENA_MODEL_STRATEGY_BACKUP_PROVIDER=anthropic
ARENA_MODEL_STRATEGY_BACKUP_MODEL=claude-3-5-haiku-latest

ARENA_MODEL_OPPONENT_PRIMARY_PROVIDER=anthropic
ARENA_MODEL_OPPONENT_PRIMARY_MODEL=claude-3-5-haiku-latest
ARENA_MODEL_OPPONENT_BACKUP_PROVIDER=anthropic
ARENA_MODEL_OPPONENT_BACKUP_MODEL=claude-3-5-haiku-latest

ARENA_MODEL_MESSAGING_PRIMARY_PROVIDER=anthropic
ARENA_MODEL_MESSAGING_PRIMARY_MODEL=claude-3-5-haiku-latest
ARENA_MODEL_MESSAGING_BACKUP_PROVIDER=anthropic
ARENA_MODEL_MESSAGING_BACKUP_MODEL=claude-3-5-haiku-latest

ARENA_MODEL_REALTIME_BACKUP_PROVIDER=groq
ARENA_MODEL_REALTIME_BACKUP_MODEL=gemma-2-2b

ARENA_MODEL_FALLBACK_STRATEGY_PROVIDER=openrouter
ARENA_MODEL_FALLBACK_STRATEGY_MODEL=gpt-4o-mini
Loading