diagnose_serialization.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #!/usr/bin/env python3
  2. """
  3. Diagnostic script to test content serialization and identify the exact issue
  4. """
  5. import subprocess
  6. import json
  7. import sys
  8. import os
  9. import tempfile
  10. def test_content_serialization():
  11. """Test content serialization by creating a simple test case"""
  12. # Create a test JSON that matches what the server should send
  13. test_prompt_response = {
  14. "jsonrpc": "2.0",
  15. "id": 2,
  16. "result": {
  17. "description": "Test prompt",
  18. "messages": [
  19. {
  20. "role": "user",
  21. "content": {
  22. "type": "text",
  23. "text": "Hello, world!"
  24. }
  25. },
  26. {
  27. "role": "assistant",
  28. "content": {
  29. "type": "image",
  30. "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==",
  31. "mimeType": "image/png"
  32. }
  33. },
  34. {
  35. "role": "user",
  36. "content": {
  37. "type": "resource",
  38. "resource": {
  39. "uri": "file:///example.txt",
  40. "text": "This is a test resource"
  41. }
  42. }
  43. }
  44. ]
  45. }
  46. }
  47. print("Testing JSON structure that should be valid:")
  48. print(json.dumps(test_prompt_response, indent=2))
  49. # Try to validate this against a simple schema
  50. try:
  51. # Basic validation of the structure
  52. result = test_prompt_response["result"]
  53. messages = result["messages"]
  54. for i, message in enumerate(messages):
  55. content = message["content"]
  56. content_type = content["type"]
  57. print(f"\nMessage {i} - Type: {content_type}")
  58. if content_type == "text":
  59. if "text" not in content:
  60. print(f" ✗ Missing 'text' field")
  61. else:
  62. print(f" ✓ Has 'text' field")
  63. elif content_type in ["image", "audio"]:
  64. if "data" not in content:
  65. print(f" ✗ Missing 'data' field")
  66. else:
  67. print(f" ✓ Has 'data' field")
  68. if "mimeType" not in content:
  69. print(f" ✗ Missing 'mimeType' field")
  70. else:
  71. print(f" ✓ Has 'mimeType' field: {content['mimeType']}")
  72. elif content_type == "resource":
  73. if "resource" not in content:
  74. print(f" ✗ Missing 'resource' field")
  75. else:
  76. resource = content["resource"]
  77. print(f" ✓ Has 'resource' field with keys: {list(resource.keys())}")
  78. if "uri" not in resource:
  79. print(f" ✗ Missing 'uri' in resource")
  80. else:
  81. print(f" ✓ Has 'uri': {resource['uri']}")
  82. # Check if resource has either text or blob
  83. has_text = "text" in resource
  84. has_blob = "blob" in resource
  85. if not (has_text or has_blob):
  86. print(f" ✗ Resource must have either 'text' or 'blob'")
  87. elif has_text:
  88. print(f" ✓ Has 'text' content")
  89. elif has_blob:
  90. print(f" ✓ Has 'blob' content")
  91. elif content_type == "resource_link":
  92. required_fields = ["name", "uri"]
  93. for field in required_fields:
  94. if field not in content:
  95. print(f" ✗ Missing '{field}' field")
  96. else:
  97. print(f" ✓ Has '{field}': {content[field]}")
  98. print("\n✓ Basic structure validation passed")
  99. return True
  100. except Exception as e:
  101. print(f"\n✗ Validation failed: {e}")
  102. import traceback
  103. traceback.print_exc()
  104. return False
  105. def test_server_response():
  106. """Test actual server response if available"""
  107. if len(sys.argv) != 2:
  108. print("Usage: python3 diagnose_serialization.py <server-executable>")
  109. return False
  110. server_path = sys.argv[1]
  111. if not os.path.exists(server_path):
  112. print(f"Error: Server executable '{server_path}' not found")
  113. return False
  114. print(f"\n{'='*60}")
  115. print(f"Testing server: {server_path}")
  116. print(f"{'='*60}")
  117. # Test the expected structure first
  118. if not test_content_serialization():
  119. print("✗ Basic structure validation failed")
  120. return False
  121. # Try to test the actual server
  122. try:
  123. # Create a simple test script
  124. test_script = '''
  125. import json
  126. import sys
  127. import subprocess
  128. # Start the server
  129. proc = subprocess.Popen([sys.argv[1]],
  130. stdin=subprocess.PIPE,
  131. stdout=subprocess.PIPE,
  132. stderr=subprocess.PIPE,
  133. text=False)
  134. # Send initialize
  135. init_msg = {
  136. "jsonrpc": "2.0",
  137. "method": "initialize",
  138. "id": 0,
  139. "params": {
  140. "protocolVersion": "2025-11-25",
  141. "capabilities": {},
  142. "clientInfo": {"name": "test", "version": "1.0.0"}
  143. }
  144. }
  145. msg_str = json.dumps(init_msg)
  146. proc.stdin.write(f"Content-Length: {len(msg_str)}\\r\\n\\r\\n{msg_str}".encode())
  147. proc.stdin.flush()
  148. # Read init response
  149. line = proc.stdout.readline()
  150. if line.startswith(b"Content-Length:"):
  151. length = int(line.decode().split(":")[1].strip())
  152. proc.stdout.readline() # empty line
  153. data = proc.stdout.read(length)
  154. response = json.loads(data.decode())
  155. print("Init response:", "success" if "result" in response else "failed")
  156. # List prompts
  157. list_msg = {"jsonrpc": "2.0", "method": "prompts/list", "id": 1, "params": {}}
  158. msg_str = json.dumps(list_msg)
  159. proc.stdin.write(f"Content-Length: {len(msg_str)}\\r\\n\\r\\n{msg_str}".encode())
  160. proc.stdin.flush()
  161. # Read list response
  162. line = proc.stdout.readline()
  163. if line.startswith(b"Content-Length:"):
  164. length = int(line.decode().split(":")[1].strip())
  165. proc.stdout.readline() # empty line
  166. data = proc.stdout.read(length)
  167. response = json.loads(data.decode())
  168. if "result" in response and "prompts" in response["result"]:
  169. prompts = response["result"]["prompts"]
  170. print(f"Found {len(prompts)} prompts")
  171. if prompts:
  172. # Get first prompt
  173. get_msg = {"jsonrpc": "2.0", "method": "prompts/get", "id": 2,
  174. "params": {"name": prompts[0]["name"]}}
  175. msg_str = json.dumps(get_msg)
  176. proc.stdin.write(f"Content-Length: {len(msg_str)}\\r\\n\\r\\n{msg_str}".encode())
  177. proc.stdin.flush()
  178. # Read get response
  179. line = proc.stdout.readline()
  180. if line.startswith(b"Content-Length:"):
  181. length = int(line.decode().split(":")[1].strip())
  182. proc.stdout.readline() # empty line
  183. data = proc.stdout.read(length)
  184. response = json.loads(data.decode())
  185. if "result" in response:
  186. print("✓ Got prompt result")
  187. result = response["result"]
  188. print(json.dumps(result, indent=2))
  189. elif "error" in response:
  190. print("✗ Got error:")
  191. print(json.dumps(response["error"], indent=2))
  192. else:
  193. print("✗ No result or error in response")
  194. proc.terminate()
  195. '''
  196. # Write test script to temp file
  197. with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
  198. f.write(test_script)
  199. temp_script = f.name
  200. # Run the test
  201. result = subprocess.run([sys.executable, temp_script, server_path],
  202. capture_output=True, text=True, timeout=10)
  203. print("Server test output:")
  204. print(result.stdout)
  205. if result.stderr:
  206. print("Server test errors:")
  207. print(result.stderr)
  208. # Clean up
  209. os.unlink(temp_script)
  210. return result.returncode == 0
  211. except subprocess.TimeoutExpired:
  212. print("✗ Server test timed out")
  213. return False
  214. except Exception as e:
  215. print(f"✗ Server test failed: {e}")
  216. import traceback
  217. traceback.print_exc()
  218. return False
  219. if __name__ == "__main__":
  220. if len(sys.argv) == 2:
  221. success = test_server_response()
  222. else:
  223. success = test_content_serialization()
  224. sys.exit(0 if success else 1)