Skip to main content
Glama
MitchellGulledge3

Cloudflare Sentinel Custom MCP Tools

README.md
# Cloudflare Sentinel Custom MCP Tools

Call-ready custom MCP tool collection for Cloudflare CCF data in Microsoft Sentinel.

This repository is for Cloudflare users, ISV developers, partner engineers, or joint customer teams that want an agent surface such as Claude Code, GitHub Copilot in VS Code, Copilot Studio, Foundry, Security Copilot, or a product-owned agent to call focused Cloudflare investigation tools over Sentinel data.

The repo includes both:

1. **Production MCP tools** over the official Cloudflare CCF table `CloudflareV2_CL`.
2. **A LogSeeder schema** generated from the official Cloudflare CCF table so you can seed sample Cloudflare-shaped rows before a call.

## Grounding

Official schema (the **Cloudflare CCF** solution, which provisions `CloudflareV2_CL`):

```text
Azure/Azure-Sentinel/Solutions/Cloudflare CCF/Data Connectors/CloudflareLog_CCF/CloudflareLog_Table.json
```

Official analytic rules used as design inspiration:

| Analytic rule | Tool inspired |
| --- | --- |
| `CloudflareBadClientIp` | `Cloudflare_Bad_Client_IP_Reputation` |
| `CloudflareEmptyUA`, `CloudflareMultipleUAs` | `Cloudflare_Bot_UserAgent_Anomalies` |
| `CloudflareMultipleErrorsSource` | `Cloudflare_Origin_Error_Burst_Detection` |
| `CloudflareUnexpectedCountry` | `Cloudflare_Unexpected_Geo_Access` |
| `CloudflareUnexpectedPost`, `CloudflareUnexpectedRequest`, `CloudflareUnexpectedUrl` | `Cloudflare_Suspicious_Request_Patterns` |
| `CloudflareWafThreatAllowed` | `Cloudflare_WAF_Allowed_Threats` |
| `CloudflareXSSProbingPattern` | `Cloudflare_XSS_Probing_Patterns` |

Important: the analytic rules use legacy parser column names like `SrcIpAddr` and `HttpRequestMethod`. These tools are re-authored against the real CCF table columns such as `ClientIP`, `ClientRequestMethod`, `ClientRequestUserAgent`, `ClientCountry`, `EdgeResponseStatus`, `SecurityAction`, and WAF attack score fields.

## What this publishes

`scripts/publish-mcp-tools.py` calls the Sentinel Platform Services authoring API and publishes each file in `mcp-tools/*.kql` as a Kqs custom MCP tool under one collection:

```text
Cloudflare-Sentinel-MCP-Tools
```

Runtime endpoint:

```text
https://sentinel.microsoft.com/mcp/custom/Cloudflare-Sentinel-MCP-Tools/
```

## Tools

| Tool | Main table | What it answers |
| --- | --- | --- |
| `Cloudflare_Zone_Security_Posture` | `CloudflareV2_CL` | Which zones have the most security pressure: allowed threats, bad IP reputation, bots, errors, suspicious countries, and bytes? |
| `Cloudflare_Bad_Client_IP_Reputation` | `CloudflareV2_CL` | Which client IPs have risky Cloudflare reputation classes such as `badHost`, `securityScanner`, `scan`, `tor`, or `unknown`? |
| `Cloudflare_Bot_UserAgent_Anomalies` | `CloudflareV2_CL` | Which clients show empty user agents, many user agents, or low BotScore automation? |
| `Cloudflare_Origin_Error_Burst_Detection` | `CloudflareV2_CL` | Which client IPs are generating bursts of edge/origin errors? |
| `Cloudflare_Unexpected_Geo_Access` | `CloudflareV2_CL` | Which zones are seeing access from watchlist countries like CN, HK, RU, and IR? |
| `Cloudflare_Suspicious_Request_Patterns` | `CloudflareV2_CL` | Which requests look like admin probing, SSRF/private-IP URLs, or suspicious successful uploads? |
| `Cloudflare_WAF_Allowed_Threats` | `CloudflareV2_CL` | Which WAF/security findings were allowed, especially where WAF attack scores indicate likely malicious traffic? |
| `Cloudflare_XSS_Probing_Patterns` | `CloudflareV2_CL` | Which clients are probing XSS payloads or have low WAF XSS attack scores? |
| `Cloudflare_Client_IP_Investigation` | `CloudflareV2_CL` | For a supplied `ClientIP`, summarize zones, methods, URLs, user agents, statuses, security actions, BotScore, WAF scores, and Ray IDs. |

For detailed usage, input arguments, KQL strategy, and expected output shape, see [`docs/tool-reference.md`](docs/tool-reference.md).

## Prerequisites

1. A Microsoft Sentinel workspace with Sentinel Platform Services / data lake enabled.
2. Production Cloudflare CCF data already flowing into `CloudflareV2_CL`, or use LogSeeder to seed sample rows before a call.
3. Azure CLI authenticated to the tenant that owns the Sentinel workspace.
4. Permission to author custom MCP collections in Sentinel Platform Services.
5. Python 3.9+.

This is an alpha/private-preview style surface. The publisher and runtime both use the Sentinel Platform Services resource ID `4500ebfb-89b6-4b14-a480-7f749797bfcd`. In practice:

- The tenant must have Microsoft Sentinel data lake and the required Microsoft Defender / Sentinel Platform Services licensing enabled.
- To **create, update, or delete** custom tools, use an identity with Security Operator, Security Administrator, or Global Administrator privileges for the Microsoft Security experience plus read access to the target Sentinel workspace.
- To **list or invoke** the tools, use an identity with Security Reader or Global Reader privileges plus read access to the target Sentinel workspace.
- If API publishing is unavailable in your tenant, create the same KQL as custom tools through the Microsoft Defender portal / Advanced hunting "Save as tool" flow, then use the same runtime endpoint pattern.

## Seed sample Cloudflare data with LogSeeder

The generated schema is in:

```text
logseeder/CloudflareV2_CL.json
```

Copy it to your LogSeeder repo and ingest:

```bash
cp logseeder/CloudflareV2_CL.json ~/sentinel-logseeder/schemas/
cd ~/sentinel-logseeder

pwsh -NoLogo -NoProfile -ExecutionPolicy Bypass \
  -File ./scripts/Invoke-SampleDataIngestion.ps1 \
  -TableName CloudflareV2_CL \
  -Schema ./schemas/CloudflareV2_CL.json \
  -RowCount 3000 \
  -TimeWindowMinutes 1440 \
  -Deploy -Ingest
```

Verify:

```kql
CloudflareV2_CL
| where TimeGenerated > ago(24h)
| summarize Rows=count(), LastSeen=max(TimeGenerated)
```

## Publish the tools through the API

```bash
git clone https://github.com/MitchellGulledge3/cloudflare-sentinel-mcp-tools.git
cd cloudflare-sentinel-mcp-tools

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

python3 scripts/publish-mcp-tools.py \
  --collection Cloudflare-Sentinel-MCP-Tools \
  --workspace-id "<workspace-customer-id>"
```

Use `--dry-run` first if you want to inspect the API payloads without writing anything.

## Quick start for Claude Code

```bash
TOKEN=$(az account get-access-token \
  --resource 4500ebfb-89b6-4b14-a480-7f749797bfcd \
  --query accessToken -o tsv)

python3 scripts/write-claude-mcp-config.py \
  --collection Cloudflare-Sentinel-MCP-Tools \
  --bearer-token "$TOKEN"
```

Suggested Claude Code prompt:

```text
Read this repo. Use the Cloudflare-Sentinel-MCP-Tools MCP server from .mcp.json.
List the available Cloudflare tools, then call Cloudflare_Zone_Security_Posture for workspace <workspace-customer-id>.
After that, call Cloudflare_Bad_Client_IP_Reputation and Cloudflare_WAF_Allowed_Threats and summarize the highest priority findings.
```

## Run locally from the terminal

```bash
cp .env.example .env
# edit .env
python3 run_tools.py --prompt "Summarize Cloudflare zone security posture" --show-raw
python3 run_tools.py --prompt "Show Cloudflare WAF allowed threats" --show-raw
python3 run_tools.py --prompt "Investigate Cloudflare client IP 203.0.113.42" --show-raw
```

## Run locally from VS Code / GitHub Copilot

```bash
TOKEN=$(az account get-access-token \
  --resource 4500ebfb-89b6-4b14-a480-7f749797bfcd \
  --query accessToken -o tsv)

python3 scripts/write-vscode-mcp-config.py \
  --collection Cloudflare-Sentinel-MCP-Tools \
  --bearer-token "$TOKEN"
```

Open `.vscode/mcp.json`, start the MCP server, and ask Copilot Chat to call the Cloudflare tools.

## Configure any MCP-capable agent

Register this remote MCP endpoint in any MCP-capable agent runtime that supports authenticated HTTP MCP servers:

```text
https://sentinel.microsoft.com/mcp/custom/Cloudflare-Sentinel-MCP-Tools/
```

At runtime, every tool requires:

```json
{
  "workspaceId": "<workspace-customer-id>"
}
```

`Cloudflare_Client_IP_Investigation` also requires:

```json
{
  "ClientIP": "203.0.113.42"
}
```

`workspaceId` is the workspace customer ID the Sentinel custom MCP runtime uses to bind the KQL execution target. The KQL text itself does not call `workspace("<id>")`; target selection is handled by the platform tool runtime.

## Repository map

| Path | Purpose |
| --- | --- |
| `mcp-tools/*.kql` | Production-table KQL definitions published as custom MCP tools |
| `logseeder/CloudflareV2_CL.json` | LogSeeder schema generated from the official Cloudflare CCF table |
| `scripts/publish-mcp-tools.py` | API publisher for the Sentinel custom MCP collection |
| `scripts/write-claude-mcp-config.py` | Writes a gitignored Claude Code `.mcp.json` config |
| `scripts/write-vscode-mcp-config.py` | Writes a gitignored VS Code MCP config |
| `run_tools.py` | Local runner that selects a tool from a natural-language prompt and calls the custom MCP endpoint |
| `docs/tool-reference.md` | Deep explanation of every tool and analytic-rule lineage |
| `docs/sample-output.md` | Captured/sanitized sample output from live runs |
| `docs/runbook.md` | Call-ready runbook |

## Notes for alpha users

- The tools are read-only KQL tools.
- All tools query the official Cloudflare CCF table `CloudflareV2_CL` directly (not a parser alias).
- `FirstSeen`/`LastSeen` in output are computed from `TimeGenerated`; time filtering is always done on `TimeGenerated`.
- If a workspace has no Cloudflare rows, the tools execute but return zero-row or zero-count output.