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.
- agenticwerx_mcp_client/__init__.py +3 -3
- agenticwerx_mcp_client/__main__.py +285 -46
- agenticwerx_mcp_client/api.py +144 -69
- agenticwerx_mcp_client/client.py +292 -81
- {agenticwerx_mcp_client-1.0.0.dist-info → agenticwerx_mcp_client-1.0.5.dist-info}/METADATA +44 -11
- agenticwerx_mcp_client-1.0.5.dist-info/RECORD +9 -0
- agenticwerx_mcp_client-1.0.0.dist-info/RECORD +0 -9
- {agenticwerx_mcp_client-1.0.0.dist-info → agenticwerx_mcp_client-1.0.5.dist-info}/WHEEL +0 -0
- {agenticwerx_mcp_client-1.0.0.dist-info → agenticwerx_mcp_client-1.0.5.dist-info}/entry_points.txt +0 -0
- {agenticwerx_mcp_client-1.0.0.dist-info → agenticwerx_mcp_client-1.0.5.dist-info}/licenses/LICENSE +0 -0
agenticwerx_mcp_client/client.py
CHANGED
|
@@ -7,172 +7,381 @@ AgenticWerx MCP server to retrieve rules.
|
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
9
|
import logging
|
|
10
|
-
from typing import Any
|
|
10
|
+
from typing import Any
|
|
11
11
|
|
|
12
12
|
from mcp.server import Server
|
|
13
|
-
from mcp.types import Resource, Tool, TextContent
|
|
14
13
|
from mcp.server.models import InitializationOptions
|
|
14
|
+
from mcp.types import Resource, TextContent, Tool
|
|
15
15
|
|
|
16
16
|
from .api import AgenticWerxAPI, AgenticWerxAPIError
|
|
17
17
|
|
|
18
|
-
|
|
19
18
|
logger = logging.getLogger(__name__)
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
class AgenticWerxMCPClient:
|
|
23
22
|
"""
|
|
24
23
|
Simple AgenticWerx MCP Client for rule retrieval.
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
This client connects to your AgenticWerx MCP server and provides
|
|
27
26
|
a simple interface to get rules through the MCP protocol.
|
|
28
27
|
"""
|
|
29
|
-
|
|
28
|
+
|
|
30
29
|
def __init__(self, api_key: str, debug: bool = False):
|
|
31
30
|
"""
|
|
32
31
|
Initialize the MCP client.
|
|
33
|
-
|
|
32
|
+
|
|
34
33
|
Args:
|
|
35
34
|
api_key: AgenticWerx API key
|
|
36
35
|
debug: Enable debug logging
|
|
37
36
|
"""
|
|
38
37
|
self.api_key = api_key
|
|
39
38
|
self.debug = debug
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
# Initialize the API client
|
|
42
41
|
self.api = AgenticWerxAPI(api_key)
|
|
43
|
-
|
|
42
|
+
|
|
44
43
|
# Initialize the MCP server
|
|
45
44
|
self.server = Server("agenticwerx")
|
|
46
|
-
|
|
45
|
+
|
|
47
46
|
# Configure logging
|
|
48
47
|
if debug:
|
|
49
48
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
50
|
-
|
|
49
|
+
|
|
51
50
|
logger.info("Initializing AgenticWerx MCP Client")
|
|
52
|
-
|
|
51
|
+
|
|
53
52
|
# Set up MCP handlers
|
|
54
53
|
self._setup_handlers()
|
|
55
|
-
|
|
54
|
+
|
|
56
55
|
def _setup_handlers(self) -> None:
|
|
57
56
|
"""Set up MCP server handlers."""
|
|
58
|
-
|
|
57
|
+
|
|
59
58
|
@self.server.list_resources()
|
|
60
|
-
async def list_resources() ->
|
|
59
|
+
async def list_resources() -> list[Resource]:
|
|
61
60
|
"""List available rule resources."""
|
|
62
61
|
logger.debug("Listing available rule resources")
|
|
63
|
-
|
|
62
|
+
|
|
64
63
|
try:
|
|
65
64
|
# Test if we can get rules from the Lambda MCP server
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
await self.api.get_rules()
|
|
66
|
+
|
|
68
67
|
# Create a single resource for all rules
|
|
69
68
|
resource = Resource(
|
|
70
69
|
uri="agenticwerx://rules",
|
|
71
70
|
name="AgenticWerx Rules",
|
|
72
71
|
description="All available AgenticWerx rules from Lambda MCP server",
|
|
73
|
-
mimeType="application/json"
|
|
72
|
+
mimeType="application/json",
|
|
74
73
|
)
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
logger.info("Listed rule resources from Lambda MCP server")
|
|
77
76
|
return [resource]
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
except AgenticWerxAPIError as e:
|
|
80
79
|
logger.error(f"API error listing resources: {e}")
|
|
81
80
|
return []
|
|
82
81
|
except Exception as e:
|
|
83
82
|
logger.error(f"Unexpected error listing resources: {e}")
|
|
84
83
|
return []
|
|
85
|
-
|
|
84
|
+
|
|
86
85
|
@self.server.read_resource()
|
|
87
86
|
async def read_resource(uri: str) -> str:
|
|
88
87
|
"""Read rule resource."""
|
|
89
88
|
logger.debug(f"Reading resource: {uri}")
|
|
90
|
-
|
|
89
|
+
|
|
91
90
|
if uri != "agenticwerx://rules":
|
|
92
91
|
raise ValueError(f"Unknown resource URI: {uri}")
|
|
93
|
-
|
|
92
|
+
|
|
94
93
|
try:
|
|
95
94
|
rules_data = await self.api.get_rules()
|
|
96
95
|
logger.debug("Successfully read rules resource from Lambda MCP server")
|
|
97
96
|
return json.dumps(rules_data, indent=2)
|
|
98
|
-
|
|
97
|
+
|
|
99
98
|
except AgenticWerxAPIError as e:
|
|
100
99
|
logger.error(f"API error reading resource: {e}")
|
|
101
100
|
raise
|
|
102
101
|
except Exception as e:
|
|
103
102
|
logger.error(f"Unexpected error reading resource: {e}")
|
|
104
|
-
raise ValueError(f"Failed to read resource: {str(e)}")
|
|
105
|
-
|
|
103
|
+
raise ValueError(f"Failed to read resource: {str(e)}") from e
|
|
104
|
+
|
|
106
105
|
@self.server.list_tools()
|
|
107
|
-
async def list_tools() ->
|
|
106
|
+
async def list_tools() -> list[Tool]:
|
|
108
107
|
"""List available tools."""
|
|
109
108
|
logger.debug("Listing available tools")
|
|
110
|
-
|
|
111
|
-
#
|
|
109
|
+
|
|
110
|
+
# Provide get_rules and analyze_code tools
|
|
112
111
|
tools = [
|
|
113
112
|
Tool(
|
|
114
|
-
name="
|
|
115
|
-
description=
|
|
113
|
+
name="get_rules",
|
|
114
|
+
description=(
|
|
115
|
+
"Get available rules for subscribed packages.\n\n"
|
|
116
|
+
"📋 Response Modes:\n"
|
|
117
|
+
" • Summary (default): Just id, title, category, severity\n"
|
|
118
|
+
" • Detailed (detailed=true): Includes instructions, rationale, tags, references\n"
|
|
119
|
+
" • With Content (includeContent=true): Full markdown/JSON content\n"
|
|
120
|
+
" • With Patterns (includePatterns=true + detailed=true): Regex patterns\n\n"
|
|
121
|
+
"💡 Tip: Start with summary mode, then use detailed=true or includeContent=true "
|
|
122
|
+
"when you need more information about specific rules."
|
|
123
|
+
),
|
|
116
124
|
inputSchema={
|
|
117
125
|
"type": "object",
|
|
118
126
|
"properties": {
|
|
119
127
|
"packageId": {
|
|
120
128
|
"type": "string",
|
|
121
|
-
"description": "
|
|
122
|
-
}
|
|
129
|
+
"description": "Specific package ID (optional)",
|
|
130
|
+
},
|
|
131
|
+
"language": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"description": "Filter by programming language (e.g., typescript, python, go)",
|
|
134
|
+
},
|
|
135
|
+
"framework": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"description": "Filter by framework (e.g., react, nextjs, express)",
|
|
138
|
+
},
|
|
139
|
+
"category": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"description": "Filter by category (e.g., security, api-design, testing)",
|
|
142
|
+
},
|
|
143
|
+
"severity": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"description": "Filter by severity (critical, high, medium, low)",
|
|
146
|
+
},
|
|
147
|
+
"appliesTo": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"description": "Filter by applies to (e.g., frontend, backend, api, all)",
|
|
150
|
+
},
|
|
151
|
+
"search": {
|
|
152
|
+
"type": "string",
|
|
153
|
+
"description": "Search in rule titles and descriptions",
|
|
154
|
+
},
|
|
155
|
+
"ruleIds": {
|
|
156
|
+
"type": "array",
|
|
157
|
+
"items": {"type": "string"},
|
|
158
|
+
"description": "Get specific rules by ID",
|
|
159
|
+
},
|
|
160
|
+
"detailed": {
|
|
161
|
+
"type": "boolean",
|
|
162
|
+
"description": "⭐ Get full rule details (instructions, rationale, tags). Default: false",
|
|
163
|
+
},
|
|
164
|
+
"includeContent": {
|
|
165
|
+
"type": "boolean",
|
|
166
|
+
"description": "⭐ Get complete rule content (markdown/JSON). Warning: Large responses. Default: false",
|
|
167
|
+
},
|
|
168
|
+
"includePatterns": {
|
|
169
|
+
"type": "boolean",
|
|
170
|
+
"description": "⭐ Include regex patterns (requires detailed=true). Default: false",
|
|
171
|
+
},
|
|
172
|
+
"limit": {
|
|
173
|
+
"type": "number",
|
|
174
|
+
"description": "Maximum rules to return (1-200). Default: 50",
|
|
175
|
+
},
|
|
176
|
+
"offset": {
|
|
177
|
+
"type": "number",
|
|
178
|
+
"description": "Skip N rules for pagination. Default: 0",
|
|
179
|
+
},
|
|
123
180
|
},
|
|
124
|
-
"additionalProperties": False
|
|
125
|
-
}
|
|
126
|
-
)
|
|
181
|
+
"additionalProperties": False,
|
|
182
|
+
},
|
|
183
|
+
),
|
|
184
|
+
Tool(
|
|
185
|
+
name="analyze_code",
|
|
186
|
+
description="Analyze code using AgenticWerx rules. Provide code snippet, optional language, and optional package IDs.",
|
|
187
|
+
inputSchema={
|
|
188
|
+
"type": "object",
|
|
189
|
+
"properties": {
|
|
190
|
+
"code": {
|
|
191
|
+
"type": "string",
|
|
192
|
+
"description": "Code to analyze",
|
|
193
|
+
},
|
|
194
|
+
"language": {
|
|
195
|
+
"type": "string",
|
|
196
|
+
"description": "Programming language (optional, will be auto-detected)",
|
|
197
|
+
},
|
|
198
|
+
"packageIds": {
|
|
199
|
+
"type": "array",
|
|
200
|
+
"items": {"type": "string"},
|
|
201
|
+
"description": "List of package IDs to use for analysis (optional)",
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
"required": ["code"],
|
|
205
|
+
"additionalProperties": False,
|
|
206
|
+
},
|
|
207
|
+
),
|
|
127
208
|
]
|
|
128
|
-
|
|
129
|
-
logger.info(f"Listed {len(tools)} available tools
|
|
209
|
+
|
|
210
|
+
logger.info(f"Listed {len(tools)} available tools")
|
|
130
211
|
return tools
|
|
131
|
-
|
|
212
|
+
|
|
132
213
|
@self.server.call_tool()
|
|
133
|
-
async def call_tool(name: str, arguments:
|
|
214
|
+
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
|
|
134
215
|
"""Execute a tool."""
|
|
135
216
|
logger.debug(f"Executing tool: {name}")
|
|
136
|
-
|
|
217
|
+
|
|
137
218
|
try:
|
|
138
|
-
if name == "
|
|
139
|
-
# Handle
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
219
|
+
if name == "get_rules":
|
|
220
|
+
# Handle get_rules tool with enhanced parameters
|
|
221
|
+
detailed = arguments.get("detailed", False)
|
|
222
|
+
include_content = arguments.get("includeContent", False)
|
|
223
|
+
include_patterns = arguments.get("includePatterns", False)
|
|
224
|
+
|
|
225
|
+
# Build params dict with all parameters
|
|
226
|
+
params = {
|
|
227
|
+
"packageId": arguments.get("packageId"),
|
|
228
|
+
"language": arguments.get("language"),
|
|
229
|
+
"framework": arguments.get("framework"),
|
|
230
|
+
"category": arguments.get("category"),
|
|
231
|
+
"severity": arguments.get("severity"),
|
|
232
|
+
"appliesTo": arguments.get("appliesTo"),
|
|
233
|
+
"search": arguments.get("search"),
|
|
234
|
+
"ruleIds": arguments.get("ruleIds"),
|
|
235
|
+
"limit": arguments.get("limit", 50),
|
|
236
|
+
"offset": arguments.get("offset", 0),
|
|
237
|
+
"detailed": detailed,
|
|
238
|
+
"includePatterns": include_patterns,
|
|
239
|
+
"includeContent": include_content,
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
# Remove None values
|
|
243
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
244
|
+
|
|
245
|
+
# Call the API with all parameters
|
|
246
|
+
result = await self.api.call_tool("get_rules", params)
|
|
247
|
+
|
|
248
|
+
# Parse the response - Lambda returns content array
|
|
249
|
+
content = result.get("content", [])
|
|
250
|
+
|
|
251
|
+
# Extract message and rules data from content array
|
|
252
|
+
message_text = ""
|
|
253
|
+
rules_data = None
|
|
254
|
+
|
|
255
|
+
for item in content:
|
|
256
|
+
if item.get("type") == "text":
|
|
257
|
+
text = item.get("text", "")
|
|
258
|
+
# Try to parse as JSON (second content item)
|
|
259
|
+
try:
|
|
260
|
+
parsed = json.loads(text)
|
|
261
|
+
if "rules" in parsed and "summary" in parsed:
|
|
262
|
+
rules_data = parsed
|
|
263
|
+
except json.JSONDecodeError:
|
|
264
|
+
# First content item - the message from Lambda
|
|
265
|
+
message_text = text
|
|
266
|
+
|
|
267
|
+
# If no rules data found, return just the message
|
|
268
|
+
if not rules_data:
|
|
269
|
+
return [
|
|
270
|
+
TextContent(
|
|
271
|
+
type="text",
|
|
272
|
+
text=message_text or "No rules found",
|
|
273
|
+
)
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
# Extract summary for hints
|
|
277
|
+
summary = rules_data.get("summary", {})
|
|
278
|
+
has_more = summary.get("hasMore", False)
|
|
279
|
+
offset = summary.get("offset", 0)
|
|
280
|
+
limit = summary.get("limit", 50)
|
|
281
|
+
|
|
282
|
+
# Build response with contextual hints
|
|
283
|
+
response_parts = [message_text]
|
|
284
|
+
|
|
285
|
+
# Add contextual hints based on current mode
|
|
286
|
+
if not detailed and not include_content:
|
|
287
|
+
response_parts.append(
|
|
288
|
+
"\n\n💡 Tip: You're viewing summary mode (minimal info). "
|
|
289
|
+
"To get more details, use:\n"
|
|
290
|
+
" • detailed=true - Get full rule details (instructions, rationale, tags)\n"
|
|
291
|
+
" • includeContent=true - Get complete rule content (markdown/JSON)\n"
|
|
292
|
+
" • includePatterns=true - Get regex patterns (requires detailed=true)"
|
|
293
|
+
)
|
|
294
|
+
elif detailed and not include_content:
|
|
295
|
+
response_parts.append(
|
|
296
|
+
"\n\n💡 Tip: Use includeContent=true to get the full rule content (markdown/JSON)"
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# Add pagination hint if there are more results
|
|
300
|
+
if has_more:
|
|
301
|
+
next_offset = offset + limit
|
|
302
|
+
response_parts.append(
|
|
303
|
+
f"\n\n📄 More results available. Use offset={next_offset} to get the next page."
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# Build final response
|
|
307
|
+
response_text = "".join(response_parts)
|
|
308
|
+
|
|
309
|
+
logger.debug("Successfully retrieved rules")
|
|
310
|
+
return [
|
|
311
|
+
TextContent(type="text", text=response_text),
|
|
312
|
+
TextContent(
|
|
313
|
+
type="text", text=json.dumps(rules_data, indent=2)
|
|
314
|
+
),
|
|
315
|
+
]
|
|
316
|
+
|
|
317
|
+
elif name == "analyze_code":
|
|
318
|
+
# Handle analyze_code tool
|
|
319
|
+
code = arguments.get("code")
|
|
320
|
+
if not code:
|
|
321
|
+
error_msg = "Missing required parameter: code"
|
|
322
|
+
logger.warning(error_msg)
|
|
323
|
+
return [
|
|
324
|
+
TextContent(
|
|
325
|
+
type="text",
|
|
326
|
+
text=json.dumps({"error": error_msg}, indent=2),
|
|
327
|
+
)
|
|
328
|
+
]
|
|
329
|
+
|
|
330
|
+
language = arguments.get("language")
|
|
331
|
+
package_ids = arguments.get("packageIds") or arguments.get(
|
|
332
|
+
"package_ids"
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
result = await self.api.analyze_code(code, language, package_ids)
|
|
336
|
+
|
|
143
337
|
response = {
|
|
144
|
-
"tool": "
|
|
145
|
-
"
|
|
146
|
-
"
|
|
338
|
+
"tool": "analyze_code",
|
|
339
|
+
"language": language,
|
|
340
|
+
"packageIds": package_ids,
|
|
341
|
+
"analysis": result,
|
|
147
342
|
}
|
|
148
|
-
|
|
149
|
-
logger.debug("Successfully
|
|
150
|
-
return [
|
|
151
|
-
|
|
343
|
+
|
|
344
|
+
logger.debug("Successfully analyzed code")
|
|
345
|
+
return [
|
|
346
|
+
TextContent(type="text", text=json.dumps(response, indent=2))
|
|
347
|
+
]
|
|
348
|
+
|
|
152
349
|
else:
|
|
153
|
-
#
|
|
154
|
-
error_msg = f"Tool '{name}' is not supported.
|
|
350
|
+
# Unsupported tool
|
|
351
|
+
error_msg = f"Tool '{name}' is not supported. Available tools: get_rules, analyze_code"
|
|
155
352
|
logger.warning(f"Unsupported tool requested: {name}")
|
|
156
|
-
return [
|
|
157
|
-
|
|
353
|
+
return [
|
|
354
|
+
TextContent(
|
|
355
|
+
type="text", text=json.dumps({"error": error_msg}, indent=2)
|
|
356
|
+
)
|
|
357
|
+
]
|
|
358
|
+
|
|
158
359
|
except AgenticWerxAPIError as e:
|
|
159
360
|
error_msg = f"AgenticWerx API Error: {str(e)}"
|
|
160
361
|
logger.error(f"API error in tool {name}: {e}")
|
|
161
|
-
return [
|
|
162
|
-
|
|
362
|
+
return [
|
|
363
|
+
TextContent(
|
|
364
|
+
type="text", text=json.dumps({"error": error_msg}, indent=2)
|
|
365
|
+
)
|
|
366
|
+
]
|
|
367
|
+
|
|
163
368
|
except Exception as e:
|
|
164
369
|
error_msg = f"Tool execution error: {str(e)}"
|
|
165
370
|
logger.error(f"Unexpected error in tool {name}: {e}")
|
|
166
|
-
return [
|
|
167
|
-
|
|
371
|
+
return [
|
|
372
|
+
TextContent(
|
|
373
|
+
type="text", text=json.dumps({"error": error_msg}, indent=2)
|
|
374
|
+
)
|
|
375
|
+
]
|
|
376
|
+
|
|
168
377
|
async def test_connection(self) -> bool:
|
|
169
378
|
"""Test connection to the Lambda MCP server."""
|
|
170
379
|
return await self.api.test_connection()
|
|
171
|
-
|
|
380
|
+
|
|
172
381
|
async def run(self) -> None:
|
|
173
382
|
"""Run the MCP server."""
|
|
174
383
|
logger.info("Starting AgenticWerx MCP Client")
|
|
175
|
-
|
|
384
|
+
|
|
176
385
|
# Test connection to Lambda MCP server on startup
|
|
177
386
|
logger.info("Testing connection to Lambda MCP server...")
|
|
178
387
|
connection_ok = await self.test_connection()
|
|
@@ -181,41 +390,43 @@ class AgenticWerxMCPClient:
|
|
|
181
390
|
# Continue anyway - the client might still work for some operations
|
|
182
391
|
else:
|
|
183
392
|
logger.info("Successfully connected to Lambda MCP server")
|
|
184
|
-
|
|
393
|
+
|
|
185
394
|
try:
|
|
186
395
|
from mcp.server.stdio import stdio_server
|
|
187
|
-
|
|
396
|
+
|
|
188
397
|
async with stdio_server() as (read_stream, write_stream):
|
|
189
398
|
logger.info("MCP Client started, waiting for connections...")
|
|
190
|
-
|
|
191
|
-
from mcp.types import
|
|
192
|
-
|
|
399
|
+
|
|
400
|
+
from mcp.types import (
|
|
401
|
+
ResourcesCapability,
|
|
402
|
+
ServerCapabilities,
|
|
403
|
+
ToolsCapability,
|
|
404
|
+
)
|
|
405
|
+
|
|
193
406
|
init_options = InitializationOptions(
|
|
194
407
|
server_name="agenticwerx",
|
|
195
408
|
server_version="1.0.0",
|
|
196
409
|
capabilities=ServerCapabilities(
|
|
197
|
-
resources=ResourcesCapability(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
await self.server.run(
|
|
203
|
-
read_stream,
|
|
204
|
-
write_stream,
|
|
205
|
-
init_options
|
|
410
|
+
resources=ResourcesCapability(
|
|
411
|
+
subscribe=False, listChanged=False
|
|
412
|
+
),
|
|
413
|
+
tools=ToolsCapability(listChanged=False),
|
|
414
|
+
),
|
|
206
415
|
)
|
|
207
|
-
|
|
416
|
+
|
|
417
|
+
await self.server.run(read_stream, write_stream, init_options)
|
|
418
|
+
|
|
208
419
|
except Exception as e:
|
|
209
420
|
logger.error(f"Error running MCP server: {e}")
|
|
210
421
|
raise
|
|
211
422
|
finally:
|
|
212
423
|
await self.api.close()
|
|
213
424
|
logger.info("AgenticWerx MCP Client stopped")
|
|
214
|
-
|
|
425
|
+
|
|
215
426
|
async def __aenter__(self):
|
|
216
427
|
"""Async context manager entry."""
|
|
217
428
|
return self
|
|
218
|
-
|
|
429
|
+
|
|
219
430
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
220
431
|
"""Async context manager exit."""
|
|
221
|
-
await self.api.close()
|
|
432
|
+
await self.api.close()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agenticwerx-mcp-client
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5
|
|
4
4
|
Summary: Simple MCP client that connects to your AgenticWerx MCP server to retrieve rules
|
|
5
5
|
Project-URL: Homepage, https://agenticwerx.com
|
|
6
6
|
Project-URL: Documentation, https://docs.agenticwerx.com/mcp-client
|
|
@@ -14,14 +14,13 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
16
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
22
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.10
|
|
25
24
|
Requires-Dist: httpx>=0.25.0
|
|
26
25
|
Requires-Dist: mcp>=1.0.0
|
|
27
26
|
Requires-Dist: pydantic>=2.0.0
|
|
@@ -55,7 +54,31 @@ A Model Context Protocol (MCP) client that connects to the AgenticWerx Lambda MC
|
|
|
55
54
|
|
|
56
55
|
## 🚀 Quick Start
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
The AgenticWerx MCP Client supports two modes:
|
|
58
|
+
|
|
59
|
+
### CLI Mode - Direct Command Line Usage
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Get rules
|
|
63
|
+
uvx agenticwerx-mcp-client@latest --api-key YOUR_KEY get-rules
|
|
64
|
+
|
|
65
|
+
# Analyze code
|
|
66
|
+
uvx agenticwerx-mcp-client@latest --api-key YOUR_KEY analyze-code --file script.py
|
|
67
|
+
|
|
68
|
+
# Analyze code snippet
|
|
69
|
+
uvx agenticwerx-mcp-client@latest --api-key YOUR_KEY analyze-code \
|
|
70
|
+
--code "print('hello')" --language python
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Features:**
|
|
74
|
+
- 🔍 Auto-detects programming language from file extensions
|
|
75
|
+
- 📦 Automatically chunks large files (>8KB) for analysis
|
|
76
|
+
- 📊 Aggregates results from multiple chunks
|
|
77
|
+
- 🎯 Supports 20+ programming languages
|
|
78
|
+
|
|
79
|
+
See [CLI_USAGE.md](CLI_USAGE.md) for detailed CLI documentation.
|
|
80
|
+
|
|
81
|
+
### MCP Server Mode - For IDE Integration
|
|
59
82
|
|
|
60
83
|
Add this configuration to your MCP-compatible IDE (Kiro, Amazon Q Developer, etc.):
|
|
61
84
|
|
|
@@ -64,7 +87,7 @@ Add this configuration to your MCP-compatible IDE (Kiro, Amazon Q Developer, etc
|
|
|
64
87
|
"mcpServers": {
|
|
65
88
|
"agenticwerx": {
|
|
66
89
|
"command": "uvx",
|
|
67
|
-
"args": ["agenticwerx-mcp-client@latest"
|
|
90
|
+
"args": ["agenticwerx-mcp-client@latest"],
|
|
68
91
|
"env": {
|
|
69
92
|
"AGENTICWERX_API_KEY": "your-api-key-here"
|
|
70
93
|
}
|
|
@@ -78,23 +101,33 @@ Add this configuration to your MCP-compatible IDE (Kiro, Amazon Q Developer, etc
|
|
|
78
101
|
1. Visit [AgenticWerx Dashboard](https://agenticwerx.com/dashboard)
|
|
79
102
|
2. Navigate to API Keys section
|
|
80
103
|
3. Create a new API key
|
|
81
|
-
4.
|
|
104
|
+
4. Use it in CLI or MCP configuration
|
|
82
105
|
|
|
83
106
|
## 🛠️ Available Tools
|
|
84
107
|
|
|
85
|
-
|
|
108
|
+
### MCP Server Mode Tools
|
|
109
|
+
|
|
110
|
+
### **get_rules**
|
|
111
|
+
Get AgenticWerx rules from the server.
|
|
86
112
|
|
|
87
|
-
|
|
113
|
+
**Parameters:**
|
|
114
|
+
- `packageId` (optional): Specific package ID to filter rules
|
|
115
|
+
|
|
116
|
+
### **analyze_code**
|
|
88
117
|
Analyze code using AgenticWerx rules from the server.
|
|
89
118
|
|
|
90
119
|
**Parameters:**
|
|
91
|
-
- `
|
|
120
|
+
- `code` (required): Code snippet to analyze
|
|
121
|
+
- `language` (optional): Programming language
|
|
122
|
+
- `packageIds` (optional): Array of package IDs to use for analysis
|
|
92
123
|
|
|
93
124
|
**Example:**
|
|
94
125
|
```json
|
|
95
126
|
{
|
|
96
|
-
"tool": "
|
|
97
|
-
"
|
|
127
|
+
"tool": "analyze_code",
|
|
128
|
+
"code": "print('hello world')",
|
|
129
|
+
"language": "python",
|
|
130
|
+
"packageIds": ["stripe-integration-excellence-pack"]
|
|
98
131
|
}
|
|
99
132
|
```
|
|
100
133
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
agenticwerx_mcp_client/__init__.py,sha256=cBAynWLhjKiLR4v44v1t0CSWtUGpGeqHjG8snleuN38,393
|
|
2
|
+
agenticwerx_mcp_client/__main__.py,sha256=sixRKAe-yjlfq6siYxArGs5MqLn7wXHFOGFwG3aE6mg,11838
|
|
3
|
+
agenticwerx_mcp_client/api.py,sha256=wapGF6LyTGCNE-3PRcEVljPigBNwJMFITxmMGHCEwCU,11025
|
|
4
|
+
agenticwerx_mcp_client/client.py,sha256=qD28gj4pBtHvV-tkCSYBij2i6dYixQqHIR6tsMIygUc,18501
|
|
5
|
+
agenticwerx_mcp_client-1.0.5.dist-info/METADATA,sha256=Q6Gc0i71ke8Jn0GFTXe7xcyLA38Tte-B7igCNofmX2Y,8697
|
|
6
|
+
agenticwerx_mcp_client-1.0.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
+
agenticwerx_mcp_client-1.0.5.dist-info/entry_points.txt,sha256=JZ_xQZG_DpeObI-W0Kkl_xJyuuWyDvp4nvvNEoTBnSo,80
|
|
8
|
+
agenticwerx_mcp_client-1.0.5.dist-info/licenses/LICENSE,sha256=q2BReOYGJ-oS4jzVbLIsPVDk1Gxw89w3EvFxTKEBfNk,1067
|
|
9
|
+
agenticwerx_mcp_client-1.0.5.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
agenticwerx_mcp_client/__init__.py,sha256=gNU_Q5Vxp_VnsKaq7YuHI4hYQ2k-o-3O2aZV6tQqNVU,392
|
|
2
|
-
agenticwerx_mcp_client/__main__.py,sha256=zo38csH7kS-iEP1v3DrOIoY2y_h9-3RHG_g-JqQNcTc,3564
|
|
3
|
-
agenticwerx_mcp_client/api.py,sha256=y14uWFFzu_YxPAu7UcuqQKCnNdzRJR5nN8KHmUKykTc,8547
|
|
4
|
-
agenticwerx_mcp_client/client.py,sha256=k8_1pblBqHi9B83A3xF7okfxnX0DTPy8WIpXlCkeQHs,8572
|
|
5
|
-
agenticwerx_mcp_client-1.0.0.dist-info/METADATA,sha256=iVy-vf-EkDY7wgmAk19lOB4fWf5A02LORyEr0Bpy0BI,7819
|
|
6
|
-
agenticwerx_mcp_client-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
7
|
-
agenticwerx_mcp_client-1.0.0.dist-info/entry_points.txt,sha256=JZ_xQZG_DpeObI-W0Kkl_xJyuuWyDvp4nvvNEoTBnSo,80
|
|
8
|
-
agenticwerx_mcp_client-1.0.0.dist-info/licenses/LICENSE,sha256=q2BReOYGJ-oS4jzVbLIsPVDk1Gxw89w3EvFxTKEBfNk,1067
|
|
9
|
-
agenticwerx_mcp_client-1.0.0.dist-info/RECORD,,
|
|
File without changes
|
{agenticwerx_mcp_client-1.0.0.dist-info → agenticwerx_mcp_client-1.0.5.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{agenticwerx_mcp_client-1.0.0.dist-info → agenticwerx_mcp_client-1.0.5.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|