#
tokens: 31462/50000 4/69 files (page 4/4)
lines: on (toggle) GitHub
raw markdown copy reset
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 | """
```
Page 4/4FirstPrevNextLast