Files
codex-chatgpt-mcp-proxy/tests/test_server.py

103 lines
4.3 KiB
Python

from fastapi.testclient import TestClient
from mcp.client.streamable_http import streamable_http_client
from codex_chatgpt_mcp_proxy.server import create_app
def test_api_auth_host_origin_and_isolation(config):
with TestClient(create_app(config), base_url=config.public_url) as c:
assert c.get("/healthz").json() == {"ok": True}
assert c.get("/healthz", headers={"host": "evil.example"}).status_code == 403
assert c.get("/healthz", headers={"origin": "https://evil.example"}).status_code == 403
for token in (None, "invalid", config.dev_mcp_token):
h = {"Authorization": "Bearer " + token} if token else {}
assert c.post("/api/worker/claim", headers=h).status_code == 401
assert (
c.post("/mcp", headers={"Authorization": "Bearer " + config.worker_token}).status_code
== 401
)
h = {"Authorization": "Bearer " + config.worker_token}
assert (
c.post(
"/api/worker/register",
headers=h,
json={
"worker_id": "home",
"protocol": "1",
"version": "test",
"workspaces": ["demo"],
},
).status_code
== 200
)
assert c.post("/api/worker/claim", headers=h).json() == {"task": None}
assert (
c.post(
"/api/worker/register",
headers=h,
json={
"worker_id": "home",
"protocol": "1",
"version": "test",
"workspaces": ["/tmp"],
},
).status_code
== 400
)
assert c.post("/api/worker/claim", headers=h, content="x" * 140000).status_code == 413
async def test_real_mcp_transport_initialize_discover_and_validation(config):
import httpx2
app = create_app(config)
async with app.router.lifespan_context(app):
async with httpx2.AsyncClient(
transport=httpx2.ASGITransport(app=app),
headers={"Authorization": "Bearer " + config.dev_mcp_token},
) as http:
async with streamable_http_client(config.public_url + "/mcp", http_client=http) as (
read,
write,
):
from mcp import ClientSession
async with ClientSession(read, write) as session:
initialization = await session.initialize()
assert initialization.server_info.name == "codex-chatgpt-mcp-proxy"
tools = await session.list_tools()
names = {t.name for t in tools.tools}
assert names == {
"bridge_status",
"submit_task",
"get_task",
"get_task_events",
"continue_task",
"cancel_task",
"list_tasks",
}
invalid = await session.call_tool(
"submit_task",
{
"instruction": "x",
"workspace": "demo",
"idempotency_key": "k",
"timeout_seconds": 0,
},
)
assert invalid.is_error
result = await session.call_tool(
"submit_task",
{"instruction": "hello", "workspace": "demo", "idempotency_key": "k"},
)
assert not result.is_error
assert result.structured_content["state"] == "queued"
repeated = await session.call_tool(
"submit_task",
{"instruction": "hello", "workspace": "demo", "idempotency_key": "k"},
)
assert not repeated.is_error
assert repeated.structured_content["id"] == result.structured_content["id"]
for tool in tools.tools:
assert tool.annotations is not None
assert tool.meta["securitySchemes"][0]["type"] == "oauth2"