debug_resources.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/env python3
  2. """
  3. Debug resource handling to see actual response format
  4. """
  5. import subprocess
  6. import time
  7. import json
  8. import sys
  9. import os
  10. import threading
  11. import queue
  12. import tempfile
  13. import shutil
  14. class MCPServerTester:
  15. def __init__(self, server_path):
  16. self.server_path = server_path
  17. self.server_process = None
  18. self.message_queue = queue.Queue()
  19. self.test_dir = None
  20. def start_server(self):
  21. """Start MCP server process"""
  22. # Create a temporary directory for testing
  23. self.test_dir = tempfile.mkdtemp(prefix="mcp_test_")
  24. # Create some test files
  25. with open(os.path.join(self.test_dir, "test.txt"), "w") as f:
  26. f.write("Hello, World!")
  27. print(f"Starting MCP server: {self.server_path} with test directory: {self.test_dir}")
  28. self.server_process = subprocess.Popen(
  29. [self.server_path, self.test_dir],
  30. stdin=subprocess.PIPE,
  31. stdout=subprocess.PIPE,
  32. stderr=subprocess.PIPE,
  33. text=False,
  34. bufsize=0
  35. )
  36. # Start thread to read stderr
  37. stderr_thread = threading.Thread(target=self._read_stderr)
  38. stderr_thread.daemon = True
  39. stderr_thread.start()
  40. # Start thread to read stdout
  41. stdout_thread = threading.Thread(target=self._read_stdout)
  42. stdout_thread.daemon = True
  43. stdout_thread.start()
  44. time.sleep(1)
  45. def _read_stderr(self):
  46. """Read stderr output from server"""
  47. while self.server_process and self.server_process.poll() is None:
  48. try:
  49. line = self.server_process.stderr.readline()
  50. if line:
  51. print(f"SERVER STDERR: {line.decode().strip()}")
  52. except:
  53. break
  54. def _read_stdout(self):
  55. """Read stdout output from server with Content-Length parsing"""
  56. buffer = b""
  57. while self.server_process and self.server_process.poll() is None:
  58. try:
  59. data = self.server_process.stdout.read(1)
  60. if not data:
  61. break
  62. buffer += data
  63. if b'\r\n\r\n' in buffer:
  64. headers, body = buffer.split(b'\r\n\r\n', 1)
  65. content_length = None
  66. for line in headers.split(b'\r\n'):
  67. if line.lower().startswith(b'content-length:'):
  68. content_length = int(line.split(b':')[1].strip())
  69. break
  70. if content_length is not None and len(body) >= content_length:
  71. message = body[:content_length]
  72. buffer = body[content_length:]
  73. try:
  74. parsed = json.loads(message.decode())
  75. self.message_queue.put(parsed)
  76. except json.JSONDecodeError as e:
  77. print(f"JSON DECODE ERROR: {e}")
  78. print(f"RAW MESSAGE: {message}")
  79. except:
  80. break
  81. def send_jsonrpc_request(self, method, params=None, id=1):
  82. """Send a JSON-RPC request with proper Content-Length header"""
  83. request = {
  84. "jsonrpc": "2.0",
  85. "method": method,
  86. "id": id,
  87. "params": params or {}
  88. }
  89. request_str = json.dumps(request)
  90. message = f"Content-Length: {len(request_str)}\r\n\r\n{request_str}"
  91. self.server_process.stdin.write(message.encode())
  92. self.server_process.stdin.flush()
  93. try:
  94. response = self.message_queue.get(timeout=10)
  95. return response
  96. except queue.Empty:
  97. print("TIMEOUT: No response received")
  98. return None
  99. def cleanup(self):
  100. """Clean up test environment"""
  101. if self.test_dir and os.path.exists(self.test_dir):
  102. shutil.rmtree(self.test_dir)
  103. def stop_server(self):
  104. """Stop MCP server process"""
  105. if self.server_process:
  106. print("\nStopping server...")
  107. self.server_process.terminate()
  108. try:
  109. self.server_process.wait(timeout=5)
  110. except subprocess.TimeoutExpired:
  111. self.server_process.kill()
  112. self.server_process = None
  113. def main():
  114. if len(sys.argv) != 2:
  115. print("Usage: python3 debug_resources.py <server-executable>")
  116. sys.exit(1)
  117. server_path = sys.argv[1]
  118. if not os.path.exists(server_path):
  119. print(f"Error: Server executable '{server_path}' not found")
  120. sys.exit(1)
  121. tester = MCPServerTester(server_path)
  122. try:
  123. tester.start_server()
  124. time.sleep(2)
  125. # Initialize first
  126. init_params = {
  127. "protocolVersion": "2025-11-25",
  128. "capabilities": {},
  129. "clientInfo": {
  130. "name": "test-client",
  131. "version": "1.0.0"
  132. }
  133. }
  134. init_response = tester.send_jsonrpc_request("initialize", init_params, id=0)
  135. if init_response:
  136. print("✓ Server initialized successfully")
  137. # List resources
  138. list_response = tester.send_jsonrpc_request("resources/list", id=1)
  139. if list_response:
  140. print(f"Resources list response: {json.dumps(list_response, indent=2)}")
  141. # Get first resource URI
  142. if "result" in list_response and "resources" in list_response["result"]:
  143. resources = list_response["result"]["resources"]
  144. if resources:
  145. first_uri = resources[0]["uri"]
  146. print(f"Trying to read resource: {first_uri}")
  147. # Read resource
  148. read_response = tester.send_jsonrpc_request("resources/read", {"uri": first_uri}, id=2)
  149. if read_response:
  150. print(f"Resource read response: {json.dumps(read_response, indent=2)}")
  151. else:
  152. print("Failed to read resource")
  153. else:
  154. print("No resources found")
  155. else:
  156. print("No resources in response")
  157. else:
  158. print("Failed to list resources")
  159. else:
  160. print("Failed to initialize server")
  161. except KeyboardInterrupt:
  162. print("\nTest interrupted by user")
  163. except Exception as e:
  164. print(f"\nError during test: {e}")
  165. import traceback
  166. traceback.print_exc()
  167. finally:
  168. tester.stop_server()
  169. tester.cleanup()
  170. if __name__ == "__main__":
  171. main()