-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathclient_httpx.py
More file actions
149 lines (122 loc) · 4.27 KB
/
client_httpx.py
File metadata and controls
149 lines (122 loc) · 4.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""
Pure httpx client for testing the Simple Tools Server.
Makes direct HTTP requests using JSON-RPC protocol.
"""
import httpx
import json
import re
class MCPClient:
"""Simple MCP client using only httpx for HTTP requests."""
def __init__(self, base_url: str = "http://localhost:8000/mcp"):
self.base_url = base_url
self.session_id = None
self.request_id = 0
def _get_next_id(self) -> int:
"""Get next request ID."""
self.request_id += 1
return self.request_id
def _build_request(self, method: str, params: dict = None) -> dict:
"""Build JSON-RPC request."""
return {
"jsonrpc": "2.0",
"id": self._get_next_id(),
"method": method,
"params": params or {}
}
def _get_headers(self) -> dict:
"""Get request headers including session ID if available."""
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream"
}
if self.session_id:
headers["Mcp-Session-Id"] = self.session_id
return headers
def _parse_sse_response(self, text: str) -> dict:
"""Parse Server-Sent Events response and extract JSON data."""
# SSE format: "event: message\ndata: {...}\n\n"
match = re.search(r'data: (.+)', text)
if match:
return json.loads(match.group(1))
# Fallback: try parsing as plain JSON
return json.loads(text)
def initialize(self) -> dict:
"""Initialize MCP session."""
request = self._build_request("initialize", {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "httpx-client",
"version": "1.0.0"
}
})
response = httpx.post(
self.base_url,
json=request,
headers=self._get_headers()
)
# Check for session ID in response headers
if "Mcp-Session-Id" in response.headers:
self.session_id = response.headers["Mcp-Session-Id"]
return self._parse_sse_response(response.text)
def list_tools(self) -> dict:
"""List available tools."""
request = self._build_request("tools/list")
response = httpx.post(
self.base_url,
json=request,
headers=self._get_headers()
)
return self._parse_sse_response(response.text)
def call_tool(self, tool_name: str, arguments: dict) -> dict:
"""Call a specific tool."""
request = self._build_request("tools/call", {
"name": tool_name,
"arguments": arguments
})
response = httpx.post(
self.base_url,
json=request,
headers=self._get_headers()
)
return self._parse_sse_response(response.text)
def main():
"""Main function to test all tools."""
client = MCPClient()
print("=" * 50)
print("Connected to Simple Tools Server via httpx")
print("=" * 50)
print()
# Initialize session
print("Initializing session...")
init_response = client.initialize()
print(f"Server info: {init_response['result']['serverInfo']}")
print()
# List available tools
print("Available tools:")
tools_response = client.list_tools()
for tool in tools_response["result"]["tools"]:
print(f" - {tool['name']}: {tool['description']}")
print()
# Test 1: Generate UUID
print("Test 1: Generate UUID")
result = client.call_tool("generate_uuid", {"version": 4})
print(f"Result: {result['result']['content'][0]['text']}")
print()
# Test 2: Convert temperature
print("Test 2: Convert temperature (0°C to Fahrenheit)")
result = client.call_tool("convert_temperature", {
"value": 0,
"from_unit": "C",
"to_unit": "F"
})
print(f"Result: {result['result']['content'][0]['text']}")
print()
# Test 3: Text statistics
print("Test 3: Text statistics")
test_text = "Hello world!\nThis is a test.\nThree lines total."
result = client.call_tool("text_statistics", {"text": test_text})
print(f"Result: {result['result']['content'][0]['text']}")
print()
if __name__ == "__main__":
main()