shellmcp: MCP stdio server and CLI

This commit is contained in:
2026-11-05 10:17:21 +01:00
parent 60219ef8f8
commit e6ec0e6882
2 changed files with 103 additions and 0 deletions
+33
View File
@@ -55,3 +55,36 @@ class Describe(unittest.TestCase):
"fd: find files (instead of find).", text)
self.assertNotIn("jq", text)
self.assertIn("full permissions", shellmcp.describe("all", "/srv", 60, 8000))
class Protocol(unittest.TestCase):
def talk(self, *messages):
lines = "".join(json.dumps(m) + "\n" for m in messages) + "not json\n"
done = subprocess.run([sys.executable, os.path.join(HERE, "shellmcp.py"), "--mode", "all",
"--cwd", HERE], input=lines, capture_output=True, text=True,
timeout=10)
return [json.loads(line) for line in done.stdout.splitlines()]
def test_initialize_list_and_call(self):
replies = self.talk(
{"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {"protocolVersion": "2025-06-18", "capabilities": {},
"clientInfo": {"name": "test", "version": "0"}}},
{"jsonrpc": "2.0", "method": "notifications/initialized"},
{"jsonrpc": "2.0", "id": 2, "method": "tools/list"},
{"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": "run", "arguments": {"command": "echo hi"}}},
{"jsonrpc": "2.0", "id": 4, "method": "tools/call",
"params": {"name": "nope", "arguments": {}}},
{"jsonrpc": "2.0", "id": 5, "method": "resources/list"})
self.assertEqual([r.get("id") for r in replies], [1, 2, 3, 4, 5, None])
self.assertEqual(replies[0]["result"]["protocolVersion"], "2025-06-18")
self.assertEqual(replies[1]["result"]["tools"][0]["name"], "run")
self.assertEqual(replies[2]["result"],
{"content": [{"type": "text", "text": "exit code 0\nhi\n"}],
"isError": False})
self.assertEqual([r["error"]["code"] for r in replies[3:]], [-32602, -32601, -32700])
def test_unknown_protocol_gets_the_newest(self):
reply = self.talk({"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {"protocolVersion": "1999-01-01"}})[0]
self.assertEqual(reply["result"]["protocolVersion"], shellmcp.PROTOCOLS[0])