mirror of
https://github.com/mcloh/codex-chatgpt-mcp-proxy.git
synced 2026-11-05 21:34:11 +00:00
Implement durable OAuth MCP bridge with local Codex worker and deployment guides
This commit is contained in:
102
tests/test_server.py
Normal file
102
tests/test_server.py
Normal file
@@ -0,0 +1,102 @@
|
||||
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"
|
||||
Reference in New Issue
Block a user