This is page 4 of 4. Use http://codebase.md/sedwardstx/demomcp?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .gitignore
├── .mcp.json
├── check_server.py
├── CLAUDE.md
├── config
│ └── default.yml
├── docs
│ ├── api_reference.md
│ ├── demo-recording
│ │ └── MCPDemo.gif
│ ├── example-context-docs
│ │ ├── mcp-ai-agent-architecture.md
│ │ ├── mcp-ai-agent-dev-task.md
│ │ └── mcp-ai-agent-prd.md
│ └── getting_started.md
├── LICENSE
├── main_tcp.py
├── main.py
├── mcp_tcp_client.py
├── pyproject.toml
├── QUICK_START.md
├── README.md
├── scripts
│ └── test_server.py
├── setup.py
├── src
│ └── mcp_log_analyzer
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ └── server.py
│ ├── config
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── core
│ │ ├── __init__.py
│ │ ├── config.py
│ │ ├── models.py
│ │ └── state_manager.py
│ ├── mcp_server
│ │ ├── __init__.py
│ │ ├── models
│ │ │ ├── __init__.py
│ │ │ └── schemas.py
│ │ ├── prompts
│ │ │ ├── __init__.py
│ │ │ ├── linux_testing_prompt.py
│ │ │ ├── log_management_prompt.py
│ │ │ ├── mcp_assets_overview_prompt.py
│ │ │ ├── network_testing_prompt.py
│ │ │ ├── process_monitoring_prompt.py
│ │ │ └── windows_testing_prompt.py
│ │ ├── resources
│ │ │ ├── __init__.py
│ │ │ ├── linux_resources.py
│ │ │ ├── logs_resources.py
│ │ │ ├── network_resources.py
│ │ │ ├── process_resources.py
│ │ │ └── windows_resources.py
│ │ ├── server.py
│ │ └── tools
│ │ ├── __init__.py
│ │ ├── health_check_tools.py
│ │ ├── linux_test_tools.py
│ │ ├── log_management_tools.py
│ │ ├── network_test_tools.py
│ │ ├── process_test_tools.py
│ │ └── windows_test_tools.py
│ ├── parsers
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── csv_parser.py
│ │ ├── etl_cached_parser.py
│ │ ├── etl_large_file_parser.py
│ │ ├── etl_parser.py
│ │ ├── etl_windows_parser.py
│ │ └── evt_parser.py
│ └── tcp_proxy.py
├── TCP_PROXY_README.md
├── tcp_proxy.py
├── tcp_server.py
├── test_server.py
├── test_tcp_proxy.py
├── test_windows_setup.py
└── tests
├── test_base_parser.py
├── test_mcp_server.py
├── test_tool_utils.py
└── test_utils.py
```
# Files
--------------------------------------------------------------------------------
/src/mcp_log_analyzer/mcp_server/prompts/mcp_assets_overview_prompt.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | MCP Assets Overview prompts for the MCP Log Analyzer server.
3 | """
4 |
5 | from typing import Optional
6 | from mcp.server import FastMCP
7 |
8 |
9 | def register_mcp_assets_prompts(mcp: FastMCP):
10 | """Register all MCP assets overview prompts."""
11 |
12 | @mcp.prompt(
13 | title="Quick Start Guide",
14 | description="Getting started with MCP Log Analyzer - essential first steps"
15 | )
16 | async def quick_start_guide() -> str:
17 | """
18 | Quick start guide for new users of MCP Log Analyzer.
19 | """
20 | return """
21 | # 🚀 MCP Log Analyzer Quick Start
22 |
23 | ## Getting Started in 5 Minutes
24 |
25 | ### Step 1: Test Your Platform
26 | ```
27 | # Windows users
28 | Tool: test_windows_event_log_access
29 |
30 | # Linux users
31 | Tool: test_linux_log_access
32 | ```
33 |
34 | ### Step 2: Check System Health
35 | ```
36 | # Windows
37 | Tool: get_windows_system_health
38 |
39 | # Linux
40 | Tool: get_linux_system_overview
41 |
42 | # Cross-platform
43 | Tool: get_system_health_summary
44 | ```
45 |
46 | ### Step 3: Register a Log Source
47 | ```
48 | # Windows Event Log
49 | Tool: register_log_source
50 | Parameters: name="windows_system", source_type="evt", path="System"
51 |
52 | # Linux systemd
53 | Tool: register_log_source
54 | Parameters: name="journal", source_type="text", path="/var/log/journal"
55 | ```
56 |
57 | ### Step 4: Query Your Logs
58 | ```
59 | Tool: query_logs
60 | Parameters: source_name="your_source", start_time="1 hour ago"
61 | ```
62 |
63 | ### Step 5: Analyze for Issues
64 | ```
65 | Tool: analyze_logs
66 | Parameters: source_name="your_source", analysis_type="summary"
67 | ```
68 |
69 | ## What's Next?
70 | - Use tool-specific prompts for detailed guidance
71 | - Explore resources for real-time monitoring
72 | - Set up regular health checks
73 | - Configure alerts for critical events
74 | """
75 |
76 | @mcp.prompt(
77 | title="Core Log Management Tools",
78 | description="Essential tools for log registration, querying, and analysis"
79 | )
80 | async def log_management_tools() -> str:
81 | """
82 | Reference for core log management tools.
83 | """
84 | return """
85 | # 📊 Core Log Management Tools
86 |
87 | ## Registration & Management
88 |
89 | ### register_log_source
90 | **Purpose**: Register new log sources for analysis
91 | **Supports**: Windows Event Logs, JSON, XML, CSV, text files
92 | ```
93 | Tool: register_log_source
94 | Parameters: name="app_logs", source_type="json", path="/var/log/app.json"
95 | ```
96 |
97 | ### list_log_sources
98 | **Purpose**: List all registered log sources
99 | ```
100 | Tool: list_log_sources
101 | ```
102 |
103 | ### get_log_source
104 | **Purpose**: Get details about a specific log source
105 | ```
106 | Tool: get_log_source
107 | Parameters: name="windows_system"
108 | ```
109 |
110 | ### delete_log_source
111 | **Purpose**: Remove a registered log source
112 | ```
113 | Tool: delete_log_source
114 | Parameters: name="old_logs"
115 | ```
116 |
117 | ## Querying & Analysis
118 |
119 | ### query_logs
120 | **Purpose**: Query and filter logs from registered sources
121 | **Features**: Time ranges, filters, pagination
122 | ```
123 | Tool: query_logs
124 | Parameters: source_name="app_logs", filters={"level": "Error"}, start_time="1 hour ago"
125 | ```
126 |
127 | ### analyze_logs
128 | **Purpose**: Advanced log analysis with ML capabilities
129 | **Types**: summary, pattern, anomaly
130 | ```
131 | Tool: analyze_logs
132 | Parameters: source_name="app_logs", analysis_type="pattern"
133 | ```
134 |
135 | ## Common Use Cases
136 | - Error investigation
137 | - Performance analysis
138 | - Security auditing
139 | - Compliance reporting
140 | - Trend analysis
141 | """
142 |
143 | @mcp.prompt(
144 | title="Windows Tools Reference",
145 | description="Windows-specific diagnostic and monitoring tools"
146 | )
147 | async def windows_tools_reference() -> str:
148 | """
149 | Complete reference for Windows system tools.
150 | """
151 | return """
152 | # 🪟 Windows Tools Reference
153 |
154 | ## Diagnostic Tools
155 |
156 | ### test_windows_event_log_access
157 | **Purpose**: Test Windows Event Log access and permissions
158 | **Checks**: System, Application, Security logs; pywin32 availability
159 | ```
160 | Tool: test_windows_event_log_access
161 | ```
162 |
163 | ### get_windows_event_log_info
164 | **Purpose**: Get detailed Event Log information
165 | **Parameters**: log_name (System/Application/Security), max_entries
166 | ```
167 | Tool: get_windows_event_log_info
168 | Parameters: log_name="System", max_entries=50
169 | ```
170 |
171 | ### query_windows_events_by_criteria
172 | **Purpose**: Query Event Logs with specific filters
173 | **Filters**: event_id, level, time_duration
174 | ```
175 | Tool: query_windows_events_by_criteria
176 | Parameters: event_id=7001, level="Error", time_duration="6h"
177 | ```
178 |
179 | ### get_windows_system_health
180 | **Purpose**: Windows health overview from Event Logs
181 | **Analyzes**: Last 24 hours of System and Application logs
182 | ```
183 | Tool: get_windows_system_health
184 | ```
185 |
186 | ## Windows Resources
187 | - `windows/system-events/{param}` - System Event logs
188 | - `windows/application-events/{param}` - Application Event logs
189 |
190 | ## Key Event IDs
191 | - **1074**: System shutdown/restart
192 | - **7000-7034**: Service control events
193 | - **1000**: Application crashes
194 | - **4624/4625**: Logon success/failure
195 | - **6008**: Unexpected shutdown
196 | """
197 |
198 | @mcp.prompt(
199 | title="Linux Tools Reference",
200 | description="Linux-specific diagnostic and monitoring tools"
201 | )
202 | async def linux_tools_reference() -> str:
203 | """
204 | Complete reference for Linux system tools.
205 | """
206 | return """
207 | # 🐧 Linux Tools Reference
208 |
209 | ## Diagnostic Tools
210 |
211 | ### test_linux_log_access
212 | **Purpose**: Test Linux log file and systemd journal access
213 | **Checks**: /var/log files, systemd journal, command availability
214 | ```
215 | Tool: test_linux_log_access
216 | ```
217 |
218 | ### query_systemd_journal
219 | **Purpose**: Query systemd journal with filters
220 | **Parameters**: service_name, priority, time_duration, max_lines
221 | ```
222 | Tool: query_systemd_journal
223 | Parameters: service_name="nginx", priority="err", time_duration="2h"
224 | ```
225 |
226 | ### analyze_linux_services
227 | **Purpose**: Analyze service status and health
228 | **Parameters**: service_pattern, include_failed
229 | ```
230 | Tool: analyze_linux_services
231 | Parameters: service_pattern="mysql|postgres", include_failed=true
232 | ```
233 |
234 | ### get_linux_system_overview
235 | **Purpose**: Comprehensive Linux system health
236 | **Provides**: System info, resources, service status, critical errors
237 | ```
238 | Tool: get_linux_system_overview
239 | ```
240 |
241 | ## Linux Resources
242 | - `linux/systemd-logs/{param}` - systemd journal logs
243 | - `linux/system-logs/{param}` - Traditional system logs
244 |
245 | ## Log Priorities
246 | - **emerg (0)**: System unusable
247 | - **alert (1)**: Immediate action
248 | - **crit (2)**: Critical conditions
249 | - **err (3)**: Error conditions
250 | - **warning (4)**: Warning conditions
251 | - **notice (5)**: Normal but significant
252 | - **info (6)**: Informational
253 | - **debug (7)**: Debug messages
254 | """
255 |
256 | @mcp.prompt(
257 | title="Process Monitoring Tools",
258 | description="Cross-platform process and resource monitoring tools"
259 | )
260 | async def process_monitoring_tools() -> str:
261 | """
262 | Reference for process monitoring tools.
263 | """
264 | return """
265 | # 🖥️ Process Monitoring Tools
266 |
267 | ## Resource Testing
268 |
269 | ### test_system_resources_access
270 | **Purpose**: Test system resource monitoring capabilities
271 | **Tests**: CPU, memory, disk, network, process access
272 | ```
273 | Tool: test_system_resources_access
274 | ```
275 |
276 | ## Performance Analysis
277 |
278 | ### analyze_system_performance
279 | **Purpose**: Comprehensive performance metrics
280 | **Parameters**: include_network, include_disk, sample_interval
281 | ```
282 | Tool: analyze_system_performance
283 | Parameters: include_network=true, sample_interval=5.0
284 | ```
285 |
286 | ### find_resource_intensive_processes
287 | **Purpose**: Identify high CPU/memory consumers
288 | **Parameters**: min_cpu_percent, min_memory_percent, sort_by, max_results
289 | ```
290 | Tool: find_resource_intensive_processes
291 | Parameters: min_cpu_percent=20, sort_by="cpu", max_results=10
292 | ```
293 |
294 | ### monitor_process_health
295 | **Purpose**: Monitor specific process health
296 | **Parameters**: process_name (required)
297 | ```
298 | Tool: monitor_process_health
299 | Parameters: process_name="postgres"
300 | ```
301 |
302 | ### get_system_health_summary
303 | **Purpose**: Overall system health score and top consumers
304 | **Provides**: Health score (0-100), resource usage, recommendations
305 | ```
306 | Tool: get_system_health_summary
307 | ```
308 |
309 | ## Process Resources
310 | - `processes/list` - Running processes with details
311 | - `processes/summary` - Process statistics
312 |
313 | ## Health Thresholds
314 | - **CPU**: >80% concerning, >95% critical
315 | - **Memory**: >90% concerning, >95% critical
316 | - **Disk**: >85% warning, >95% critical
317 | """
318 |
319 | @mcp.prompt(
320 | title="Network Diagnostic Tools",
321 | description="Network connectivity and troubleshooting tools"
322 | )
323 | async def network_diagnostic_tools() -> str:
324 | """
325 | Reference for network diagnostic tools.
326 | """
327 | return """
328 | # 🌐 Network Diagnostic Tools
329 |
330 | ## Connectivity Testing
331 |
332 | ### test_network_tools_availability
333 | **Purpose**: Check if network diagnostic tools are available
334 | **Tests**: ping, ss/netstat, traceroute, dig/nslookup
335 | ```
336 | Tool: test_network_tools_availability
337 | ```
338 |
339 | ### test_port_connectivity
340 | **Purpose**: Test specific port connectivity
341 | **Parameters**: ports (list), host, timeout
342 | ```
343 | Tool: test_port_connectivity
344 | Parameters: ports=[80, 443, 3306], host="localhost"
345 | ```
346 |
347 | ### test_network_connectivity
348 | **Purpose**: Test connectivity to multiple hosts
349 | **Parameters**: hosts (list), ping_count
350 | ```
351 | Tool: test_network_connectivity
352 | Parameters: hosts=["google.com", "8.8.8.8"], ping_count=3
353 | ```
354 |
355 | ## Analysis Tools
356 |
357 | ### analyze_network_connections
358 | **Purpose**: Analyze active connections and listening ports
359 | **Parameters**: include_listening, include_established, analyze_traffic
360 | ```
361 | Tool: analyze_network_connections
362 | Parameters: include_listening=true, analyze_traffic=true
363 | ```
364 |
365 | ### diagnose_network_issues
366 | **Purpose**: Comprehensive network diagnostics
367 | **Tests**: Multiple aspects of network health
368 | ```
369 | Tool: diagnose_network_issues
370 | ```
371 |
372 | ## Network Resources
373 | - `network/listening-ports` - Active listening ports
374 | - `network/established-connections` - Active connections
375 | - `network/all-connections` - All connections
376 | - `network/statistics` - Interface statistics
377 | - `network/routing-table` - Routing information
378 | - `network/port/{port}` - Specific port details
379 | """
380 |
381 | @mcp.prompt(
382 | title="Resource Parameters Guide",
383 | description="How to use flexible parameters with MCP resources"
384 | )
385 | async def resource_parameters_guide(
386 | param_type: Optional[str] = None
387 | ) -> str:
388 | """
389 | Guide for using resource parameters.
390 |
391 | Args:
392 | param_type: Type of parameter (time, count, range)
393 | """
394 |
395 | base_guide = """
396 | # 🎯 Resource Parameters Guide
397 |
398 | ## Overview
399 | Many MCP resources support flexible parameters for filtering and time-based queries.
400 | """
401 |
402 | param_guides = {
403 | "time": """
404 | ## Time-based Parameters
405 |
406 | ### Duration Format: `/time/{duration}`
407 | - **Minutes**: `/time/30m`, `/time/45m`
408 | - **Hours**: `/time/1h`, `/time/6h`, `/time/12h`
409 | - **Days**: `/time/1d`, `/time/7d`, `/time/30d`
410 |
411 | ### Examples
412 | ```
413 | # Last hour of Windows events
414 | Resource: windows/system-events/time/1h
415 |
416 | # Last 30 minutes of Linux logs
417 | Resource: linux/systemd-logs/time/30m
418 | ```
419 | """,
420 | "count": """
421 | ## Count-based Parameters
422 |
423 | ### Format: `/last/{n}`
424 | - Returns the last N entries
425 | - Useful for quick checks
426 | - Sorted by most recent first
427 |
428 | ### Examples
429 | ```
430 | # Last 100 system events
431 | Resource: windows/system-events/last/100
432 |
433 | # Last 50 journal entries
434 | Resource: linux/systemd-logs/last/50
435 | ```
436 | """,
437 | "range": """
438 | ## Time Range Parameters
439 |
440 | ### Format: `/range/{start}/{end}`
441 | - Specific time window queries
442 | - ISO format or readable dates
443 | - Timezone aware
444 |
445 | ### Examples
446 | ```
447 | # Specific hour
448 | Resource: windows/system-events/range/2025-01-07 13:00/2025-01-07 14:00
449 |
450 | # Date range
451 | Resource: linux/systemd-logs/range/2025-01-06/2025-01-07
452 | ```
453 | """
454 | }
455 |
456 | if param_type and param_type.lower() in param_guides:
457 | base_guide += param_guides[param_type.lower()]
458 | else:
459 | for guide in param_guides.values():
460 | base_guide += guide
461 |
462 | base_guide += """
463 | ## Best Practices
464 | - Start with shorter time ranges
465 | - Use count limits for large datasets
466 | - Combine with tool queries for filtering
467 | - Cache results when analyzing patterns
468 | """
469 |
470 | return base_guide
471 |
472 | @mcp.prompt(
473 | title="Platform Support Overview",
474 | description="Cross-platform capabilities and requirements"
475 | )
476 | async def platform_support_overview() -> str:
477 | """
478 | Overview of platform support and requirements.
479 | """
480 | return """
481 | # 🔍 Platform Support Overview
482 |
483 | ## Windows Support
484 |
485 | ### Requirements
486 | - Windows 7+ (Server 2008 R2+)
487 | - Python 3.7+
488 | - pywin32 package (pip install pywin32)
489 | - Administrator rights for Security log
490 |
491 | ### Capabilities
492 | ✅ Full Windows Event Log support
493 | ✅ Custom application logs (e.g., "Microsoft-Service Fabric/Admin")
494 | ✅ Performance counter access
495 | ✅ WMI integration
496 | ✅ Process and network monitoring
497 |
498 | ### Limitations
499 | - Security log requires elevation
500 | - Some ETW logs need special permissions
501 | - Remote log access needs credentials
502 |
503 | ## Linux Support
504 |
505 | ### Requirements
506 | - Linux kernel 3.10+
507 | - systemd 219+ (for journal)
508 | - Python 3.7+
509 | - psutil package
510 |
511 | ### Capabilities
512 | ✅ systemd journal queries
513 | ✅ Traditional log file parsing
514 | ✅ Process and resource monitoring
515 | ✅ Network diagnostics
516 | ✅ Service management
517 |
518 | ### Distribution Support
519 | - **Full**: Ubuntu 16.04+, Debian 8+, RHEL/CentOS 7+, Fedora 15+
520 | - **Partial**: Older distributions (log files only)
521 | - **Limited**: Non-systemd distributions
522 |
523 | ## Cross-Platform Features
524 |
525 | ### Available Everywhere
526 | - Process monitoring (psutil)
527 | - Network analysis
528 | - Log file parsing (JSON, XML, CSV, text)
529 | - Resource usage tracking
530 | - Performance metrics
531 |
532 | ### Platform-Specific
533 | - **Windows**: Event Logs, WMI, Performance Counters
534 | - **Linux**: systemd journal, syslog, package managers
535 | - **macOS**: Limited support (process/network only)
536 |
537 | ## Installation
538 | ```bash
539 | # Core installation
540 | pip install mcp-log-analyzer
541 |
542 | # Windows-specific
543 | pip install pywin32>=300
544 |
545 | # Development mode
546 | pip install -e ".[dev]"
547 | ```
548 | """
549 |
550 | @mcp.prompt(
551 | title="Common Workflows",
552 | description="Step-by-step guides for common analysis tasks"
553 | )
554 | async def common_workflows(
555 | workflow_type: Optional[str] = None
556 | ) -> str:
557 | """
558 | Common workflow patterns for log analysis.
559 |
560 | Args:
561 | workflow_type: Type of workflow (troubleshooting, security, performance)
562 | """
563 |
564 | base_guide = """
565 | # 🔄 Common Workflows
566 |
567 | ## Choose Your Workflow
568 | Select from troubleshooting, security, or performance analysis workflows.
569 | """
570 |
571 | workflow_guides = {
572 | "troubleshooting": """
573 | ## 🔧 Troubleshooting Workflow
574 |
575 | ### 1. Initial Assessment
576 | ```
577 | # Check system health
578 | Tool: get_system_health_summary
579 |
580 | # Platform-specific health
581 | Tool: get_windows_system_health # or get_linux_system_overview
582 | ```
583 |
584 | ### 2. Register Relevant Logs
585 | ```
586 | # System logs
587 | Tool: register_log_source
588 | Parameters: name="system", source_type="evt", path="System"
589 |
590 | # Application logs
591 | Tool: register_log_source
592 | Parameters: name="app", source_type="json", path="/var/log/app.json"
593 | ```
594 |
595 | ### 3. Search for Errors
596 | ```
597 | # Recent errors
598 | Tool: query_logs
599 | Parameters: source_name="system", filters={"level": "Error"}, start_time="6 hours ago"
600 |
601 | # Specific error patterns
602 | Tool: analyze_logs
603 | Parameters: source_name="app", analysis_type="pattern"
604 | ```
605 |
606 | ### 4. Deep Dive
607 | ```
608 | # Find root cause
609 | Tool: analyze_logs
610 | Parameters: source_name="system", analysis_type="anomaly", time_duration="24h"
611 | ```
612 | """,
613 | "security": """
614 | ## 🔒 Security Analysis Workflow
615 |
616 | ### 1. Security Baseline
617 | ```
618 | # Windows Security log
619 | Tool: register_log_source
620 | Parameters: name="security", source_type="evt", path="Security"
621 |
622 | # Linux auth logs
623 | Tool: query_systemd_journal
624 | Parameters: service_name="sshd", time_duration="24h"
625 | ```
626 |
627 | ### 2. Authentication Analysis
628 | ```
629 | # Failed logins (Windows)
630 | Tool: query_logs
631 | Parameters: source_name="security", filters={"event_id": 4625}
632 |
633 | # SSH failures (Linux)
634 | Tool: query_systemd_journal
635 | Parameters: priority="warning", time_duration="6h"
636 | ```
637 |
638 | ### 3. Anomaly Detection
639 | ```
640 | # Unusual patterns
641 | Tool: analyze_logs
642 | Parameters: source_name="security", analysis_type="anomaly"
643 |
644 | # Network connections
645 | Tool: analyze_network_connections
646 | Parameters: analyze_traffic=true
647 | ```
648 |
649 | ### 4. Incident Response
650 | ```
651 | # Track specific user
652 | Tool: query_logs
653 | Parameters: filters={"username": "suspicious_user"}
654 |
655 | # Timeline analysis
656 | Tool: query_logs
657 | Parameters: start_time="2025-01-07 10:00", end_time="2025-01-07 14:00"
658 | ```
659 | """,
660 | "performance": """
661 | ## 📊 Performance Analysis Workflow
662 |
663 | ### 1. Resource Baseline
664 | ```
665 | # Current performance
666 | Tool: analyze_system_performance
667 | Parameters: sample_interval=5.0
668 |
669 | # Resource consumers
670 | Tool: find_resource_intensive_processes
671 | Parameters: min_cpu_percent=10, sort_by="cpu"
672 | ```
673 |
674 | ### 2. Historical Analysis
675 | ```
676 | # Register performance logs
677 | Tool: register_log_source
678 | Parameters: name="perf_logs", source_type="csv", path="/var/log/performance.csv"
679 |
680 | # Query performance data
681 | Tool: query_logs
682 | Parameters: source_name="perf_logs", start_time="7 days ago"
683 | ```
684 |
685 | ### 3. Pattern Detection
686 | ```
687 | # Find performance patterns
688 | Tool: analyze_logs
689 | Parameters: source_name="perf_logs", analysis_type="pattern"
690 |
691 | # Monitor specific process
692 | Tool: monitor_process_health
693 | Parameters: process_name="database"
694 | ```
695 |
696 | ### 4. Optimization
697 | ```
698 | # Identify bottlenecks
699 | Tool: analyze_logs
700 | Parameters: analysis_type="summary", filters={"response_time": ">1000"}
701 |
702 | # Resource planning
703 | Resource: processes/summary
704 | ```
705 | """
706 | }
707 |
708 | if workflow_type and workflow_type.lower() in workflow_guides:
709 | base_guide += workflow_guides[workflow_type.lower()]
710 | else:
711 | base_guide += """
712 | ## Available Workflows
713 | - **troubleshooting**: Error investigation and root cause analysis
714 | - **security**: Authentication monitoring and threat detection
715 | - **performance**: Resource usage and optimization
716 |
717 | Specify a workflow_type for detailed steps.
718 | """
719 |
720 | return base_guide
721 |
722 | @mcp.prompt(
723 | title="Tool Categories Overview",
724 | description="High-level overview of all tool categories"
725 | )
726 | async def tool_categories_overview() -> str:
727 | """
728 | Overview of all available tool categories.
729 | """
730 | return """
731 | # 🛠️ Tool Categories Overview
732 |
733 | ## 📊 Log Management (6 tools)
734 | **Purpose**: Core functionality for log handling
735 | - Registration and source management
736 | - Querying with advanced filters
737 | - ML-powered analysis
738 | - Multiple format support
739 |
740 | ## 🪟 Windows Tools (4 tools)
741 | **Purpose**: Windows-specific diagnostics
742 | - Event Log access testing
743 | - Event querying and filtering
744 | - System health assessment
745 | - Service and application monitoring
746 |
747 | ## 🐧 Linux Tools (4 tools)
748 | **Purpose**: Linux-specific diagnostics
749 | - Log file and journal access
750 | - systemd service analysis
751 | - System overview and health
752 | - Distribution compatibility
753 |
754 | ## 🖥️ Process Monitoring (5 tools)
755 | **Purpose**: System resource analysis
756 | - Resource access testing
757 | - Performance metrics
758 | - Process identification
759 | - Health scoring
760 |
761 | ## 🌐 Network Diagnostics (5 tools)
762 | **Purpose**: Network troubleshooting
763 | - Tool availability checks
764 | - Port and host connectivity
765 | - Connection analysis
766 | - Issue diagnosis
767 |
768 | ## 📋 Resources (15+ endpoints)
769 | **Purpose**: Real-time data access
770 | - System logs and events
771 | - Process information
772 | - Network statistics
773 | - Flexible time parameters
774 |
775 | ## 💡 Prompts (60+ guides)
776 | **Purpose**: Interactive guidance
777 | - Step-by-step tutorials
778 | - Best practices
779 | - Troubleshooting help
780 | - Platform-specific advice
781 |
782 | ## Total Assets
783 | - **24** Tools
784 | - **15+** Resources
785 | - **60+** Prompts
786 | - **5** Major categories
787 | - **2** Primary platforms
788 | """
789 |
790 | @mcp.prompt(
791 | title="Troubleshooting Guide",
792 | description="Common issues and solutions when using MCP Log Analyzer"
793 | )
794 | async def troubleshooting_guide() -> str:
795 | """
796 | Troubleshooting common MCP Log Analyzer issues.
797 | """
798 | return """
799 | # 🔧 Troubleshooting Guide
800 |
801 | ## Installation Issues
802 |
803 | ### "pywin32 not found" (Windows)
804 | **Solution**:
805 | ```bash
806 | pip install pywin32>=300
807 | python -c "import win32api" # Test
808 | ```
809 |
810 | ### "Permission denied" errors
811 | **Windows**: Run as Administrator for Security logs
812 | **Linux**: Add user to systemd-journal group:
813 | ```bash
814 | sudo usermod -a -G systemd-journal $USER
815 | ```
816 |
817 | ### "Module not found" errors
818 | **Solution**: Install in development mode
819 | ```bash
820 | pip install -e ".[dev]"
821 | ```
822 |
823 | ## Tool Errors
824 |
825 | ### "No logs returned"
826 | **Possible causes**:
827 | 1. Time range too restrictive
828 | 2. Filters excluding all data
829 | 3. Log source not properly registered
830 | 4. No data in specified timeframe
831 |
832 | **Debug steps**:
833 | ```
834 | # Check source is registered
835 | Tool: list_log_sources
836 |
837 | # Try without filters
838 | Tool: query_logs
839 | Parameters: source_name="your_source"
840 |
841 | # Expand time range
842 | Tool: query_logs
843 | Parameters: source_name="your_source", start_time="7 days ago"
844 | ```
845 |
846 | ### "Access denied" to logs
847 | **Windows**:
848 | - Event Viewer works but tool doesn't? Check pywin32
849 | - Security log needs admin rights
850 | - Some logs need specific group membership
851 |
852 | **Linux**:
853 | - Check file permissions: `ls -la /var/log/`
854 | - Journal access: `groups` should show systemd-journal
855 | - Try with sudo as last resort
856 |
857 | ### "Analysis returns empty"
858 | **Requirements**:
859 | - Sufficient data (24+ hours for anomaly detection)
860 | - Consistent log format
861 | - Proper time range specification
862 | - Valid analysis type
863 |
864 | ## Performance Issues
865 |
866 | ### Slow queries
867 | **Solutions**:
868 | 1. Use specific time ranges (not "all time")
869 | 2. Add filters to reduce data
870 | 3. Use pagination (limit/offset)
871 | 4. Query smaller time windows
872 |
873 | ### High memory usage
874 | **Solutions**:
875 | 1. Process logs in chunks
876 | 2. Use streaming where available
877 | 3. Limit concurrent operations
878 | 4. Clear old log sources
879 |
880 | ## Platform-Specific
881 |
882 | ### Windows Event Log issues
883 | - Verify Event Log service is running
884 | - Check Event Log size limits
885 | - Clear full Event Logs if needed
886 | - Ensure proper Windows version
887 |
888 | ### Linux systemd issues
889 | - Verify systemd version (219+)
890 | - Check journal persistence settings
891 | - Ensure journal isn't corrupted
892 | - Verify systemctl works
893 |
894 | ## Getting Help
895 | 1. Check the specific tool's prompt for guidance
896 | 2. Use platform-specific testing tools first
897 | 3. Verify prerequisites are met
898 | 4. Check system logs for errors
899 | 5. Report issues with full error messages
900 | """
901 |
902 | @mcp.prompt(
903 | title="Best Practices",
904 | description="Best practices for effective log analysis with MCP"
905 | )
906 | async def best_practices() -> str:
907 | """
908 | Best practices for using MCP Log Analyzer effectively.
909 | """
910 | return """
911 | # 📋 Best Practices
912 |
913 | ## Log Source Management
914 |
915 | ### Naming Conventions
916 | ✅ Use descriptive, consistent names
917 | ```
918 | # Good
919 | name="prod_web_nginx"
920 | name="dev_app_json"
921 | name="windows_system_events"
922 |
923 | # Avoid
924 | name="logs1"
925 | name="test"
926 | name="x"
927 | ```
928 |
929 | ### Organization
930 | - Group by environment (prod/dev/test)
931 | - Include service/application name
932 | - Add log type suffix
933 | - Document purpose
934 |
935 | ### Maintenance
936 | - Regularly review registered sources
937 | - Remove obsolete sources
938 | - Update paths after log rotation
939 | - Monitor source accessibility
940 |
941 | ## Query Optimization
942 |
943 | ### Time Ranges
944 | 1. Start with recent data (1-6 hours)
945 | 2. Expand gradually if needed
946 | 3. Use specific ranges for investigations
947 | 4. Avoid open-ended queries
948 |
949 | ### Filtering Strategy
950 | ```
951 | # Efficient: Specific filters
952 | filters={"level": "Error", "service": "database"}
953 |
954 | # Inefficient: Broad search
955 | filters={"message_contains": "error"}
956 | ```
957 |
958 | ### Pagination
959 | ```
960 | # For large datasets
961 | limit=100, offset=0 # First page
962 | limit=100, offset=100 # Second page
963 | ```
964 |
965 | ## Analysis Strategy
966 |
967 | ### Progressive Analysis
968 | 1. **Summary** → Overview
969 | 2. **Pattern** → Recurring issues
970 | 3. **Anomaly** → Unusual events
971 |
972 | ### Correlation
973 | - Compare multiple log sources
974 | - Cross-reference timestamps
975 | - Look for cascading failures
976 | - Track error propagation
977 |
978 | ## Resource Monitoring
979 |
980 | ### Establish Baselines
981 | - Normal CPU usage
982 | - Typical memory consumption
983 | - Average process count
984 | - Standard network activity
985 |
986 | ### Regular Health Checks
987 | ```
988 | # Daily
989 | Tool: get_system_health_summary
990 |
991 | # Weekly
992 | Tool: analyze_logs
993 | Parameters: analysis_type="pattern", time_duration="7d"
994 |
995 | # Monthly
996 | Full system audit and capacity review
997 | ```
998 |
999 | ## Security Practices
1000 |
1001 | ### Access Control
1002 | - Limit Security log access
1003 | - Use read-only permissions
1004 | - Audit log access
1005 | - Rotate credentials
1006 |
1007 | ### Sensitive Data
1008 | - Filter out passwords
1009 | - Mask personal information
1010 | - Comply with regulations
1011 | - Secure log storage
1012 |
1013 | ## Performance Tips
1014 |
1015 | ### Query Performance
1016 | - Index frequently searched fields
1017 | - Archive old logs
1018 | - Use appropriate time windows
1019 | - Cache analysis results
1020 |
1021 | ### System Impact
1022 | - Schedule intensive analysis off-peak
1023 | - Monitor resource usage during queries
1024 | - Use sampling for large datasets
1025 | - Implement rate limiting
1026 |
1027 | ## Documentation
1028 |
1029 | ### What to Document
1030 | - Registered log sources and purposes
1031 | - Common query patterns
1032 | - Known issues and solutions
1033 | - Analysis findings
1034 | - Custom configurations
1035 |
1036 | ### Automation
1037 | - Script common workflows
1038 | - Set up alerts for critical events
1039 | - Automate health reports
1040 | - Schedule regular analyses
1041 | """
1042 |
```
--------------------------------------------------------------------------------
/tcp_proxy.py:
--------------------------------------------------------------------------------
```python
1 | #!/usr/bin/env python3
2 | """
3 | TCP proxy for MCP servers that bridges TCP connections to stdio-based MCP servers.
4 | Enhanced with automatic process restart, heartbeat, and connection resilience.
5 | """
6 |
7 | import asyncio
8 | import argparse
9 | import json
10 | import logging
11 | import time
12 | from typing import Optional, Dict, Any
13 |
14 | # Set up logging
15 | logging.basicConfig(
16 | level=logging.INFO,
17 | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
18 | )
19 | logger = logging.getLogger(__name__)
20 |
21 |
22 | class MCPProcess:
23 | """Manages an MCP server subprocess with automatic restart capability."""
24 |
25 | def __init__(self, command: list[str], auto_restart: bool = True):
26 | self.command = command
27 | self.process: Optional[asyncio.subprocess.Process] = None
28 | self._closed = False
29 | self.auto_restart = auto_restart
30 | self.restart_count = 0
31 | self.max_restarts = 5
32 | self.last_restart_time = 0
33 | self.restart_cooldown = 5.0 # Minimum seconds between restarts
34 |
35 | async def start(self):
36 | """Start the MCP server process."""
37 | logger.info(f"Starting MCP server: {' '.join(self.command)}")
38 | self.process = await asyncio.create_subprocess_exec(
39 | *self.command,
40 | stdin=asyncio.subprocess.PIPE,
41 | stdout=asyncio.subprocess.PIPE,
42 | stderr=asyncio.subprocess.PIPE,
43 | limit=10 * 1024 * 1024 # 10MB limit for large responses
44 | )
45 | logger.info(f"MCP server started with PID {self.process.pid}")
46 | self.last_restart_time = time.time()
47 |
48 | async def restart(self) -> bool:
49 | """Restart the MCP server process if allowed."""
50 | if not self.auto_restart:
51 | return False
52 |
53 | current_time = time.time()
54 | # Reduce cooldown for normal restarts (process completed successfully)
55 | cooldown = self.restart_cooldown if self.restart_count > 0 else 1.0
56 | if current_time - self.last_restart_time < cooldown:
57 | wait_time = cooldown - (current_time - self.last_restart_time)
58 | logger.info(f"Waiting {wait_time:.1f}s before restart (cooldown)")
59 | await asyncio.sleep(wait_time)
60 |
61 | if self.restart_count >= self.max_restarts:
62 | logger.error(f"Max restarts ({self.max_restarts}) reached, not restarting")
63 | return False
64 |
65 | self.restart_count += 1
66 | logger.info(f"Restarting MCP server (attempt {self.restart_count}/{self.max_restarts})")
67 |
68 | # Close existing process
69 | if self.process:
70 | try:
71 | self.process.terminate()
72 | await asyncio.wait_for(self.process.wait(), timeout=5.0)
73 | except asyncio.TimeoutError:
74 | logger.warning("Process didn't terminate, killing it")
75 | self.process.kill()
76 | await self.process.wait()
77 |
78 | self._closed = False
79 | self.process = None
80 |
81 | # Start new process
82 | try:
83 | await self.start()
84 | logger.info("MCP server restarted successfully")
85 | return True
86 | except Exception as e:
87 | logger.error(f"Failed to restart MCP server: {e}")
88 | return False
89 |
90 | def is_alive(self) -> bool:
91 | """Check if the process is still running."""
92 | return self.process is not None and self.process.returncode is None
93 |
94 | async def send_message(self, message: Dict[str, Any]) -> None:
95 | """Send a message to the MCP server."""
96 | if self.process is None or self.process.stdin is None:
97 | raise RuntimeError("MCP process not started")
98 |
99 | message_str = json.dumps(message) + '\n'
100 | self.process.stdin.write(message_str.encode('utf-8'))
101 | await self.process.stdin.drain()
102 |
103 | async def read_message(self) -> Optional[Dict[str, Any]]:
104 | """Read a message from the MCP server."""
105 | if self.process is None or self.process.stdout is None:
106 | raise RuntimeError("MCP process not started")
107 |
108 | try:
109 | # Increase the limit for readline to handle larger responses
110 | line = await self.process.stdout.readline()
111 | if not line:
112 | return None
113 |
114 | message_str = line.decode('utf-8').strip()
115 | if message_str:
116 | return json.loads(message_str)
117 | return None
118 | except json.JSONDecodeError as e:
119 | logger.error(f"Failed to decode JSON: {e}")
120 | return None
121 |
122 | async def read_stderr(self) -> Optional[str]:
123 | """Read from stderr (non-blocking)."""
124 | if self.process is None or self.process.stderr is None:
125 | return None
126 |
127 | try:
128 | # Try to read stderr without blocking
129 | line = await asyncio.wait_for(
130 | self.process.stderr.readline(),
131 | timeout=0.1
132 | )
133 | if line:
134 | return line.decode('utf-8').strip()
135 | except asyncio.TimeoutError:
136 | pass
137 | return None
138 |
139 | async def close(self) -> None:
140 | """Close the MCP server process."""
141 | if self.process is not None and not self._closed:
142 | self._closed = True
143 | self.auto_restart = False # Disable auto-restart on explicit close
144 | if self.process.stdin:
145 | self.process.stdin.close()
146 | self.process.terminate()
147 | await self.process.wait()
148 | logger.info(f"MCP server process {self.process.pid} terminated")
149 |
150 |
151 | class TCPToMCPBridge:
152 | """Bridges TCP connections to MCP server processes with heartbeat support."""
153 |
154 | def __init__(self, mcp_command: list[str], heartbeat_interval: float = 30.0):
155 | self.mcp_command = mcp_command
156 | self.heartbeat_interval = heartbeat_interval
157 | self.heartbeat_timeout = heartbeat_interval * 2
158 |
159 | async def handle_client(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
160 | """Handle a TCP client connection with resilience."""
161 | addr = writer.get_extra_info('peername')
162 | logger.info(f"New client connected from {addr}")
163 |
164 | # Track connection state
165 | connection_state = {
166 | 'last_heartbeat_sent': time.time(),
167 | 'last_heartbeat_received': time.time(),
168 | 'connected': True,
169 | 'client_supports_heartbeat': False,
170 | 'mcp_initialized': False,
171 | 'pending_requests': {}, # Track pending requests
172 | 'last_request_id': None,
173 | 'writer': writer # Store writer for use in process monitor
174 | }
175 |
176 | # Start MCP process for this client
177 | mcp_process = MCPProcess(self.mcp_command, auto_restart=True)
178 |
179 | try:
180 | await mcp_process.start()
181 |
182 | # Don't initialize MCP session here - let the client drive it
183 | # The client will send the initialize request when ready
184 | logger.info("MCP process started, waiting for client initialization...")
185 |
186 | # Create tasks for bidirectional communication
187 | tcp_to_mcp_task = asyncio.create_task(
188 | self._tcp_to_mcp(reader, mcp_process, connection_state)
189 | )
190 | mcp_to_tcp_task = asyncio.create_task(
191 | self._mcp_to_tcp(mcp_process, writer, connection_state)
192 | )
193 | stderr_monitor_task = asyncio.create_task(
194 | self._monitor_stderr(mcp_process)
195 | )
196 | heartbeat_task = asyncio.create_task(
197 | self._heartbeat_loop(writer, mcp_process, connection_state)
198 | )
199 | process_monitor_task = asyncio.create_task(
200 | self._monitor_process(mcp_process, connection_state)
201 | )
202 |
203 | # Wait for any task to complete
204 | done, pending = await asyncio.wait(
205 | [tcp_to_mcp_task, mcp_to_tcp_task, heartbeat_task, process_monitor_task],
206 | return_when=asyncio.FIRST_COMPLETED
207 | )
208 |
209 | # Cancel remaining tasks
210 | for task in pending:
211 | task.cancel()
212 | stderr_monitor_task.cancel()
213 |
214 | # Wait for cancellation
215 | await asyncio.gather(*pending, stderr_monitor_task, return_exceptions=True)
216 |
217 | except Exception as e:
218 | logger.error(f"Error handling client {addr}: {e}", exc_info=True)
219 | finally:
220 | logger.info(f"Client {addr} disconnected")
221 | connection_state['connected'] = False
222 | await mcp_process.close()
223 | writer.close()
224 | await writer.wait_closed()
225 |
226 | async def _tcp_to_mcp(self, reader: asyncio.StreamReader, mcp_process: MCPProcess, connection_state: dict) -> None:
227 | """Forward messages from TCP client to MCP process, handling heartbeats."""
228 | buffer = b""
229 |
230 | while connection_state['connected']:
231 | try:
232 | # Read data from TCP
233 | chunk = await reader.read(4096)
234 | if not chunk:
235 | logger.info("TCP connection closed by client")
236 | break
237 |
238 | buffer += chunk
239 |
240 | # Process complete messages
241 | while b'\n' in buffer:
242 | line, buffer = buffer.split(b'\n', 1)
243 | if line:
244 | try:
245 | message = json.loads(line.decode('utf-8'))
246 |
247 | # Handle heartbeat messages
248 | if message.get('type') == 'heartbeat':
249 | connection_state['last_heartbeat_received'] = time.time()
250 | connection_state['client_supports_heartbeat'] = True
251 | # Don't forward heartbeats to MCP server
252 | continue
253 | elif message.get('type') == 'handshake':
254 | connection_state['client_supports_heartbeat'] = True
255 | # Don't forward handshake to MCP server
256 | continue
257 |
258 | logger.debug(f"TCP -> MCP: {message}")
259 |
260 | # Track request if it has an ID (for potential replay)
261 | request_id = message.get('id')
262 | if request_id:
263 | connection_state['pending_requests'][request_id] = message
264 | connection_state['last_request_id'] = request_id
265 |
266 | # Check if MCP process is alive before sending
267 | if not mcp_process.is_alive():
268 | logger.warning("MCP process is dead, waiting for monitor to restart...")
269 | # Don't manually restart here, let the monitor handle it
270 | # This prevents race conditions
271 | await asyncio.sleep(0.5)
272 | continue
273 |
274 | # Always forward messages - let MCP server handle initialization state
275 | await mcp_process.send_message(message)
276 |
277 | # Mark as initialized if this was an initialize request
278 | if message.get('method') == 'initialize':
279 | connection_state['mcp_initialized'] = True
280 |
281 | except json.JSONDecodeError as e:
282 | logger.error(f"Invalid JSON from TCP client: {e}")
283 | except Exception as e:
284 | logger.error(f"Error forwarding to MCP: {e}")
285 |
286 | except asyncio.CancelledError:
287 | raise
288 | except Exception as e:
289 | logger.error(f"Error reading from TCP: {e}")
290 | break
291 |
292 | async def _mcp_to_tcp(self, mcp_process: MCPProcess, writer: asyncio.StreamWriter, connection_state: dict) -> None:
293 | """Forward messages from MCP process to TCP client."""
294 | while connection_state['connected']:
295 | try:
296 | message = await mcp_process.read_message()
297 | if message is None:
298 | logger.info("MCP process closed - letting monitor handle restart")
299 | # Don't restart here, let the monitor handle it
300 | # Just wait briefly and check again
301 | await asyncio.sleep(0.5)
302 | continue
303 |
304 | logger.debug(f"MCP -> TCP: {message}")
305 |
306 | # Clear pending request if this is a response
307 | response_id = message.get('id')
308 | if response_id and response_id in connection_state.get('pending_requests', {}):
309 | del connection_state['pending_requests'][response_id]
310 | logger.debug(f"Cleared pending request {response_id}")
311 |
312 | # Send to TCP client
313 | message_str = json.dumps(message) + '\n'
314 | writer.write(message_str.encode('utf-8'))
315 | await writer.drain()
316 |
317 | except asyncio.CancelledError:
318 | raise
319 | except Exception as e:
320 | logger.error(f"Error forwarding to TCP: {e}")
321 | # Check if the error is due to closed connection
322 | if writer.is_closing():
323 | logger.info("TCP connection is closed")
324 | break
325 | # Otherwise, might be MCP process issue - let monitor handle it
326 | if not mcp_process.is_alive():
327 | logger.debug("MCP process not alive, waiting for monitor to restart")
328 | await asyncio.sleep(0.5)
329 | continue
330 | break
331 |
332 | async def _monitor_stderr(self, mcp_process: MCPProcess) -> None:
333 | """Monitor MCP process stderr for debugging."""
334 | while True:
335 | try:
336 | stderr_line = await mcp_process.read_stderr()
337 | if stderr_line:
338 | logger.warning(f"MCP stderr: {stderr_line}")
339 | else:
340 | await asyncio.sleep(0.1)
341 | except asyncio.CancelledError:
342 | break
343 | except Exception as e:
344 | logger.error(f"Error reading stderr: {e}")
345 | await asyncio.sleep(1)
346 |
347 | async def _heartbeat_loop(self, writer: asyncio.StreamWriter, mcp_process: MCPProcess, connection_state: dict) -> None:
348 | """Send periodic heartbeat messages to the client."""
349 | while connection_state['connected']:
350 | try:
351 | await asyncio.sleep(self.heartbeat_interval)
352 |
353 | # Only send heartbeats if client supports them
354 | if connection_state['client_supports_heartbeat']:
355 | heartbeat_msg = {
356 | 'type': 'heartbeat_response',
357 | 'timestamp': time.time(),
358 | 'mcp_alive': mcp_process.is_alive()
359 | }
360 |
361 | message_str = json.dumps(heartbeat_msg) + '\n'
362 | writer.write(message_str.encode('utf-8'))
363 | await writer.drain()
364 |
365 | connection_state['last_heartbeat_sent'] = time.time()
366 |
367 | # Check if we've received a heartbeat recently
368 | if time.time() - connection_state['last_heartbeat_received'] > self.heartbeat_timeout:
369 | logger.warning("Client heartbeat timeout")
370 | # Client might be disconnected, but let TCP detect it
371 |
372 | except asyncio.CancelledError:
373 | break
374 | except Exception as e:
375 | logger.error(f"Error in heartbeat loop: {e}")
376 | if writer.is_closing():
377 | break
378 |
379 | async def _initialize_mcp_session(self, mcp_process: MCPProcess, writer: asyncio.StreamWriter, connection_state: dict) -> None:
380 | """Initialize MCP session after process start/restart."""
381 | try:
382 | logger.info("Initializing MCP session...")
383 |
384 | # Send MCP initialization message
385 | init_msg = {
386 | "jsonrpc": "2.0",
387 | "method": "initialize",
388 | "params": {
389 | "capabilities": {
390 | "tools": True,
391 | "resources": True,
392 | "prompts": True
393 | }
394 | },
395 | "id": "init-" + str(time.time())
396 | }
397 |
398 | await mcp_process.send_message(init_msg)
399 | logger.debug(f"Sent MCP initialize request: {init_msg}")
400 |
401 | # Wait for initialization response
402 | start_time = time.time()
403 | while time.time() - start_time < 10: # 10 second timeout
404 | response = await mcp_process.read_message()
405 | if response:
406 | logger.debug(f"MCP initialization response: {response}")
407 | if response.get("id") == init_msg["id"]:
408 | if "result" in response:
409 | connection_state['mcp_initialized'] = True
410 | logger.info("MCP session initialized successfully")
411 |
412 | # Send initialized notification
413 | initialized_msg = {
414 | "jsonrpc": "2.0",
415 | "method": "initialized",
416 | "params": {}
417 | }
418 | await mcp_process.send_message(initialized_msg)
419 | logger.debug("Sent MCP initialized notification")
420 |
421 | # Forward the initialization response to the client
422 | if writer and not writer.is_closing():
423 | response_str = json.dumps(response) + '\n'
424 | writer.write(response_str.encode('utf-8'))
425 | await writer.drain()
426 |
427 | return
428 | elif "error" in response:
429 | logger.error(f"MCP initialization failed: {response['error']}")
430 | return
431 | else:
432 | # Handle other messages during initialization
433 | if writer and not writer.is_closing():
434 | response_str = json.dumps(response) + '\n'
435 | writer.write(response_str.encode('utf-8'))
436 | await writer.drain()
437 |
438 | await asyncio.sleep(0.1)
439 |
440 | logger.error("MCP initialization timed out")
441 |
442 | except Exception as e:
443 | logger.error(f"Error initializing MCP session: {e}")
444 | connection_state['mcp_initialized'] = False
445 |
446 | async def _monitor_process(self, mcp_process: MCPProcess, connection_state: dict) -> None:
447 | """Monitor the MCP process health and restart if needed."""
448 | while connection_state['connected']:
449 | try:
450 | await asyncio.sleep(2) # Check every 2 seconds for faster response
451 |
452 | if not mcp_process.is_alive() and mcp_process.auto_restart:
453 | logger.info("MCP process terminated, restarting to maintain session...")
454 |
455 | # Store pending requests that might need to be replayed
456 | pending_requests = connection_state.get('pending_requests', {}).copy()
457 |
458 | if await mcp_process.restart():
459 | logger.info("MCP process restarted successfully")
460 |
461 | # Reset initialization state
462 | connection_state['mcp_initialized'] = False
463 |
464 | # Wait a moment for the process to stabilize
465 | await asyncio.sleep(0.5)
466 |
467 | # Check if we have a valid writer
468 | writer = connection_state.get('writer')
469 | if writer and not writer.is_closing():
470 | # Send a notification to the client about the restart
471 | restart_notification = {
472 | "jsonrpc": "2.0",
473 | "method": "$/mcp/serverRestarted",
474 | "params": {
475 | "timestamp": time.time(),
476 | "reason": "process_terminated"
477 | }
478 | }
479 | try:
480 | notification_str = json.dumps(restart_notification) + '\n'
481 | writer.write(notification_str.encode('utf-8'))
482 | await writer.drain()
483 | logger.info("Notified client of server restart")
484 | except Exception as e:
485 | logger.error(f"Failed to notify client of restart: {e}")
486 |
487 | # The client should reinitialize when it receives this notification
488 | logger.info("Waiting for client to reinitialize MCP session...")
489 | else:
490 | logger.warning("No valid writer available for client notification")
491 |
492 | # Reset restart count on successful restart to be more forgiving
493 | if mcp_process.restart_count > 0:
494 | mcp_process.restart_count = max(0, mcp_process.restart_count - 1)
495 |
496 | # Clear old pending requests as they're likely stale after restart
497 | if pending_requests:
498 | logger.info(f"Clearing {len(pending_requests)} stale pending requests after restart")
499 | connection_state['pending_requests'].clear()
500 | else:
501 | logger.error("Failed to restart MCP process")
502 | # If we can't restart, terminate the connection
503 | connection_state['connected'] = False
504 | break
505 |
506 | except asyncio.CancelledError:
507 | break
508 | except Exception as e:
509 | logger.error(f"Error in process monitor: {e}")
510 | await asyncio.sleep(2)
511 |
512 |
513 | async def main():
514 | """Main entry point."""
515 | parser = argparse.ArgumentParser(description='TCP proxy for MCP servers')
516 | parser.add_argument('--host', default='0.0.0.0',
517 | help='Host to bind to (default: 0.0.0.0)')
518 | parser.add_argument('--port', type=int, default=8080,
519 | help='Port to bind to (default: 8080)')
520 | parser.add_argument('--heartbeat-interval', type=float, default=30.0,
521 | help='Heartbeat interval in seconds (default: 30)')
522 | parser.add_argument('--auto-restart', action='store_true', default=True,
523 | help='Enable automatic MCP process restart (default: enabled)')
524 | parser.add_argument('--no-auto-restart', dest='auto_restart', action='store_false',
525 | help='Disable automatic MCP process restart')
526 | parser.add_argument('--debug', action='store_true',
527 | help='Enable debug logging')
528 | parser.add_argument('mcp_command', nargs='+',
529 | help='Command to run the MCP server (e.g., python main.py)')
530 |
531 | args = parser.parse_args()
532 |
533 | if args.debug:
534 | logging.getLogger().setLevel(logging.DEBUG)
535 |
536 | # Create bridge
537 | bridge = TCPToMCPBridge(args.mcp_command, heartbeat_interval=args.heartbeat_interval)
538 |
539 | # Start TCP server
540 | logger.info(f"Starting TCP proxy on {args.host}:{args.port}")
541 | logger.info(f"MCP command: {' '.join(args.mcp_command)}")
542 | logger.info(f"Heartbeat interval: {args.heartbeat_interval}s")
543 | logger.info(f"Auto-restart: {'enabled' if args.auto_restart else 'disabled'}")
544 |
545 | server = await asyncio.start_server(
546 | bridge.handle_client,
547 | args.host,
548 | args.port,
549 | limit=10 * 1024 * 1024 # 10MB limit for large messages
550 | )
551 |
552 | addr = server.sockets[0].getsockname()
553 | logger.info(f"TCP proxy listening on {addr[0]}:{addr[1]}")
554 |
555 | async with server:
556 | await server.serve_forever()
557 |
558 |
559 | if __name__ == "__main__":
560 | try:
561 | asyncio.run(main())
562 | except KeyboardInterrupt:
563 | logger.info("TCP proxy stopped by user")
```
--------------------------------------------------------------------------------
/src/mcp_log_analyzer/mcp_server/tools/network_test_tools.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | Network monitoring and testing MCP tools.
3 | """
4 |
5 | import platform
6 | import socket
7 | import subprocess
8 | from typing import Any, Dict, List
9 |
10 | from mcp.server import FastMCP
11 | from pydantic import BaseModel, Field
12 |
13 |
14 | class NetworkPortTestRequest(BaseModel):
15 | """Request model for network port testing."""
16 |
17 | ports: List[int] = Field(..., description="List of ports to test")
18 | host: str = Field("localhost", description="Host to test (default: localhost)")
19 | timeout: int = Field(5, description="Connection timeout in seconds")
20 |
21 |
22 | class NetworkConnectivityRequest(BaseModel):
23 | """Request model for network connectivity testing."""
24 |
25 | hosts: List[str] = Field(
26 | default_factory=lambda: ["8.8.8.8", "google.com", "github.com"],
27 | description="List of hosts to test connectivity to",
28 | )
29 | ping_count: int = Field(3, description="Number of ping packets to send")
30 |
31 |
32 | class NetworkAnalysisRequest(BaseModel):
33 | """Request model for network analysis."""
34 |
35 | include_listening: bool = Field(
36 | True, description="Include listening ports analysis"
37 | )
38 | include_established: bool = Field(
39 | True, description="Include established connections"
40 | )
41 | analyze_traffic: bool = Field(False, description="Analyze network traffic patterns")
42 |
43 |
44 | def register_network_test_tools(mcp: FastMCP):
45 | """Register all network testing tools with the MCP server."""
46 |
47 | @mcp.tool()
48 | async def test_network_tools_availability() -> Dict[str, Any]:
49 | """
50 | Test availability of network diagnostic tools.
51 |
52 | This tool checks if essential network tools are available
53 | on the system for network troubleshooting.
54 | """
55 | tools_to_test = {
56 | "ping": "Network connectivity testing",
57 | "netstat": "Network connections and statistics",
58 | "ss": "Modern replacement for netstat (Linux)",
59 | "nslookup": "DNS lookup utility",
60 | "curl": "HTTP client for testing web connectivity",
61 | "wget": "HTTP client alternative",
62 | "telnet": "TCP connection testing",
63 | "nc": "Netcat - networking utility",
64 | }
65 |
66 | available_tools = {}
67 |
68 | for tool, description in tools_to_test.items():
69 | try:
70 | # Test if tool exists and can run
71 | result = subprocess.run(
72 | [tool, "--help"] if tool != "telnet" else [tool],
73 | capture_output=True,
74 | text=True,
75 | timeout=5,
76 | )
77 |
78 | # Most tools return 0 for --help, but some may not
79 | available_tools[tool] = {
80 | "available": True,
81 | "description": description,
82 | "test_successful": True,
83 | }
84 |
85 | except FileNotFoundError:
86 | available_tools[tool] = {
87 | "available": False,
88 | "description": description,
89 | "error": "Command not found",
90 | }
91 | except subprocess.TimeoutExpired:
92 | available_tools[tool] = {
93 | "available": True,
94 | "description": description,
95 | "test_successful": False,
96 | "note": "Tool exists but test timed out",
97 | }
98 | except Exception as e:
99 | available_tools[tool] = {
100 | "available": False,
101 | "description": description,
102 | "error": str(e),
103 | }
104 |
105 | # Count available tools
106 | available_count = sum(
107 | 1 for tool in available_tools.values() if tool["available"]
108 | )
109 | total_count = len(tools_to_test)
110 |
111 | return {
112 | "platform": platform.system(),
113 | "tools_summary": {
114 | "total_tools": total_count,
115 | "available_tools": available_count,
116 | "availability_percentage": round(
117 | (available_count / total_count) * 100, 1
118 | ),
119 | },
120 | "tools": available_tools,
121 | }
122 |
123 | @mcp.tool()
124 | async def test_port_connectivity(
125 | request: NetworkPortTestRequest,
126 | ) -> Dict[str, Any]:
127 | """
128 | Test connectivity to specific ports.
129 |
130 | This tool tests whether specific ports are open and accepting
131 | connections on the specified host.
132 | """
133 | try:
134 | test_results = {}
135 |
136 | for port in request.ports:
137 | try:
138 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
139 | sock.settimeout(request.timeout)
140 |
141 | start_time = __import__("time").time()
142 | result = sock.connect_ex((request.host, port))
143 | end_time = __import__("time").time()
144 |
145 | sock.close()
146 |
147 | if result == 0:
148 | test_results[port] = {
149 | "status": "open",
150 | "accessible": True,
151 | "response_time_ms": round(
152 | (end_time - start_time) * 1000, 2
153 | ),
154 | }
155 | else:
156 | test_results[port] = {
157 | "status": "closed",
158 | "accessible": False,
159 | "error_code": result,
160 | }
161 |
162 | except socket.timeout:
163 | test_results[port] = {
164 | "status": "timeout",
165 | "accessible": False,
166 | "error": f"Connection timed out after {request.timeout} seconds",
167 | }
168 | except Exception as e:
169 | test_results[port] = {
170 | "status": "error",
171 | "accessible": False,
172 | "error": str(e),
173 | }
174 |
175 | # Summary statistics
176 | open_ports = [p for p, r in test_results.items() if r["accessible"]]
177 | closed_ports = [p for p, r in test_results.items() if not r["accessible"]]
178 |
179 | return {
180 | "target_host": request.host,
181 | "timeout_seconds": request.timeout,
182 | "summary": {
183 | "total_ports_tested": len(request.ports),
184 | "open_ports": len(open_ports),
185 | "closed_ports": len(closed_ports),
186 | "open_port_list": open_ports,
187 | },
188 | "detailed_results": test_results,
189 | }
190 |
191 | except Exception as e:
192 | return {"error": f"Error testing port connectivity: {str(e)}"}
193 |
194 | @mcp.tool()
195 | async def test_network_connectivity(
196 | request: NetworkConnectivityRequest,
197 | ) -> Dict[str, Any]:
198 | """
199 | Test network connectivity to various hosts.
200 |
201 | This tool tests network connectivity using ping and provides
202 | latency and packet loss information.
203 | """
204 | try:
205 | connectivity_results = {}
206 |
207 | for host in request.hosts:
208 | try:
209 | # Determine ping command based on platform
210 | if platform.system() == "Windows":
211 | ping_cmd = ["ping", "-n", str(request.ping_count), host]
212 | else:
213 | ping_cmd = ["ping", "-c", str(request.ping_count), host]
214 |
215 | result = subprocess.run(
216 | ping_cmd,
217 | capture_output=True,
218 | text=True,
219 | timeout=request.ping_count * 5 + 10, # Dynamic timeout
220 | )
221 |
222 | if result.returncode == 0:
223 | # Parse ping output for statistics
224 | output = result.stdout
225 |
226 | # Extract basic connectivity info
227 | connectivity_results[host] = {
228 | "reachable": True,
229 | "ping_output": output,
230 | "command_used": " ".join(ping_cmd),
231 | }
232 |
233 | # Try to extract timing information (platform-specific parsing)
234 | if platform.system() == "Windows":
235 | # Windows ping output parsing
236 | if "Average" in output:
237 | lines = output.split("\n")
238 | for line in lines:
239 | if "Average" in line:
240 | avg_time = line.split("=")[-1].strip()
241 | connectivity_results[host][
242 | "average_latency"
243 | ] = avg_time
244 | else:
245 | # Linux/Unix ping output parsing
246 | if "min/avg/max" in output:
247 | lines = output.split("\n")
248 | for line in lines:
249 | if "min/avg/max" in line:
250 | times = line.split("=")[-1].strip()
251 | connectivity_results[host][
252 | "latency_stats"
253 | ] = times
254 |
255 | else:
256 | connectivity_results[host] = {
257 | "reachable": False,
258 | "error": result.stderr or "Ping failed",
259 | "command_used": " ".join(ping_cmd),
260 | }
261 |
262 | except subprocess.TimeoutExpired:
263 | connectivity_results[host] = {
264 | "reachable": False,
265 | "error": "Ping command timed out",
266 | }
267 | except Exception as e:
268 | connectivity_results[host] = {
269 | "reachable": False,
270 | "error": str(e),
271 | }
272 |
273 | # Summary statistics
274 | reachable_hosts = [
275 | h for h, r in connectivity_results.items() if r["reachable"]
276 | ]
277 | unreachable_hosts = [
278 | h for h, r in connectivity_results.items() if not r["reachable"]
279 | ]
280 |
281 | return {
282 | "test_parameters": {
283 | "ping_count": request.ping_count,
284 | "total_hosts": len(request.hosts),
285 | },
286 | "summary": {
287 | "reachable_hosts": len(reachable_hosts),
288 | "unreachable_hosts": len(unreachable_hosts),
289 | "success_rate": round(
290 | (len(reachable_hosts) / len(request.hosts)) * 100, 1
291 | ),
292 | "reachable_list": reachable_hosts,
293 | "unreachable_list": unreachable_hosts,
294 | },
295 | "detailed_results": connectivity_results,
296 | }
297 |
298 | except Exception as e:
299 | return {"error": f"Error testing network connectivity: {str(e)}"}
300 |
301 | @mcp.tool()
302 | async def analyze_network_connections(
303 | request: NetworkAnalysisRequest,
304 | ) -> Dict[str, Any]:
305 | """
306 | Analyze current network connections and listening ports.
307 |
308 | This tool provides comprehensive analysis of network connections,
309 | listening ports, and traffic patterns for troubleshooting.
310 | """
311 | try:
312 | analysis_results = {}
313 |
314 | if request.include_listening:
315 | # Analyze listening ports
316 | try:
317 | if platform.system() == "Windows":
318 | cmd = ["netstat", "-an"]
319 | else:
320 | # Try ss first, fall back to netstat
321 | try:
322 | cmd_result = subprocess.run(
323 | ["ss", "-tlnp"],
324 | capture_output=True,
325 | text=True,
326 | timeout=10,
327 | )
328 | if cmd_result.returncode == 0:
329 | cmd = ["ss", "-tlnp"]
330 | else:
331 | cmd = ["netstat", "-tlnp"]
332 | except FileNotFoundError:
333 | cmd = ["netstat", "-tlnp"]
334 |
335 | result = subprocess.run(
336 | cmd, capture_output=True, text=True, timeout=10
337 | )
338 |
339 | if result.returncode == 0:
340 | lines = result.stdout.split("\n")
341 | listening_ports = []
342 |
343 | for line in lines:
344 | if "LISTEN" in line or (
345 | platform.system() != "Windows" and "tcp" in line.lower()
346 | ):
347 | parts = line.split()
348 | if len(parts) >= 4:
349 | local_address = (
350 | parts[3]
351 | if platform.system() == "Windows"
352 | else parts[0]
353 | )
354 | if ":" in local_address:
355 | port = local_address.split(":")[-1]
356 | listening_ports.append(
357 | {
358 | "port": port,
359 | "address": local_address,
360 | "protocol": "TCP",
361 | }
362 | )
363 |
364 | analysis_results["listening_ports"] = {
365 | "total_count": len(listening_ports),
366 | "ports": listening_ports[:20], # Limit to first 20
367 | "command_used": " ".join(cmd),
368 | }
369 | else:
370 | analysis_results["listening_ports"] = {"error": result.stderr}
371 |
372 | except Exception as e:
373 | analysis_results["listening_ports"] = {"error": str(e)}
374 |
375 | if request.include_established:
376 | # Analyze established connections
377 | try:
378 | if platform.system() == "Windows":
379 | cmd = ["netstat", "-an"]
380 | else:
381 | try:
382 | cmd_result = subprocess.run(
383 | ["ss", "-tnp", "state", "established"],
384 | capture_output=True,
385 | text=True,
386 | timeout=10,
387 | )
388 | if cmd_result.returncode == 0:
389 | cmd = ["ss", "-tnp", "state", "established"]
390 | else:
391 | cmd = ["netstat", "-tnp"]
392 | except FileNotFoundError:
393 | cmd = ["netstat", "-tnp"]
394 |
395 | result = subprocess.run(
396 | cmd, capture_output=True, text=True, timeout=10
397 | )
398 |
399 | if result.returncode == 0:
400 | lines = result.stdout.split("\n")
401 | established_connections = []
402 |
403 | for line in lines:
404 | if "ESTABLISHED" in line or "ESTAB" in line:
405 | parts = line.split()
406 | if len(parts) >= 5:
407 | local_addr = (
408 | parts[3]
409 | if platform.system() == "Windows"
410 | else parts[0]
411 | )
412 | foreign_addr = (
413 | parts[4]
414 | if platform.system() == "Windows"
415 | else parts[1]
416 | )
417 | established_connections.append(
418 | {
419 | "local_address": local_addr,
420 | "foreign_address": foreign_addr,
421 | "state": "ESTABLISHED",
422 | }
423 | )
424 |
425 | analysis_results["established_connections"] = {
426 | "total_count": len(established_connections),
427 | "connections": established_connections[
428 | :20
429 | ], # Limit to first 20
430 | "command_used": " ".join(cmd),
431 | }
432 | else:
433 | analysis_results["established_connections"] = {
434 | "error": result.stderr
435 | }
436 |
437 | except Exception as e:
438 | analysis_results["established_connections"] = {"error": str(e)}
439 |
440 | # Network interface information
441 | try:
442 | if platform.system() == "Windows":
443 | result = subprocess.run(
444 | ["ipconfig", "/all"], capture_output=True, text=True, timeout=10
445 | )
446 | else:
447 | result = subprocess.run(
448 | ["ip", "addr", "show"],
449 | capture_output=True,
450 | text=True,
451 | timeout=10,
452 | )
453 |
454 | if result.returncode == 0:
455 | analysis_results["network_interfaces"] = {
456 | "configuration": result.stdout[:2000], # Limit output size
457 | "command_used": (
458 | "ipconfig /all"
459 | if platform.system() == "Windows"
460 | else "ip addr show"
461 | ),
462 | }
463 | else:
464 | analysis_results["network_interfaces"] = {"error": result.stderr}
465 |
466 | except Exception as e:
467 | analysis_results["network_interfaces"] = {"error": str(e)}
468 |
469 | return {
470 | "analysis_scope": {
471 | "include_listening": request.include_listening,
472 | "include_established": request.include_established,
473 | "analyze_traffic": request.analyze_traffic,
474 | },
475 | "platform": platform.system(),
476 | "results": analysis_results,
477 | }
478 |
479 | except Exception as e:
480 | return {"error": f"Error analyzing network connections: {str(e)}"}
481 |
482 | @mcp.tool()
483 | async def diagnose_network_issues() -> Dict[str, Any]:
484 | """
485 | Perform comprehensive network diagnostics.
486 |
487 | This tool runs multiple network tests to identify potential
488 | network connectivity or configuration issues.
489 | """
490 | try:
491 | diagnostic_results = {}
492 |
493 | # Test 1: Basic connectivity to well-known servers
494 | connectivity_hosts = ["8.8.8.8", "1.1.1.1", "google.com"]
495 | connectivity_results = {}
496 |
497 | for host in connectivity_hosts:
498 | try:
499 | if platform.system() == "Windows":
500 | ping_cmd = ["ping", "-n", "1", host]
501 | else:
502 | ping_cmd = ["ping", "-c", "1", host]
503 |
504 | result = subprocess.run(
505 | ping_cmd, capture_output=True, text=True, timeout=10
506 | )
507 | connectivity_results[host] = {
508 | "reachable": result.returncode == 0,
509 | "details": (
510 | "Success" if result.returncode == 0 else result.stderr[:200]
511 | ),
512 | }
513 | except Exception as e:
514 | connectivity_results[host] = {"reachable": False, "error": str(e)}
515 |
516 | diagnostic_results["connectivity_test"] = connectivity_results
517 |
518 | # Test 2: DNS Resolution
519 | dns_test_hosts = ["google.com", "github.com", "stackoverflow.com"]
520 | dns_results = {}
521 |
522 | for host in dns_test_hosts:
523 | try:
524 | import socket
525 |
526 | ip = socket.gethostbyname(host)
527 | dns_results[host] = {"resolved": True, "ip_address": ip}
528 | except Exception as e:
529 | dns_results[host] = {"resolved": False, "error": str(e)}
530 |
531 | diagnostic_results["dns_resolution_test"] = dns_results
532 |
533 | # Test 3: Common port connectivity
534 | important_ports = [80, 443, 53, 22]
535 | port_results = {}
536 |
537 | for port in important_ports:
538 | try:
539 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
540 | sock.settimeout(3)
541 | result = sock.connect_ex(("google.com", port))
542 | sock.close()
543 |
544 | port_results[port] = {
545 | "accessible": result == 0,
546 | "service": {80: "HTTP", 443: "HTTPS", 53: "DNS", 22: "SSH"}.get(
547 | port, "Unknown"
548 | ),
549 | }
550 | except Exception as e:
551 | port_results[port] = {"accessible": False, "error": str(e)}
552 |
553 | diagnostic_results["port_connectivity_test"] = port_results
554 |
555 | # Test 4: Network interface status
556 | try:
557 | if platform.system() == "Windows":
558 | result = subprocess.run(
559 | ["ipconfig"], capture_output=True, text=True, timeout=5
560 | )
561 | else:
562 | result = subprocess.run(
563 | ["ip", "link", "show"],
564 | capture_output=True,
565 | text=True,
566 | timeout=5,
567 | )
568 |
569 | diagnostic_results["interface_status"] = {
570 | "command_successful": result.returncode == 0,
571 | "output_preview": (
572 | result.stdout[:500]
573 | if result.returncode == 0
574 | else result.stderr[:500]
575 | ),
576 | }
577 | except Exception as e:
578 | diagnostic_results["interface_status"] = {"error": str(e)}
579 |
580 | # Overall assessment
581 | connectivity_success = sum(
582 | 1 for r in connectivity_results.values() if r["reachable"]
583 | )
584 | dns_success = sum(1 for r in dns_results.values() if r["resolved"])
585 | port_success = sum(1 for r in port_results.values() if r["accessible"])
586 |
587 | total_tests = (
588 | len(connectivity_hosts) + len(dns_test_hosts) + len(important_ports)
589 | )
590 | successful_tests = connectivity_success + dns_success + port_success
591 | success_rate = (successful_tests / total_tests) * 100
592 |
593 | if success_rate >= 80:
594 | overall_status = "healthy"
595 | elif success_rate >= 60:
596 | overall_status = "fair"
597 | else:
598 | overall_status = "issues_detected"
599 |
600 | return {
601 | "overall_status": overall_status,
602 | "success_rate": round(success_rate, 1),
603 | "test_summary": {
604 | "connectivity_tests": f"{connectivity_success}/{len(connectivity_hosts)} passed",
605 | "dns_tests": f"{dns_success}/{len(dns_test_hosts)} passed",
606 | "port_tests": f"{port_success}/{len(important_ports)} passed",
607 | },
608 | "detailed_results": diagnostic_results,
609 | "recommendations": _generate_network_recommendations(
610 | diagnostic_results
611 | ),
612 | }
613 |
614 | except Exception as e:
615 | return {"error": f"Error performing network diagnostics: {str(e)}"}
616 |
617 |
618 | def _generate_network_recommendations(results: Dict) -> List[str]:
619 | """Generate network troubleshooting recommendations based on test results."""
620 | recommendations = []
621 |
622 | # Check connectivity issues
623 | connectivity = results.get("connectivity_test", {})
624 | failed_connectivity = [
625 | host
626 | for host, result in connectivity.items()
627 | if not result.get("reachable", False)
628 | ]
629 |
630 | if failed_connectivity:
631 | recommendations.append(
632 | f"Check internet connectivity - failed to reach: {', '.join(failed_connectivity)}"
633 | )
634 |
635 | # Check DNS issues
636 | dns = results.get("dns_resolution_test", {})
637 | failed_dns = [
638 | host for host, result in dns.items() if not result.get("resolved", False)
639 | ]
640 |
641 | if failed_dns:
642 | recommendations.append(
643 | f"Check DNS configuration - failed to resolve: {', '.join(failed_dns)}"
644 | )
645 |
646 | # Check port issues
647 | ports = results.get("port_connectivity_test", {})
648 | failed_ports = [
649 | str(port)
650 | for port, result in ports.items()
651 | if not result.get("accessible", False)
652 | ]
653 |
654 | if failed_ports:
655 | recommendations.append(
656 | f"Check firewall settings - blocked ports: {', '.join(failed_ports)}"
657 | )
658 |
659 | if not recommendations:
660 | recommendations.append("Network appears to be functioning normally")
661 |
662 | return recommendations
663 |
```
--------------------------------------------------------------------------------
/src/mcp_log_analyzer/mcp_server/prompts/network_testing_prompt.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | Network testing and diagnostics prompts for the MCP Log Analyzer server.
3 | """
4 |
5 | from typing import Optional
6 | from mcp.server import FastMCP
7 |
8 |
9 | def register_network_testing_prompts(mcp: FastMCP):
10 | """Register all network testing prompts."""
11 |
12 | @mcp.prompt(
13 | title="Network Tools Availability Check",
14 | description="Guide for testing availability of network diagnostic tools on the system"
15 | )
16 | async def network_tools_check() -> str:
17 | """
18 | Guide for checking which network diagnostic tools are available on the system.
19 | """
20 | return """
21 | # 🔍 Network Tools Availability Check
22 |
23 | ## Tool: test_network_tools_availability
24 |
25 | ### Purpose
26 | Tests availability of essential network diagnostic tools on your system.
27 |
28 | ### What It Checks
29 | - **ping**: Network connectivity testing
30 | - **netstat**: Network connections and statistics
31 | - **ss**: Modern netstat replacement (Linux)
32 | - **nslookup**: DNS lookup utility
33 | - **curl**: HTTP client for web connectivity
34 | - **wget**: Alternative HTTP client
35 | - **telnet**: TCP connection testing
36 | - **nc (netcat)**: Versatile networking utility
37 |
38 | ### Usage Example
39 | ```
40 | Tool: test_network_tools_availability
41 | ```
42 |
43 | ### Interpreting Results
44 | - **Available tools**: Can be used for diagnostics
45 | - **Missing tools**: May need installation
46 | - **Availability percentage**: Overall tool coverage
47 | - **Platform notes**: OS-specific tool variations
48 |
49 | ### Next Steps
50 | - Install missing critical tools if needed
51 | - Use available tools for network diagnostics
52 | - Consider platform alternatives for missing tools
53 | """
54 |
55 | @mcp.prompt(
56 | title="Port Connectivity Testing Guide",
57 | description="How to test connectivity to specific network ports"
58 | )
59 | async def port_connectivity_guide(
60 | service_type: Optional[str] = None
61 | ) -> str:
62 | """
63 | Guide for testing port connectivity.
64 |
65 | Args:
66 | service_type: Optional filter for specific service types (web, database, email, etc.)
67 | """
68 |
69 | base_guide = """
70 | # 🔌 Port Connectivity Testing Guide
71 |
72 | ## Tool: test_port_connectivity
73 |
74 | ### Purpose
75 | Tests TCP port accessibility and connection response times.
76 |
77 | ### Parameters
78 | - **ports**: List of ports to test (e.g., [80, 443, 22, 3306])
79 | - **host**: Target host (default: "localhost")
80 | - **timeout**: Connection timeout in seconds (default: 5)
81 |
82 | ### Usage Examples
83 | ```
84 | # Test web server ports
85 | Tool: test_port_connectivity
86 | Parameters: ports=[80, 443], host="example.com"
87 |
88 | # Test database ports
89 | Tool: test_port_connectivity
90 | Parameters: ports=[3306, 5432, 1433], host="db-server"
91 |
92 | # Test with custom timeout
93 | Tool: test_port_connectivity
94 | Parameters: ports=[8080], host="slow-server", timeout=10
95 | ```
96 |
97 | ### Capabilities
98 | ✅ Tests TCP port accessibility
99 | ✅ Measures connection response times
100 | ✅ Identifies open, closed, and filtered ports
101 | ✅ Provides summary statistics
102 | ✅ Handles connection timeouts gracefully
103 | """
104 |
105 | # Add service-specific guidance if requested
106 | service_guides = {
107 | "web": """
108 | ### Web Service Ports
109 | - **80**: HTTP (unencrypted web traffic)
110 | - **443**: HTTPS (encrypted web traffic)
111 | - **8080**: Alternative HTTP port
112 | - **8443**: Alternative HTTPS port
113 | """,
114 | "database": """
115 | ### Database Service Ports
116 | - **3306**: MySQL/MariaDB
117 | - **5432**: PostgreSQL
118 | - **1433**: Microsoft SQL Server
119 | - **1521**: Oracle Database
120 | - **27017**: MongoDB
121 | - **6379**: Redis
122 | """,
123 | "email": """
124 | ### Email Service Ports
125 | - **25**: SMTP (sending mail)
126 | - **110**: POP3 (retrieving mail)
127 | - **143**: IMAP (accessing mail)
128 | - **465**: SMTP over SSL
129 | - **587**: SMTP submission
130 | - **993**: IMAP over SSL
131 | - **995**: POP3 over SSL
132 | """,
133 | "remote": """
134 | ### Remote Access Ports
135 | - **22**: SSH (Secure Shell)
136 | - **23**: Telnet (insecure)
137 | - **3389**: RDP (Remote Desktop)
138 | - **5900**: VNC (Virtual Network Computing)
139 | """
140 | }
141 |
142 | if service_type and service_type.lower() in service_guides:
143 | base_guide += service_guides[service_type.lower()]
144 |
145 | base_guide += """
146 | ### Interpreting Results
147 | - **Open**: Port is accessible and service is listening
148 | - **Closed**: Port is reachable but no service listening
149 | - **Filtered**: Firewall or security device blocking access
150 | - **Timeout**: No response within timeout period
151 |
152 | ### Troubleshooting Failed Connections
153 | 1. Verify service is running on target host
154 | 2. Check firewall rules on both client and server
155 | 3. Ensure correct hostname/IP address
156 | 4. Test from different network locations
157 | 5. Verify network routing between hosts
158 | """
159 |
160 | return base_guide
161 |
162 | @mcp.prompt(
163 | title="Network Connectivity Test Guide",
164 | description="Guide for testing basic network connectivity using ping"
165 | )
166 | async def connectivity_test_guide() -> str:
167 | """
168 | Guide for testing network connectivity to various hosts.
169 | """
170 | return """
171 | # 📡 Network Connectivity Test Guide
172 |
173 | ## Tool: test_network_connectivity
174 |
175 | ### Purpose
176 | Tests network reachability using ping to measure latency and packet loss.
177 |
178 | ### Parameters
179 | - **hosts**: List of hosts to test (default: ["8.8.8.8", "google.com", "github.com"])
180 | - **ping_count**: Number of ping packets (default: 3)
181 |
182 | ### Usage Examples
183 | ```
184 | # Test default hosts
185 | Tool: test_network_connectivity
186 |
187 | # Test specific hosts
188 | Tool: test_network_connectivity
189 | Parameters: hosts=["192.168.1.1", "10.0.0.1", "gateway.local"]
190 |
191 | # Extended test with more packets
192 | Tool: test_network_connectivity
193 | Parameters: hosts=["remote-server.com"], ping_count=10
194 | ```
195 |
196 | ### Capabilities
197 | ✅ Tests network reachability using ping
198 | ✅ Measures latency and packet loss
199 | ✅ Cross-platform ping command support
200 | ✅ Parses ping output for statistics
201 | ✅ Provides connectivity success rates
202 |
203 | ### Interpreting Results
204 | - **Success Rate**: Percentage of successful pings
205 | - 100%: Excellent connectivity
206 | - 80-99%: Good with minor packet loss
207 | - 50-79%: Fair, noticeable issues
208 | - <50%: Poor connectivity
209 |
210 | - **Latency (Round-Trip Time)**:
211 | - <10ms: Excellent (local network)
212 | - 10-50ms: Good (same region)
213 | - 50-150ms: Fair (cross-country)
214 | - >150ms: High latency (international/satellite)
215 |
216 | ### Common Test Scenarios
217 | 1. **Local Network Test**: Test router/gateway
218 | 2. **Internet Test**: Test public DNS servers (8.8.8.8, 1.1.1.1)
219 | 3. **Service Test**: Test specific service endpoints
220 | 4. **ISP Test**: Test ISP's DNS servers
221 | """
222 |
223 | @mcp.prompt(
224 | title="Network Connection Analysis Guide",
225 | description="How to analyze current network connections and listening ports"
226 | )
227 | async def connection_analysis_guide() -> str:
228 | """
229 | Guide for analyzing network connections and listening services.
230 | """
231 | return """
232 | # 🔍 Network Connection Analysis Guide
233 |
234 | ## Tool: analyze_network_connections
235 |
236 | ### Purpose
237 | Analyzes current network connections, listening ports, and network interfaces.
238 |
239 | ### Parameters
240 | - **include_listening**: Include listening ports analysis (default: true)
241 | - **include_established**: Include established connections (default: true)
242 | - **analyze_traffic**: Analyze traffic patterns (default: false)
243 |
244 | ### Usage Examples
245 | ```
246 | # Full analysis
247 | Tool: analyze_network_connections
248 |
249 | # Only listening ports
250 | Tool: analyze_network_connections
251 | Parameters: include_established=false
252 |
253 | # Only active connections
254 | Tool: analyze_network_connections
255 | Parameters: include_listening=false
256 | ```
257 |
258 | ### What It Analyzes
259 | 1. **Listening Ports**
260 | - Services accepting connections
261 | - Port numbers and protocols
262 | - Potential security exposure
263 |
264 | 2. **Established Connections**
265 | - Active network sessions
266 | - Remote endpoints
267 | - Connection states
268 |
269 | 3. **Network Interfaces**
270 | - Interface configuration
271 | - IP addresses and DNS settings
272 | - Interface status
273 |
274 | ### Security Considerations
275 | - Review listening ports for unnecessary services
276 | - Check established connections for suspicious endpoints
277 | - Verify services bind to appropriate interfaces
278 | - Monitor for unusual connection patterns
279 |
280 | ### Typical Port Ranges
281 | - **Well-known**: 0-1023 (system services)
282 | - **Registered**: 1024-49151 (user applications)
283 | - **Dynamic**: 49152-65535 (temporary connections)
284 | """
285 |
286 | @mcp.prompt(
287 | title="Quick Network Diagnostics",
288 | description="Fast network health check procedure"
289 | )
290 | async def quick_diagnostics() -> str:
291 | """
292 | Quick network diagnostics procedure for rapid assessment.
293 | """
294 | return """
295 | # ⚡ Quick Network Diagnostics
296 |
297 | ## Tool: diagnose_network_issues
298 |
299 | ### Purpose
300 | Performs comprehensive network diagnostics in a single operation.
301 |
302 | ### What It Tests
303 | ✅ Basic connectivity to well-known servers
304 | ✅ DNS resolution functionality
305 | ✅ Common port accessibility
306 | ✅ Network interface status
307 | ✅ Overall network health assessment
308 |
309 | ### Usage
310 | ```
311 | Tool: diagnose_network_issues
312 | ```
313 |
314 | ### Results Include
315 | - **Connectivity Status**: Internet and local network
316 | - **DNS Health**: Resolution success/failure
317 | - **Service Availability**: Common ports status
318 | - **Network Interfaces**: Configuration and status
319 | - **Health Score**: Overall network assessment
320 | - **Recommendations**: Suggested fixes for issues
321 |
322 | ### When to Use
323 | - Initial network troubleshooting
324 | - Quick health check before detailed analysis
325 | - Periodic network monitoring
326 | - After network configuration changes
327 | - When users report connectivity issues
328 |
329 | ### Follow-up Actions
330 | Based on results, you may need to:
331 | 1. Run specific port tests
332 | 2. Check DNS configuration
333 | 3. Analyze network connections
334 | 4. Test specific services
335 | 5. Review firewall rules
336 | """
337 |
338 | @mcp.prompt(
339 | title="Network Port Reference",
340 | description="Common network ports and their services"
341 | )
342 | async def port_reference(
343 | category: Optional[str] = None
344 | ) -> str:
345 | """
346 | Reference guide for common network ports.
347 |
348 | Args:
349 | category: Optional category filter (web, database, email, remote, etc.)
350 | """
351 |
352 | all_ports = {
353 | "web": """
354 | ## 🌐 Web Service Ports
355 | - **80**: HTTP - Standard web traffic
356 | - **443**: HTTPS - Secure web traffic
357 | - **8080**: HTTP alternate - Common development port
358 | - **8443**: HTTPS alternate - Secure development port
359 | - **3000**: Node.js development server
360 | - **4200**: Angular development server
361 | - **8000**: Python HTTP server
362 | """,
363 | "database": """
364 | ## 💾 Database Ports
365 | - **3306**: MySQL/MariaDB
366 | - **5432**: PostgreSQL
367 | - **1433**: Microsoft SQL Server
368 | - **1521**: Oracle Database
369 | - **27017**: MongoDB
370 | - **6379**: Redis
371 | - **5984**: CouchDB
372 | - **7474**: Neo4j
373 | - **9042**: Cassandra
374 | """,
375 | "email": """
376 | ## 📧 Email Service Ports
377 | - **25**: SMTP - Mail sending
378 | - **110**: POP3 - Mail retrieval
379 | - **143**: IMAP - Mail access
380 | - **465**: SMTP SSL - Secure mail sending
381 | - **587**: SMTP submission
382 | - **993**: IMAP SSL - Secure mail access
383 | - **995**: POP3 SSL - Secure mail retrieval
384 | """,
385 | "remote": """
386 | ## 🖥️ Remote Access Ports
387 | - **22**: SSH - Secure Shell
388 | - **23**: Telnet - Unsecure remote access
389 | - **3389**: RDP - Windows Remote Desktop
390 | - **5900**: VNC - Virtual Network Computing
391 | - **5985**: WinRM HTTP
392 | - **5986**: WinRM HTTPS
393 | """,
394 | "messaging": """
395 | ## 💬 Messaging & Queue Ports
396 | - **5672**: RabbitMQ
397 | - **61613**: ActiveMQ STOMP
398 | - **9092**: Apache Kafka
399 | - **4222**: NATS
400 | - **6667**: IRC
401 | - **5222**: XMPP client
402 | """,
403 | "monitoring": """
404 | ## 📊 Monitoring & Management Ports
405 | - **161**: SNMP - Network monitoring
406 | - **514**: Syslog
407 | - **2003**: Graphite
408 | - **8086**: InfluxDB
409 | - **9090**: Prometheus
410 | - **3000**: Grafana
411 | - **9200**: Elasticsearch
412 | - **5601**: Kibana
413 | """
414 | }
415 |
416 | result = "# 🔌 Network Port Reference\n\n"
417 |
418 | if category and category.lower() in all_ports:
419 | result += all_ports[category.lower()]
420 | else:
421 | result += "## Common Network Ports by Category\n\n"
422 | for cat_name, content in all_ports.items():
423 | result += content + "\n"
424 |
425 | result += """
426 | ## Port Number Ranges
427 | - **0-1023**: Well-known ports (require root/admin)
428 | - **1024-49151**: Registered ports (user applications)
429 | - **49152-65535**: Dynamic/private ports (temporary)
430 |
431 | ## Security Notes
432 | - Only open ports that are necessary
433 | - Use encrypted alternatives when available
434 | - Monitor listening ports regularly
435 | - Implement firewall rules for protection
436 | """
437 |
438 | return result
439 |
440 | @mcp.prompt(
441 | title="Network Issue: Cannot Connect to Internet",
442 | description="Troubleshooting guide for complete internet connectivity loss"
443 | )
444 | async def troubleshoot_no_internet() -> str:
445 | """
446 | Step-by-step guide for troubleshooting internet connectivity issues.
447 | """
448 | return """
449 | # 🚫 Troubleshooting: Cannot Connect to Internet
450 |
451 | ## Symptoms
452 | - No websites load
453 | - Ping to external IPs fails
454 | - DNS resolution fails
455 | - Local network may still work
456 |
457 | ## Diagnostic Steps
458 |
459 | ### Step 1: Test Network Tools
460 | ```
461 | Tool: test_network_tools_availability
462 | ```
463 | Verify diagnostic tools are available.
464 |
465 | ### Step 2: Test Local Network
466 | ```
467 | Tool: test_network_connectivity
468 | Parameters: hosts=["192.168.1.1", "10.0.0.1"]
469 | ```
470 | Check if local network/router is reachable.
471 |
472 | ### Step 3: Test DNS
473 | ```
474 | Tool: test_port_connectivity
475 | Parameters: ports=[53], host="8.8.8.8"
476 | ```
477 | Check if DNS servers are reachable.
478 |
479 | ### Step 4: Test External Connectivity
480 | ```
481 | Tool: test_network_connectivity
482 | Parameters: hosts=["8.8.8.8", "1.1.1.1"]
483 | ```
484 | Test connectivity to public DNS servers.
485 |
486 | ### Step 5: Comprehensive Check
487 | ```
488 | Tool: diagnose_network_issues
489 | ```
490 | Run full network diagnostics.
491 |
492 | ## Solutions by Root Cause
493 |
494 | ### Router/Gateway Issue
495 | - Restart router/modem
496 | - Check cable connections
497 | - Verify router lights/status
498 | - Access router admin panel
499 |
500 | ### ISP Outage
501 | - Check ISP status page
502 | - Contact ISP support
503 | - Wait for service restoration
504 | - Consider backup connection
505 |
506 | ### DNS Issues
507 | - Change DNS servers to 8.8.8.8, 1.1.1.1
508 | - Flush DNS cache
509 | - Check DNS configuration
510 | - Test with IP addresses directly
511 |
512 | ### Network Interface
513 | - Check interface status
514 | - Restart network service
515 | - Update network drivers
516 | - Reset network settings
517 | """
518 |
519 | @mcp.prompt(
520 | title="Network Issue: Slow Performance",
521 | description="Troubleshooting guide for slow network performance"
522 | )
523 | async def troubleshoot_slow_network() -> str:
524 | """
525 | Guide for diagnosing and fixing slow network performance.
526 | """
527 | return """
528 | # 🐌 Troubleshooting: Slow Network Performance
529 |
530 | ## Symptoms
531 | - Websites load very slowly
532 | - High latency in ping tests
533 | - Downloads/uploads are slow
534 | - Intermittent timeouts
535 |
536 | ## Diagnostic Steps
537 |
538 | ### Step 1: Measure Baseline Performance
539 | ```
540 | Tool: test_network_connectivity
541 | Parameters: hosts=["8.8.8.8", "google.com", "cloudflare.com"], ping_count=10
542 | ```
543 | Measure latency to various destinations.
544 |
545 | ### Step 2: Test Port Response Times
546 | ```
547 | Tool: test_port_connectivity
548 | Parameters: ports=[80, 443], host="google.com", timeout=10
549 | ```
550 | Measure connection establishment times.
551 |
552 | ### Step 3: Check Network Utilization
553 | ```
554 | Tool: analyze_network_connections
555 | Parameters: include_established=true
556 | ```
557 | Look for high connection counts or unusual traffic.
558 |
559 | ### Step 4: Test Different Destinations
560 | ```
561 | Tool: test_network_connectivity
562 | Parameters: hosts=["local-server", "regional-server", "global-server"]
563 | ```
564 | Identify if slowness is location-specific.
565 |
566 | ## Performance Benchmarks
567 |
568 | ### Latency Guidelines
569 | - **Excellent**: <50ms
570 | - **Good**: 50-100ms
571 | - **Fair**: 100-200ms
572 | - **Poor**: >200ms
573 |
574 | ### Connection Times
575 | - **Fast**: <1s
576 | - **Normal**: 1-3s
577 | - **Slow**: 3-10s
578 | - **Very Slow**: >10s
579 |
580 | ## Common Causes & Solutions
581 |
582 | ### High Latency
583 | - Check for network congestion
584 | - Review QoS settings
585 | - Test wired vs wireless
586 | - Check for interference
587 |
588 | ### Bandwidth Issues
589 | - Run speed test
590 | - Check for bandwidth limits
591 | - Monitor usage patterns
592 | - Upgrade internet plan
593 |
594 | ### Local Congestion
595 | - Limit bandwidth-heavy apps
596 | - Schedule large downloads
597 | - Check for malware
598 | - Review connected devices
599 |
600 | ### DNS Delays
601 | - Switch to faster DNS (1.1.1.1, 8.8.8.8)
602 | - Enable DNS caching
603 | - Check DNS server load
604 | - Use local DNS server
605 | """
606 |
607 | @mcp.prompt(
608 | title="Network Issue: Service Unreachable",
609 | description="Troubleshooting guide for when specific services cannot be reached"
610 | )
611 | async def troubleshoot_service_unreachable() -> str:
612 | """
613 | Guide for troubleshooting unreachable network services.
614 | """
615 | return """
616 | # 🔌 Troubleshooting: Service Unreachable
617 |
618 | ## Symptoms
619 | - Specific website/service won't load
620 | - Other internet services work fine
621 | - "Connection refused" or timeout errors
622 | - Service works for others
623 |
624 | ## Diagnostic Steps
625 |
626 | ### Step 1: Test Service Ports
627 | ```
628 | Tool: test_port_connectivity
629 | Parameters: ports=[80, 443], host="target-server.com"
630 | ```
631 | Check if service ports are accessible.
632 |
633 | ### Step 2: Test Basic Connectivity
634 | ```
635 | Tool: test_network_connectivity
636 | Parameters: hosts=["target-server.com"]
637 | ```
638 | Verify basic network path to server.
639 |
640 | ### Step 3: Check DNS Resolution
641 | ```
642 | Tool: diagnose_network_issues
643 | ```
644 | Verify DNS is resolving correctly.
645 |
646 | ### Step 4: Test From Different Network
647 | If possible, test from:
648 | - Different device
649 | - Mobile hotspot
650 | - VPN connection
651 | - Different location
652 |
653 | ### Step 5: Check Local Services
654 | ```
655 | Tool: analyze_network_connections
656 | Parameters: include_listening=true
657 | ```
658 | For local services, verify they're listening.
659 |
660 | ## Root Cause Analysis
661 |
662 | ### Port Blocked
663 | - **Local Firewall**: Check outbound rules
664 | - **Corporate Firewall**: Contact IT
665 | - **ISP Blocking**: Try different port/VPN
666 | - **Server Firewall**: Contact service admin
667 |
668 | ### Service Down
669 | - Check service status page
670 | - Try alternative endpoints
671 | - Contact service support
672 | - Wait for restoration
673 |
674 | ### DNS Issues
675 | - Try direct IP if known
676 | - Use different DNS server
677 | - Clear DNS cache
678 | - Check hosts file
679 |
680 | ### Routing Issue
681 | - Traceroute to identify where it fails
682 | - Try VPN to bypass routing
683 | - Contact ISP if persistent
684 | - Wait for route fix
685 |
686 | ## Service-Specific Checks
687 |
688 | ### Web Services (80/443)
689 | - Test HTTP and HTTPS separately
690 | - Check for SSL/TLS issues
691 | - Try different browsers
692 | - Clear browser cache
693 |
694 | ### Database Services
695 | - Verify connection string
696 | - Check authentication
697 | - Test from DB client
698 | - Review access permissions
699 |
700 | ### Email Services
701 | - Test each protocol separately
702 | - Verify authentication
703 | - Check SSL/TLS settings
704 | - Review port numbers
705 | """
706 |
707 | @mcp.prompt(
708 | title="Network Security Audit",
709 | description="Guide for performing basic network security assessment"
710 | )
711 | async def network_security_audit() -> str:
712 | """
713 | Guide for conducting a basic network security audit.
714 | """
715 | return """
716 | # 🔒 Network Security Audit Guide
717 |
718 | ## Purpose
719 | Identify potential security risks in network configuration.
720 |
721 | ## Audit Steps
722 |
723 | ### Step 1: Audit Listening Ports
724 | ```
725 | Tool: analyze_network_connections
726 | Parameters: include_listening=true, include_established=false
727 | ```
728 | Identify all services accepting connections.
729 |
730 | ### Step 2: Check Established Connections
731 | ```
732 | Tool: analyze_network_connections
733 | Parameters: include_listening=false, include_established=true
734 | ```
735 | Review current connections for suspicious activity.
736 |
737 | ### Step 3: Test External Exposure
738 | ```
739 | Tool: test_port_connectivity
740 | Parameters: ports=[22, 3389, 3306, 5432], host="your-external-ip"
741 | ```
742 | Check if sensitive services are exposed.
743 |
744 | ### Step 4: Verify Critical Services
745 | ```
746 | Tool: test_port_connectivity
747 | Parameters: ports=[80, 443, 22], host="localhost"
748 | ```
749 | Ensure legitimate services are accessible.
750 |
751 | ## Security Checklist
752 |
753 | ### Listening Ports Review
754 | - [ ] Document all listening services
755 | - [ ] Identify unnecessary open ports
756 | - [ ] Verify services bind to correct interfaces
757 | - [ ] Check for default/development ports
758 |
759 | ### Connection Analysis
760 | - [ ] Review established connections
761 | - [ ] Look for unusual destinations
762 | - [ ] Check for high connection counts
763 | - [ ] Monitor for persistent connections
764 |
765 | ### Common Security Issues
766 |
767 | #### Unnecessary Services
768 | - Development servers on production
769 | - Default services never disabled
770 | - Debug ports left open
771 | - Unused database ports
772 |
773 | #### Weak Bindings
774 | - Services bound to 0.0.0.0 unnecessarily
775 | - No firewall rules in place
776 | - Default configurations unchanged
777 | - Missing network segmentation
778 |
779 | #### Suspicious Activity
780 | - Connections to unknown IPs
781 | - Unusual port numbers
782 | - High-numbered listening ports
783 | - Services running as root/admin
784 |
785 | ## Remediation Steps
786 |
787 | 1. **Close Unnecessary Ports**
788 | - Stop unused services
789 | - Update firewall rules
790 | - Document required ports
791 |
792 | 2. **Restrict Access**
793 | - Bind to specific interfaces
794 | - Implement access controls
795 | - Use VPN for sensitive services
796 |
797 | 3. **Monitor Regularly**
798 | - Schedule periodic audits
799 | - Set up port monitoring
800 | - Alert on new services
801 | - Log connection attempts
802 |
803 | 4. **Follow Best Practices**
804 | - Change default ports
805 | - Use encrypted protocols
806 | - Implement least privilege
807 | - Keep services updated
808 | """
809 |
810 | @mcp.prompt(
811 | title="Emergency Network Diagnostics",
812 | description="Quick triage protocol for network emergencies"
813 | )
814 | async def emergency_diagnostics() -> str:
815 | """
816 | Emergency response guide for critical network issues.
817 | """
818 | return """
819 | # 🚨 Emergency Network Diagnostics Protocol
820 |
821 | ## When to Use
822 | - Complete network outage
823 | - Critical service failure
824 | - Performance degradation affecting business
825 | - Security incident response
826 |
827 | ## Phase 1: Immediate Assessment (< 2 minutes)
828 |
829 | ### Quick Health Check
830 | ```
831 | Tool: diagnose_network_issues
832 | ```
833 | Get overall network status immediately.
834 |
835 | ### Basic Connectivity Test
836 | ```
837 | Tool: test_network_connectivity
838 | Parameters: hosts=["8.8.8.8", "google.com"]
839 | ```
840 | Determine scope of outage.
841 |
842 | ### Decision Point
843 | - **Local issue**: Proceed to Phase 2A
844 | - **Widespread issue**: Proceed to Phase 2B
845 | - **Service-specific**: Proceed to Phase 2C
846 |
847 | ## Phase 2A: Local Issue Investigation (2-5 minutes)
848 |
849 | ### Check Local Services
850 | ```
851 | Tool: analyze_network_connections
852 | Parameters: include_listening=true
853 | ```
854 | Verify critical services are running.
855 |
856 | ### Test Critical Ports
857 | ```
858 | Tool: test_port_connectivity
859 | Parameters: ports=[critical-service-ports]
860 | ```
861 | Ensure services are accessible.
862 |
863 | ## Phase 2B: Widespread Outage (2-5 minutes)
864 |
865 | ### Test Network Path
866 | ```
867 | Tool: test_network_connectivity
868 | Parameters: hosts=["gateway", "isp-dns", "8.8.8.8"]
869 | ```
870 | Identify where connectivity fails.
871 |
872 | ### Check Interfaces
873 | ```
874 | Tool: analyze_network_connections
875 | ```
876 | Verify network interfaces are up.
877 |
878 | ## Phase 2C: Service-Specific Issue (2-5 minutes)
879 |
880 | ### Test Service Connectivity
881 | ```
882 | Tool: test_port_connectivity
883 | Parameters: ports=[service-ports], host="service-host"
884 | ```
885 | Check specific service accessibility.
886 |
887 | ### Verify DNS
888 | ```
889 | Tool: test_network_connectivity
890 | Parameters: hosts=["service-hostname"]
891 | ```
892 | Ensure name resolution works.
893 |
894 | ## Phase 3: Detailed Analysis (5+ minutes)
895 | Based on Phase 2 results:
896 | - Run targeted diagnostics
897 | - Check logs and events
898 | - Test from multiple locations
899 | - Verify recent changes
900 |
901 | ## Emergency Response Actions
902 |
903 | ### Communication
904 | 1. Alert stakeholders immediately
905 | 2. Document timeline and impacts
906 | 3. Provide regular updates
907 | 4. Track resolution progress
908 |
909 | ### Temporary Measures
910 | - Implement workarounds
911 | - Redirect traffic if possible
912 | - Enable backup systems
913 | - Communicate alternatives
914 |
915 | ### Root Cause Analysis
916 | - Document all findings
917 | - Identify contributing factors
918 | - Plan preventive measures
919 | - Schedule post-mortem
920 |
921 | ## Critical Service Priority
922 | 1. **Network Core**: Routers, switches
923 | 2. **Security**: Firewalls, IDS/IPS
924 | 3. **External Access**: Internet gateway
925 | 4. **DNS Services**: Name resolution
926 | 5. **Business Critical**: Specific to organization
927 |
928 | ## Escalation Triggers
929 | - No progress after 15 minutes
930 | - Multiple services affected
931 | - Security incident suspected
932 | - Hardware failure indicated
933 | - Business impact increasing
934 |
935 | Remember: In emergencies, speed is critical but accuracy prevents making things worse. Follow the protocol, document everything, and escalate when needed.
936 | """
937 |
938 | @mcp.prompt(
939 | title="Network Performance Baseline",
940 | description="Guide for establishing network performance baselines"
941 | )
942 | async def performance_baseline_guide() -> str:
943 | """
944 | Guide for establishing and monitoring network performance baselines.
945 | """
946 | return """
947 | # 📊 Network Performance Baseline Guide
948 |
949 | ## Why Establish Baselines?
950 | - Detect performance degradation early
951 | - Identify abnormal behavior
952 | - Plan capacity upgrades
953 | - Troubleshoot more effectively
954 |
955 | ## Baseline Measurements
956 |
957 | ### 1. Latency Baseline
958 | ```
959 | Tool: test_network_connectivity
960 | Parameters: hosts=["local-router", "isp-gateway", "major-sites"], ping_count=20
961 | ```
962 |
963 | Measure and record:
964 | - Local network latency (should be <5ms)
965 | - ISP gateway latency (typically <20ms)
966 | - Internet latency (varies by distance)
967 | - Peak vs off-peak differences
968 |
969 | ### 2. Service Response Times
970 | ```
971 | Tool: test_port_connectivity
972 | Parameters: ports=[your-service-ports], timeout=10
973 | ```
974 |
975 | Track:
976 | - Connection establishment time
977 | - Service response time
978 | - Timeout frequency
979 | - Time-of-day variations
980 |
981 | ### 3. Connection Patterns
982 | ```
983 | Tool: analyze_network_connections
984 | ```
985 |
986 | Monitor:
987 | - Typical connection count
988 | - Common connection destinations
989 | - Port usage patterns
990 | - Protocol distribution
991 |
992 | ## Baseline Schedule
993 |
994 | ### Daily Measurements
995 | - Morning: Before business hours
996 | - Midday: Peak usage time
997 | - Evening: After business hours
998 | - Night: Minimum usage baseline
999 |
1000 | ### Weekly Analysis
1001 | - Compare daily patterns
1002 | - Identify usage trends
1003 | - Note any anomalies
1004 | - Update documentation
1005 |
1006 | ### Monthly Review
1007 | - Calculate averages
1008 | - Identify long-term trends
1009 | - Plan for capacity
1010 | - Update thresholds
1011 |
1012 | ## Key Metrics to Track
1013 |
1014 | ### Latency Metrics
1015 | - Minimum RTT
1016 | - Average RTT
1017 | - Maximum RTT
1018 | - Standard deviation
1019 | - Packet loss percentage
1020 |
1021 | ### Bandwidth Metrics
1022 | - Peak utilization
1023 | - Average utilization
1024 | - Time above 80%
1025 | - Growth rate
1026 |
1027 | ### Connection Metrics
1028 | - Peak connection count
1029 | - Average connections
1030 | - New connections/second
1031 | - Connection duration
1032 |
1033 | ## Setting Alert Thresholds
1034 |
1035 | ### Latency Alerts
1036 | - Warning: 150% of baseline
1037 | - Critical: 200% of baseline
1038 | - Sustained: Over 5 minutes
1039 |
1040 | ### Connection Alerts
1041 | - Warning: 150% of baseline
1042 | - Critical: 200% of baseline
1043 | - New services detected
1044 |
1045 | ### Availability Alerts
1046 | - Service down: Immediate
1047 | - Intermittent: >3 failures/hour
1048 | - Degraded: Response >2x baseline
1049 |
1050 | ## Using Baselines for Troubleshooting
1051 |
1052 | 1. **Compare Current to Baseline**
1053 | - Is latency higher than normal?
1054 | - Are connection patterns different?
1055 | - Are new services appearing?
1056 |
1057 | 2. **Identify Deviations**
1058 | - When did change occur?
1059 | - What else changed then?
1060 | - Is it following a pattern?
1061 |
1062 | 3. **Correlate with Events**
1063 | - System updates
1064 | - Configuration changes
1065 | - Usage patterns
1066 | - External factors
1067 |
1068 | ## Documentation Template
1069 |
1070 | ### Network Performance Baseline Record
1071 | ```
1072 | Date: [YYYY-MM-DD]
1073 | Time: [HH:MM]
1074 | Measured By: [Name]
1075 |
1076 | Latency Baseline:
1077 | - Local Network: [X]ms
1078 | - ISP Gateway: [X]ms
1079 | - Internet (avg): [X]ms
1080 |
1081 | Connection Baseline:
1082 | - Active Connections: [X]
1083 | - Listening Ports: [List]
1084 | - Peak Usage Time: [Time]
1085 |
1086 | Notes:
1087 | - Special conditions
1088 | - Anomalies observed
1089 | - Changes from previous
1090 | ```
1091 |
1092 | ## Best Practices
1093 |
1094 | 1. **Consistency**
1095 | - Same measurement points
1096 | - Same time periods
1097 | - Same tools/methods
1098 | - Regular schedule
1099 |
1100 | 2. **Documentation**
1101 | - Record all measurements
1102 | - Note environmental factors
1103 | - Track configuration changes
1104 | - Maintain history
1105 |
1106 | 3. **Review & Adjust**
1107 | - Update baselines quarterly
1108 | - Account for growth
1109 | - Adjust thresholds
1110 | - Plan for capacity
1111 |
1112 | A good baseline is your most valuable troubleshooting tool!
1113 | """
```