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.
Files changed (69) hide show
  1. crowdsec_local_mcp-0.8.0.post1.dev0/.github/workflows/build-mcpb.yml +46 -0
  2. crowdsec_local_mcp-0.8.0.post1.dev0/.github/workflows/build.yml +45 -0
  3. crowdsec_local_mcp-0.8.0.post1.dev0/.github/workflows/lint.yaml +43 -0
  4. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/.github/workflows/publish.yml +2 -2
  5. crowdsec_local_mcp-0.8.0.post1.dev0/.mcpbignore +10 -0
  6. crowdsec_local_mcp-0.8.0.post1.dev0/.python-version +1 -0
  7. crowdsec_local_mcp-0.8.0.post1.dev0/PKG-INFO +114 -0
  8. crowdsec_local_mcp-0.8.0.post1.dev0/README.md +91 -0
  9. crowdsec_local_mcp-0.8.0.post1.dev0/crowdsec_logo.png +0 -0
  10. crowdsec_local_mcp-0.8.0.post1.dev0/manifest.json +134 -0
  11. crowdsec_local_mcp-0.8.0.post1.dev0/pyproject.toml +132 -0
  12. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/__init__.py +10 -0
  13. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/__main__.py +1 -3
  14. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/_version.py +1 -0
  15. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/compose/scenario-test/.gitignore +1 -0
  16. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/compose/scenario-test/docker-compose.yml +19 -0
  17. {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
  18. {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
  19. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/compose/waf-test/rules/.gitkeep +0 -0
  20. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/mcp_core.py +245 -0
  21. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/mcp_scenarios.py +936 -0
  22. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/mcp_waf.py +1542 -0
  23. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-expr-helpers.txt +514 -0
  24. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-scenario-deploy.txt +76 -0
  25. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/prompts/prompt-scenario.txt +26 -2
  26. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-waf-pr.txt +10 -0
  27. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-waf-tests.txt +113 -0
  28. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp/prompts/prompt-waf-top-level.txt +33 -0
  29. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/prompts/prompt-waf.txt +0 -26
  30. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/setup_cli.py +98 -29
  31. crowdsec_local_mcp-0.8.0.post1.dev0/src/crowdsec_local_mcp.egg-info/PKG-INFO +114 -0
  32. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp.egg-info/SOURCES.txt +19 -1
  33. crowdsec_local_mcp-0.8.0.post1.dev0/tests/__init__.py +0 -0
  34. crowdsec_local_mcp-0.8.0.post1.dev0/tests/test_mcp_waf_lint.py +81 -0
  35. crowdsec_local_mcp-0.8.0.post1.dev0/tools/__init__.py +1 -0
  36. crowdsec_local_mcp-0.8.0.post1.dev0/tools/update_manifest_version.py +20 -0
  37. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/uv.lock +431 -264
  38. crowdsec_local_mcp-0.2.0/.github/workflows/build.yml +0 -21
  39. crowdsec_local_mcp-0.2.0/PKG-INFO +0 -74
  40. crowdsec_local_mcp-0.2.0/README.md +0 -61
  41. crowdsec_local_mcp-0.2.0/pyproject.toml +0 -34
  42. crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/__init__.py +0 -5
  43. crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/mcp_core.py +0 -151
  44. crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/mcp_scenarios.py +0 -380
  45. crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/mcp_waf.py +0 -1170
  46. crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp/prompts/prompt-scenario-deploy.txt +0 -27
  47. crowdsec_local_mcp-0.2.0/src/crowdsec_local_mcp.egg-info/PKG-INFO +0 -74
  48. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/.gitignore +0 -0
  49. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/LICENSE +0 -0
  50. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/MANIFEST.in +0 -0
  51. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/setup.cfg +0 -0
  52. {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
  53. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp/compose/waf-test/.gitignore +0 -0
  54. {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
  55. {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
  56. {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
  57. {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
  58. {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
  59. {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
  60. {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
  61. {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
  62. {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
  63. {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
  64. {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
  65. {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
  66. {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
  67. {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
  68. {crowdsec_local_mcp-0.2.0 → crowdsec_local_mcp-0.8.0.post1.dev0}/src/crowdsec_local_mcp.egg-info/requires.txt +0 -0
  69. {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
@@ -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@v6
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,10 @@
1
+ .venv/*
2
+ dist/*
3
+ .git/*
4
+ .github/*
5
+ src/crowdsec_local_mcp.egg-info/*
6
+ src/crowdsec_local_mcp/__pycache__/*
7
+ src/crowdsec_local_mcp/cached-exploits/*
8
+ tests/__pycache__/*
9
+ *.log
10
+ *.mcpb
@@ -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`.
@@ -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,10 @@
1
+ """CrowdSec MCP package."""
2
+
3
+ from .mcp_core import main
4
+
5
+ try:
6
+ from ._version import __version__
7
+ except ModuleNotFoundError: # pragma: no cover - generated during release
8
+ __version__ = "0.0.0"
9
+
10
+ __all__ = ["__version__", "main"]
@@ -1,6 +1,4 @@
1
- #!/usr/bin/env python3
2
-
3
- # Use `uv run --project . <command>` to run this module directly for testing.
1
+ # Use `uv run --project . crowdsec-mcp` to run this module directly for testing.
4
2
 
5
3
  import asyncio
6
4
 
@@ -0,0 +1 @@
1
+ __version__ = "0.8.0.post1.dev0"