#!/usr/bin/env python3
"""
Working MCP Client Test for Lemon Email
"""
import asyncio
import json
import os
import subprocess
import sys
import time
class WorkingMCPClient:
"""A simple working MCP client using subprocess"""
def __init__(self):
self.server_path = "simple_mcp_server.py"
self.api_key = os.getenv("LEMON_EMAIL_API_KEY")
async def test_mcp_server(self):
"""Test the MCP server with direct subprocess communication"""
print("π§ Testing MCP Server with Direct Communication")
print("=" * 50)
# Set up environment
env = os.environ.copy()
env["LEMON_EMAIL_API_KEY"] = self.api_key
print("π‘ Starting MCP server process...")
# Start server process
process = subprocess.Popen(
[sys.executable, self.server_path],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
env=env,
bufsize=0 # Unbuffered
)
try:
print("β
Server process started (PID: {})".format(process.pid))
# Wait a moment for server to initialize
await asyncio.sleep(0.5)
# Step 1: Initialize the connection
print("\nπ€ Step 1: Initialize MCP connection")
print("-" * 30)
init_request = {
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"experimental": {},
"sampling": {}
},
"clientInfo": {
"name": "lemon-email-test-client",
"version": "1.0.0"
}
}
}
success = await self.send_and_receive(process, init_request, "initialization")
if not success:
return False
# Step 2: Send initialized notification
print("\nπ’ Step 2: Send initialized notification")
print("-" * 30)
initialized_notif = {
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
await self.send_notification(process, initialized_notif)
# Step 3: List available tools
print("\nπ Step 3: List available tools")
print("-" * 30)
list_tools_request = {
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}
tools_response = await self.send_and_receive(process, list_tools_request, "tools list")
if not tools_response:
return False
# Step 4: Call the send_email tool
print("\nπ§ Step 4: Test send_email tool")
print("-" * 30)
call_tool_request = {
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "send_email",
"arguments": {
"to": "manojk030303@gmail.com",
"subject": "π€ MCP Protocol Test Success!",
"body": "Congratulations! π\n\nYour Lemon Email MCP server is working perfectly!\n\nThis email was sent through:\nβ
MCP Protocol communication\nβ
Your custom MCP server\nβ
Lemon Email API\n\nYour server is ready for AI agent integration!",
"fromname": "MCP Test Robot",
"fromemail": "mail@member-notification.com",
"tag": "mcp-success-test"
}
}
}
email_response = await self.send_and_receive(process, call_tool_request, "email sending")
if email_response:
print("\nπ SUCCESS! Your MCP server is working perfectly!")
print("π― Ready for AI agent integration!")
return True
else:
return False
except Exception as e:
print(f"β Test failed with error: {type(e).__name__}: {e}")
return False
finally:
# Clean up
try:
process.terminate()
await asyncio.sleep(1)
if process.poll() is None:
process.kill()
except:
pass
async def send_notification(self, process, notification):
"""Send a notification (no response expected)"""
try:
message = json.dumps(notification) + "\n"
process.stdin.write(message)
process.stdin.flush()
print(f"π€ Sent notification: {notification['method']}")
# Give server time to process
await asyncio.sleep(0.2)
except Exception as e:
print(f"β Failed to send notification: {e}")
async def send_and_receive(self, process, request, operation_name):
"""Send request and wait for response"""
try:
# Send request
message = json.dumps(request) + "\n"
process.stdin.write(message)
process.stdin.flush()
print(f"π€ Sent {operation_name} request (ID: {request.get('id')})")
# Read response with timeout
response_text = None
for _ in range(50): # 5 second timeout
if process.stdout.readable():
line = process.stdout.readline()
if line.strip():
response_text = line.strip()
break
await asyncio.sleep(0.1)
if not response_text:
print(f"β No response received for {operation_name}")
return False
# Parse response
try:
response = json.loads(response_text)
except json.JSONDecodeError as e:
print(f"β Invalid JSON response for {operation_name}: {e}")
print(f"Raw response: {response_text[:200]}...")
return False
# Check for errors
if "error" in response:
error = response["error"]
print(f"β Server error for {operation_name}:")
print(f" Code: {error.get('code')}")
print(f" Message: {error.get('message')}")
return False
# Process successful response
if "result" in response:
result = response["result"]
if operation_name == "initialization":
server_info = result.get("serverInfo", {})
print(f"β
Connected to: {server_info.get('name', 'Unknown')} v{server_info.get('version', 'Unknown')}")
print(f" Protocol version: {result.get('protocolVersion')}")
elif operation_name == "tools list":
tools = result.get("tools", [])
print(f"β
Found {len(tools)} tool(s):")
for tool in tools:
print(f" π§ {tool['name']}: {tool['description'][:60]}...")
elif operation_name == "email sending":
content = result.get("content", [])
print("β
Email tool response:")
for item in content:
text = item.get("text", "")
for line in text.split("\n"):
if line.strip():
print(f" {line}")
return True
else:
print(f"β Unexpected response format for {operation_name}")
return False
except Exception as e:
print(f"β Communication error for {operation_name}: {type(e).__name__}: {e}")
return False
async def test_simple_connection():
"""Simple connection test"""
print("π Quick Connection Test")
print("=" * 30)
# Check if server file exists
if not os.path.exists("simple_mcp_server.py"):
print("β simple_mcp_server.py not found!")
return False
# Test standalone mode first
print("1οΈβ£ Testing standalone mode...")
try:
if not os.getenv("LEMON_EMAIL_API_KEY"):
print("β LEMON_EMAIL_API_KEY environment variable required")
return
result = subprocess.run([
sys.executable, "simple_mcp_server.py", "test"
], capture_output=True, text=True, timeout=10, env={
**os.environ,
"LEMON_EMAIL_API_KEY": os.getenv("LEMON_EMAIL_API_KEY")
})
if result.returncode == 0 and "β
" in result.stdout:
print("β
Standalone mode works!")
else:
print("β Standalone mode failed")
print(f"Output: {result.stdout}")
print(f"Error: {result.stderr}")
return False
except subprocess.TimeoutExpired:
print("β Standalone test timed out")
return False
except Exception as e:
print(f"β Standalone test error: {e}")
return False
print("\n2οΈβ£ Testing MCP server startup...")
# Test MCP server starts
env = os.environ.copy()
env["LEMON_EMAIL_API_KEY"] = os.getenv("LEMON_EMAIL_API_KEY")
process = subprocess.Popen([
sys.executable, "simple_mcp_server.py"
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, env=env)
try:
# Wait for startup message
await asyncio.sleep(2)
if process.poll() is None:
print("β
MCP server started successfully!")
process.terminate()
return True
else:
stdout, stderr = process.communicate()
print("β MCP server failed to start")
print(f"Output: {stdout}")
print(f"Error: {stderr}")
return False
except Exception as e:
print(f"β MCP server test error: {e}")
process.terminate()
return False
async def main():
"""Main test runner"""
print("π LEMON EMAIL MCP - COMPREHENSIVE TEST")
print("=" * 60)
# Quick checks first
simple_ok = await test_simple_connection()
if not simple_ok:
print("\nβ Basic tests failed. Fix these issues first.")
return
print("\n" + "=" * 60)
# Full MCP protocol test
client = WorkingMCPClient()
mcp_ok = await client.test_mcp_server()
print("\n" + "=" * 60)
print("π FINAL RESULTS")
print("=" * 60)
if mcp_ok:
print("π CONGRATULATIONS!")
print("β
Your Lemon Email MCP server is fully functional!")
print("\nπ Next Steps:")
print(" 1. Your server works with the MCP protocol β
")
print(" 2. AI agents can discover and use your email tool β
")
print(" 3. Ready to integrate with:")
print(" β’ Continue.dev (VS Code extension)")
print(" β’ Cline (VS Code extension)")
print(" β’ Other MCP-compatible tools")
print(" β’ Custom AI applications")
print("\nπ¦ Ready to publish to:")
print(" β’ GitHub (for community use)")
print(" β’ PyPI (pip install lemon-email-mcp)")
else:
print("β MCP protocol test failed")
print("π§ But your email API is working - check the errors above")
if __name__ == "__main__":
asyncio.run(main())