#!/usr/bin/env python3 """Minimal stdio MCP server for the Cowork probe (plan Step 1). Standard library only, and deliberately so: the point of the probe is to learn whether a plugin-declared stdio server appears in a Cowork session at all. A server that failed because a dependency was missing would answer a different question than the one being asked. Exposes one tool, ``probe_ping``, which reports the interpreter that is actually running it. Transport is newline-delimited JSON-RPC 2.0 over stdin/stdout, which is what MCP stdio means; nothing is written to stdout except protocol messages. """ import json import sys SERVER_NAME = "probe-tools" SERVER_VERSION = "0.0.1" DEFAULT_PROTOCOL_VERSION = "2024-11-05" TOOLS = [ { "name": "probe_ping", "description": ( "Return the interpreter version and executable path of the process " "serving this tool. Used to establish whether a plugin-declared " "stdio MCP server runs at all in a Cowork session." ), "inputSchema": {"type": "object", "properties": {}, "additionalProperties": False}, } ] def log(message): """Diagnostics go to stderr; stdout carries protocol traffic only.""" print("[probe-tools] %s" % message, file=sys.stderr, flush=True) def ping_payload(): return { "server": SERVER_NAME, "server_version": SERVER_VERSION, "python_version": sys.version, "python_executable": sys.executable, } def handle(request): """Return a response dict, or None for a notification (no reply expected).""" method = request.get("method") req_id = request.get("id") if req_id is None: # A notification. `notifications/initialized` is the one we expect. return None if method == "initialize": params = request.get("params") or {} # Echo the client's protocol version when it offers one; guessing a # newer version than the client speaks is how handshakes fail silently. protocol_version = params.get("protocolVersion") or DEFAULT_PROTOCOL_VERSION result = { "protocolVersion": protocol_version, "capabilities": {"tools": {}}, "serverInfo": {"name": SERVER_NAME, "version": SERVER_VERSION}, } elif method == "tools/list": result = {"tools": TOOLS} elif method == "tools/call": params = request.get("params") or {} if params.get("name") != "probe_ping": return { "jsonrpc": "2.0", "id": req_id, "error": {"code": -32602, "message": "unknown tool: %r" % params.get("name")}, } result = { "content": [ {"type": "text", "text": json.dumps(ping_payload(), indent=2, sort_keys=True)} ], "isError": False, } elif method == "ping": result = {} else: return { "jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message": "method not found: %r" % method}, } return {"jsonrpc": "2.0", "id": req_id, "result": result} def main(): log("started on %s" % sys.version.replace("\n", " ")) for line in sys.stdin: line = line.strip() if not line: continue try: request = json.loads(line) except ValueError as exc: log("undecodable line: %s" % exc) continue response = handle(request) if response is not None: sys.stdout.write(json.dumps(response) + "\n") sys.stdout.flush() return 0 if __name__ == "__main__": sys.exit(main())