mirror of
https://github.com/andrewyng/openworker.git
synced 2026-09-10 22:20:27 +00:00
Add MCP server flow: Remote URL + JSON tabs, Test connection
Explicit connect reports stderr tails; a 401 on an anonymous http probe becomes needs-sign-in with a one-click OAuth switch. Test button probes any enabled server row without opening a session.
This commit is contained in:
@@ -312,3 +312,85 @@ async def test_prepare_records_failure_status_and_session_notice(
|
||||
assert [n for n, _ in drained] == ["sales-db"]
|
||||
assert "boom: bad args" in (drained[0][1] or "")
|
||||
assert manager.pop_mcp_failures("s1") == [] # one-shot
|
||||
|
||||
|
||||
# -- explicit connect (UX-033: add → Test → fix, without opening a session) ------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_connect_mcp_failure_includes_stderr_tail(tmp_path, monkeypatch):
|
||||
"""The Test button's connect path reports the same stderr evidence as the
|
||||
session path — a crashing stdio server yields error + status=error."""
|
||||
monkeypatch.setenv("COWORKER_STATE_DIR", str(tmp_path / "state"))
|
||||
_write_json(
|
||||
tmp_path / "state" / "mcp.json",
|
||||
{
|
||||
"mcpServers": {
|
||||
"doomed": {
|
||||
"command": "/bin/sh",
|
||||
"args": ["-c", "echo 'usage: doomed --flag' >&2; exit 7"],
|
||||
"enabled": True,
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
manager = SessionManager(data_dir=tmp_path / "data")
|
||||
|
||||
result = await manager.connect_mcp("doomed")
|
||||
assert result["ok"] is False
|
||||
assert "usage: doomed --flag" in result["error"]
|
||||
|
||||
listed = {s["name"]: s for s in manager.list_mcp()}
|
||||
assert listed["doomed"]["status"] == "error"
|
||||
assert listed["doomed"]["auth_hint"] is False
|
||||
|
||||
# Removing the server takes its stale failure state with it.
|
||||
manager.delete_mcp("doomed")
|
||||
assert manager._mcp_errors.get("doomed") is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_connect_mcp_http_401_sets_auth_hint(tmp_path, monkeypatch):
|
||||
"""An anonymous connect that hits 401 is reported as "needs sign-in" (the GUI
|
||||
offers the OAuth switch), not as a raw HTTP error dump."""
|
||||
import http.server
|
||||
import threading
|
||||
|
||||
class _Deny(http.server.BaseHTTPRequestHandler):
|
||||
def _deny(self):
|
||||
self.send_response(401)
|
||||
self.send_header("Content-Length", "0")
|
||||
self.end_headers()
|
||||
|
||||
do_GET = do_POST = do_DELETE = _deny
|
||||
|
||||
def log_message(self, *args): # keep pytest output clean
|
||||
pass
|
||||
|
||||
srv = http.server.ThreadingHTTPServer(("127.0.0.1", 0), _Deny)
|
||||
threading.Thread(target=srv.serve_forever, daemon=True).start()
|
||||
try:
|
||||
monkeypatch.setenv("COWORKER_STATE_DIR", str(tmp_path / "state"))
|
||||
_write_json(
|
||||
tmp_path / "state" / "mcp.json",
|
||||
{
|
||||
"mcpServers": {
|
||||
"guarded": {
|
||||
"url": f"http://127.0.0.1:{srv.server_address[1]}/mcp",
|
||||
"enabled": True,
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
manager = SessionManager(data_dir=tmp_path / "data")
|
||||
|
||||
result = await manager.connect_mcp("guarded")
|
||||
assert result["ok"] is False
|
||||
assert "sign in" in result["error"]
|
||||
|
||||
listed = {s["name"]: s for s in manager.list_mcp()}
|
||||
assert listed["guarded"]["auth_hint"] is True
|
||||
assert listed["guarded"]["status"] == "error"
|
||||
finally:
|
||||
srv.shutdown()
|
||||
srv.server_close()
|
||||
|
||||
Reference in New Issue
Block a user