test_message_sizes.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. #!/usr/bin/env python3
  2. """
  3. Test MCP server with various message sizes and edge cases
  4. """
  5. import subprocess
  6. import time
  7. import json
  8. import sys
  9. import os
  10. import threading
  11. import queue
  12. class MCPServerTester:
  13. def __init__(self, server_path):
  14. self.server_path = server_path
  15. self.server_process = None
  16. self.message_queue = queue.Queue()
  17. def start_server(self):
  18. """Start MCP server process"""
  19. print(f"Starting MCP server: {self.server_path}")
  20. self.server_process = subprocess.Popen(
  21. [self.server_path],
  22. stdin=subprocess.PIPE,
  23. stdout=subprocess.PIPE,
  24. stderr=subprocess.PIPE,
  25. text=False,
  26. bufsize=0
  27. )
  28. # Start thread to read stderr
  29. stderr_thread = threading.Thread(target=self._read_stderr)
  30. stderr_thread.daemon = True
  31. stderr_thread.start()
  32. # Start thread to read stdout
  33. stdout_thread = threading.Thread(target=self._read_stdout)
  34. stdout_thread.daemon = True
  35. stdout_thread.start()
  36. time.sleep(1)
  37. def _read_stderr(self):
  38. """Read stderr output from server"""
  39. while self.server_process and self.server_process.poll() is None:
  40. try:
  41. line = self.server_process.stderr.readline()
  42. if line:
  43. print(f"SERVER STDERR: {line.decode().strip()}")
  44. except:
  45. break
  46. def _read_stdout(self):
  47. """Read stdout output from server without Content-Length parsing"""
  48. buffer = b""
  49. while self.server_process and self.server_process.poll() is None:
  50. try:
  51. data = self.server_process.stdout.readline()
  52. if not data:
  53. break
  54. buffer += data
  55. # Try to parse JSON directly from each line
  56. try:
  57. message = buffer.strip()
  58. if message:
  59. parsed = json.loads(message.decode())
  60. self.message_queue.put(parsed)
  61. buffer = b""
  62. except json.JSONDecodeError:
  63. # If not valid JSON yet, continue reading
  64. continue
  65. except:
  66. break
  67. def send_jsonrpc_request(self, method, params=None, id=1):
  68. """Send a JSON-RPC request without Content-Length header"""
  69. request = {
  70. "jsonrpc": "2.0",
  71. "method": method,
  72. "id": id,
  73. "params": params or {}
  74. }
  75. request_str = json.dumps(request)
  76. message = f"{request_str}\n"
  77. self.server_process.stdin.write(message.encode())
  78. self.server_process.stdin.flush()
  79. try:
  80. response = self.message_queue.get(timeout=10)
  81. return response
  82. except queue.Empty:
  83. print("TIMEOUT: No response received")
  84. return None
  85. def test_message_sizes(self):
  86. """Test various message sizes"""
  87. print("\n=== Testing Various Message Sizes ===")
  88. # Test small message
  89. print("\nTesting small message...")
  90. small_response = self.send_jsonrpc_request("ping", id=1)
  91. if small_response:
  92. print("✓ Small message successful")
  93. else:
  94. print("✗ Small message failed")
  95. # Test medium message
  96. print("\nTesting medium message...")
  97. medium_params = {
  98. "data": "x" * 1000, # 1KB of data
  99. "metadata": {
  100. "timestamp": "2025-12-12T03:29:00Z",
  101. "source": "test-client",
  102. "version": "1.0.0"
  103. }
  104. }
  105. medium_response = self.send_jsonrpc_request("ping", medium_params, id=2)
  106. if medium_response:
  107. print("✓ Medium message successful")
  108. else:
  109. print("✗ Medium message failed")
  110. # Test large message
  111. print("\nTesting large message...")
  112. large_params = {
  113. "data": "x" * 10000, # 10KB of data
  114. "metadata": {
  115. "timestamp": "2025-12-12T03:29:00Z",
  116. "source": "test-client",
  117. "version": "1.0.0",
  118. "extra": "y" * 5000
  119. }
  120. }
  121. large_response = self.send_jsonrpc_request("ping", large_params, id=3)
  122. if large_response:
  123. print("✓ Large message successful")
  124. else:
  125. print("✗ Large message failed")
  126. # Test very large message
  127. print("\nTesting very large message...")
  128. very_large_params = {
  129. "data": "x" * 50000, # 50KB of data
  130. "metadata": {
  131. "timestamp": "2025-12-12T03:29:00Z",
  132. "source": "test-client",
  133. "version": "1.0.0",
  134. "extra": "y" * 25000
  135. }
  136. }
  137. very_large_response = self.send_jsonrpc_request("ping", very_large_params, id=4)
  138. if very_large_response:
  139. print("✓ Very large message successful")
  140. else:
  141. print("✗ Very large message failed")
  142. def test_edge_cases(self):
  143. """Test edge cases"""
  144. print("\n=== Testing Edge Cases ===")
  145. # Test empty params
  146. print("\nTesting empty params...")
  147. empty_response = self.send_jsonrpc_request("ping", {}, id=5)
  148. if empty_response:
  149. print("✓ Empty params successful")
  150. else:
  151. print("✗ Empty params failed")
  152. # Test null params
  153. print("\nTesting null params...")
  154. null_response = self.send_jsonrpc_request("ping", None, id=6)
  155. if null_response:
  156. print("✓ Null params successful")
  157. else:
  158. print("✗ Null params failed")
  159. # Test special characters
  160. print("\nTesting special characters...")
  161. special_params = {
  162. "data": "Special chars: \n\t\r\"'\\",
  163. "unicode": "Unicode: ñáéíóú 中文 🚀",
  164. "emoji": "🎉👍💻🔧"
  165. }
  166. special_response = self.send_jsonrpc_request("ping", special_params, id=7)
  167. if special_response:
  168. print("✓ Special characters successful")
  169. else:
  170. print("✗ Special characters failed")
  171. def test_concurrent_requests(self):
  172. """Test concurrent requests"""
  173. print("\n=== Testing Concurrent Requests ===")
  174. def send_request(request_id):
  175. params = {"request_id": request_id, "data": f"concurrent_{request_id}"}
  176. return self.send_jsonrpc_request("ping", params, request_id)
  177. # Send multiple requests quickly
  178. print("\nSending 10 concurrent requests...")
  179. responses = []
  180. for i in range(10):
  181. response = send_request(10 + i)
  182. responses.append(response)
  183. successful = sum(1 for r in responses if r is not None)
  184. print(f"✓ {successful}/10 concurrent requests successful")
  185. def stop_server(self):
  186. """Stop MCP server process"""
  187. if self.server_process:
  188. print("\nStopping server...")
  189. self.server_process.terminate()
  190. try:
  191. self.server_process.wait(timeout=5)
  192. except subprocess.TimeoutExpired:
  193. self.server_process.kill()
  194. self.server_process = None
  195. def main():
  196. if len(sys.argv) != 2:
  197. print("Usage: python3 test_message_sizes.py <server-executable>")
  198. sys.exit(1)
  199. server_path = sys.argv[1]
  200. if not os.path.exists(server_path):
  201. print(f"Error: Server executable '{server_path}' not found")
  202. sys.exit(1)
  203. tester = MCPServerTester(server_path)
  204. try:
  205. tester.start_server()
  206. time.sleep(2)
  207. # Initialize first
  208. init_params = {
  209. "protocolVersion": "2025-11-25",
  210. "capabilities": {},
  211. "clientInfo": {
  212. "name": "test-client",
  213. "version": "1.0.0"
  214. }
  215. }
  216. init_response = tester.send_jsonrpc_request("initialize", init_params, id=0)
  217. if init_response:
  218. print("✓ Server initialized successfully")
  219. # Run tests
  220. tester.test_message_sizes()
  221. tester.test_edge_cases()
  222. tester.test_concurrent_requests()
  223. print("\n✓ All message size tests completed successfully")
  224. else:
  225. print("✗ Failed to initialize server")
  226. except KeyboardInterrupt:
  227. print("\nTest interrupted by user")
  228. except Exception as e:
  229. print(f"\nError during test: {e}")
  230. import traceback
  231. traceback.print_exc()
  232. finally:
  233. tester.stop_server()
  234. if __name__ == "__main__":
  235. main()