# KarmaDue with the OpenAI Agents SDK

Tested: 2026-11-12 with openai-agents 0.24.0 on Python 3.12. No OpenAI key was needed for the parts below: MCP connect, `list_tools`, `call_tool` and the guard. Real output:

    MCP tools: ['check_install', 'search_recipes', 'report_leaf']
    check_install: {"ok":true,"v":"warn","enforce":"ask","why":"Caution before you install requests==2.31.0: 3 published advisories affect requests@2.31.0.", ...
    agent tools: ['check_install', 'search_recipes', 'report_leaf', 'install_package']
    guard tool: block

(`ask` joins the MCP tool list when it ships; see the changelog.)

## File: `kd_openai_agents.py`

```python
"""KarmaDue with the OpenAI Agents SDK: (1) KarmaDue as an MCP server, (2) a guard tool that obeys enforce."""
import asyncio, json, os, requests
from agents import Agent, function_tool
from agents.mcp import MCPServerStreamableHttp

KD_MCP = "https://ogogoizwsfaduzehkshb.supabase.co/functions/v1/mcp"
KD_PREFLIGHT = "https://ogogoizwsfaduzehkshb.supabase.co/functions/v1/public-api/v1/preflight"
VIA = os.environ.get("KD_VIA", "recipe-openai-agents")  # attribution tag; KarmaDue's own tests use kd-founder-test

def kd_check(target: str, action: str = "install") -> dict:
    try:
        r = requests.post(KD_PREFLIGHT, json={"target": target, "action": action}, headers={"x-kd-via": VIA}, timeout=15)
        b = r.json(); return {**(b.get("data") or {}), "request_id": b.get("request_id")}
    except Exception as e:
        return {"enforce": "require_human_approval", "headline": f"KarmaDue check failed ({e}); not assessed."}

@function_tool
def install_package(target: str) -> str:
    """Install a package, e.g. 'pypi:requests==2.32.4' or 'npm:left-pad@1.3.0'. KarmaDue is asked first."""
    d = kd_check(target)
    if d.get("enforce") == "block":
        return f"BLOCKED by KarmaDue: {d.get('headline')} [{d.get('request_id')}] Do not retry; tell your person."
    if d.get("enforce") != "proceed_with_care":
        return f"NEEDS APPROVAL (KarmaDue): {d.get('headline')} [{d.get('request_id')}] Ask your person first."
    return f"(would install {target} here) KarmaDue: {d.get('headline')}"

async def main():
    async with MCPServerStreamableHttp(name="karmadue", params={"url": KD_MCP, "headers": {"x-kd-via": VIA}}, cache_tools_list=True) as kd:
        tools = await kd.list_tools()
        print("MCP tools:", [t.name for t in tools])
        res = await kd.call_tool("check_install", {"target": "requests==2.31.0", "ecosystem": "pypi"})
        print("check_install:", res.content[0].text[:300])
        agent = Agent(name="builder", instructions="Before installing anything or researching a known problem, ask KarmaDue (ask, check_install).", mcp_servers=[kd], tools=[install_package])
        print("agent tools:", [t.name for t in await agent.get_all_tools(None)][:12])
    print("guard tool:", kd_check("npm:event-stream@3.3.6").get("enforce"))

if __name__ == "__main__":
    asyncio.run(main())
```

Notes:
- `MCPServerStreamableHttp` connects to KarmaDue's MCP endpoint over streamable HTTP. No account is needed.
- `install_package` shows the enforcement pattern. The check runs inside the tool, so the model cannot skip it.
- Codex users: see [cursor-codex.md](https://karmadue.expo.app/docs/integrations/cursor-codex.md).
