crowdsec-local-mcp 0.2.0__tar.gz → 0.8.0.post1.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crowdsec_local_mcp-0.8.0.post1.dev0/.github/workflows/build-mcpb.yml +46 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/.github/workflows/build.yml +45 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/.github/workflows/lint.yaml +43 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/.github/workflows/publish.yml +2 -2
- crowdsec_local_mcp-0.8.0.post1.dev0/.mcpbignore +10 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/.python-version +1 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/PKG-INFO +114 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/README.md +91 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/crowdsec_logo.png +0 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/manifest.json +134 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/pyproject.toml +132 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/__init__.py +10 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/__main__.py +1 -3
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/_version.py +1 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/compose/scenario-test/.gitignore +1 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/compose/scenario-test/docker-compose.yml +19 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/docker-compose.yml +5 -6
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/nginx/Dockerfile +8 -2
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/compose/waf-test/rules/.gitkeep +0 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/mcp_core.py +245 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/mcp_scenarios.py +936 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/mcp_waf.py +1542 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-expr-helpers.txt +514 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-scenario-deploy.txt +76 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/prompts/prompt-scenario.txt +26 -2
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-waf-pr.txt +10 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-waf-tests.txt +113 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-waf-top-level.txt +33 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/prompts/prompt-waf.txt +0 -26
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/setup_cli.py +98 -29
- crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp.egg-info/PKG-INFO +114 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp.egg-info/SOURCES.txt +19 -1
- crowdsec_local_mcp-0.8.0.post1.dev0/tests/__init__.py +0 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/tests/test_mcp_waf_lint.py +81 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/tools/__init__.py +1 -0
- crowdsec_local_mcp-0.8.0.post1.dev0/tools/update_manifest_version.py +20 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/uv.lock +431 -264
- crowdsec_local_mcp-0.2.0/.github/workflows/build.yml +0 -21
- crowdsec_local_mcp-0.2.0/PKG-INFO +0 -74
- crowdsec_local_mcp-0.2.0/README.md +0 -61
- crowdsec_local_mcp-0.2.0/pyproject.toml +0 -34
- crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/__init__.py +0 -5
- crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/mcp_core.py +0 -151
- crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/mcp_scenarios.py +0 -380
- crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/mcp_waf.py +0 -1170
- crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/prompts/prompt-scenario-deploy.txt +0 -27
- crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp.egg-info/PKG-INFO +0 -74
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/.gitignore +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/LICENSE +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/MANIFEST.in +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/setup.cfg +0 -0
- {crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/compose/waf-test/rules → crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/compose/scenario-test/scenarios}/.gitkeep +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/.gitignore +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/crowdsec/acquis.d/appsec.yaml +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/crowdsec/appsec-configs/mcp-appsec.yaml.template +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/crowdsec/init-bouncer.sh +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/nginx/crowdsec/crowdsec-openresty-bouncer.conf +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/nginx/nginx.conf +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/nginx/site-enabled/default-site.conf +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/rules/base-config.yaml +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/prompts/prompt-scenario-examples.txt +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/prompts/prompt-waf-deploy.txt +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/prompts/prompt-waf-examples.txt +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/yaml-schemas/appsec_rules_schema.yaml +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/yaml-schemas/scenario_schema.yaml +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp.egg-info/dependency_links.txt +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp.egg-info/entry_points.txt +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp.egg-info/requires.txt +0 -0
- {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Build MCPB Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build-mcpb:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout repository
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Setup Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.12'
|
|
21
|
+
|
|
22
|
+
- name: Sync manifest version
|
|
23
|
+
run: |
|
|
24
|
+
python -m pip install --upgrade pip setuptools_scm
|
|
25
|
+
python tools/update_manifest_version.py
|
|
26
|
+
|
|
27
|
+
- name: Setup Node.js
|
|
28
|
+
uses: actions/setup-node@v4
|
|
29
|
+
with:
|
|
30
|
+
node-version: '20'
|
|
31
|
+
|
|
32
|
+
- name: Build MCPB package
|
|
33
|
+
run: |
|
|
34
|
+
mkdir -p dist
|
|
35
|
+
npx --yes @anthropic-ai/mcpb@v1.1.1 pack
|
|
36
|
+
|
|
37
|
+
- name: Upload package artifact
|
|
38
|
+
uses: actions/upload-artifact@v4
|
|
39
|
+
with:
|
|
40
|
+
name: crowdsec-local-mcp.mcpb
|
|
41
|
+
path: crowdsec-local-mcp.mcpb
|
|
42
|
+
|
|
43
|
+
- name: Attach package to release
|
|
44
|
+
uses: softprops/action-gh-release@v2
|
|
45
|
+
with:
|
|
46
|
+
files: crowdsec-local-mcp.mcpb
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: "Build"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- master
|
|
8
|
+
pull_request:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout
|
|
15
|
+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0
|
|
18
|
+
- name: Install Python 3.13
|
|
19
|
+
run: uv python install 3.13
|
|
20
|
+
- name: Build package
|
|
21
|
+
run: uv build
|
|
22
|
+
|
|
23
|
+
tests:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
28
|
+
|
|
29
|
+
- name: Install uv
|
|
30
|
+
uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0
|
|
31
|
+
with:
|
|
32
|
+
version: 0.9.3
|
|
33
|
+
enable-cache: true
|
|
34
|
+
cache-dependency-glob: "uv.lock"
|
|
35
|
+
|
|
36
|
+
- name: Set up Python
|
|
37
|
+
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
|
38
|
+
with:
|
|
39
|
+
python-version-file: ".python-version"
|
|
40
|
+
|
|
41
|
+
- name: Install dependencies
|
|
42
|
+
run: uv sync --dev
|
|
43
|
+
|
|
44
|
+
- name: Run pytest
|
|
45
|
+
run: uv run pytest
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Lint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
tests:
|
|
11
|
+
name: ruff + basedpyright
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0
|
|
20
|
+
with:
|
|
21
|
+
version: 0.9.3
|
|
22
|
+
enable-cache: true
|
|
23
|
+
cache-dependency-glob: "uv.lock"
|
|
24
|
+
|
|
25
|
+
- name: "Set up Python"
|
|
26
|
+
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
|
27
|
+
with:
|
|
28
|
+
python-version-file: ".python-version"
|
|
29
|
+
|
|
30
|
+
- name: Install the project
|
|
31
|
+
run: uv sync --all-extras --dev
|
|
32
|
+
|
|
33
|
+
- name: Lint
|
|
34
|
+
run: |
|
|
35
|
+
uv run ruff check || ruff_status=$? || ruff_status=0
|
|
36
|
+
uv run basedpyright || pyright_status=$? || pyright_status=0
|
|
37
|
+
|
|
38
|
+
if [ "${ruff_status:-0}" -ne 0 ] || [ "${pyright_status:-0}" -ne 0 ]; then
|
|
39
|
+
echo "❌ Linting failed:"
|
|
40
|
+
echo " Ruff exit code: ${ruff_status:-0}"
|
|
41
|
+
echo " BasedPyright exit code: ${pyright_status:-0}"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
{crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/.github/workflows/publish.yml
RENAMED
|
@@ -15,9 +15,9 @@ jobs:
|
|
|
15
15
|
contents: read
|
|
16
16
|
steps:
|
|
17
17
|
- name: Checkout
|
|
18
|
-
uses: actions/checkout@v5
|
|
18
|
+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
|
19
19
|
- name: Install uv
|
|
20
|
-
uses: astral-sh/setup-uv@
|
|
20
|
+
uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0
|
|
21
21
|
- name: Install Python 3.13
|
|
22
22
|
run: uv python install 3.13
|
|
23
23
|
- name: Build
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: crowdsec-local-mcp
|
|
3
|
+
Version: 0.8.0.post1.dev0
|
|
4
|
+
Summary: An MCP exposing prompts and tools to help users write WAF rules, scenarios etc.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Classifier: Development Status :: 4 - Beta
|
|
7
|
+
Classifier: Intended Audience :: Developers
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Topic :: Security
|
|
13
|
+
Classifier: Topic :: System :: Systems Administration
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: jsonschema>=4.25.1
|
|
19
|
+
Requires-Dist: mcp>=1.15.0
|
|
20
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
21
|
+
Requires-Dist: requests>=2.32.5
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<img src="https://github.com/crowdsecurity/crowdsec-docs/blob/main/crowdsec-docs/static/img/crowdsec_logo.png" alt="CrowdSec" title="CrowdSec" width="400" height="260"/>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
**Life is too short to write YAML, just ask nicely!**
|
|
30
|
+
|
|
31
|
+
> A Model Context Protocol (MCP) server to generate, validate, and deploy CrowdSec WAF rules & Scenarios.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
### WAF Rules Features
|
|
37
|
+
|
|
38
|
+
- **WAF Rule Generation**: Generate CrowdSec WAF rules from user input or a CVE reference
|
|
39
|
+
- **Validation**: Validate syntaxical correctness of WAF rules
|
|
40
|
+
- **Linting**: Get warnings and hints to improve your WAF rules
|
|
41
|
+
- **Deployment Guide**: Step-by-step deployment instructions
|
|
42
|
+
- **Docker Test Harness**: Spin up CrowdSec + nginx + bouncer to exercise rules for false positives/negatives
|
|
43
|
+
- **Nuclei Lookup**: Quickly jump to existing templates in the official `projectdiscovery/nuclei-templates` repository for a given CVE
|
|
44
|
+
|
|
45
|
+
### Scenarios Features
|
|
46
|
+
|
|
47
|
+
- **CrowdSec Scenarios Generation**: Generate CrowdSec scenarios
|
|
48
|
+
- **Validation**: Validate syntaxical correctness of scenarios
|
|
49
|
+
- **Linting**: Get warnings and hints to improve your scenarios
|
|
50
|
+
- **Deployment Guide**: Step-by-step deployment instructions
|
|
51
|
+
- **Docker Test Harness**: Spin up CrowdSec to test scenario behavior
|
|
52
|
+
|
|
53
|
+
## Demo
|
|
54
|
+
|
|
55
|
+
### WAF Rules Creation and testing
|
|
56
|
+
|
|
57
|
+
- [Rule creation from natural language](https://claude.ai/share/f0f246b2-6b20-4d70-a16c-c6b627ab2d80)
|
|
58
|
+
- [Rule creation from CVE reference](https://claude.ai/share/b6599407-82dd-443c-a12d-9a9825ed99df)
|
|
59
|
+
|
|
60
|
+
### Scenario Creation and testing
|
|
61
|
+
|
|
62
|
+
- [Rule creation on HTTP events](https://claude.ai/share/3658165a-5636-4a7e-8043-01e7a7517200)
|
|
63
|
+
- [Rule creation based on GeoLocation factors](https://claude.ai/share/ff154e66-3c1a-44e6-a464-b694f65bd67e)
|
|
64
|
+
|
|
65
|
+
## Prerequisites
|
|
66
|
+
|
|
67
|
+
- [uv](https://docs.astral.sh/uv/) 0.4 or newer, which provides the `uvx` runner used in the examples below.
|
|
68
|
+
- Docker with the Compose plugin (Compose v2).
|
|
69
|
+
|
|
70
|
+
## Installation
|
|
71
|
+
|
|
72
|
+
You can install the MCP using `uvx` **or** use packaged `.mcpb` file for claude code.
|
|
73
|
+
|
|
74
|
+
### Using `.mcpb` package
|
|
75
|
+
|
|
76
|
+
If you're using `claude desktop`, you can configure the MCP directly by double-clicking the `.mcpb` file that accompanies the release.
|
|
77
|
+
|
|
78
|
+
> [!IMPORTANT]
|
|
79
|
+
> On MacOS, configure `uv` path in the extension settings if `uv` isn't installed in the standard path.
|
|
80
|
+
|
|
81
|
+
### Using `uvx`
|
|
82
|
+
|
|
83
|
+
- Configure supported clients automatically with `uvx --from crowdsec-local-mcp init <client>`, where `<client>` is one of `claude-desktop`, `claude-code`, `chatgpt`, `vscode`, or `stdio`:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
uvx --from crowdsec-local-mcp init --dry-run claude-code
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Run `uvx --from crowdsec-local-mcp init --help` to see all flags and supported targets.
|
|
90
|
+
|
|
91
|
+
#### What `init` configures
|
|
92
|
+
|
|
93
|
+
The `init` helper writes the CrowdSec MCP server definition into the client’s JSON configuration:
|
|
94
|
+
|
|
95
|
+
- `claude-desktop` → `claude_desktop_config.json` in the Claude Desktop settings directory
|
|
96
|
+
- `claude-code` → invoke `claude mcp` command with needed args
|
|
97
|
+
- `chatgpt` → `config.json` in the ChatGPT Desktop settings directory
|
|
98
|
+
- `vscode` → `mcp.json` for VS Code (stable and insiders are both detected)
|
|
99
|
+
|
|
100
|
+
If the client's configuration file already exists, a `.bak` backup is created before the MCP server block is updated. When the file is missing you can either pass `--force` to create it, or point `--config-path` to a custom location. Combine `--dry-run` with these options to preview the JSON without making any changes.
|
|
101
|
+
|
|
102
|
+
By default the CLI launches the server with `uvx --from crowdsec-local-mcp crowdsec-mcp`. If neither `uvx` nor `uv` is available, it falls back to your current Python interpreter; you can override the executable with `--command` and the working directory with `--cwd`.
|
|
103
|
+
|
|
104
|
+
#### Using the `stdio` target
|
|
105
|
+
|
|
106
|
+
`stdio` does not modify any files. Instead, `init stdio` prints a ready-to-paste JSON snippet that you can drop into any stdio-compatible MCP client configuration. This is useful when you want to manually wire the server into tools that do not have built-in automation support yet.
|
|
107
|
+
|
|
108
|
+
## Troubleshooting
|
|
109
|
+
|
|
110
|
+
If you just installed the mcp extension via `.mcpb` and `uv` or `uvx` isn't in the standard path, check the extension settings to configure `uv` path.
|
|
111
|
+
|
|
112
|
+
## Logging
|
|
113
|
+
|
|
114
|
+
- The MCP server writes its log file to your operating system's temporary directory. On Linux/macOS this is typically `/tmp/crowdsec-mcp.log`; on Windows it resolves via `%TEMP%\crowdsec-mcp.log`.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://github.com/crowdsecurity/crowdsec-docs/blob/main/crowdsec-docs/static/img/crowdsec_logo.png" alt="CrowdSec" title="CrowdSec" width="400" height="260"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
**Life is too short to write YAML, just ask nicely!**
|
|
7
|
+
|
|
8
|
+
> A Model Context Protocol (MCP) server to generate, validate, and deploy CrowdSec WAF rules & Scenarios.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
### WAF Rules Features
|
|
14
|
+
|
|
15
|
+
- **WAF Rule Generation**: Generate CrowdSec WAF rules from user input or a CVE reference
|
|
16
|
+
- **Validation**: Validate syntaxical correctness of WAF rules
|
|
17
|
+
- **Linting**: Get warnings and hints to improve your WAF rules
|
|
18
|
+
- **Deployment Guide**: Step-by-step deployment instructions
|
|
19
|
+
- **Docker Test Harness**: Spin up CrowdSec + nginx + bouncer to exercise rules for false positives/negatives
|
|
20
|
+
- **Nuclei Lookup**: Quickly jump to existing templates in the official `projectdiscovery/nuclei-templates` repository for a given CVE
|
|
21
|
+
|
|
22
|
+
### Scenarios Features
|
|
23
|
+
|
|
24
|
+
- **CrowdSec Scenarios Generation**: Generate CrowdSec scenarios
|
|
25
|
+
- **Validation**: Validate syntaxical correctness of scenarios
|
|
26
|
+
- **Linting**: Get warnings and hints to improve your scenarios
|
|
27
|
+
- **Deployment Guide**: Step-by-step deployment instructions
|
|
28
|
+
- **Docker Test Harness**: Spin up CrowdSec to test scenario behavior
|
|
29
|
+
|
|
30
|
+
## Demo
|
|
31
|
+
|
|
32
|
+
### WAF Rules Creation and testing
|
|
33
|
+
|
|
34
|
+
- [Rule creation from natural language](https://claude.ai/share/f0f246b2-6b20-4d70-a16c-c6b627ab2d80)
|
|
35
|
+
- [Rule creation from CVE reference](https://claude.ai/share/b6599407-82dd-443c-a12d-9a9825ed99df)
|
|
36
|
+
|
|
37
|
+
### Scenario Creation and testing
|
|
38
|
+
|
|
39
|
+
- [Rule creation on HTTP events](https://claude.ai/share/3658165a-5636-4a7e-8043-01e7a7517200)
|
|
40
|
+
- [Rule creation based on GeoLocation factors](https://claude.ai/share/ff154e66-3c1a-44e6-a464-b694f65bd67e)
|
|
41
|
+
|
|
42
|
+
## Prerequisites
|
|
43
|
+
|
|
44
|
+
- [uv](https://docs.astral.sh/uv/) 0.4 or newer, which provides the `uvx` runner used in the examples below.
|
|
45
|
+
- Docker with the Compose plugin (Compose v2).
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
You can install the MCP using `uvx` **or** use packaged `.mcpb` file for claude code.
|
|
50
|
+
|
|
51
|
+
### Using `.mcpb` package
|
|
52
|
+
|
|
53
|
+
If you're using `claude desktop`, you can configure the MCP directly by double-clicking the `.mcpb` file that accompanies the release.
|
|
54
|
+
|
|
55
|
+
> [!IMPORTANT]
|
|
56
|
+
> On MacOS, configure `uv` path in the extension settings if `uv` isn't installed in the standard path.
|
|
57
|
+
|
|
58
|
+
### Using `uvx`
|
|
59
|
+
|
|
60
|
+
- Configure supported clients automatically with `uvx --from crowdsec-local-mcp init <client>`, where `<client>` is one of `claude-desktop`, `claude-code`, `chatgpt`, `vscode`, or `stdio`:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uvx --from crowdsec-local-mcp init --dry-run claude-code
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Run `uvx --from crowdsec-local-mcp init --help` to see all flags and supported targets.
|
|
67
|
+
|
|
68
|
+
#### What `init` configures
|
|
69
|
+
|
|
70
|
+
The `init` helper writes the CrowdSec MCP server definition into the client’s JSON configuration:
|
|
71
|
+
|
|
72
|
+
- `claude-desktop` → `claude_desktop_config.json` in the Claude Desktop settings directory
|
|
73
|
+
- `claude-code` → invoke `claude mcp` command with needed args
|
|
74
|
+
- `chatgpt` → `config.json` in the ChatGPT Desktop settings directory
|
|
75
|
+
- `vscode` → `mcp.json` for VS Code (stable and insiders are both detected)
|
|
76
|
+
|
|
77
|
+
If the client's configuration file already exists, a `.bak` backup is created before the MCP server block is updated. When the file is missing you can either pass `--force` to create it, or point `--config-path` to a custom location. Combine `--dry-run` with these options to preview the JSON without making any changes.
|
|
78
|
+
|
|
79
|
+
By default the CLI launches the server with `uvx --from crowdsec-local-mcp crowdsec-mcp`. If neither `uvx` nor `uv` is available, it falls back to your current Python interpreter; you can override the executable with `--command` and the working directory with `--cwd`.
|
|
80
|
+
|
|
81
|
+
#### Using the `stdio` target
|
|
82
|
+
|
|
83
|
+
`stdio` does not modify any files. Instead, `init stdio` prints a ready-to-paste JSON snippet that you can drop into any stdio-compatible MCP client configuration. This is useful when you want to manually wire the server into tools that do not have built-in automation support yet.
|
|
84
|
+
|
|
85
|
+
## Troubleshooting
|
|
86
|
+
|
|
87
|
+
If you just installed the mcp extension via `.mcpb` and `uv` or `uvx` isn't in the standard path, check the extension settings to configure `uv` path.
|
|
88
|
+
|
|
89
|
+
## Logging
|
|
90
|
+
|
|
91
|
+
- The MCP server writes its log file to your operating system's temporary directory. On Linux/macOS this is typically `/tmp/crowdsec-mcp.log`; on Windows it resolves via `%TEMP%\crowdsec-mcp.log`.
|
|
Binary file
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": "0.2",
|
|
3
|
+
"name": "crowdsec-local-mcp",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Helps CrowdSec users to write, test and deploy WAF rules, scenarios, parsers etc.",
|
|
6
|
+
"long_description": "Provide tools and prompts to help CrowdSec users to write, test and deploy WAF rules, scenarios, parsers etc. in an easy way.",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "CrowdSec",
|
|
9
|
+
"email": "crowdsec-local-mcp@crowdsec.net",
|
|
10
|
+
"url": "https://www.crowdsec.net/"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://www.crowdsec.net/",
|
|
13
|
+
"documentation": "https://doc.crowdsec.net/",
|
|
14
|
+
"icon": "./crowdsec_logo.png",
|
|
15
|
+
"server": {
|
|
16
|
+
"type": "python",
|
|
17
|
+
"entry_point": "src/crowdsec_local_mcp/__main__.py",
|
|
18
|
+
"mcp_config": {
|
|
19
|
+
"command": "${user_config.uv_path}",
|
|
20
|
+
"args": [
|
|
21
|
+
"run",
|
|
22
|
+
"--project",
|
|
23
|
+
"${__dirname}",
|
|
24
|
+
"crowdsec-mcp"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"user_config": {
|
|
29
|
+
"uv_path": {
|
|
30
|
+
"type": "file",
|
|
31
|
+
"default": "uv",
|
|
32
|
+
"title": "Path to uv executable",
|
|
33
|
+
"description": "Path to the 'uv' executable used to run the server.",
|
|
34
|
+
"required": false
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"tools": [
|
|
38
|
+
{
|
|
39
|
+
"name": "get_waf_top_level_prompt",
|
|
40
|
+
"description": "Get the top-level CrowdSec WAF workflow prompt that explains how to approach rule and test creation"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "get_waf_prompt",
|
|
44
|
+
"description": "Get the main WAF rule generation prompt for CrowdSec"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "get_waf_examples",
|
|
48
|
+
"description": "Get WAF rule generation examples for CrowdSec"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "generate_waf_rule",
|
|
52
|
+
"description": "Get the complete WAF rule generation prompt (main prompt + examples) for CrowdSec"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "generate_waf_tests",
|
|
56
|
+
"description": "Get the WAF test generation prompt for producing config.yaml and adapted Nuclei templates"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"name": "get_waf_pr_prompt",
|
|
60
|
+
"description": "Get the WAF PR preparation prompt for writing test assets and drafting a PR comment"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "run_waf_tests",
|
|
64
|
+
"description": "Start the WAF harness and execute the provided nuclei test template against it"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "validate_waf_rule",
|
|
68
|
+
"description": "Validate that a CrowdSec WAF rule YAML is syntactically correct"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"name": "lint_waf_rule",
|
|
72
|
+
"description": "Lint a CrowdSec WAF rule and provide warnings/hints for improvement"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "deploy_waf_rule",
|
|
76
|
+
"description": "Get deployment instructions for CrowdSec WAF rules"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "prepare_waf_pr",
|
|
80
|
+
"description": "Write the generated WAF rule and AppSec test assets into a local CrowdSec hub clone, and optionally add the rule to the appsec-virtual-patching collection"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "fetch_nuclei_exploit",
|
|
84
|
+
"description": "Retrieve nuclei templates from the official repository for a CVE to help with generation of WAF rules"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"name": "manage_waf_stack",
|
|
88
|
+
"description": "Start or stop the Docker-based CrowdSec AppSec test stack so the rule can be exercised with allowed and blocked requests"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "curl_waf_endpoint",
|
|
92
|
+
"description": "Execute an HTTP request against the local WAF test endpoint (http://localhost:8081)"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "get_scenario_prompt",
|
|
96
|
+
"description": "Retrieve the base prompt for authoring CrowdSec scenarios"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "get_scenario_examples",
|
|
100
|
+
"description": "Retrieve example CrowdSec scenarios and annotations"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "validate_scenario_yaml",
|
|
104
|
+
"description": "Validate CrowdSec scenario YAML structure for required fields"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"name": "lint_scenario_yaml",
|
|
108
|
+
"description": "Lint CrowdSec scenario YAML and highlight potential improvements"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "deploy_scenario",
|
|
112
|
+
"description": "Retrieve guidance for packaging and deploying a CrowdSec scenario"
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
"tools_generated": true,
|
|
116
|
+
"prompts_generated": true,
|
|
117
|
+
"keywords": [
|
|
118
|
+
"crowdsec",
|
|
119
|
+
"foss",
|
|
120
|
+
"waf",
|
|
121
|
+
"web application firewall",
|
|
122
|
+
"appsec",
|
|
123
|
+
"scenario",
|
|
124
|
+
"parser",
|
|
125
|
+
"grok",
|
|
126
|
+
"yaml",
|
|
127
|
+
"security engine"
|
|
128
|
+
],
|
|
129
|
+
"license": "MIT",
|
|
130
|
+
"repository": {
|
|
131
|
+
"type": "git",
|
|
132
|
+
"url": "https://github.com/crowdsecurity/crowdsec-local-mcp"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "crowdsec-local-mcp"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
description = "An MCP exposing prompts and tools to help users write WAF rules, scenarios etc."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 4 - Beta",
|
|
11
|
+
"Intended Audience :: Developers",
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"Programming Language :: Python :: 3.10",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Topic :: Security",
|
|
17
|
+
"Topic :: System :: Systems Administration",
|
|
18
|
+
"Topic :: Utilities",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
dependencies = [
|
|
22
|
+
"jsonschema>=4.25.1",
|
|
23
|
+
"mcp>=1.15.0",
|
|
24
|
+
"pyyaml>=6.0.3",
|
|
25
|
+
"requests>=2.32.5",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[dependency-groups]
|
|
29
|
+
dev = [
|
|
30
|
+
"basedpyright>=1.25.0",
|
|
31
|
+
"pytest>=8.3.0",
|
|
32
|
+
"ruff>=0.9.3",
|
|
33
|
+
"setuptools-scm>=8",
|
|
34
|
+
"types-pyyaml>=6.0.12.20241230",
|
|
35
|
+
"types-requests>=2.32.0.20241016",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
crowdsec-mcp = "crowdsec_local_mcp.__main__:run"
|
|
40
|
+
init = "crowdsec_local_mcp.setup_cli:main"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["setuptools>=69", "wheel", "setuptools_scm>=8"]
|
|
44
|
+
build-backend = "setuptools.build_meta"
|
|
45
|
+
|
|
46
|
+
[tool.setuptools]
|
|
47
|
+
include-package-data = true
|
|
48
|
+
|
|
49
|
+
[tool.setuptools.package-dir]
|
|
50
|
+
"" = "src"
|
|
51
|
+
|
|
52
|
+
[tool.setuptools.packages.find]
|
|
53
|
+
where = ["src"]
|
|
54
|
+
|
|
55
|
+
[tool.setuptools_scm]
|
|
56
|
+
tag_regex = "^v?(?P<version>[0-9]+(\\.[0-9]+)*)$"
|
|
57
|
+
version_scheme = "no-guess-dev"
|
|
58
|
+
local_scheme = "no-local-version"
|
|
59
|
+
write_to = "src/crowdsec_local_mcp/_version.py"
|
|
60
|
+
write_to_template = "__version__ = \"{version}\"\n"
|
|
61
|
+
fallback_version = "0.0.0"
|
|
62
|
+
|
|
63
|
+
[tool.ruff]
|
|
64
|
+
target-version = "py312"
|
|
65
|
+
line-length = 193
|
|
66
|
+
#fix = true
|
|
67
|
+
#unsafe-fixes = false
|
|
68
|
+
#extend-select = ["I", "UP"] # import sorting, modern syntax upgrades
|
|
69
|
+
|
|
70
|
+
[tool.ruff.format]
|
|
71
|
+
#quote-style = "double"
|
|
72
|
+
#indent-style = "space"
|
|
73
|
+
#skip-magic-trailing-comma = false
|
|
74
|
+
#line-ending = "lf"
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint.per-file-ignores]
|
|
77
|
+
#"path/to/file.py" = [
|
|
78
|
+
# "T201", # `print` found
|
|
79
|
+
#]
|
|
80
|
+
|
|
81
|
+
[tool.ruff.lint]
|
|
82
|
+
select = [
|
|
83
|
+
"ALL"
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
ignore = [
|
|
87
|
+
"ANN", # Missing type annotations
|
|
88
|
+
"BLE001", # Do not catch blind exception: `Exception`
|
|
89
|
+
"COM", # flake8-commas
|
|
90
|
+
"D", # pydocstyle
|
|
91
|
+
"EM101", # Exception must not use a string literal, assign to variable first
|
|
92
|
+
"EM102", # Exception must not use an f-string literal, assign to variable first
|
|
93
|
+
"FBT001", # Boolean-typed positional argument in function definition
|
|
94
|
+
"FBT002", # Boolean default positional argument in function definition
|
|
95
|
+
"I001", # Import block is un-sorted or un-formatted
|
|
96
|
+
"PERF401", # Use `list.extend` to create a transformed list
|
|
97
|
+
"PLW0603", # Using the global statement to update `...` is discouraged
|
|
98
|
+
"PLW1510", # `subprocess.run` without explicit `check` argument
|
|
99
|
+
"RUF005", # Consider `[...]` instead of concatenation
|
|
100
|
+
"S603", # `subprocess` call: check for execution of untrusted input
|
|
101
|
+
"SIM102", # Use a single `if` statement instead of nested `if` statements
|
|
102
|
+
"T201", # `print` found
|
|
103
|
+
"TRY003", # Avoid specifying long messages outside the exception class
|
|
104
|
+
"TRY004", # Prefer `TypeError` exception for invalid type
|
|
105
|
+
"TRY301", # Abstract `raise` to an inner function
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint.pylint]
|
|
109
|
+
max-statements = 75
|
|
110
|
+
max-branches = 20
|
|
111
|
+
max-returns = 12
|
|
112
|
+
max-args = 10 #Marco <3
|
|
113
|
+
|
|
114
|
+
[tool.ruff.lint.mccabe]
|
|
115
|
+
max-complexity = 33
|
|
116
|
+
|
|
117
|
+
[tool.basedpyright]
|
|
118
|
+
pythonVersion = "3.12"
|
|
119
|
+
reportAny = "none"
|
|
120
|
+
reportArgumentType = "none"
|
|
121
|
+
reportConstantRedefinition = "none"
|
|
122
|
+
reportDeprecated = "none"
|
|
123
|
+
reportExplicitAny = "none"
|
|
124
|
+
reportImplicitStringConcatenation = "none"
|
|
125
|
+
reportMissingTypeArgument = "none"
|
|
126
|
+
reportUnknownArgumentType = "none"
|
|
127
|
+
reportUnknownMemberType = "none"
|
|
128
|
+
reportUnknownParameterType = "none"
|
|
129
|
+
reportUnknownVariableType = "none"
|
|
130
|
+
reportUnnecessaryIsInstance = "none"
|
|
131
|
+
reportUnusedCallResult = "none"
|
|
132
|
+
reportUnusedImport = "none"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.8.0.post1.dev0"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
scenarios/*.yaml
|