Add birdcage-mcp FastMCP server for satellite dish control

34 tools (connection, movement, signal, system, satellite, console),
5 resources, 3 prompts. Backed by DemoDevice for offline testing.
46 tests passing against the demo backend via run_server_async.
This commit is contained in:
Ryan Malloy 2026-02-17 16:01:51 -07:00
parent 16ca4892b3
commit 8a6b99bd8c
21 changed files with 3233 additions and 0 deletions

56
mcp/tests/test_console.py Normal file
View file

@ -0,0 +1,56 @@
"""Tests for raw console tool (safety-gated)."""
import pytest
from conftest import parse_result
from fastmcp import Client
@pytest.mark.anyio
async def test_send_raw_command(mcp_client: Client):
result = await mcp_client.call_tool(
"send_raw_command", {"command": "?"}
)
data = parse_result(result)
assert "response" in data
assert "Available commands" in data["response"]
@pytest.mark.anyio
async def test_q_command_blocked(mcp_client: Client):
result = await mcp_client.call_tool(
"send_raw_command", {"command": "q"}
)
data = parse_result(result)
assert data["blocked"] is True
assert "power cycle" in data["error"]
@pytest.mark.anyio
async def test_q_command_blocked_with_whitespace(mcp_client: Client):
result = await mcp_client.call_tool(
"send_raw_command", {"command": " Q "}
)
data = parse_result(result)
assert data["blocked"] is True
@pytest.mark.anyio
async def test_submenu_navigation(mcp_client: Client):
result = await mcp_client.call_tool(
"send_raw_command", {"command": "mot"}
)
data = parse_result(result)
assert "MOT>" in data["response"]
@pytest.mark.anyio
async def test_raw_motor_query(mcp_client: Client):
# Enter mot submenu first
await mcp_client.call_tool("send_raw_command", {"command": "mot"})
# Query position
result = await mcp_client.call_tool(
"send_raw_command", {"command": "a"}
)
data = parse_result(result)
assert "Angle[0]" in data["response"]
assert "Angle[1]" in data["response"]