agenticwerx-mcp-client 1.0.0__py3-none-any.whl → 1.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,17 +8,17 @@ using proper JSON-RPC 2.0 protocol.
8
8
  import logging
9
9
  import random
10
10
  import string
11
- from typing import Dict, List, Any, Optional
12
- import httpx
11
+ from typing import Any
13
12
 
13
+ import httpx
14
14
 
15
15
  logger = logging.getLogger(__name__)
16
16
 
17
17
 
18
18
  class AgenticWerxAPIError(Exception):
19
19
  """Custom exception for API errors."""
20
-
21
- def __init__(self, message: str, status_code: Optional[int] = None):
20
+
21
+ def __init__(self, message: str, status_code: int | None = None):
22
22
  super().__init__(message)
23
23
  self.status_code = status_code
24
24
 
@@ -26,116 +26,125 @@ class AgenticWerxAPIError(Exception):
26
26
  class AgenticWerxAPI:
27
27
  """
28
28
  AgenticWerx Lambda MCP API client.
29
-
29
+
30
30
  This client connects to the AgenticWerx Lambda MCP server using
31
31
  proper JSON-RPC 2.0 protocol for MCP communication.
32
32
  """
33
-
33
+
34
34
  def __init__(self, api_key: str):
35
35
  """
36
36
  Initialize the API client.
37
-
37
+
38
38
  Args:
39
39
  api_key: AgenticWerx API key
40
40
  """
41
41
  self.api_key = api_key
42
- self.lambda_url = "https://rph7c2jq5zpisbenj73y2hpjfm0gtwdw.lambda-url.us-west-2.on.aws/"
43
-
42
+ self.lambda_url = (
43
+ "https://rph7c2jq5zpisbenj73y2hpjfm0gtwdw.lambda-url.us-west-2.on.aws/"
44
+ )
45
+
44
46
  # Create HTTP client with proper headers and timeout
47
+ # Note: SSL verification disabled since this connects to your own trusted Lambda endpoint
45
48
  self.client = httpx.AsyncClient(
46
49
  headers={
47
50
  "Authorization": f"Bearer {api_key}",
48
51
  "User-Agent": "AgenticWerx-Lambda-MCP-Client/1.0.0",
49
- "Content-Type": "application/json"
52
+ "Content-Type": "application/json",
50
53
  },
51
- timeout=httpx.Timeout(30.0, connect=10.0)
54
+ timeout=httpx.Timeout(30.0, connect=10.0),
55
+ verify=False, # Safe to disable for your own Lambda endpoint
52
56
  )
53
-
57
+
54
58
  logger.debug(f"Initialized Lambda MCP client for: {self.lambda_url}")
55
-
59
+
56
60
  async def __aenter__(self):
57
61
  """Async context manager entry."""
58
62
  return self
59
-
63
+
60
64
  async def __aexit__(self, exc_type, exc_val, exc_tb):
61
65
  """Async context manager exit."""
62
66
  await self.close()
63
-
67
+
64
68
  async def close(self) -> None:
65
69
  """Close the HTTP client."""
66
70
  await self.client.aclose()
67
-
71
+
68
72
  def _generate_request_id(self) -> str:
69
73
  """Generate a random request ID."""
70
- return ''.join(random.choices(string.ascii_lowercase + string.digits, k=7))
71
-
72
- async def _make_mcp_request(self, method: str, params: Optional[Dict[str, Any]] = None) -> Any:
74
+ return "".join(random.choices(string.ascii_lowercase + string.digits, k=7))
75
+
76
+ async def _make_mcp_request(
77
+ self, method: str, params: dict[str, Any] | None = None
78
+ ) -> Any:
73
79
  """
74
80
  Make an MCP request to the Lambda function.
75
-
81
+
76
82
  Args:
77
83
  method: MCP method name
78
84
  params: Optional parameters for the method
79
-
85
+
80
86
  Returns:
81
87
  The result from the MCP server
82
88
  """
83
89
  request_id = self._generate_request_id()
84
-
90
+
85
91
  mcp_request = {
86
92
  "jsonrpc": "2.0",
87
93
  "id": request_id,
88
94
  "method": method,
89
- "params": params or {}
95
+ "params": params or {},
90
96
  }
91
-
97
+
92
98
  logger.debug(f"Making MCP request to Lambda: {method}")
93
99
  logger.debug(f"Request payload: {mcp_request}")
94
-
100
+
95
101
  try:
96
- response = await self.client.post(
97
- self.lambda_url,
98
- json=mcp_request
99
- )
100
-
102
+ response = await self.client.post(self.lambda_url, json=mcp_request)
103
+
101
104
  logger.debug(f"Response status: {response.status_code}")
102
105
  logger.debug(f"Response headers: {dict(response.headers)}")
103
-
106
+
104
107
  if response.status_code >= 400:
105
108
  error_text = response.text
106
- logger.error(f"Lambda function returned error: {response.status_code} {error_text}")
109
+ logger.error(
110
+ f"Lambda function returned error: {response.status_code} {error_text}"
111
+ )
107
112
  raise AgenticWerxAPIError(
108
113
  f"Lambda request failed: {response.status_code}",
109
- status_code=response.status_code
114
+ status_code=response.status_code,
110
115
  )
111
-
116
+
112
117
  try:
113
118
  result = response.json()
114
- logger.debug(f"Lambda response received for request {request_id}: {result}")
119
+ logger.debug(
120
+ f"Lambda response received for request {request_id}: {result}"
121
+ )
115
122
  except Exception as json_error:
116
123
  logger.error(f"Failed to parse JSON response: {json_error}")
117
124
  logger.error(f"Raw response: {response.text}")
118
- raise AgenticWerxAPIError(f"Invalid JSON response from Lambda: {json_error}")
119
-
125
+ raise AgenticWerxAPIError(
126
+ f"Invalid JSON response from Lambda: {json_error}"
127
+ ) from json_error
128
+
120
129
  if "error" in result:
121
130
  error_msg = result["error"].get("message", "Unknown MCP error")
122
131
  logger.error(f"MCP error from Lambda: {error_msg}")
123
132
  raise AgenticWerxAPIError(f"MCP Error: {error_msg}")
124
-
133
+
125
134
  return result.get("result")
126
-
127
- except httpx.TimeoutException:
128
- raise AgenticWerxAPIError("Request timeout")
129
- except httpx.ConnectError:
130
- raise AgenticWerxAPIError("Connection error")
135
+
136
+ except httpx.TimeoutException as e:
137
+ raise AgenticWerxAPIError("Request timeout") from e
138
+ except httpx.ConnectError as e:
139
+ raise AgenticWerxAPIError("Connection error") from e
131
140
  except Exception as e:
132
141
  logger.error(f"Error making MCP request: {e}")
133
- raise AgenticWerxAPIError(f"Failed to make MCP request: {str(e)}")
134
-
142
+ raise AgenticWerxAPIError(f"Failed to make MCP request: {str(e)}") from e
143
+
135
144
  async def test_connection(self) -> bool:
136
145
  """
137
146
  Test connection to the Lambda MCP server.
138
-
147
+
139
148
  Returns:
140
149
  True if connection is successful, False otherwise
141
150
  """
@@ -147,11 +156,11 @@ class AgenticWerxAPI:
147
156
  except Exception as e:
148
157
  logger.error(f"Lambda connection test failed: {e}")
149
158
  return False
150
-
151
- async def list_tools(self) -> List[Dict[str, Any]]:
159
+
160
+ async def list_tools(self) -> list[dict[str, Any]]:
152
161
  """
153
162
  List available tools from the MCP server.
154
-
163
+
155
164
  Returns:
156
165
  List of available tools
157
166
  """
@@ -161,48 +170,49 @@ class AgenticWerxAPI:
161
170
  except Exception as e:
162
171
  logger.error(f"Failed to list tools: {e}")
163
172
  return []
164
-
165
- async def call_tool(self, name: str, arguments: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
173
+
174
+ async def call_tool(
175
+ self, name: str, arguments: dict[str, Any] | None = None
176
+ ) -> dict[str, Any]:
166
177
  """
167
178
  Call a tool on the MCP server.
168
-
179
+
169
180
  Args:
170
181
  name: Tool name
171
182
  arguments: Tool arguments
172
-
183
+
173
184
  Returns:
174
185
  Tool execution result
175
186
  """
176
187
  try:
177
- result = await self._make_mcp_request("tools/call", {
178
- "name": name,
179
- "arguments": arguments or {}
180
- })
188
+ result = await self._make_mcp_request(
189
+ "tools/call", {"name": name, "arguments": arguments or {}}
190
+ )
181
191
  return result
182
192
  except Exception as e:
183
193
  logger.error(f"Tool call failed for {name}: {e}")
184
194
  raise
185
-
186
- async def get_rules(self, package_id: Optional[str] = None) -> Dict[str, Any]:
195
+
196
+ async def get_rules(self, package_id: str | None = None) -> dict[str, Any]:
187
197
  """
188
198
  Get rules from the AgenticWerx MCP server.
189
-
199
+
190
200
  Args:
191
201
  package_id: Optional specific package ID to retrieve
192
-
202
+
193
203
  Returns:
194
204
  Rules data from the server
195
205
  """
196
206
  logger.debug("Fetching rules via MCP tool call")
197
-
207
+
198
208
  try:
199
209
  # Use the get_rules tool via MCP
200
210
  arguments = {}
201
211
  if package_id:
202
212
  arguments["packageId"] = package_id
203
-
213
+
204
214
  result = await self.call_tool("get_rules", arguments)
205
-
215
+
206
216
  # Extract the actual rules data from the MCP response
207
217
  if "content" in result and result["content"]:
208
218
  # The content should be a list with text content
@@ -215,11 +225,12 @@ class AgenticWerxAPI:
215
225
  if text.strip().startswith(("{", "[")):
216
226
  try:
217
227
  import json
228
+
218
229
  json_content = json.loads(text)
219
230
  break
220
231
  except json.JSONDecodeError:
221
232
  continue
222
-
233
+
223
234
  if json_content:
224
235
  logger.info("Successfully retrieved rules via MCP")
225
236
  return json_content
@@ -228,12 +239,76 @@ class AgenticWerxAPI:
228
239
  logger.info("No JSON content found, returning raw content")
229
240
  return {
230
241
  "content": result["content"],
231
- "message": "Rules retrieved but not in JSON format"
242
+ "message": "Rules retrieved but not in JSON format",
232
243
  }
233
-
244
+
234
245
  logger.warning("No rules content found in MCP response")
235
246
  return {"rules": [], "message": "No rules found"}
236
-
247
+
237
248
  except Exception as e:
238
249
  logger.error(f"Error fetching rules via MCP: {e}")
239
- raise AgenticWerxAPIError(f"Failed to fetch rules: {str(e)}")
250
+ raise AgenticWerxAPIError(f"Failed to fetch rules: {str(e)}") from e
251
+
252
+ async def analyze_code(
253
+ self,
254
+ code: str,
255
+ language: str | None = None,
256
+ package_ids: list[str] | None = None,
257
+ ) -> dict[str, Any]:
258
+ """
259
+ Analyze code using AgenticWerx rules.
260
+
261
+ Args:
262
+ code: Code to analyze
263
+ language: Programming language (optional, will be auto-detected)
264
+ package_ids: List of package IDs to use for analysis (optional)
265
+
266
+ Returns:
267
+ Analysis results from the server
268
+ """
269
+ logger.debug("Analyzing code via MCP tool call")
270
+
271
+ try:
272
+ # Use the analyze_code tool via MCP
273
+ arguments = {"code": code}
274
+ if language:
275
+ arguments["language"] = language
276
+ if package_ids:
277
+ arguments["packageIds"] = package_ids
278
+
279
+ result = await self.call_tool("analyze_code", arguments)
280
+
281
+ # Extract the actual analysis data from the MCP response
282
+ if "content" in result and result["content"]:
283
+ # The content should be a list with text content
284
+ json_content = None
285
+ for content_item in result["content"]:
286
+ if content_item.get("type") == "text":
287
+ text = content_item["text"]
288
+ # Try to parse as JSON
289
+ if text.strip().startswith(("{", "[")):
290
+ try:
291
+ import json
292
+
293
+ json_content = json.loads(text)
294
+ break
295
+ except json.JSONDecodeError:
296
+ continue
297
+
298
+ if json_content:
299
+ logger.info("Successfully analyzed code via MCP")
300
+ return json_content
301
+ else:
302
+ # If no JSON found, return the raw content
303
+ logger.info("No JSON content found, returning raw content")
304
+ return {
305
+ "content": result["content"],
306
+ "message": "Analysis completed but not in JSON format",
307
+ }
308
+
309
+ logger.warning("No analysis content found in MCP response")
310
+ return {"issues": [], "message": "No analysis results found"}
311
+
312
+ except Exception as e:
313
+ logger.error(f"Error analyzing code via MCP: {e}")
314
+ raise AgenticWerxAPIError(f"Failed to analyze code: {str(e)}") from e