Metadata-Version: 2.4
Name: tshark-mcp
Version: 1.0.0
Summary: MCP server for using TShark to analyze network packets
Author: Neo
License-Expression: MIT
Project-URL: Homepage, https://github.com/ouonet/tshark-mcp
Project-URL: Repository, https://github.com/ouonet/tshark-mcp
Project-URL: Issues, https://github.com/ouonet/tshark-mcp/issues
Keywords: mcp,tshark,wireshark,pcap,network-analysis,ss7
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Internet
Classifier: Topic :: System :: Networking :: Monitoring
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp[cli]>=1.0.0
Requires-Dist: tomli>=2.0; python_version < "3.11"
Provides-Extra: windows-service
Requires-Dist: pywin32>=306; sys_platform == "win32" and extra == "windows-service"
Dynamic: license-file

# TShark MCP Server

An MCP (Model Context Protocol) server that exposes TShark as tools for AI-assisted network packet analysis. Supports PCAP analysis, live capture, TLS decryption, and telecom / SS7 signaling protocols.

## Requirements

- Python 3.10+
- [Wireshark / TShark](https://www.wireshark.org/download.html) installed on the system
- `mergecap` (bundled with Wireshark, required for `merge_pcap_files`)

## Installation

```bash
# Recommended — installs into an isolated env and puts the
# tshark-mcp / tshark-mcp-http commands on your PATH.
uv tool install tshark-mcp

# With Windows service support (Windows only).
uv tool install "tshark-mcp[windows-service]"

# Or into a project venv:
uv pip install tshark-mcp
```

**From a local source build** (in the project root):

```powershell
uv build
uv tool install --reinstall ".\dist\tshark_mcp-1.0.0-py3-none-any.whl[windows-service]"
```

**Verify the commands are on PATH:**

```powershell
Get-Command tshark-mcp, tshark-mcp-http, tshark-mcp-win-service | Select-Object Name, Source
```

**Uninstall the system installation** (after removing the Windows service if any — see below):

```powershell
uv tool uninstall tshark-mcp
```

After install you have three console scripts:

| Command | Default | What it does |
|---------|---------|--------------|
| `tshark-mcp` | stdio | Run via MCP client (Claude Code / VS Code) — client manages the process |
| `tshark-mcp-http` | HTTP on 127.0.0.1:8100 | Standalone HTTP server (WSL, remote, shared) |
| `tshark-mcp-win-service` | Windows service | Register as a Windows service (auto-start at boot) |

## Running modes

### STDIO — managed by your MCP client

The MCP client launches `tshark-mcp` as a child process. You don't run anything manually. Just configure the client.

**Claude Code** — `.mcp.json` (project) or `~/.claude.json` (user):

```json
{
  "mcpServers": {
    "tshark-mcp": {
      "type": "stdio",
      "command": "tshark-mcp"
    }
  }
}
```

Or via CLI:

```bash
claude mcp add tshark-mcp -- tshark-mcp
```

**VS Code** — `.vscode/mcp.json` (project) or your user `mcp.json`:

```json
{
  "servers": {
    "tshark-mcp": {
      "type": "stdio",
      "command": "tshark-mcp"
    }
  }
}
```

> If `tshark-mcp` is not on PATH (you installed via `uv pip install` instead of `uv tool install`), replace `command: "tshark-mcp"` with `command: "uv", args: ["tool", "run", "tshark-mcp"]`.

### HTTP — standalone server

You start the server yourself; clients connect to its URL. Stays running across client restarts and can be shared by multiple clients.

```bash
# Default 127.0.0.1:8100, endpoint /mcp
tshark-mcp-http

# Custom host/port
tshark-mcp-http --host 0.0.0.0 --port 9000

# Use a config file (see Configuration below)
tshark-mcp-http --config /path/to/config.toml
```

The endpoint URL is `http://<host>:<port>/mcp`.

**Claude Code**:

```json
{
  "mcpServers": {
    "tshark-mcp": {
      "type": "http",
      "url": "http://127.0.0.1:8100/mcp"
    }
  }
}
```

Or via CLI:

```bash
claude mcp add --transport http tshark-mcp http://127.0.0.1:8100/mcp
```

**VS Code**:

```json
{
  "servers": {
    "tshark-mcp": {
      "type": "http",
      "url": "http://127.0.0.1:8100/mcp"
    }
  }
}
```

> WSL: run the HTTP server inside WSL and point Windows-side Claude Code / VS Code at `http://127.0.0.1:8100/mcp` — WSL2 forwards `localhost` automatically.

### Windows service — auto-start at boot

Register `tshark-mcp-http` as a Windows service. Survives reboots, runs in the background under `LocalSystem`. All commands below need an **elevated PowerShell** (admin).

> pywin32 expects options BEFORE the verb (`install`/`start`/`stop`/`remove`). `tshark-mcp-win-service install --startup auto` is wrong — it must be `--startup auto install`.

**Install + start:**

```powershell
tshark-mcp-win-service --startup auto install
tshark-mcp-win-service --wait 15 start
```

**Verify it's running:**

```powershell
Get-Service TsharkMcp                                  # Status should be Running
Get-NetTCPConnection -LocalPort 8100 -State Listen     # 127.0.0.1:8100 listening
```

**Manage:**

```powershell
tshark-mcp-win-service stop
tshark-mcp-win-service restart        # reload after editing config.toml
```

**Uninstall the service only:**

```powershell
tshark-mcp-win-service stop
tshark-mcp-win-service remove
```

**Full cleanup (service + uv tool + leftover pywin32 DLLs):**

```powershell
# 1. Remove the service (admin PS)
tshark-mcp-win-service stop
tshark-mcp-win-service remove

# 2. Uninstall the uv tool venv (admin not required)
uv tool uninstall tshark-mcp

# 3. Optional — pywin32 leaves two DLLs in the uv-managed Python dir.
#    Only remove these if no other pywin32-using uv tool is installed.
$pyDir = "$env:APPDATA\uv\python\cpython-3.13-windows-x86_64-none"
Remove-Item -Force -ErrorAction SilentlyContinue `
    "$pyDir\pywintypes313.dll", "$pyDir\pythoncom313.dll"
```

Because Windows services don't receive command-line arguments, configure the service via:

- **Config file** at `%PROGRAMDATA%\tshark-mcp\config.toml` (recommended) — restart the service after editing
- **System-wide environment variables** (`TSHARK_MCP_HOST`, `TSHARK_MCP_PORT`, `TSHARK_PATH`, …)

Once running, point your MCP client at `http://127.0.0.1:8100/mcp` exactly as in the HTTP section above.

## Configuration

Configuration is layered — later sources override earlier ones:

```
built-in defaults  <  config file (TOML)  <  environment variables  <  CLI arguments
```

### Config file (TOML)

Search order (first match wins):

1. `--config <path>` CLI argument
2. `TSHARK_MCP_CONFIG` environment variable
3. **Windows**: `%APPDATA%\tshark-mcp\config.toml`, then `%PROGRAMDATA%\tshark-mcp\config.toml`
4. **Linux/macOS**: `$XDG_CONFIG_HOME/tshark-mcp/config.toml` (or `~/.config/tshark-mcp/config.toml`), then `/etc/tshark-mcp/config.toml`

Full schema (also see [config.example.toml](config.example.toml)):

```toml
[server]
# stdio | http | streamable-http | sse
# "http" is an alias for "streamable-http" (the current MCP HTTP transport).
# "sse" is the deprecated MCP HTTP+SSE transport; kept for legacy clients.
transport = "http"
host = "127.0.0.1"
port = 8100

# Optional endpoint paths (default to FastMCP defaults)
# mount_path = "/"
# streamable_http_path = "/mcp"
# sse_path = "/sse"
# message_path = "/messages"

[tshark]
# Override tshark binary location (otherwise auto-detected).
# path = "C:\\Program Files\\Wireshark\\tshark.exe"
```

### Environment variables

| Variable | Maps to |
|----------|---------|
| `TSHARK_MCP_CONFIG` | Path to TOML config file |
| `TSHARK_MCP_TRANSPORT` | `[server] transport` |
| `TSHARK_MCP_HOST` | `[server] host` |
| `TSHARK_MCP_PORT` | `[server] port` |
| `TSHARK_MCP_MOUNT_PATH` | `[server] mount_path` |
| `TSHARK_MCP_STREAMABLE_HTTP_PATH` | `[server] streamable_http_path` |
| `TSHARK_MCP_SSE_PATH` | `[server] sse_path` |
| `TSHARK_MCP_MESSAGE_PATH` | `[server] message_path` |
| `TSHARK_PATH` | `[tshark] path` |

### CLI arguments

`tshark-mcp` and `tshark-mcp-http` accept the same flags:

```
--config PATH                  TOML config file (overrides search paths)
--transport {stdio,http,streamable-http,sse}
--host HOST
--port PORT
--mount-path PATH
--streamable-http-path PATH    default '/mcp'
--sse-path PATH
--message-path PATH
--tshark-path PATH             tshark binary (overrides TSHARK_PATH env)
```

The two scripts differ only in their starting defaults — `tshark-mcp` starts from stdio defaults, `tshark-mcp-http` starts from `transport=http, host=127.0.0.1, port=8100`. Either way, file → env → CLI all layer on top.

### TShark binary auto-detection

If `[tshark] path`, `TSHARK_PATH`, and `--tshark-path` are all unset, the server probes:

- **Windows**: `C:\Program Files\Wireshark\tshark.exe`, `C:\Program Files (x86)\Wireshark\tshark.exe`
- **macOS**: `/usr/local/bin/tshark`, `/opt/homebrew/bin/tshark`
- **Linux**: `/usr/bin/tshark`, `/usr/sbin/tshark`, `/usr/local/bin/tshark`

Then falls back to PATH lookup.

---

## Tools (25 total)

### Basic Analysis

| Tool | Key Parameters | Description |
|------|---------------|-------------|
| `analyze_pcap_file` | `display_filter`, `keylog_file`, `max_packets` | Packet summaries with optional display filter and TLS decryption |
| `get_packet_statistics` | — | Protocol hierarchy statistics (`io,phs`) — shows all protocol layers present |
| `extract_packet_details` | `packet_number` | Full verbose detail for a specific packet (1-based index) |
| `extract_fields` | `fields`, `display_filter`, `keylog_file` | Extract any tshark field as tab-separated values |
| `export_to_json` | `display_filter`, `keylog_file`, `max_packets` | Export packets as JSON for structured analysis |
| `run_tshark_command` | `command_args` | Run any raw tshark command |

### Traffic Aggregation & Statistics

| Tool | Key Parameters | Description |
|------|---------------|-------------|
| `get_conversations` | `protocol` | Conversation statistics — protocol: `eth` / `ip` / `tcp` / `udp` / `sctp` |
| `get_flow_matrix` | `display_filter`, `top_n` | Host-pair communication matrix (ip.src × ip.dst), ranked by bytes |
| `get_traffic_timeseries` | `interval_seconds`, `display_filter` | Packets and bytes per time bucket — identifies bursts and periodic patterns |
| `aggregate_flows` | `group_by`, `display_filter`, `top_n` | Group packets by any field combination (e.g. `ip.src,tcp.dstport`) |

### Protocol-Specific Analysis

| Tool | Key Parameters | Description |
|------|---------------|-------------|
| `analyze_dns` | `display_filter`, `top_n` | DNS query patterns, NXDOMAIN detection, response time statistics |
| `get_tcp_performance` | `display_filter` | RTT, retransmissions, window size — diagnose network quality issues |
| `follow_stream` | `protocol`, `stream_index`, `keylog_file` | Reconstruct a TCP / UDP / **SCTP** stream as ASCII text |

### Telecom / SS7 Signaling

These tools handle the telecom core network signaling stack:
**SCTP → M3UA → SCCP → TCAP → MAP**

| Tool | Key Parameters | Description |
|------|---------------|-------------|
| `reconstruct_tcap_dialogue` | `display_filter`, `max_dialogues` | Group TCAP messages (Begin/Continue/End/Abort) by transaction ID (OTID/DTID) |
| `analyze_map_operations` | `display_filter`, `top_n` | MAP operation frequency table + per-IMSI activity summary |

### TLS Decryption

> Requires a [TLS key log file](#tls-decryption-setup) generated by the target application.

| Tool | Description |
|------|-------------|
| `follow_tls_stream` | Reconstruct a decrypted TLS stream as plaintext from a PCAP + key log file |
| `capture_and_decrypt` | Capture live traffic and immediately show decrypted TLS content |
| `tshark_reading_manual` | **Read this first** — full TLS decryption workflow including debugger-based key extraction |

### Live Capture

| Tool | Key Parameters | Description |
|------|---------------|-------------|
| `list_interfaces` | — | List available network interfaces for live capture |
| `capture_live` | `interface`, `packet_count`, `duration`, `display_filter` | Capture live packets (max 500 packets / 60 s) |
| `capture_process` | `pid`, `interface`, `output_pcap`, `duration`, `keylog_file` | Capture traffic for a specific process by PID |

### File Operations

| Tool | Key Parameters | Description |
|------|---------------|-------------|
| `filter_and_save` | `display_filter` | Filter packets from a PCAP and save to a new PCAP file |
| `export_objects` | `protocol`, `output_dir` | Extract files transferred over HTTP / SMB / TFTP / IMF / DICOM |
| `merge_pcap_files` | `input_files`, `output_file`, `display_filter` | Merge multiple PCAPs in timestamp order (uses `mergecap`) |

### Process Management

| Tool | Description |
|------|-------------|
| `list_processes` | List running processes with PIDs (filter by name) |

---

## Examples

### General PCAP Analysis

```python
# Protocol hierarchy — confirm what layers are in the capture
get_packet_statistics("/captures/traffic.pcap")

# First 100 packets, HTTP only
analyze_pcap_file("/captures/traffic.pcap", display_filter="http")

# Extract source IPs, methods, and URIs from HTTP requests
extract_fields(
    file_path="/captures/traffic.pcap",
    fields="ip.src,http.request.method,http.request.uri",
    display_filter="http.request"
)

# Full detail for packet 42
extract_packet_details("/captures/traffic.pcap", packet_number=42)
```

### Traffic Aggregation

```python
# Which hosts talk to each other most? (top 20 by bytes)
get_flow_matrix("/captures/traffic.pcap")

# Traffic volume over time — 5-second buckets
get_traffic_timeseries("/captures/traffic.pcap", interval_seconds=5.0)

# TCP traffic only, 1-second buckets
get_traffic_timeseries("/captures/traffic.pcap", interval_seconds=1.0, display_filter="tcp")

# Per-service breakdown: which src IP hits which dst port most?
aggregate_flows(
    file_path="/captures/traffic.pcap",
    group_by="ip.src,ip.dst,tcp.dstport",
    display_filter="tcp"
)

# SCTP conversation statistics
get_conversations("/captures/ss7.pcap", protocol="sctp")
```

### DNS Analysis

```python
# Top queried domains, NXDOMAIN failures, response times
analyze_dns("/captures/traffic.pcap")

# DNS from a specific client only
analyze_dns("/captures/traffic.pcap", display_filter="ip.src == 192.168.1.10")
```

### TCP Performance Diagnosis

```python
# RTT, retransmission rate, window size — is the network healthy?
get_tcp_performance("/captures/traffic.pcap")

# Performance for a specific server
get_tcp_performance("/captures/traffic.pcap", display_filter="ip.addr == 10.0.0.1")
```

### Stream Reconstruction

```python
# Follow the first TCP stream
follow_stream("/captures/traffic.pcap", protocol="tcp", stream_index=0)

# Follow an SCTP stream
follow_stream("/captures/ss7.pcap", protocol="sctp", stream_index=0)

# Follow a TELNET session (TELNET runs over TCP port 23)
follow_stream("/captures/traffic.pcap", protocol="tcp", stream_index=0)
```

### Telecom / SS7 Signaling Analysis

The typical protocol stack is: **SCTP → M3UA → SCCP → TCAP → MAP**

```python
# Step 1 — confirm SS7 layers are present
get_packet_statistics("/captures/ss7.pcap")
# Expected output includes: sctp, m3ua, mtp3, sccp, tcap, gsm_map

# Step 2 — reconstruct TCAP dialogues (Begin→Continue→End chains)
reconstruct_tcap_dialogue("/captures/ss7.pcap")

# Step 3 — MAP operation frequency + IMSI tracking
analyze_map_operations("/captures/ss7.pcap")

# Step 4 — raw MAP field extraction
extract_fields(
    file_path="/captures/ss7.pcap",
    fields="gsm_map.opr.code,gsm_map.imsi,gsm_map.msisdn.digits",
    display_filter="gsm_map"
)

# SCCP routing analysis — who calls whom?
aggregate_flows(
    file_path="/captures/ss7.pcap",
    group_by="sccp.calling_party,sccp.called_party",
    display_filter="sccp"
)

# Filter to a specific TCAP dialogue by OTID
extract_fields(
    file_path="/captures/ss7.pcap",
    fields="frame.time_relative,tcap.MessageType,tcap.otid,tcap.dtid,gsm_map.opr.code",
    display_filter="tcap.otid == aabbccdd"
)
```

### File Extraction (Forensics)

```python
# Extract files transferred over HTTP in a capture
export_objects(
    file_path="/captures/traffic.pcap",
    protocol="http",
    output_dir="/tmp/extracted/"
)

# Extract SMB file transfers
export_objects(
    file_path="/captures/traffic.pcap",
    protocol="smb",
    output_dir="/tmp/smb_files/"
)
```

### Multi-PCAP Correlation

```python
# Merge two captures from different taps, analyze combined
merge_pcap_files(
    input_files="/captures/tap1.pcap,/captures/tap2.pcap",
    output_file="/captures/merged.pcap"
)

# With a display filter on the merged result
merge_pcap_files(
    input_files="/captures/tap1.pcap,/captures/tap2.pcap",
    output_file="/captures/merged.pcap",
    display_filter="tcp"
)
```

### TLS Decryption

```python
# Decrypt and reconstruct HTTPS stream
follow_tls_stream(
    file_path="/captures/traffic.pcap",
    keylog_file="C:/captures/keys.log",
    stream_index=0
)

# Extract HTTP fields from decrypted traffic
extract_fields(
    file_path="/captures/traffic.pcap",
    fields="ip.src,http.request.method,http.request.uri",
    display_filter="http.request",
    keylog_file="C:/captures/keys.log"
)

# Live capture + real-time TLS decryption
capture_and_decrypt(
    interface=r"\Device\NPF_{...}",
    keylog_file="C:/captures/keys.log",
    output_pcap="C:/captures/session.pcap",
    duration=30
)
```

### Process-Specific Capture

```python
# Find process PID
list_processes("chrome")
# → chrome.exe  PID 4812

# Capture traffic for that process
capture_process(
    pid=4812,
    interface=r"\Device\NPF_{...}",   # from list_interfaces()
    output_pcap="C:/captures/chrome.pcap",
    duration=30
)

# Capture + decrypt TLS in one step
capture_process(
    pid=4812,
    interface=r"\Device\NPF_{...}",
    output_pcap="C:/captures/chrome.pcap",
    duration=30,
    keylog_file="C:/captures/keys.log"   # set SSLKEYLOGFILE before launching Chrome
)
```

---

## Protocol Support Reference

| Protocol | Filter | Relevant Fields | Best Tool |
|----------|--------|-----------------|-----------|
| TCP | `tcp` | `tcp.srcport`, `tcp.dstport`, `tcp.stream` | `follow_stream`, `get_tcp_performance` |
| UDP | `udp` | `udp.srcport`, `udp.dstport` | `follow_stream`, `get_conversations` |
| **SCTP** | `sctp` | `sctp.srcport`, `sctp.dstport`, `sctp.chunk_type` | `get_conversations`, `follow_stream` |
| HTTP | `http` | `http.request.uri`, `http.response.code` | `extract_fields`, `export_objects` |
| TLS/HTTPS | `tls` | `tls.record.content_type` | `follow_tls_stream`, `capture_and_decrypt` |
| DNS | `dns` | `dns.qry.name`, `dns.flags.rcode`, `dns.time` | `analyze_dns` |
| TELNET | `telnet` | (follow TCP stream) | `follow_stream` (protocol=tcp) |
| **M3UA** | `m3ua` | `m3ua.protocol_data_opc`, `m3ua.protocol_data_dpc` | `extract_fields`, `aggregate_flows` |
| **SCCP** | `sccp` | `sccp.calling_party`, `sccp.called_party`, `sccp.ssn` | `aggregate_flows`, `extract_fields` |
| **TCAP** | `tcap` | `tcap.otid`, `tcap.dtid`, `tcap.MessageType` | `reconstruct_tcap_dialogue` |
| **MAP** | `gsm_map` | `gsm_map.opr.code`, `gsm_map.imsi`, `gsm_map.msisdn.digits` | `analyze_map_operations` |

---

## TLS Decryption Setup

TShark can decrypt TLS traffic when given the session keys written by the application. Set the `SSLKEYLOGFILE` environment variable **before** launching the target application:

```bash
# Windows
set SSLKEYLOGFILE=C:\captures\keys.log
start chrome

# Linux / macOS
export SSLKEYLOGFILE=/tmp/keys.log
google-chrome &
```

Supported runtimes: Chrome, Edge, Firefox, curl, Python (requests / httpx / aiohttp), Go `crypto/tls` (with `SSLKEYLOGFILE` patch), Node.js (`--tls-keylog`).

For applications that do **not** support `SSLKEYLOGFILE` (compiled binaries, custom TLS stacks), keys must be extracted from process memory using a debugger. Call `tshark_reading_manual` for the complete step-by-step workflow including x64dbg-based key extraction.

---

## Process-Specific Capture — How It Works

1. **`list_processes`** — find the PID of the target process.
2. **`capture_process`** — snapshots the process's open connections at capture start, builds a BPF filter from its local ports, then runs a timed capture saving to a PCAP file.

Because the filter is derived at capture start, connections opened later still get captured if they share a port already in the filter. For long-running captures or applications with many short-lived connections, re-run `capture_process` as needed, or use `capture_live` without a filter and post-filter with `filter_and_save`.

| Platform | Tool used internally | Notes |
|----------|---------------------|-------|
| Windows  | `netstat -ano` (built-in) | No extra installation needed |
| macOS    | `lsof` (built-in) | No extra installation needed |
| Linux    | `ss` (iproute2) | Usually pre-installed; `apt install iproute2` if missing |

---

## Development

```bash
git clone <repository-url>
cd tshark-mcp
uv sync

# Run during development
uv run server.py                                     # stdio
uv run server.py --transport http --port 8100        # HTTP
uv run tshark-mcp-http                               # HTTP (entry-point alias)

# Tests (no TShark installation required — subprocess is mocked)
uv run python -m pytest test_server.py -v

# Build a local wheel and install it as a uv tool (Windows service ready)
uv build
uv tool install --reinstall ".\dist\tshark_mcp-1.0.0-py3-none-any.whl[windows-service]"

# Clean build artifacts
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue dist, build, *.egg-info
```

## Project Policies

- License: see [LICENSE](LICENSE)
- Contributing: see [CONTRIBUTING.md](CONTRIBUTING.md)
- Code of conduct: see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
- Security: see [SECURITY.md](SECURITY.md)

## Release

Automated via [.github/workflows/release.yml](.github/workflows/release.yml). Pushing a `v*` tag builds the wheel and publishes to PyPI using the `PYPI_API_TOKEN` repo secret:

```bash
git tag v1.2.3
git push origin v1.2.3
```

- Pre-release check: `uv run python scripts/release_check.py`
- Full release process + one-time `PYPI_API_TOKEN` setup: see [RELEASE.md](RELEASE.md)
