pwndoc-mcp-server 1.0.8__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.
- pwndoc_mcp_server/__init__.py +87 -0
- pwndoc_mcp_server/cli.py +635 -0
- pwndoc_mcp_server/client.py +1122 -0
- pwndoc_mcp_server/config.py +414 -0
- pwndoc_mcp_server/logging_config.py +329 -0
- pwndoc_mcp_server/mcp_installer.py +348 -0
- pwndoc_mcp_server/server.py +1987 -0
- pwndoc_mcp_server/version.py +26 -0
- pwndoc_mcp_server-1.0.8.dist-info/METADATA +552 -0
- pwndoc_mcp_server-1.0.8.dist-info/RECORD +12 -0
- pwndoc_mcp_server-1.0.8.dist-info/WHEEL +4 -0
- pwndoc_mcp_server-1.0.8.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,1987 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PwnDoc MCP Server - Model Context Protocol implementation.
|
|
3
|
+
|
|
4
|
+
This module implements the MCP server that exposes PwnDoc functionality
|
|
5
|
+
to AI assistants like Claude through a standardized protocol.
|
|
6
|
+
|
|
7
|
+
Supports multiple transports:
|
|
8
|
+
- stdio: Standard input/output (default, for Claude Desktop)
|
|
9
|
+
- sse: Server-Sent Events (for web clients)
|
|
10
|
+
- websocket: WebSocket (for real-time applications)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
import sys
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
19
|
+
|
|
20
|
+
from .client import PwnDocClient, PwnDocError
|
|
21
|
+
from .config import Config, load_config
|
|
22
|
+
from .version import get_version
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class Tool:
|
|
29
|
+
"""MCP Tool definition."""
|
|
30
|
+
|
|
31
|
+
name: str
|
|
32
|
+
description: str
|
|
33
|
+
parameters: Dict[str, Any]
|
|
34
|
+
handler: Callable
|
|
35
|
+
required: List[str] = field(default_factory=list)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class MCPMessage:
|
|
40
|
+
"""MCP protocol message."""
|
|
41
|
+
|
|
42
|
+
jsonrpc: str = "2.0"
|
|
43
|
+
id: Optional[Union[str, int]] = None
|
|
44
|
+
method: Optional[str] = None
|
|
45
|
+
params: Optional[Dict[str, Any]] = None
|
|
46
|
+
result: Optional[Any] = None
|
|
47
|
+
error: Optional[Dict[str, Any]] = None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class PwnDocMCPServer:
|
|
51
|
+
"""
|
|
52
|
+
Model Context Protocol server for PwnDoc.
|
|
53
|
+
|
|
54
|
+
Exposes PwnDoc API functionality as MCP tools that can be called
|
|
55
|
+
by AI assistants like Claude.
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
>>> server = PwnDocMCPServer(config)
|
|
59
|
+
>>> server.run() # Starts stdio transport
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
SERVER_NAME = "pwndoc-mcp-server"
|
|
63
|
+
SERVER_VERSION = get_version()
|
|
64
|
+
PROTOCOL_VERSION = "2024-11-05"
|
|
65
|
+
|
|
66
|
+
def __init__(
|
|
67
|
+
self,
|
|
68
|
+
config: Optional[Config] = None,
|
|
69
|
+
transport: Optional[str] = None,
|
|
70
|
+
_silent: bool = False,
|
|
71
|
+
):
|
|
72
|
+
"""
|
|
73
|
+
Initialize MCP server.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
config: Configuration object (loads from environment if not provided)
|
|
77
|
+
transport: Transport type (stdio, sse, websocket)
|
|
78
|
+
_silent: Internal flag to suppress logging during tool definition extraction
|
|
79
|
+
"""
|
|
80
|
+
self.config = config or load_config()
|
|
81
|
+
self.transport = transport or self.config.mcp_transport
|
|
82
|
+
|
|
83
|
+
# Validate transport
|
|
84
|
+
valid_transports = ["stdio", "sse", "websocket"]
|
|
85
|
+
if self.transport not in valid_transports:
|
|
86
|
+
raise ValueError(f"Invalid transport: {self.transport}")
|
|
87
|
+
|
|
88
|
+
self._client: Optional[PwnDocClient] = None
|
|
89
|
+
self._tools: Dict[str, Tool] = {}
|
|
90
|
+
self._initialized = False
|
|
91
|
+
|
|
92
|
+
# Register all tools
|
|
93
|
+
self._register_tools()
|
|
94
|
+
|
|
95
|
+
# Only log if not silent (prevents stdout pollution during module import)
|
|
96
|
+
if not _silent:
|
|
97
|
+
logger.info(f"PwnDocMCPServer initialized with {len(self._tools)} tools")
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def name(self) -> str:
|
|
101
|
+
"""Get server name."""
|
|
102
|
+
return self.SERVER_NAME
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def version(self) -> str:
|
|
106
|
+
"""Get server version."""
|
|
107
|
+
return self.SERVER_VERSION
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def client(self) -> PwnDocClient:
|
|
111
|
+
"""Get or create PwnDoc client."""
|
|
112
|
+
if self._client is None:
|
|
113
|
+
self._client = PwnDocClient(self.config)
|
|
114
|
+
self._client.authenticate()
|
|
115
|
+
return self._client
|
|
116
|
+
|
|
117
|
+
def _register_tools(self):
|
|
118
|
+
"""Register all available tools."""
|
|
119
|
+
|
|
120
|
+
# =====================================================================
|
|
121
|
+
# AUDIT TOOLS
|
|
122
|
+
# =====================================================================
|
|
123
|
+
|
|
124
|
+
self._register_tool(
|
|
125
|
+
name="list_audits",
|
|
126
|
+
description="List all audits/pentests. Can filter by finding title.",
|
|
127
|
+
parameters={
|
|
128
|
+
"type": "object",
|
|
129
|
+
"properties": {
|
|
130
|
+
"finding_title": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"description": "Filter audits containing findings with this title (optional)",
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
handler=self._handle_list_audits,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self._register_tool(
|
|
140
|
+
name="get_audit",
|
|
141
|
+
description="Get detailed information about a specific audit including all findings, scope, sections, and metadata.",
|
|
142
|
+
parameters={
|
|
143
|
+
"type": "object",
|
|
144
|
+
"properties": {
|
|
145
|
+
"audit_id": {"type": "string", "description": "The audit ID (MongoDB ObjectId)"}
|
|
146
|
+
},
|
|
147
|
+
"required": ["audit_id"],
|
|
148
|
+
},
|
|
149
|
+
handler=self._handle_get_audit,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
self._register_tool(
|
|
153
|
+
name="create_audit",
|
|
154
|
+
description="Create a new audit/pentest.",
|
|
155
|
+
parameters={
|
|
156
|
+
"type": "object",
|
|
157
|
+
"properties": {
|
|
158
|
+
"name": {"type": "string", "description": "Audit name"},
|
|
159
|
+
"language": {"type": "string", "description": "Language code (e.g., 'en')"},
|
|
160
|
+
"audit_type": {"type": "string", "description": "Type of audit"},
|
|
161
|
+
},
|
|
162
|
+
"required": ["name", "language", "audit_type"],
|
|
163
|
+
},
|
|
164
|
+
handler=self._handle_create_audit,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
self._register_tool(
|
|
168
|
+
name="update_audit_general",
|
|
169
|
+
description="Update general information of an audit.",
|
|
170
|
+
parameters={
|
|
171
|
+
"type": "object",
|
|
172
|
+
"properties": {
|
|
173
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
174
|
+
"name": {"type": "string", "description": "Audit name"},
|
|
175
|
+
"client": {"type": "string", "description": "Client ID"},
|
|
176
|
+
"company": {"type": "string", "description": "Company ID"},
|
|
177
|
+
"date_start": {"type": "string", "description": "Start date (ISO format)"},
|
|
178
|
+
"date_end": {"type": "string", "description": "End date (ISO format)"},
|
|
179
|
+
"scope": {
|
|
180
|
+
"type": "array",
|
|
181
|
+
"items": {"type": "string"},
|
|
182
|
+
"description": "Scope items",
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
"required": ["audit_id"],
|
|
186
|
+
},
|
|
187
|
+
handler=self._handle_update_audit_general,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
self._register_tool(
|
|
191
|
+
name="delete_audit",
|
|
192
|
+
description="Delete an audit permanently.",
|
|
193
|
+
parameters={
|
|
194
|
+
"type": "object",
|
|
195
|
+
"properties": {
|
|
196
|
+
"audit_id": {"type": "string", "description": "The audit ID to delete"}
|
|
197
|
+
},
|
|
198
|
+
"required": ["audit_id"],
|
|
199
|
+
},
|
|
200
|
+
handler=self._handle_delete_audit,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
self._register_tool(
|
|
204
|
+
name="generate_audit_report",
|
|
205
|
+
description="Generate and download the audit report (DOCX).",
|
|
206
|
+
parameters={
|
|
207
|
+
"type": "object",
|
|
208
|
+
"properties": {"audit_id": {"type": "string", "description": "The audit ID"}},
|
|
209
|
+
"required": ["audit_id"],
|
|
210
|
+
},
|
|
211
|
+
handler=self._handle_generate_report,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
self._register_tool(
|
|
215
|
+
name="get_audit_general",
|
|
216
|
+
description="Get audit general information (dates, client, company, scope).",
|
|
217
|
+
parameters={
|
|
218
|
+
"type": "object",
|
|
219
|
+
"properties": {"audit_id": {"type": "string", "description": "The audit ID"}},
|
|
220
|
+
"required": ["audit_id"],
|
|
221
|
+
},
|
|
222
|
+
handler=self._handle_get_audit_general,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
self._register_tool(
|
|
226
|
+
name="get_audit_network",
|
|
227
|
+
description="Get audit network information.",
|
|
228
|
+
parameters={
|
|
229
|
+
"type": "object",
|
|
230
|
+
"properties": {"audit_id": {"type": "string", "description": "The audit ID"}},
|
|
231
|
+
"required": ["audit_id"],
|
|
232
|
+
},
|
|
233
|
+
handler=self._handle_get_audit_network,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
self._register_tool(
|
|
237
|
+
name="update_audit_network",
|
|
238
|
+
description="Update audit network information.",
|
|
239
|
+
parameters={
|
|
240
|
+
"type": "object",
|
|
241
|
+
"properties": {
|
|
242
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
243
|
+
"network_data": {"type": "object", "description": "Network configuration data"},
|
|
244
|
+
},
|
|
245
|
+
"required": ["audit_id", "network_data"],
|
|
246
|
+
},
|
|
247
|
+
handler=self._handle_update_audit_network,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
self._register_tool(
|
|
251
|
+
name="toggle_audit_approval",
|
|
252
|
+
description="Toggle audit approval status.",
|
|
253
|
+
parameters={
|
|
254
|
+
"type": "object",
|
|
255
|
+
"properties": {"audit_id": {"type": "string", "description": "The audit ID"}},
|
|
256
|
+
"required": ["audit_id"],
|
|
257
|
+
},
|
|
258
|
+
handler=self._handle_toggle_audit_approval,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
self._register_tool(
|
|
262
|
+
name="update_review_status",
|
|
263
|
+
description="Update audit ready-for-review status.",
|
|
264
|
+
parameters={
|
|
265
|
+
"type": "object",
|
|
266
|
+
"properties": {
|
|
267
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
268
|
+
"state": {"type": "boolean", "description": "Ready for review state"},
|
|
269
|
+
},
|
|
270
|
+
"required": ["audit_id", "state"],
|
|
271
|
+
},
|
|
272
|
+
handler=self._handle_update_review_status,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
self._register_tool(
|
|
276
|
+
name="get_audit_sections",
|
|
277
|
+
description="Get audit sections content.",
|
|
278
|
+
parameters={
|
|
279
|
+
"type": "object",
|
|
280
|
+
"properties": {"audit_id": {"type": "string", "description": "The audit ID"}},
|
|
281
|
+
"required": ["audit_id"],
|
|
282
|
+
},
|
|
283
|
+
handler=self._handle_get_audit_sections,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
self._register_tool(
|
|
287
|
+
name="update_audit_sections",
|
|
288
|
+
description="Update audit sections content.",
|
|
289
|
+
parameters={
|
|
290
|
+
"type": "object",
|
|
291
|
+
"properties": {
|
|
292
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
293
|
+
"sections": {"type": "object", "description": "Sections data to update"},
|
|
294
|
+
},
|
|
295
|
+
"required": ["audit_id", "sections"],
|
|
296
|
+
},
|
|
297
|
+
handler=self._handle_update_audit_sections,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
# =====================================================================
|
|
301
|
+
# FINDING TOOLS
|
|
302
|
+
# =====================================================================
|
|
303
|
+
|
|
304
|
+
self._register_tool(
|
|
305
|
+
name="get_audit_findings",
|
|
306
|
+
description="Get all findings/vulnerabilities from a specific audit.",
|
|
307
|
+
parameters={
|
|
308
|
+
"type": "object",
|
|
309
|
+
"properties": {"audit_id": {"type": "string", "description": "The audit ID"}},
|
|
310
|
+
"required": ["audit_id"],
|
|
311
|
+
},
|
|
312
|
+
handler=self._handle_get_findings,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
self._register_tool(
|
|
316
|
+
name="get_finding",
|
|
317
|
+
description="Get details of a specific finding in an audit.",
|
|
318
|
+
parameters={
|
|
319
|
+
"type": "object",
|
|
320
|
+
"properties": {
|
|
321
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
322
|
+
"finding_id": {"type": "string", "description": "The finding ID"},
|
|
323
|
+
},
|
|
324
|
+
"required": ["audit_id", "finding_id"],
|
|
325
|
+
},
|
|
326
|
+
handler=self._handle_get_finding,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
self._register_tool(
|
|
330
|
+
name="create_finding",
|
|
331
|
+
description="Create a new finding in an audit.",
|
|
332
|
+
parameters={
|
|
333
|
+
"type": "object",
|
|
334
|
+
"properties": {
|
|
335
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
336
|
+
"title": {"type": "string", "description": "Finding title"},
|
|
337
|
+
"description": {"type": "string", "description": "Detailed description"},
|
|
338
|
+
"observation": {"type": "string", "description": "Observation/evidence"},
|
|
339
|
+
"remediation": {"type": "string", "description": "Remediation steps"},
|
|
340
|
+
"cvssv3": {"type": "string", "description": "CVSS v3 score/vector"},
|
|
341
|
+
"priority": {"type": "integer", "description": "Priority (1-4)"},
|
|
342
|
+
"category": {"type": "string", "description": "Category"},
|
|
343
|
+
"vuln_type": {"type": "string", "description": "Vulnerability type"},
|
|
344
|
+
"poc": {"type": "string", "description": "Proof of concept"},
|
|
345
|
+
"scope": {"type": "string", "description": "Affected scope"},
|
|
346
|
+
"references": {
|
|
347
|
+
"type": "array",
|
|
348
|
+
"items": {"type": "string"},
|
|
349
|
+
"description": "References",
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
"required": ["audit_id", "title"],
|
|
353
|
+
},
|
|
354
|
+
handler=self._handle_create_finding,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
self._register_tool(
|
|
358
|
+
name="update_finding",
|
|
359
|
+
description="Update an existing finding.",
|
|
360
|
+
parameters={
|
|
361
|
+
"type": "object",
|
|
362
|
+
"properties": {
|
|
363
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
364
|
+
"finding_id": {"type": "string", "description": "The finding ID"},
|
|
365
|
+
"title": {"type": "string"},
|
|
366
|
+
"description": {"type": "string"},
|
|
367
|
+
"observation": {"type": "string"},
|
|
368
|
+
"remediation": {"type": "string"},
|
|
369
|
+
"cvssv3": {"type": "string"},
|
|
370
|
+
"priority": {"type": "integer"},
|
|
371
|
+
"category": {"type": "string"},
|
|
372
|
+
"vuln_type": {"type": "string"},
|
|
373
|
+
"poc": {"type": "string"},
|
|
374
|
+
"scope": {"type": "string"},
|
|
375
|
+
"references": {"type": "array", "items": {"type": "string"}},
|
|
376
|
+
},
|
|
377
|
+
"required": ["audit_id", "finding_id"],
|
|
378
|
+
},
|
|
379
|
+
handler=self._handle_update_finding,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
self._register_tool(
|
|
383
|
+
name="delete_finding",
|
|
384
|
+
description="Delete a finding from an audit.",
|
|
385
|
+
parameters={
|
|
386
|
+
"type": "object",
|
|
387
|
+
"properties": {
|
|
388
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
389
|
+
"finding_id": {"type": "string", "description": "The finding ID to delete"},
|
|
390
|
+
},
|
|
391
|
+
"required": ["audit_id", "finding_id"],
|
|
392
|
+
},
|
|
393
|
+
handler=self._handle_delete_finding,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
self._register_tool(
|
|
397
|
+
name="search_findings",
|
|
398
|
+
description="Search for findings across all audits by various criteria.",
|
|
399
|
+
parameters={
|
|
400
|
+
"type": "object",
|
|
401
|
+
"properties": {
|
|
402
|
+
"title": {"type": "string", "description": "Search by finding title"},
|
|
403
|
+
"category": {"type": "string", "description": "Filter by category"},
|
|
404
|
+
"severity": {
|
|
405
|
+
"type": "string",
|
|
406
|
+
"description": "Filter by severity (Critical, High, Medium, Low)",
|
|
407
|
+
},
|
|
408
|
+
"status": {"type": "string", "description": "Filter by status"},
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
handler=self._handle_search_findings,
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
self._register_tool(
|
|
415
|
+
name="get_all_findings_with_context",
|
|
416
|
+
description="Get ALL findings from ALL audits with full context (company, dates, team, scope, description, CWE, references) in a single request.",
|
|
417
|
+
parameters={
|
|
418
|
+
"type": "object",
|
|
419
|
+
"properties": {
|
|
420
|
+
"include_failed": {
|
|
421
|
+
"type": "boolean",
|
|
422
|
+
"description": "Include 'Failed' category findings (default: false)",
|
|
423
|
+
},
|
|
424
|
+
"exclude_categories": {
|
|
425
|
+
"type": "array",
|
|
426
|
+
"items": {"type": "string"},
|
|
427
|
+
"description": "Categories to exclude",
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
handler=self._handle_get_all_findings_with_context,
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
self._register_tool(
|
|
435
|
+
name="sort_findings",
|
|
436
|
+
description="Reorder findings within an audit.",
|
|
437
|
+
parameters={
|
|
438
|
+
"type": "object",
|
|
439
|
+
"properties": {
|
|
440
|
+
"audit_id": {"type": "string", "description": "The audit ID"},
|
|
441
|
+
"finding_order": {
|
|
442
|
+
"type": "array",
|
|
443
|
+
"items": {"type": "string"},
|
|
444
|
+
"description": "Ordered array of finding IDs",
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
"required": ["audit_id", "finding_order"],
|
|
448
|
+
},
|
|
449
|
+
handler=self._handle_sort_findings,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
self._register_tool(
|
|
453
|
+
name="move_finding",
|
|
454
|
+
description="Move a finding from one audit to another.",
|
|
455
|
+
parameters={
|
|
456
|
+
"type": "object",
|
|
457
|
+
"properties": {
|
|
458
|
+
"audit_id": {"type": "string", "description": "Source audit ID"},
|
|
459
|
+
"finding_id": {"type": "string", "description": "Finding ID to move"},
|
|
460
|
+
"destination_audit_id": {
|
|
461
|
+
"type": "string",
|
|
462
|
+
"description": "Destination audit ID",
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
"required": ["audit_id", "finding_id", "destination_audit_id"],
|
|
466
|
+
},
|
|
467
|
+
handler=self._handle_move_finding,
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# =====================================================================
|
|
471
|
+
# CLIENT & COMPANY TOOLS
|
|
472
|
+
# =====================================================================
|
|
473
|
+
|
|
474
|
+
self._register_tool(
|
|
475
|
+
name="list_clients",
|
|
476
|
+
description="List all clients.",
|
|
477
|
+
parameters={"type": "object", "properties": {}},
|
|
478
|
+
handler=self._handle_list_clients,
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
self._register_tool(
|
|
482
|
+
name="create_client",
|
|
483
|
+
description="Create a new client.",
|
|
484
|
+
parameters={
|
|
485
|
+
"type": "object",
|
|
486
|
+
"properties": {
|
|
487
|
+
"firstname": {"type": "string", "description": "First name"},
|
|
488
|
+
"lastname": {"type": "string", "description": "Last name"},
|
|
489
|
+
"email": {"type": "string", "description": "Client email"},
|
|
490
|
+
"phone": {"type": "string", "description": "Phone number"},
|
|
491
|
+
"cell": {"type": "string", "description": "Cell phone"},
|
|
492
|
+
"title": {"type": "string", "description": "Job title"},
|
|
493
|
+
"company": {"type": "string", "description": "Company ID"},
|
|
494
|
+
},
|
|
495
|
+
"required": ["email", "firstname", "lastname"],
|
|
496
|
+
},
|
|
497
|
+
handler=self._handle_create_client,
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
self._register_tool(
|
|
501
|
+
name="update_client",
|
|
502
|
+
description="Update an existing client.",
|
|
503
|
+
parameters={
|
|
504
|
+
"type": "object",
|
|
505
|
+
"properties": {
|
|
506
|
+
"client_id": {"type": "string", "description": "Client ID"},
|
|
507
|
+
"firstname": {"type": "string", "description": "First name"},
|
|
508
|
+
"lastname": {"type": "string", "description": "Last name"},
|
|
509
|
+
"email": {"type": "string", "description": "Client email"},
|
|
510
|
+
"phone": {"type": "string", "description": "Phone number"},
|
|
511
|
+
"cell": {"type": "string", "description": "Cell phone"},
|
|
512
|
+
"title": {"type": "string", "description": "Job title"},
|
|
513
|
+
"company": {"type": "string", "description": "Company ID"},
|
|
514
|
+
},
|
|
515
|
+
"required": ["client_id"],
|
|
516
|
+
},
|
|
517
|
+
handler=self._handle_update_client,
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
self._register_tool(
|
|
521
|
+
name="delete_client",
|
|
522
|
+
description="Delete a client.",
|
|
523
|
+
parameters={
|
|
524
|
+
"type": "object",
|
|
525
|
+
"properties": {
|
|
526
|
+
"client_id": {"type": "string", "description": "Client ID to delete"}
|
|
527
|
+
},
|
|
528
|
+
"required": ["client_id"],
|
|
529
|
+
},
|
|
530
|
+
handler=self._handle_delete_client,
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
self._register_tool(
|
|
534
|
+
name="list_companies",
|
|
535
|
+
description="List all companies.",
|
|
536
|
+
parameters={"type": "object", "properties": {}},
|
|
537
|
+
handler=self._handle_list_companies,
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
self._register_tool(
|
|
541
|
+
name="create_company",
|
|
542
|
+
description="Create a new company.",
|
|
543
|
+
parameters={
|
|
544
|
+
"type": "object",
|
|
545
|
+
"properties": {
|
|
546
|
+
"name": {"type": "string", "description": "Company name"},
|
|
547
|
+
"short_name": {"type": "string", "description": "Short name/abbreviation"},
|
|
548
|
+
"logo": {"type": "string", "description": "Logo (base64)"},
|
|
549
|
+
},
|
|
550
|
+
"required": ["name"],
|
|
551
|
+
},
|
|
552
|
+
handler=self._handle_create_company,
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
self._register_tool(
|
|
556
|
+
name="update_company",
|
|
557
|
+
description="Update an existing company.",
|
|
558
|
+
parameters={
|
|
559
|
+
"type": "object",
|
|
560
|
+
"properties": {
|
|
561
|
+
"company_id": {"type": "string", "description": "Company ID"},
|
|
562
|
+
"name": {"type": "string", "description": "Company name"},
|
|
563
|
+
"short_name": {"type": "string", "description": "Short name/abbreviation"},
|
|
564
|
+
"logo": {"type": "string", "description": "Logo (base64)"},
|
|
565
|
+
},
|
|
566
|
+
"required": ["company_id"],
|
|
567
|
+
},
|
|
568
|
+
handler=self._handle_update_company,
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
self._register_tool(
|
|
572
|
+
name="delete_company",
|
|
573
|
+
description="Delete a company.",
|
|
574
|
+
parameters={
|
|
575
|
+
"type": "object",
|
|
576
|
+
"properties": {
|
|
577
|
+
"company_id": {"type": "string", "description": "Company ID to delete"}
|
|
578
|
+
},
|
|
579
|
+
"required": ["company_id"],
|
|
580
|
+
},
|
|
581
|
+
handler=self._handle_delete_company,
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
# =====================================================================
|
|
585
|
+
# VULNERABILITY TEMPLATE TOOLS
|
|
586
|
+
# =====================================================================
|
|
587
|
+
|
|
588
|
+
self._register_tool(
|
|
589
|
+
name="list_vulnerabilities",
|
|
590
|
+
description="List all vulnerability templates in the library.",
|
|
591
|
+
parameters={"type": "object", "properties": {}},
|
|
592
|
+
handler=self._handle_list_vulnerabilities,
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
self._register_tool(
|
|
596
|
+
name="get_vulnerabilities_by_locale",
|
|
597
|
+
description="Get vulnerability templates for a specific language.",
|
|
598
|
+
parameters={
|
|
599
|
+
"type": "object",
|
|
600
|
+
"properties": {
|
|
601
|
+
"locale": {
|
|
602
|
+
"type": "string",
|
|
603
|
+
"description": "Language code (e.g., 'en', 'fr')",
|
|
604
|
+
"default": "en",
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
handler=self._handle_get_vulnerabilities_by_locale,
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
self._register_tool(
|
|
612
|
+
name="create_vulnerability",
|
|
613
|
+
description="Create a new vulnerability template.",
|
|
614
|
+
parameters={
|
|
615
|
+
"type": "object",
|
|
616
|
+
"properties": {
|
|
617
|
+
"details": {"type": "object", "description": "Vulnerability details by locale"},
|
|
618
|
+
"cvssv3": {"type": "string", "description": "CVSS v3 score"},
|
|
619
|
+
"priority": {"type": "integer", "description": "Priority (1-4)"},
|
|
620
|
+
"remediation_complexity": {
|
|
621
|
+
"type": "integer",
|
|
622
|
+
"description": "Complexity (1-3)",
|
|
623
|
+
},
|
|
624
|
+
"category": {"type": "string", "description": "Category"},
|
|
625
|
+
},
|
|
626
|
+
"required": ["details"],
|
|
627
|
+
},
|
|
628
|
+
handler=self._handle_create_vulnerability,
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
self._register_tool(
|
|
632
|
+
name="update_vulnerability",
|
|
633
|
+
description="Update an existing vulnerability template.",
|
|
634
|
+
parameters={
|
|
635
|
+
"type": "object",
|
|
636
|
+
"properties": {
|
|
637
|
+
"vuln_id": {"type": "string", "description": "Vulnerability template ID"},
|
|
638
|
+
"details": {"type": "object", "description": "Vulnerability details by locale"},
|
|
639
|
+
"cvssv3": {"type": "string", "description": "CVSS v3 score"},
|
|
640
|
+
"priority": {"type": "integer", "description": "Priority (1-4)"},
|
|
641
|
+
"remediation_complexity": {
|
|
642
|
+
"type": "integer",
|
|
643
|
+
"description": "Complexity (1-3)",
|
|
644
|
+
},
|
|
645
|
+
"category": {"type": "string", "description": "Category"},
|
|
646
|
+
},
|
|
647
|
+
"required": ["vuln_id"],
|
|
648
|
+
},
|
|
649
|
+
handler=self._handle_update_vulnerability,
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
self._register_tool(
|
|
653
|
+
name="delete_vulnerability",
|
|
654
|
+
description="Delete a vulnerability template.",
|
|
655
|
+
parameters={
|
|
656
|
+
"type": "object",
|
|
657
|
+
"properties": {
|
|
658
|
+
"vuln_id": {
|
|
659
|
+
"type": "string",
|
|
660
|
+
"description": "Vulnerability template ID to delete",
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
"required": ["vuln_id"],
|
|
664
|
+
},
|
|
665
|
+
handler=self._handle_delete_vulnerability,
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
self._register_tool(
|
|
669
|
+
name="bulk_delete_vulnerabilities",
|
|
670
|
+
description="Delete multiple vulnerability templates at once.",
|
|
671
|
+
parameters={
|
|
672
|
+
"type": "object",
|
|
673
|
+
"properties": {
|
|
674
|
+
"vuln_ids": {
|
|
675
|
+
"type": "array",
|
|
676
|
+
"items": {"type": "string"},
|
|
677
|
+
"description": "Array of vulnerability template IDs to delete",
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
"required": ["vuln_ids"],
|
|
681
|
+
},
|
|
682
|
+
handler=self._handle_bulk_delete_vulnerabilities,
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
self._register_tool(
|
|
686
|
+
name="export_vulnerabilities",
|
|
687
|
+
description="Export all vulnerability templates.",
|
|
688
|
+
parameters={"type": "object", "properties": {}},
|
|
689
|
+
handler=self._handle_export_vulnerabilities,
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
self._register_tool(
|
|
693
|
+
name="create_vulnerability_from_finding",
|
|
694
|
+
description="Create a vulnerability template from an existing finding.",
|
|
695
|
+
parameters={
|
|
696
|
+
"type": "object",
|
|
697
|
+
"properties": {
|
|
698
|
+
"audit_id": {"type": "string", "description": "Audit ID"},
|
|
699
|
+
"finding_id": {"type": "string", "description": "Finding ID"},
|
|
700
|
+
"locale": {"type": "string", "description": "Language code (e.g., 'en')"},
|
|
701
|
+
},
|
|
702
|
+
"required": ["audit_id", "finding_id"],
|
|
703
|
+
},
|
|
704
|
+
handler=self._handle_create_vulnerability_from_finding,
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
self._register_tool(
|
|
708
|
+
name="get_vulnerability_updates",
|
|
709
|
+
description="Get available vulnerability template updates.",
|
|
710
|
+
parameters={"type": "object", "properties": {}},
|
|
711
|
+
handler=self._handle_get_vulnerability_updates,
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
self._register_tool(
|
|
715
|
+
name="merge_vulnerability",
|
|
716
|
+
description="Merge vulnerability template with an update.",
|
|
717
|
+
parameters={
|
|
718
|
+
"type": "object",
|
|
719
|
+
"properties": {
|
|
720
|
+
"vuln_id": {"type": "string", "description": "Vulnerability template ID"},
|
|
721
|
+
"update_id": {"type": "string", "description": "Update ID to merge"},
|
|
722
|
+
},
|
|
723
|
+
"required": ["vuln_id", "update_id"],
|
|
724
|
+
},
|
|
725
|
+
handler=self._handle_merge_vulnerability,
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
# =====================================================================
|
|
729
|
+
# USER TOOLS
|
|
730
|
+
# =====================================================================
|
|
731
|
+
|
|
732
|
+
self._register_tool(
|
|
733
|
+
name="list_users",
|
|
734
|
+
description="List all users (admin only).",
|
|
735
|
+
parameters={"type": "object", "properties": {}},
|
|
736
|
+
handler=self._handle_list_users,
|
|
737
|
+
)
|
|
738
|
+
|
|
739
|
+
self._register_tool(
|
|
740
|
+
name="get_current_user",
|
|
741
|
+
description="Get current authenticated user's info.",
|
|
742
|
+
parameters={"type": "object", "properties": {}},
|
|
743
|
+
handler=self._handle_get_current_user,
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
self._register_tool(
|
|
747
|
+
name="get_user",
|
|
748
|
+
description="Get user information by username.",
|
|
749
|
+
parameters={
|
|
750
|
+
"type": "object",
|
|
751
|
+
"properties": {"username": {"type": "string", "description": "Username"}},
|
|
752
|
+
"required": ["username"],
|
|
753
|
+
},
|
|
754
|
+
handler=self._handle_get_user,
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
self._register_tool(
|
|
758
|
+
name="create_user",
|
|
759
|
+
description="Create a new user (admin only).",
|
|
760
|
+
parameters={
|
|
761
|
+
"type": "object",
|
|
762
|
+
"properties": {
|
|
763
|
+
"username": {"type": "string", "description": "Username"},
|
|
764
|
+
"password": {"type": "string", "description": "Password"},
|
|
765
|
+
"firstname": {"type": "string", "description": "First name"},
|
|
766
|
+
"lastname": {"type": "string", "description": "Last name"},
|
|
767
|
+
"email": {"type": "string", "description": "Email address"},
|
|
768
|
+
"role": {"type": "string", "description": "User role"},
|
|
769
|
+
},
|
|
770
|
+
"required": ["username", "password", "firstname", "lastname", "email", "role"],
|
|
771
|
+
},
|
|
772
|
+
handler=self._handle_create_user,
|
|
773
|
+
)
|
|
774
|
+
|
|
775
|
+
self._register_tool(
|
|
776
|
+
name="update_user",
|
|
777
|
+
description="Update a user (admin only).",
|
|
778
|
+
parameters={
|
|
779
|
+
"type": "object",
|
|
780
|
+
"properties": {
|
|
781
|
+
"user_id": {"type": "string", "description": "User ID"},
|
|
782
|
+
"username": {"type": "string", "description": "Username"},
|
|
783
|
+
"firstname": {"type": "string", "description": "First name"},
|
|
784
|
+
"lastname": {"type": "string", "description": "Last name"},
|
|
785
|
+
"email": {"type": "string", "description": "Email address"},
|
|
786
|
+
"role": {"type": "string", "description": "User role"},
|
|
787
|
+
},
|
|
788
|
+
"required": ["user_id"],
|
|
789
|
+
},
|
|
790
|
+
handler=self._handle_update_user,
|
|
791
|
+
)
|
|
792
|
+
|
|
793
|
+
self._register_tool(
|
|
794
|
+
name="update_current_user",
|
|
795
|
+
description="Update current user's profile.",
|
|
796
|
+
parameters={
|
|
797
|
+
"type": "object",
|
|
798
|
+
"properties": {
|
|
799
|
+
"firstname": {"type": "string", "description": "First name"},
|
|
800
|
+
"lastname": {"type": "string", "description": "Last name"},
|
|
801
|
+
"email": {"type": "string", "description": "Email address"},
|
|
802
|
+
"password": {"type": "string", "description": "New password"},
|
|
803
|
+
},
|
|
804
|
+
},
|
|
805
|
+
handler=self._handle_update_current_user,
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
self._register_tool(
|
|
809
|
+
name="list_reviewers",
|
|
810
|
+
description="List all users with reviewer role.",
|
|
811
|
+
parameters={"type": "object", "properties": {}},
|
|
812
|
+
handler=self._handle_list_reviewers,
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
self._register_tool(
|
|
816
|
+
name="get_totp_status",
|
|
817
|
+
description="Get TOTP (2FA) status for current user.",
|
|
818
|
+
parameters={"type": "object", "properties": {}},
|
|
819
|
+
handler=self._handle_get_totp,
|
|
820
|
+
)
|
|
821
|
+
|
|
822
|
+
self._register_tool(
|
|
823
|
+
name="setup_totp",
|
|
824
|
+
description="Setup TOTP (2FA) for current user.",
|
|
825
|
+
parameters={"type": "object", "properties": {}},
|
|
826
|
+
handler=self._handle_setup_totp,
|
|
827
|
+
)
|
|
828
|
+
|
|
829
|
+
self._register_tool(
|
|
830
|
+
name="disable_totp",
|
|
831
|
+
description="Disable TOTP (2FA) for current user.",
|
|
832
|
+
parameters={
|
|
833
|
+
"type": "object",
|
|
834
|
+
"properties": {
|
|
835
|
+
"token": {"type": "string", "description": "TOTP token for verification"}
|
|
836
|
+
},
|
|
837
|
+
"required": ["token"],
|
|
838
|
+
},
|
|
839
|
+
handler=self._handle_disable_totp,
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
# =====================================================================
|
|
843
|
+
# SETTINGS & DATA TOOLS
|
|
844
|
+
# =====================================================================
|
|
845
|
+
|
|
846
|
+
self._register_tool(
|
|
847
|
+
name="list_templates",
|
|
848
|
+
description="List all report templates.",
|
|
849
|
+
parameters={"type": "object", "properties": {}},
|
|
850
|
+
handler=self._handle_list_templates,
|
|
851
|
+
)
|
|
852
|
+
|
|
853
|
+
self._register_tool(
|
|
854
|
+
name="create_template",
|
|
855
|
+
description="Create/upload a report template.",
|
|
856
|
+
parameters={
|
|
857
|
+
"type": "object",
|
|
858
|
+
"properties": {
|
|
859
|
+
"name": {"type": "string", "description": "Template name"},
|
|
860
|
+
"ext": {"type": "string", "description": "File extension (e.g., 'docx')"},
|
|
861
|
+
"file_content": {
|
|
862
|
+
"type": "string",
|
|
863
|
+
"description": "Base64-encoded file content",
|
|
864
|
+
},
|
|
865
|
+
},
|
|
866
|
+
"required": ["name", "ext", "file_content"],
|
|
867
|
+
},
|
|
868
|
+
handler=self._handle_create_template,
|
|
869
|
+
)
|
|
870
|
+
|
|
871
|
+
self._register_tool(
|
|
872
|
+
name="update_template",
|
|
873
|
+
description="Update an existing template.",
|
|
874
|
+
parameters={
|
|
875
|
+
"type": "object",
|
|
876
|
+
"properties": {
|
|
877
|
+
"template_id": {"type": "string", "description": "Template ID"},
|
|
878
|
+
"name": {"type": "string", "description": "Template name"},
|
|
879
|
+
"ext": {"type": "string", "description": "File extension"},
|
|
880
|
+
"file_content": {
|
|
881
|
+
"type": "string",
|
|
882
|
+
"description": "Base64-encoded file content",
|
|
883
|
+
},
|
|
884
|
+
},
|
|
885
|
+
"required": ["template_id"],
|
|
886
|
+
},
|
|
887
|
+
handler=self._handle_update_template,
|
|
888
|
+
)
|
|
889
|
+
|
|
890
|
+
self._register_tool(
|
|
891
|
+
name="delete_template",
|
|
892
|
+
description="Delete a report template.",
|
|
893
|
+
parameters={
|
|
894
|
+
"type": "object",
|
|
895
|
+
"properties": {
|
|
896
|
+
"template_id": {"type": "string", "description": "Template ID to delete"}
|
|
897
|
+
},
|
|
898
|
+
"required": ["template_id"],
|
|
899
|
+
},
|
|
900
|
+
handler=self._handle_delete_template,
|
|
901
|
+
)
|
|
902
|
+
|
|
903
|
+
self._register_tool(
|
|
904
|
+
name="download_template",
|
|
905
|
+
description="Download a template file.",
|
|
906
|
+
parameters={
|
|
907
|
+
"type": "object",
|
|
908
|
+
"properties": {
|
|
909
|
+
"template_id": {"type": "string", "description": "Template ID to download"}
|
|
910
|
+
},
|
|
911
|
+
"required": ["template_id"],
|
|
912
|
+
},
|
|
913
|
+
handler=self._handle_download_template,
|
|
914
|
+
)
|
|
915
|
+
|
|
916
|
+
self._register_tool(
|
|
917
|
+
name="get_settings",
|
|
918
|
+
description="Get system settings.",
|
|
919
|
+
parameters={"type": "object", "properties": {}},
|
|
920
|
+
handler=self._handle_get_settings,
|
|
921
|
+
)
|
|
922
|
+
|
|
923
|
+
self._register_tool(
|
|
924
|
+
name="get_public_settings",
|
|
925
|
+
description="Get public settings (no authentication required).",
|
|
926
|
+
parameters={"type": "object", "properties": {}},
|
|
927
|
+
handler=self._handle_get_public_settings,
|
|
928
|
+
)
|
|
929
|
+
|
|
930
|
+
self._register_tool(
|
|
931
|
+
name="update_settings",
|
|
932
|
+
description="Update system settings (admin only).",
|
|
933
|
+
parameters={
|
|
934
|
+
"type": "object",
|
|
935
|
+
"properties": {"settings": {"type": "object", "description": "Settings to update"}},
|
|
936
|
+
"required": ["settings"],
|
|
937
|
+
},
|
|
938
|
+
handler=self._handle_update_settings,
|
|
939
|
+
)
|
|
940
|
+
|
|
941
|
+
self._register_tool(
|
|
942
|
+
name="export_settings",
|
|
943
|
+
description="Export all system settings.",
|
|
944
|
+
parameters={"type": "object", "properties": {}},
|
|
945
|
+
handler=self._handle_export_settings,
|
|
946
|
+
)
|
|
947
|
+
|
|
948
|
+
self._register_tool(
|
|
949
|
+
name="import_settings",
|
|
950
|
+
description="Import/revert system settings from export.",
|
|
951
|
+
parameters={
|
|
952
|
+
"type": "object",
|
|
953
|
+
"properties": {"settings": {"type": "object", "description": "Settings to import"}},
|
|
954
|
+
"required": ["settings"],
|
|
955
|
+
},
|
|
956
|
+
handler=self._handle_import_settings,
|
|
957
|
+
)
|
|
958
|
+
|
|
959
|
+
self._register_tool(
|
|
960
|
+
name="list_languages",
|
|
961
|
+
description="List all configured languages.",
|
|
962
|
+
parameters={"type": "object", "properties": {}},
|
|
963
|
+
handler=self._handle_list_languages,
|
|
964
|
+
)
|
|
965
|
+
|
|
966
|
+
self._register_tool(
|
|
967
|
+
name="create_language",
|
|
968
|
+
description="Create a new language.",
|
|
969
|
+
parameters={
|
|
970
|
+
"type": "object",
|
|
971
|
+
"properties": {
|
|
972
|
+
"language": {"type": "string", "description": "Language code (e.g., 'en')"},
|
|
973
|
+
"name": {"type": "string", "description": "Language name"},
|
|
974
|
+
},
|
|
975
|
+
"required": ["language", "name"],
|
|
976
|
+
},
|
|
977
|
+
handler=self._handle_create_language,
|
|
978
|
+
)
|
|
979
|
+
|
|
980
|
+
self._register_tool(
|
|
981
|
+
name="update_language",
|
|
982
|
+
description="Update a language.",
|
|
983
|
+
parameters={
|
|
984
|
+
"type": "object",
|
|
985
|
+
"properties": {
|
|
986
|
+
"language_id": {"type": "string", "description": "Language ID"},
|
|
987
|
+
"language": {"type": "string", "description": "Language code"},
|
|
988
|
+
"name": {"type": "string", "description": "Language name"},
|
|
989
|
+
},
|
|
990
|
+
"required": ["language_id"],
|
|
991
|
+
},
|
|
992
|
+
handler=self._handle_update_language,
|
|
993
|
+
)
|
|
994
|
+
|
|
995
|
+
self._register_tool(
|
|
996
|
+
name="delete_language",
|
|
997
|
+
description="Delete a language.",
|
|
998
|
+
parameters={
|
|
999
|
+
"type": "object",
|
|
1000
|
+
"properties": {
|
|
1001
|
+
"language_id": {"type": "string", "description": "Language ID to delete"}
|
|
1002
|
+
},
|
|
1003
|
+
"required": ["language_id"],
|
|
1004
|
+
},
|
|
1005
|
+
handler=self._handle_delete_language,
|
|
1006
|
+
)
|
|
1007
|
+
|
|
1008
|
+
self._register_tool(
|
|
1009
|
+
name="list_audit_types",
|
|
1010
|
+
description="List all audit types.",
|
|
1011
|
+
parameters={"type": "object", "properties": {}},
|
|
1012
|
+
handler=self._handle_list_audit_types,
|
|
1013
|
+
)
|
|
1014
|
+
|
|
1015
|
+
self._register_tool(
|
|
1016
|
+
name="create_audit_type",
|
|
1017
|
+
description="Create a new audit type.",
|
|
1018
|
+
parameters={
|
|
1019
|
+
"type": "object",
|
|
1020
|
+
"properties": {
|
|
1021
|
+
"name": {"type": "string", "description": "Audit type name"},
|
|
1022
|
+
"templates": {
|
|
1023
|
+
"type": "array",
|
|
1024
|
+
"items": {"type": "string"},
|
|
1025
|
+
"description": "Template IDs",
|
|
1026
|
+
},
|
|
1027
|
+
},
|
|
1028
|
+
"required": ["name"],
|
|
1029
|
+
},
|
|
1030
|
+
handler=self._handle_create_audit_type,
|
|
1031
|
+
)
|
|
1032
|
+
|
|
1033
|
+
self._register_tool(
|
|
1034
|
+
name="update_audit_type",
|
|
1035
|
+
description="Update an audit type.",
|
|
1036
|
+
parameters={
|
|
1037
|
+
"type": "object",
|
|
1038
|
+
"properties": {
|
|
1039
|
+
"audit_type_id": {"type": "string", "description": "Audit type ID"},
|
|
1040
|
+
"name": {"type": "string", "description": "Audit type name"},
|
|
1041
|
+
"templates": {"type": "array", "items": {"type": "string"}},
|
|
1042
|
+
},
|
|
1043
|
+
"required": ["audit_type_id"],
|
|
1044
|
+
},
|
|
1045
|
+
handler=self._handle_update_audit_type,
|
|
1046
|
+
)
|
|
1047
|
+
|
|
1048
|
+
self._register_tool(
|
|
1049
|
+
name="delete_audit_type",
|
|
1050
|
+
description="Delete an audit type.",
|
|
1051
|
+
parameters={
|
|
1052
|
+
"type": "object",
|
|
1053
|
+
"properties": {
|
|
1054
|
+
"audit_type_id": {"type": "string", "description": "Audit type ID to delete"}
|
|
1055
|
+
},
|
|
1056
|
+
"required": ["audit_type_id"],
|
|
1057
|
+
},
|
|
1058
|
+
handler=self._handle_delete_audit_type,
|
|
1059
|
+
)
|
|
1060
|
+
|
|
1061
|
+
self._register_tool(
|
|
1062
|
+
name="list_vulnerability_types",
|
|
1063
|
+
description="List all vulnerability types.",
|
|
1064
|
+
parameters={"type": "object", "properties": {}},
|
|
1065
|
+
handler=self._handle_list_vulnerability_types,
|
|
1066
|
+
)
|
|
1067
|
+
|
|
1068
|
+
self._register_tool(
|
|
1069
|
+
name="create_vulnerability_type",
|
|
1070
|
+
description="Create a new vulnerability type.",
|
|
1071
|
+
parameters={
|
|
1072
|
+
"type": "object",
|
|
1073
|
+
"properties": {
|
|
1074
|
+
"name": {"type": "string", "description": "Vulnerability type name"}
|
|
1075
|
+
},
|
|
1076
|
+
"required": ["name"],
|
|
1077
|
+
},
|
|
1078
|
+
handler=self._handle_create_vulnerability_type,
|
|
1079
|
+
)
|
|
1080
|
+
|
|
1081
|
+
self._register_tool(
|
|
1082
|
+
name="update_vulnerability_type",
|
|
1083
|
+
description="Update a vulnerability type.",
|
|
1084
|
+
parameters={
|
|
1085
|
+
"type": "object",
|
|
1086
|
+
"properties": {
|
|
1087
|
+
"vuln_type_id": {"type": "string", "description": "Vulnerability type ID"},
|
|
1088
|
+
"name": {"type": "string", "description": "Vulnerability type name"},
|
|
1089
|
+
},
|
|
1090
|
+
"required": ["vuln_type_id"],
|
|
1091
|
+
},
|
|
1092
|
+
handler=self._handle_update_vulnerability_type,
|
|
1093
|
+
)
|
|
1094
|
+
|
|
1095
|
+
self._register_tool(
|
|
1096
|
+
name="delete_vulnerability_type",
|
|
1097
|
+
description="Delete a vulnerability type.",
|
|
1098
|
+
parameters={
|
|
1099
|
+
"type": "object",
|
|
1100
|
+
"properties": {
|
|
1101
|
+
"vuln_type_id": {
|
|
1102
|
+
"type": "string",
|
|
1103
|
+
"description": "Vulnerability type ID to delete",
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
"required": ["vuln_type_id"],
|
|
1107
|
+
},
|
|
1108
|
+
handler=self._handle_delete_vulnerability_type,
|
|
1109
|
+
)
|
|
1110
|
+
|
|
1111
|
+
self._register_tool(
|
|
1112
|
+
name="list_vulnerability_categories",
|
|
1113
|
+
description="List all vulnerability categories.",
|
|
1114
|
+
parameters={"type": "object", "properties": {}},
|
|
1115
|
+
handler=self._handle_list_vulnerability_categories,
|
|
1116
|
+
)
|
|
1117
|
+
|
|
1118
|
+
self._register_tool(
|
|
1119
|
+
name="create_vulnerability_category",
|
|
1120
|
+
description="Create a new vulnerability category.",
|
|
1121
|
+
parameters={
|
|
1122
|
+
"type": "object",
|
|
1123
|
+
"properties": {"name": {"type": "string", "description": "Category name"}},
|
|
1124
|
+
"required": ["name"],
|
|
1125
|
+
},
|
|
1126
|
+
handler=self._handle_create_vulnerability_category,
|
|
1127
|
+
)
|
|
1128
|
+
|
|
1129
|
+
self._register_tool(
|
|
1130
|
+
name="update_vulnerability_category",
|
|
1131
|
+
description="Update a vulnerability category.",
|
|
1132
|
+
parameters={
|
|
1133
|
+
"type": "object",
|
|
1134
|
+
"properties": {
|
|
1135
|
+
"category_id": {"type": "string", "description": "Category ID"},
|
|
1136
|
+
"name": {"type": "string", "description": "Category name"},
|
|
1137
|
+
},
|
|
1138
|
+
"required": ["category_id"],
|
|
1139
|
+
},
|
|
1140
|
+
handler=self._handle_update_vulnerability_category,
|
|
1141
|
+
)
|
|
1142
|
+
|
|
1143
|
+
self._register_tool(
|
|
1144
|
+
name="delete_vulnerability_category",
|
|
1145
|
+
description="Delete a vulnerability category.",
|
|
1146
|
+
parameters={
|
|
1147
|
+
"type": "object",
|
|
1148
|
+
"properties": {
|
|
1149
|
+
"category_id": {"type": "string", "description": "Category ID to delete"}
|
|
1150
|
+
},
|
|
1151
|
+
"required": ["category_id"],
|
|
1152
|
+
},
|
|
1153
|
+
handler=self._handle_delete_vulnerability_category,
|
|
1154
|
+
)
|
|
1155
|
+
|
|
1156
|
+
self._register_tool(
|
|
1157
|
+
name="list_sections",
|
|
1158
|
+
description="List all section definitions.",
|
|
1159
|
+
parameters={"type": "object", "properties": {}},
|
|
1160
|
+
handler=self._handle_list_sections,
|
|
1161
|
+
)
|
|
1162
|
+
|
|
1163
|
+
self._register_tool(
|
|
1164
|
+
name="create_section",
|
|
1165
|
+
description="Create a new section definition.",
|
|
1166
|
+
parameters={
|
|
1167
|
+
"type": "object",
|
|
1168
|
+
"properties": {
|
|
1169
|
+
"field": {"type": "string", "description": "Section field name"},
|
|
1170
|
+
"name": {"type": "string", "description": "Section display name"},
|
|
1171
|
+
},
|
|
1172
|
+
"required": ["field", "name"],
|
|
1173
|
+
},
|
|
1174
|
+
handler=self._handle_create_section,
|
|
1175
|
+
)
|
|
1176
|
+
|
|
1177
|
+
self._register_tool(
|
|
1178
|
+
name="update_section",
|
|
1179
|
+
description="Update a section definition.",
|
|
1180
|
+
parameters={
|
|
1181
|
+
"type": "object",
|
|
1182
|
+
"properties": {
|
|
1183
|
+
"section_id": {"type": "string", "description": "Section ID"},
|
|
1184
|
+
"field": {"type": "string", "description": "Section field name"},
|
|
1185
|
+
"name": {"type": "string", "description": "Section display name"},
|
|
1186
|
+
},
|
|
1187
|
+
"required": ["section_id"],
|
|
1188
|
+
},
|
|
1189
|
+
handler=self._handle_update_section,
|
|
1190
|
+
)
|
|
1191
|
+
|
|
1192
|
+
self._register_tool(
|
|
1193
|
+
name="delete_section",
|
|
1194
|
+
description="Delete a section definition.",
|
|
1195
|
+
parameters={
|
|
1196
|
+
"type": "object",
|
|
1197
|
+
"properties": {
|
|
1198
|
+
"section_id": {"type": "string", "description": "Section ID to delete"}
|
|
1199
|
+
},
|
|
1200
|
+
"required": ["section_id"],
|
|
1201
|
+
},
|
|
1202
|
+
handler=self._handle_delete_section,
|
|
1203
|
+
)
|
|
1204
|
+
|
|
1205
|
+
self._register_tool(
|
|
1206
|
+
name="list_custom_fields",
|
|
1207
|
+
description="List all custom field definitions.",
|
|
1208
|
+
parameters={"type": "object", "properties": {}},
|
|
1209
|
+
handler=self._handle_list_custom_fields,
|
|
1210
|
+
)
|
|
1211
|
+
|
|
1212
|
+
self._register_tool(
|
|
1213
|
+
name="create_custom_field",
|
|
1214
|
+
description="Create a new custom field definition.",
|
|
1215
|
+
parameters={
|
|
1216
|
+
"type": "object",
|
|
1217
|
+
"properties": {
|
|
1218
|
+
"label": {"type": "string", "description": "Field label"},
|
|
1219
|
+
"field_type": {
|
|
1220
|
+
"type": "string",
|
|
1221
|
+
"description": "Field type (text, select, etc.)",
|
|
1222
|
+
},
|
|
1223
|
+
},
|
|
1224
|
+
"required": ["label", "field_type"],
|
|
1225
|
+
},
|
|
1226
|
+
handler=self._handle_create_custom_field,
|
|
1227
|
+
)
|
|
1228
|
+
|
|
1229
|
+
self._register_tool(
|
|
1230
|
+
name="update_custom_field",
|
|
1231
|
+
description="Update a custom field definition.",
|
|
1232
|
+
parameters={
|
|
1233
|
+
"type": "object",
|
|
1234
|
+
"properties": {
|
|
1235
|
+
"field_id": {"type": "string", "description": "Custom field ID"},
|
|
1236
|
+
"label": {"type": "string", "description": "Field label"},
|
|
1237
|
+
"field_type": {"type": "string", "description": "Field type"},
|
|
1238
|
+
},
|
|
1239
|
+
"required": ["field_id"],
|
|
1240
|
+
},
|
|
1241
|
+
handler=self._handle_update_custom_field,
|
|
1242
|
+
)
|
|
1243
|
+
|
|
1244
|
+
self._register_tool(
|
|
1245
|
+
name="delete_custom_field",
|
|
1246
|
+
description="Delete a custom field definition.",
|
|
1247
|
+
parameters={
|
|
1248
|
+
"type": "object",
|
|
1249
|
+
"properties": {
|
|
1250
|
+
"field_id": {"type": "string", "description": "Custom field ID to delete"}
|
|
1251
|
+
},
|
|
1252
|
+
"required": ["field_id"],
|
|
1253
|
+
},
|
|
1254
|
+
handler=self._handle_delete_custom_field,
|
|
1255
|
+
)
|
|
1256
|
+
|
|
1257
|
+
self._register_tool(
|
|
1258
|
+
name="list_roles",
|
|
1259
|
+
description="List all user roles.",
|
|
1260
|
+
parameters={"type": "object", "properties": {}},
|
|
1261
|
+
handler=self._handle_list_roles,
|
|
1262
|
+
)
|
|
1263
|
+
|
|
1264
|
+
# =====================================================================
|
|
1265
|
+
# IMAGE TOOLS
|
|
1266
|
+
# =====================================================================
|
|
1267
|
+
|
|
1268
|
+
self._register_tool(
|
|
1269
|
+
name="get_image",
|
|
1270
|
+
description="Get image metadata.",
|
|
1271
|
+
parameters={
|
|
1272
|
+
"type": "object",
|
|
1273
|
+
"properties": {"image_id": {"type": "string", "description": "Image ID"}},
|
|
1274
|
+
"required": ["image_id"],
|
|
1275
|
+
},
|
|
1276
|
+
handler=self._handle_get_image,
|
|
1277
|
+
)
|
|
1278
|
+
|
|
1279
|
+
self._register_tool(
|
|
1280
|
+
name="download_image",
|
|
1281
|
+
description="Download an image file.",
|
|
1282
|
+
parameters={
|
|
1283
|
+
"type": "object",
|
|
1284
|
+
"properties": {
|
|
1285
|
+
"image_id": {"type": "string", "description": "Image ID to download"}
|
|
1286
|
+
},
|
|
1287
|
+
"required": ["image_id"],
|
|
1288
|
+
},
|
|
1289
|
+
handler=self._handle_download_image,
|
|
1290
|
+
)
|
|
1291
|
+
|
|
1292
|
+
self._register_tool(
|
|
1293
|
+
name="upload_image",
|
|
1294
|
+
description="Upload an image to an audit.",
|
|
1295
|
+
parameters={
|
|
1296
|
+
"type": "object",
|
|
1297
|
+
"properties": {
|
|
1298
|
+
"audit_id": {"type": "string", "description": "Audit ID"},
|
|
1299
|
+
"name": {"type": "string", "description": "Image name"},
|
|
1300
|
+
"value": {"type": "string", "description": "Base64-encoded image data"},
|
|
1301
|
+
},
|
|
1302
|
+
"required": ["audit_id", "name", "value"],
|
|
1303
|
+
},
|
|
1304
|
+
handler=self._handle_upload_image,
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
self._register_tool(
|
|
1308
|
+
name="delete_image",
|
|
1309
|
+
description="Delete an image.",
|
|
1310
|
+
parameters={
|
|
1311
|
+
"type": "object",
|
|
1312
|
+
"properties": {"image_id": {"type": "string", "description": "Image ID to delete"}},
|
|
1313
|
+
"required": ["image_id"],
|
|
1314
|
+
},
|
|
1315
|
+
handler=self._handle_delete_image,
|
|
1316
|
+
)
|
|
1317
|
+
|
|
1318
|
+
# =====================================================================
|
|
1319
|
+
# STATISTICS
|
|
1320
|
+
# =====================================================================
|
|
1321
|
+
|
|
1322
|
+
self._register_tool(
|
|
1323
|
+
name="get_statistics",
|
|
1324
|
+
description="Get comprehensive statistics about audits, findings, clients, and more.",
|
|
1325
|
+
parameters={"type": "object", "properties": {}},
|
|
1326
|
+
handler=self._handle_get_statistics,
|
|
1327
|
+
)
|
|
1328
|
+
|
|
1329
|
+
def _register_tool(
|
|
1330
|
+
self,
|
|
1331
|
+
name: str,
|
|
1332
|
+
description: str,
|
|
1333
|
+
parameters: Dict[str, Any],
|
|
1334
|
+
handler: Callable,
|
|
1335
|
+
required: Optional[List[str]] = None,
|
|
1336
|
+
):
|
|
1337
|
+
"""Register a tool."""
|
|
1338
|
+
self._tools[name] = Tool(
|
|
1339
|
+
name=name,
|
|
1340
|
+
description=description,
|
|
1341
|
+
parameters=parameters,
|
|
1342
|
+
handler=handler,
|
|
1343
|
+
required=required or parameters.get("required", []),
|
|
1344
|
+
)
|
|
1345
|
+
|
|
1346
|
+
# =========================================================================
|
|
1347
|
+
# TOOL HANDLERS
|
|
1348
|
+
# =========================================================================
|
|
1349
|
+
|
|
1350
|
+
def _handle_list_audits(self, finding_title: Optional[str] = None) -> List[Dict]:
|
|
1351
|
+
return self.client.list_audits(finding_title)
|
|
1352
|
+
|
|
1353
|
+
def _handle_get_audit(self, audit_id: str) -> Dict:
|
|
1354
|
+
return self.client.get_audit(audit_id)
|
|
1355
|
+
|
|
1356
|
+
def _handle_create_audit(self, name: str, language: str, audit_type: str) -> Dict:
|
|
1357
|
+
return self.client.create_audit(name, language, audit_type)
|
|
1358
|
+
|
|
1359
|
+
def _handle_update_audit_general(self, audit_id: str, **kwargs) -> Dict:
|
|
1360
|
+
return self.client.update_audit_general(audit_id, **kwargs)
|
|
1361
|
+
|
|
1362
|
+
def _handle_delete_audit(self, audit_id: str) -> Dict:
|
|
1363
|
+
self.client.delete_audit(audit_id)
|
|
1364
|
+
return {"success": True, "message": f"Audit {audit_id} deleted"}
|
|
1365
|
+
|
|
1366
|
+
def _handle_generate_report(self, audit_id: str) -> Dict:
|
|
1367
|
+
content = self.client.generate_report(audit_id)
|
|
1368
|
+
return {"success": True, "size_bytes": len(content)}
|
|
1369
|
+
|
|
1370
|
+
def _handle_get_findings(self, audit_id: str) -> List[Dict]:
|
|
1371
|
+
return self.client.get_findings(audit_id)
|
|
1372
|
+
|
|
1373
|
+
def _handle_get_finding(self, audit_id: str, finding_id: str) -> Dict:
|
|
1374
|
+
return self.client.get_finding(audit_id, finding_id)
|
|
1375
|
+
|
|
1376
|
+
def _handle_create_finding(self, audit_id: str, **kwargs) -> Dict:
|
|
1377
|
+
return self.client.create_finding(audit_id, **kwargs)
|
|
1378
|
+
|
|
1379
|
+
def _handle_update_finding(self, audit_id: str, finding_id: str, **kwargs) -> Dict:
|
|
1380
|
+
return self.client.update_finding(audit_id, finding_id, **kwargs)
|
|
1381
|
+
|
|
1382
|
+
def _handle_delete_finding(self, audit_id: str, finding_id: str) -> Dict:
|
|
1383
|
+
self.client.delete_finding(audit_id, finding_id)
|
|
1384
|
+
return {"success": True, "message": f"Finding {finding_id} deleted"}
|
|
1385
|
+
|
|
1386
|
+
def _handle_search_findings(self, **kwargs) -> List[Dict]:
|
|
1387
|
+
return self.client.search_findings(**kwargs)
|
|
1388
|
+
|
|
1389
|
+
def _handle_get_all_findings_with_context(
|
|
1390
|
+
self, include_failed: bool = False, exclude_categories: Optional[List[str]] = None
|
|
1391
|
+
) -> List[Dict]:
|
|
1392
|
+
return self.client.get_all_findings_with_context(include_failed, exclude_categories)
|
|
1393
|
+
|
|
1394
|
+
def _handle_list_clients(self) -> List[Dict]:
|
|
1395
|
+
return self.client.list_clients()
|
|
1396
|
+
|
|
1397
|
+
def _handle_create_client(self, **kwargs) -> Dict:
|
|
1398
|
+
return self.client.create_client(**kwargs)
|
|
1399
|
+
|
|
1400
|
+
def _handle_update_client(self, client_id: str, **kwargs) -> Dict:
|
|
1401
|
+
return self.client.update_client(client_id, **kwargs)
|
|
1402
|
+
|
|
1403
|
+
def _handle_delete_client(self, client_id: str) -> Dict:
|
|
1404
|
+
self.client.delete_client(client_id)
|
|
1405
|
+
return {"success": True, "message": f"Client {client_id} deleted"}
|
|
1406
|
+
|
|
1407
|
+
def _handle_list_companies(self) -> List[Dict]:
|
|
1408
|
+
return self.client.list_companies()
|
|
1409
|
+
|
|
1410
|
+
def _handle_create_company(self, **kwargs) -> Dict:
|
|
1411
|
+
return self.client.create_company(**kwargs)
|
|
1412
|
+
|
|
1413
|
+
def _handle_list_vulnerabilities(self) -> List[Dict]:
|
|
1414
|
+
return self.client.list_vulnerabilities()
|
|
1415
|
+
|
|
1416
|
+
def _handle_get_vulnerabilities_by_locale(self, locale: str = "en") -> List[Dict]:
|
|
1417
|
+
return self.client.get_vulnerabilities_by_locale(locale)
|
|
1418
|
+
|
|
1419
|
+
def _handle_create_vulnerability(self, **kwargs) -> Dict:
|
|
1420
|
+
return self.client.create_vulnerability(**kwargs)
|
|
1421
|
+
|
|
1422
|
+
def _handle_list_users(self) -> List[Dict]:
|
|
1423
|
+
return self.client.list_users()
|
|
1424
|
+
|
|
1425
|
+
def _handle_get_current_user(self) -> Dict:
|
|
1426
|
+
return self.client.get_current_user()
|
|
1427
|
+
|
|
1428
|
+
def _handle_list_templates(self) -> List[Dict]:
|
|
1429
|
+
return self.client.list_templates()
|
|
1430
|
+
|
|
1431
|
+
def _handle_list_languages(self) -> List[Dict]:
|
|
1432
|
+
return self.client.list_languages()
|
|
1433
|
+
|
|
1434
|
+
def _handle_list_audit_types(self) -> List[Dict]:
|
|
1435
|
+
return self.client.list_audit_types()
|
|
1436
|
+
|
|
1437
|
+
def _handle_get_statistics(self) -> Dict:
|
|
1438
|
+
return self.client.get_statistics()
|
|
1439
|
+
|
|
1440
|
+
# Audit handlers
|
|
1441
|
+
def _handle_get_audit_general(self, audit_id: str) -> Dict:
|
|
1442
|
+
return self.client.get_audit_general(audit_id)
|
|
1443
|
+
|
|
1444
|
+
def _handle_get_audit_network(self, audit_id: str) -> Dict:
|
|
1445
|
+
return self.client.get_audit_network(audit_id)
|
|
1446
|
+
|
|
1447
|
+
def _handle_update_audit_network(self, audit_id: str, network_data: Dict) -> Dict:
|
|
1448
|
+
return self.client.update_audit_network(audit_id, network_data)
|
|
1449
|
+
|
|
1450
|
+
def _handle_toggle_audit_approval(self, audit_id: str) -> Dict:
|
|
1451
|
+
return self.client.toggle_audit_approval(audit_id)
|
|
1452
|
+
|
|
1453
|
+
def _handle_update_review_status(self, audit_id: str, state: bool) -> Dict:
|
|
1454
|
+
return self.client.update_review_status(audit_id, state)
|
|
1455
|
+
|
|
1456
|
+
# Finding handlers
|
|
1457
|
+
def _handle_sort_findings(self, audit_id: str, finding_order: List[str]) -> Dict:
|
|
1458
|
+
return self.client.sort_findings(audit_id, finding_order)
|
|
1459
|
+
|
|
1460
|
+
def _handle_move_finding(
|
|
1461
|
+
self, audit_id: str, finding_id: str, destination_audit_id: str
|
|
1462
|
+
) -> Dict:
|
|
1463
|
+
return self.client.move_finding(audit_id, finding_id, destination_audit_id)
|
|
1464
|
+
|
|
1465
|
+
# Company handlers
|
|
1466
|
+
def _handle_update_company(self, company_id: str, **kwargs) -> Dict:
|
|
1467
|
+
return self.client.update_company(company_id, **kwargs)
|
|
1468
|
+
|
|
1469
|
+
def _handle_delete_company(self, company_id: str) -> Dict:
|
|
1470
|
+
self.client.delete_company(company_id)
|
|
1471
|
+
return {"success": True, "message": f"Company {company_id} deleted"}
|
|
1472
|
+
|
|
1473
|
+
# Vulnerability handlers
|
|
1474
|
+
def _handle_update_vulnerability(self, vuln_id: str, **kwargs) -> Dict:
|
|
1475
|
+
return self.client.update_vulnerability(vuln_id, **kwargs)
|
|
1476
|
+
|
|
1477
|
+
def _handle_delete_vulnerability(self, vuln_id: str) -> Dict:
|
|
1478
|
+
self.client.delete_vulnerability(vuln_id)
|
|
1479
|
+
return {"success": True, "message": f"Vulnerability {vuln_id} deleted"}
|
|
1480
|
+
|
|
1481
|
+
def _handle_bulk_delete_vulnerabilities(self, vuln_ids: List[str]) -> Dict:
|
|
1482
|
+
self.client.bulk_delete_vulnerabilities(vuln_ids)
|
|
1483
|
+
return {"success": True, "message": f"Deleted {len(vuln_ids)} vulnerabilities"}
|
|
1484
|
+
|
|
1485
|
+
def _handle_export_vulnerabilities(self) -> Dict:
|
|
1486
|
+
return self.client.export_vulnerabilities()
|
|
1487
|
+
|
|
1488
|
+
def _handle_create_vulnerability_from_finding(self, **kwargs) -> Dict:
|
|
1489
|
+
return self.client.create_vulnerability_from_finding(**kwargs)
|
|
1490
|
+
|
|
1491
|
+
# User handlers
|
|
1492
|
+
def _handle_get_user(self, username: str) -> Dict:
|
|
1493
|
+
return self.client.get_user(username)
|
|
1494
|
+
|
|
1495
|
+
def _handle_create_user(self, **kwargs) -> Dict:
|
|
1496
|
+
return self.client.create_user(**kwargs)
|
|
1497
|
+
|
|
1498
|
+
def _handle_update_user(self, user_id: str, **kwargs) -> Dict:
|
|
1499
|
+
return self.client.update_user(user_id, **kwargs)
|
|
1500
|
+
|
|
1501
|
+
def _handle_update_current_user(self, **kwargs) -> Dict:
|
|
1502
|
+
return self.client.update_current_user(**kwargs)
|
|
1503
|
+
|
|
1504
|
+
def _handle_list_reviewers(self) -> List[Dict]:
|
|
1505
|
+
return self.client.list_reviewers()
|
|
1506
|
+
|
|
1507
|
+
# Template handlers
|
|
1508
|
+
def _handle_create_template(self, name: str, ext: str, file_content: str) -> Dict:
|
|
1509
|
+
return self.client.create_template(name, ext, file_content)
|
|
1510
|
+
|
|
1511
|
+
def _handle_update_template(self, template_id: str, **kwargs) -> Dict:
|
|
1512
|
+
return self.client.update_template(template_id, **kwargs)
|
|
1513
|
+
|
|
1514
|
+
def _handle_delete_template(self, template_id: str) -> Dict:
|
|
1515
|
+
self.client.delete_template(template_id)
|
|
1516
|
+
return {"success": True, "message": f"Template {template_id} deleted"}
|
|
1517
|
+
|
|
1518
|
+
def _handle_download_template(self, template_id: str) -> Dict:
|
|
1519
|
+
content = self.client.download_template(template_id)
|
|
1520
|
+
return {"success": True, "size_bytes": len(content)}
|
|
1521
|
+
|
|
1522
|
+
# Settings handlers
|
|
1523
|
+
def _handle_get_settings(self) -> Dict:
|
|
1524
|
+
return self.client.get_settings()
|
|
1525
|
+
|
|
1526
|
+
def _handle_get_public_settings(self) -> Dict:
|
|
1527
|
+
return self.client.get_public_settings()
|
|
1528
|
+
|
|
1529
|
+
def _handle_update_settings(self, settings: Dict) -> Dict:
|
|
1530
|
+
return self.client.update_settings(settings)
|
|
1531
|
+
|
|
1532
|
+
# Data type handlers
|
|
1533
|
+
def _handle_list_vulnerability_types(self) -> List[Dict]:
|
|
1534
|
+
return self.client.list_vulnerability_types()
|
|
1535
|
+
|
|
1536
|
+
def _handle_list_vulnerability_categories(self) -> List[Dict]:
|
|
1537
|
+
return self.client.list_vulnerability_categories()
|
|
1538
|
+
|
|
1539
|
+
def _handle_list_sections(self) -> List[Dict]:
|
|
1540
|
+
return self.client.list_sections()
|
|
1541
|
+
|
|
1542
|
+
def _handle_list_custom_fields(self) -> List[Dict]:
|
|
1543
|
+
return self.client.list_custom_fields()
|
|
1544
|
+
|
|
1545
|
+
def _handle_list_roles(self) -> List[Dict]:
|
|
1546
|
+
return self.client.list_roles()
|
|
1547
|
+
|
|
1548
|
+
# Image handlers
|
|
1549
|
+
def _handle_get_image(self, image_id: str) -> Dict:
|
|
1550
|
+
return self.client.get_image(image_id)
|
|
1551
|
+
|
|
1552
|
+
def _handle_download_image(self, image_id: str) -> Dict:
|
|
1553
|
+
content = self.client.download_image(image_id)
|
|
1554
|
+
return {"success": True, "size_bytes": len(content)}
|
|
1555
|
+
|
|
1556
|
+
def _handle_upload_image(self, audit_id: str, name: str, value: str) -> Dict:
|
|
1557
|
+
return self.client.upload_image(audit_id, name, value)
|
|
1558
|
+
|
|
1559
|
+
def _handle_delete_image(self, image_id: str) -> Dict:
|
|
1560
|
+
self.client.delete_image(image_id)
|
|
1561
|
+
return {"success": True, "message": f"Image {image_id} deleted"}
|
|
1562
|
+
|
|
1563
|
+
# Audit section handlers
|
|
1564
|
+
def _handle_get_audit_sections(self, audit_id: str) -> Dict:
|
|
1565
|
+
return self.client.get_audit_sections(audit_id)
|
|
1566
|
+
|
|
1567
|
+
def _handle_update_audit_sections(self, audit_id: str, sections: Dict) -> Dict:
|
|
1568
|
+
return self.client.update_audit_sections(audit_id, sections)
|
|
1569
|
+
|
|
1570
|
+
# TOTP handlers
|
|
1571
|
+
def _handle_get_totp(self) -> Dict:
|
|
1572
|
+
return self.client.get_totp()
|
|
1573
|
+
|
|
1574
|
+
def _handle_setup_totp(self) -> Dict:
|
|
1575
|
+
return self.client.setup_totp()
|
|
1576
|
+
|
|
1577
|
+
def _handle_disable_totp(self, token: str) -> Dict:
|
|
1578
|
+
return self.client.disable_totp(token)
|
|
1579
|
+
|
|
1580
|
+
# Settings handlers
|
|
1581
|
+
def _handle_export_settings(self) -> Dict:
|
|
1582
|
+
return self.client.export_settings()
|
|
1583
|
+
|
|
1584
|
+
def _handle_import_settings(self, settings: Dict) -> Dict:
|
|
1585
|
+
return self.client.import_settings(settings)
|
|
1586
|
+
|
|
1587
|
+
# Language handlers
|
|
1588
|
+
def _handle_create_language(self, **kwargs) -> Dict:
|
|
1589
|
+
return self.client.create_language(**kwargs)
|
|
1590
|
+
|
|
1591
|
+
def _handle_update_language(self, language_id: str, **kwargs) -> Dict:
|
|
1592
|
+
return self.client.update_language(language_id, **kwargs)
|
|
1593
|
+
|
|
1594
|
+
def _handle_delete_language(self, language_id: str) -> Dict:
|
|
1595
|
+
self.client.delete_language(language_id)
|
|
1596
|
+
return {"success": True, "message": f"Language {language_id} deleted"}
|
|
1597
|
+
|
|
1598
|
+
# Audit type handlers
|
|
1599
|
+
def _handle_create_audit_type(self, **kwargs) -> Dict:
|
|
1600
|
+
return self.client.create_audit_type(**kwargs)
|
|
1601
|
+
|
|
1602
|
+
def _handle_update_audit_type(self, audit_type_id: str, **kwargs) -> Dict:
|
|
1603
|
+
return self.client.update_audit_type(audit_type_id, **kwargs)
|
|
1604
|
+
|
|
1605
|
+
def _handle_delete_audit_type(self, audit_type_id: str) -> Dict:
|
|
1606
|
+
self.client.delete_audit_type(audit_type_id)
|
|
1607
|
+
return {"success": True, "message": f"Audit type {audit_type_id} deleted"}
|
|
1608
|
+
|
|
1609
|
+
# Vulnerability type handlers
|
|
1610
|
+
def _handle_create_vulnerability_type(self, **kwargs) -> Dict:
|
|
1611
|
+
return self.client.create_vulnerability_type(**kwargs)
|
|
1612
|
+
|
|
1613
|
+
def _handle_update_vulnerability_type(self, vuln_type_id: str, **kwargs) -> Dict:
|
|
1614
|
+
return self.client.update_vulnerability_type(vuln_type_id, **kwargs)
|
|
1615
|
+
|
|
1616
|
+
def _handle_delete_vulnerability_type(self, vuln_type_id: str) -> Dict:
|
|
1617
|
+
self.client.delete_vulnerability_type(vuln_type_id)
|
|
1618
|
+
return {"success": True, "message": f"Vulnerability type {vuln_type_id} deleted"}
|
|
1619
|
+
|
|
1620
|
+
# Vulnerability category handlers
|
|
1621
|
+
def _handle_create_vulnerability_category(self, **kwargs) -> Dict:
|
|
1622
|
+
return self.client.create_vulnerability_category(**kwargs)
|
|
1623
|
+
|
|
1624
|
+
def _handle_update_vulnerability_category(self, category_id: str, **kwargs) -> Dict:
|
|
1625
|
+
return self.client.update_vulnerability_category(category_id, **kwargs)
|
|
1626
|
+
|
|
1627
|
+
def _handle_delete_vulnerability_category(self, category_id: str) -> Dict:
|
|
1628
|
+
self.client.delete_vulnerability_category(category_id)
|
|
1629
|
+
return {"success": True, "message": f"Vulnerability category {category_id} deleted"}
|
|
1630
|
+
|
|
1631
|
+
# Section handlers
|
|
1632
|
+
def _handle_create_section(self, **kwargs) -> Dict:
|
|
1633
|
+
return self.client.create_section(**kwargs)
|
|
1634
|
+
|
|
1635
|
+
def _handle_update_section(self, section_id: str, **kwargs) -> Dict:
|
|
1636
|
+
return self.client.update_section(section_id, **kwargs)
|
|
1637
|
+
|
|
1638
|
+
def _handle_delete_section(self, section_id: str) -> Dict:
|
|
1639
|
+
self.client.delete_section(section_id)
|
|
1640
|
+
return {"success": True, "message": f"Section {section_id} deleted"}
|
|
1641
|
+
|
|
1642
|
+
# Custom field handlers
|
|
1643
|
+
def _handle_create_custom_field(self, **kwargs) -> Dict:
|
|
1644
|
+
return self.client.create_custom_field(**kwargs)
|
|
1645
|
+
|
|
1646
|
+
def _handle_update_custom_field(self, field_id: str, **kwargs) -> Dict:
|
|
1647
|
+
return self.client.update_custom_field(field_id, **kwargs)
|
|
1648
|
+
|
|
1649
|
+
def _handle_delete_custom_field(self, field_id: str) -> Dict:
|
|
1650
|
+
self.client.delete_custom_field(field_id)
|
|
1651
|
+
return {"success": True, "message": f"Custom field {field_id} deleted"}
|
|
1652
|
+
|
|
1653
|
+
# Vulnerability update handlers
|
|
1654
|
+
def _handle_get_vulnerability_updates(self) -> List[Dict]:
|
|
1655
|
+
return self.client.get_vulnerability_updates()
|
|
1656
|
+
|
|
1657
|
+
def _handle_merge_vulnerability(self, vuln_id: str, update_id: str) -> Dict:
|
|
1658
|
+
return self.client.merge_vulnerability(vuln_id, update_id)
|
|
1659
|
+
|
|
1660
|
+
# =========================================================================
|
|
1661
|
+
# PUBLIC API METHODS (for testing and direct use)
|
|
1662
|
+
# =========================================================================
|
|
1663
|
+
|
|
1664
|
+
async def handle_initialize(self, params: Dict) -> Dict:
|
|
1665
|
+
"""
|
|
1666
|
+
Handle MCP initialize request (async public method).
|
|
1667
|
+
|
|
1668
|
+
Args:
|
|
1669
|
+
params: Initialize parameters
|
|
1670
|
+
|
|
1671
|
+
Returns:
|
|
1672
|
+
Initialize response with capabilities
|
|
1673
|
+
"""
|
|
1674
|
+
return self._handle_initialize(params)
|
|
1675
|
+
|
|
1676
|
+
async def handle_list_tools(self) -> List[Dict]:
|
|
1677
|
+
"""
|
|
1678
|
+
Handle list tools request (async public method).
|
|
1679
|
+
|
|
1680
|
+
Returns:
|
|
1681
|
+
List of tool definitions
|
|
1682
|
+
"""
|
|
1683
|
+
from typing import cast
|
|
1684
|
+
|
|
1685
|
+
result = self._handle_list_tools({})
|
|
1686
|
+
return cast(List[Dict], result.get("tools", []))
|
|
1687
|
+
|
|
1688
|
+
async def handle_call_tool(self, name: str, arguments: Dict) -> Any:
|
|
1689
|
+
"""
|
|
1690
|
+
Handle call tool request (async public method).
|
|
1691
|
+
|
|
1692
|
+
Args:
|
|
1693
|
+
name: Tool name
|
|
1694
|
+
arguments: Tool arguments
|
|
1695
|
+
|
|
1696
|
+
Returns:
|
|
1697
|
+
Tool result
|
|
1698
|
+
|
|
1699
|
+
Raises:
|
|
1700
|
+
ValueError: If tool is unknown
|
|
1701
|
+
"""
|
|
1702
|
+
params = {"name": name, "arguments": arguments}
|
|
1703
|
+
return self._handle_call_tool(params)
|
|
1704
|
+
|
|
1705
|
+
def _format_result(self, data: Any) -> str:
|
|
1706
|
+
"""
|
|
1707
|
+
Format result data for output.
|
|
1708
|
+
|
|
1709
|
+
Args:
|
|
1710
|
+
data: Data to format
|
|
1711
|
+
|
|
1712
|
+
Returns:
|
|
1713
|
+
Formatted string
|
|
1714
|
+
"""
|
|
1715
|
+
if isinstance(data, str):
|
|
1716
|
+
return data
|
|
1717
|
+
elif data is None:
|
|
1718
|
+
return "null"
|
|
1719
|
+
else:
|
|
1720
|
+
return json.dumps(data, indent=2, default=str)
|
|
1721
|
+
|
|
1722
|
+
# =========================================================================
|
|
1723
|
+
# MCP PROTOCOL HANDLING
|
|
1724
|
+
# =========================================================================
|
|
1725
|
+
|
|
1726
|
+
def _handle_initialize(self, params: Dict) -> Dict:
|
|
1727
|
+
"""Handle MCP initialize request."""
|
|
1728
|
+
self._initialized = True
|
|
1729
|
+
return {
|
|
1730
|
+
"protocolVersion": self.PROTOCOL_VERSION,
|
|
1731
|
+
"capabilities": {
|
|
1732
|
+
"tools": {"listChanged": True},
|
|
1733
|
+
"logging": {},
|
|
1734
|
+
},
|
|
1735
|
+
"serverInfo": {
|
|
1736
|
+
"name": self.SERVER_NAME,
|
|
1737
|
+
"version": self.SERVER_VERSION,
|
|
1738
|
+
},
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
def _handle_list_tools(self, params: Dict) -> Dict:
|
|
1742
|
+
"""Handle tools/list request."""
|
|
1743
|
+
tools = []
|
|
1744
|
+
for tool in self._tools.values():
|
|
1745
|
+
tools.append(
|
|
1746
|
+
{
|
|
1747
|
+
"name": tool.name,
|
|
1748
|
+
"description": tool.description,
|
|
1749
|
+
"inputSchema": tool.parameters,
|
|
1750
|
+
}
|
|
1751
|
+
)
|
|
1752
|
+
return {"tools": tools}
|
|
1753
|
+
|
|
1754
|
+
def _handle_call_tool(self, params: Dict) -> Dict:
|
|
1755
|
+
"""Handle tools/call request."""
|
|
1756
|
+
tool_name = params.get("name")
|
|
1757
|
+
arguments = params.get("arguments", {})
|
|
1758
|
+
|
|
1759
|
+
if tool_name not in self._tools:
|
|
1760
|
+
raise ValueError(f"Unknown tool: {tool_name}")
|
|
1761
|
+
|
|
1762
|
+
tool = self._tools[tool_name]
|
|
1763
|
+
|
|
1764
|
+
try:
|
|
1765
|
+
result = tool.handler(**arguments)
|
|
1766
|
+
return {
|
|
1767
|
+
"content": [{"type": "text", "text": json.dumps(result, indent=2, default=str)}]
|
|
1768
|
+
}
|
|
1769
|
+
except PwnDocError as e:
|
|
1770
|
+
return {"content": [{"type": "text", "text": f"Error: {str(e)}"}], "isError": True}
|
|
1771
|
+
|
|
1772
|
+
def _handle_message(self, message: Dict) -> Optional[Dict]:
|
|
1773
|
+
"""Process an incoming MCP message."""
|
|
1774
|
+
method = message.get("method")
|
|
1775
|
+
params = message.get("params", {})
|
|
1776
|
+
msg_id = message.get("id")
|
|
1777
|
+
|
|
1778
|
+
handlers = {
|
|
1779
|
+
"initialize": self._handle_initialize,
|
|
1780
|
+
"initialized": lambda p: None, # Notification, no response
|
|
1781
|
+
"tools/list": self._handle_list_tools,
|
|
1782
|
+
"tools/call": self._handle_call_tool,
|
|
1783
|
+
"ping": lambda p: {},
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
if method in handlers:
|
|
1787
|
+
try:
|
|
1788
|
+
result = handlers[method](params)
|
|
1789
|
+
if result is None: # Notification
|
|
1790
|
+
return None
|
|
1791
|
+
return {"jsonrpc": "2.0", "id": msg_id, "result": result}
|
|
1792
|
+
except Exception as e:
|
|
1793
|
+
logger.exception(f"Error handling {method}")
|
|
1794
|
+
return {
|
|
1795
|
+
"jsonrpc": "2.0",
|
|
1796
|
+
"id": msg_id,
|
|
1797
|
+
"error": {"code": -32603, "message": str(e)},
|
|
1798
|
+
}
|
|
1799
|
+
else:
|
|
1800
|
+
return {
|
|
1801
|
+
"jsonrpc": "2.0",
|
|
1802
|
+
"id": msg_id,
|
|
1803
|
+
"error": {"code": -32601, "message": f"Method not found: {method}"},
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
# =========================================================================
|
|
1807
|
+
# TRANSPORT IMPLEMENTATIONS
|
|
1808
|
+
# =========================================================================
|
|
1809
|
+
|
|
1810
|
+
def run_stdio(self):
|
|
1811
|
+
"""Run server with stdio transport (for Claude Desktop)."""
|
|
1812
|
+
logger.info("Starting PwnDoc MCP Server (stdio transport)")
|
|
1813
|
+
|
|
1814
|
+
while True:
|
|
1815
|
+
try:
|
|
1816
|
+
line = sys.stdin.readline()
|
|
1817
|
+
if not line:
|
|
1818
|
+
break
|
|
1819
|
+
|
|
1820
|
+
message = json.loads(line)
|
|
1821
|
+
logger.debug(f"Received: {message.get('method', 'response')}")
|
|
1822
|
+
|
|
1823
|
+
response = self._handle_message(message)
|
|
1824
|
+
if response:
|
|
1825
|
+
sys.stdout.write(json.dumps(response) + "\n")
|
|
1826
|
+
sys.stdout.flush()
|
|
1827
|
+
|
|
1828
|
+
except json.JSONDecodeError as e:
|
|
1829
|
+
logger.warning(f"Invalid JSON: {e}")
|
|
1830
|
+
except KeyboardInterrupt:
|
|
1831
|
+
logger.info("Server interrupted")
|
|
1832
|
+
break
|
|
1833
|
+
except Exception as e:
|
|
1834
|
+
logger.exception(f"Error: {e}")
|
|
1835
|
+
|
|
1836
|
+
async def run_sse(self, host: str = "127.0.0.1", port: int = 8080):
|
|
1837
|
+
"""Run server with SSE transport."""
|
|
1838
|
+
try:
|
|
1839
|
+
from aiohttp import web
|
|
1840
|
+
except ImportError:
|
|
1841
|
+
raise ImportError("aiohttp required for SSE transport: pip install aiohttp")
|
|
1842
|
+
|
|
1843
|
+
async def handle_sse(request):
|
|
1844
|
+
response = web.StreamResponse(
|
|
1845
|
+
status=200,
|
|
1846
|
+
headers={
|
|
1847
|
+
"Content-Type": "text/event-stream",
|
|
1848
|
+
"Cache-Control": "no-cache",
|
|
1849
|
+
"Connection": "keep-alive",
|
|
1850
|
+
},
|
|
1851
|
+
)
|
|
1852
|
+
await response.prepare(request)
|
|
1853
|
+
|
|
1854
|
+
# Read messages from POST body
|
|
1855
|
+
data = await request.json()
|
|
1856
|
+
result = self._handle_message(data)
|
|
1857
|
+
|
|
1858
|
+
if result:
|
|
1859
|
+
await response.write(f"data: {json.dumps(result)}\n\n".encode())
|
|
1860
|
+
|
|
1861
|
+
return response
|
|
1862
|
+
|
|
1863
|
+
app = web.Application()
|
|
1864
|
+
app.router.add_post("/mcp", handle_sse)
|
|
1865
|
+
|
|
1866
|
+
runner = web.AppRunner(app)
|
|
1867
|
+
await runner.setup()
|
|
1868
|
+
site = web.TCPSite(runner, host, port)
|
|
1869
|
+
await site.start()
|
|
1870
|
+
|
|
1871
|
+
logger.info(f"SSE server running at http://{host}:{port}/mcp")
|
|
1872
|
+
|
|
1873
|
+
# Keep running
|
|
1874
|
+
while True:
|
|
1875
|
+
await asyncio.sleep(3600)
|
|
1876
|
+
|
|
1877
|
+
def run(self, transport: Optional[str] = None):
|
|
1878
|
+
"""
|
|
1879
|
+
Run the MCP server.
|
|
1880
|
+
|
|
1881
|
+
Args:
|
|
1882
|
+
transport: Transport type (stdio, sse, websocket). Defaults to config value.
|
|
1883
|
+
"""
|
|
1884
|
+
transport = transport or self.config.mcp_transport
|
|
1885
|
+
|
|
1886
|
+
if transport == "stdio":
|
|
1887
|
+
self.run_stdio()
|
|
1888
|
+
elif transport == "sse":
|
|
1889
|
+
asyncio.run(self.run_sse(self.config.mcp_host, self.config.mcp_port))
|
|
1890
|
+
else:
|
|
1891
|
+
raise ValueError(f"Unsupported transport: {transport}")
|
|
1892
|
+
|
|
1893
|
+
|
|
1894
|
+
# Module-level constant for tool definitions (for compatibility)
|
|
1895
|
+
TOOL_DEFINITIONS: Optional[List[Dict]] = None
|
|
1896
|
+
|
|
1897
|
+
|
|
1898
|
+
def _get_tool_definitions() -> List[Dict]:
|
|
1899
|
+
"""
|
|
1900
|
+
Get tool definitions from server instance.
|
|
1901
|
+
|
|
1902
|
+
Returns:
|
|
1903
|
+
List of tool definitions
|
|
1904
|
+
"""
|
|
1905
|
+
# Create a temporary server to extract tool definitions
|
|
1906
|
+
# Use _silent=True to prevent logging during module import
|
|
1907
|
+
config = Config(url="http://temp", token="temp")
|
|
1908
|
+
server = PwnDocMCPServer(config, _silent=True)
|
|
1909
|
+
tools = []
|
|
1910
|
+
for tool in server._tools.values():
|
|
1911
|
+
tools.append(
|
|
1912
|
+
{
|
|
1913
|
+
"name": tool.name,
|
|
1914
|
+
"description": tool.description,
|
|
1915
|
+
"inputSchema": tool.parameters,
|
|
1916
|
+
}
|
|
1917
|
+
)
|
|
1918
|
+
return tools
|
|
1919
|
+
|
|
1920
|
+
|
|
1921
|
+
def get_tool_definitions() -> List[Dict]:
|
|
1922
|
+
"""
|
|
1923
|
+
Get tool definitions, initializing them lazily on first access.
|
|
1924
|
+
|
|
1925
|
+
Returns:
|
|
1926
|
+
List of tool definitions
|
|
1927
|
+
"""
|
|
1928
|
+
global TOOL_DEFINITIONS
|
|
1929
|
+
if TOOL_DEFINITIONS is None:
|
|
1930
|
+
TOOL_DEFINITIONS = _get_tool_definitions()
|
|
1931
|
+
return TOOL_DEFINITIONS
|
|
1932
|
+
|
|
1933
|
+
|
|
1934
|
+
def create_server(config: Optional[Config] = None, **kwargs) -> PwnDocMCPServer:
|
|
1935
|
+
"""
|
|
1936
|
+
Create and configure a PwnDoc MCP server.
|
|
1937
|
+
|
|
1938
|
+
Args:
|
|
1939
|
+
config: Configuration object (if provided, kwargs are ignored)
|
|
1940
|
+
**kwargs: Configuration parameters (url, token, etc.)
|
|
1941
|
+
|
|
1942
|
+
Returns:
|
|
1943
|
+
Configured PwnDocMCPServer instance
|
|
1944
|
+
|
|
1945
|
+
Raises:
|
|
1946
|
+
ValueError: If configuration is invalid
|
|
1947
|
+
|
|
1948
|
+
Example:
|
|
1949
|
+
>>> server = create_server(url="https://pwndoc.com", token="...")
|
|
1950
|
+
>>> server = create_server(config)
|
|
1951
|
+
"""
|
|
1952
|
+
if config is None:
|
|
1953
|
+
config = Config(**kwargs)
|
|
1954
|
+
|
|
1955
|
+
# Validate configuration
|
|
1956
|
+
errors = config.validate()
|
|
1957
|
+
if errors:
|
|
1958
|
+
raise ValueError(f"Invalid configuration: {'; '.join(errors)}")
|
|
1959
|
+
|
|
1960
|
+
return PwnDocMCPServer(config)
|
|
1961
|
+
|
|
1962
|
+
|
|
1963
|
+
def main():
|
|
1964
|
+
"""Main entry point."""
|
|
1965
|
+
import argparse
|
|
1966
|
+
|
|
1967
|
+
parser = argparse.ArgumentParser(description="PwnDoc MCP Server")
|
|
1968
|
+
parser.add_argument("--transport", choices=["stdio", "sse"], default="stdio")
|
|
1969
|
+
parser.add_argument("--host", default="127.0.0.1")
|
|
1970
|
+
parser.add_argument("--port", type=int, default=8080)
|
|
1971
|
+
parser.add_argument("--log-level", default="INFO")
|
|
1972
|
+
args = parser.parse_args()
|
|
1973
|
+
|
|
1974
|
+
logging.basicConfig(level=getattr(logging, args.log_level))
|
|
1975
|
+
|
|
1976
|
+
config = load_config(
|
|
1977
|
+
mcp_transport=args.transport,
|
|
1978
|
+
mcp_host=args.host,
|
|
1979
|
+
mcp_port=args.port,
|
|
1980
|
+
)
|
|
1981
|
+
|
|
1982
|
+
server = PwnDocMCPServer(config)
|
|
1983
|
+
server.run()
|
|
1984
|
+
|
|
1985
|
+
|
|
1986
|
+
if __name__ == "__main__":
|
|
1987
|
+
main()
|