Skip to content

Commit f8bbb15

Browse files
authored
Claude code setup + minor readme (#25)
* add claude-code support for init * update readme
1 parent 9bbeb78 commit f8bbb15

File tree

5 files changed

+70
-13
lines changed

5 files changed

+70
-13
lines changed

.github/workflows/build-mcpb.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- name: Build MCPB package
2323
run: |
2424
mkdir -p dist
25-
npx --yes @anthropic-ai/mcpb pack
25+
npx --yes @anthropic-ai/mcpb@v1.1.1 pack
2626
2727
- name: Upload package artifact
2828
uses: actions/upload-artifact@v4

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,19 @@
4646

4747
## Installation
4848

49-
### Quick MCP client setup
49+
### Using `.mcpb` package
5050

51-
- Configure supported clients automatically with `uvx --from crowdsec-local-mcp init <client>`, where `<client>` is one of `claude-desktop`, `chatgpt`, `vscode`, or `stdio`:
51+
If you're using `claude desktop`, you can configure the MCP directly by double-clicking the `.mcpb` file that accompanies the release.
52+
53+
> [!IMPORTANT]
54+
> On MacOS, configure `uv` path in the extension settings if `uv` isn't installed in the standard path.
55+
56+
### Using `uvx`
57+
58+
- 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`:
5259

5360
```bash
54-
uvx --from crowdsec-local-mcp init claude-desktop
61+
uvx --from crowdsec-local-mcp init --dry-run claude-code
5562
```
5663

5764
Run `uvx --from crowdsec-local-mcp init --help` to see all flags and supported targets.
@@ -60,7 +67,8 @@ Run `uvx --from crowdsec-local-mcp init --help` to see all flags and supported t
6067

6168
The `init` helper writes the CrowdSec MCP server definition into the client’s JSON configuration:
6269

63-
- `claude-desktop``claude_desktop_config.json`
70+
- `claude-desktop``claude_desktop_config.json` in the Claude Desktop settings directory
71+
- `claude-code` → invoke `claude mcp` command with needed args
6472
- `chatgpt``config.json` in the ChatGPT Desktop settings directory
6573
- `vscode``mcp.json` for VS Code (stable and insiders are both detected)
6674

@@ -72,6 +80,10 @@ By default the CLI launches the server with `uvx --from crowdsec-local-mcp crowd
7280

7381
`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.
7482

83+
## Troubleshooting
84+
85+
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.
86+
7587
## Logging
7688

7789
- 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`.

manifest.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,6 @@
106106
],
107107
"tools_generated": true,
108108
"prompts_generated": true,
109-
"compatibility": {
110-
"uv": ">=0.5.0"
111-
},
112109
"keywords": [
113110
"crowdsec",
114111
"foss",

src/crowdsec_local_mcp/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.0.2.post1.dev24"
1+
__version__ = "0.4.0.post1.dev0"

src/crowdsec_local_mcp/setup_cli.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
import json
33
import os
44
import platform
5+
import shlex
56
import shutil
7+
import subprocess
68
import sys
79
from dataclasses import dataclass
810
from pathlib import Path
911
from collections.abc import Iterable
1012

1113
SERVER_KEY = "crowdsec-local-mcp"
12-
SERVER_LABEL = "CrowdSec MCP"
13-
14+
SERVER_LABEL = "CrowdSecMCP"
1415

1516
@dataclass
1617
class CLIArgs:
@@ -42,6 +43,8 @@ def main(argv: Iterable[str] | None = None) -> None:
4243

4344
if args.target == "claude-desktop":
4445
_configure_claude(args, server_payload)
46+
elif args.target == "claude-code":
47+
_configure_claude_code(args, server_payload)
4548
elif args.target == "chatgpt":
4649
_configure_chatgpt(args, server_payload)
4750
elif args.target == "vscode":
@@ -55,12 +58,12 @@ def _parse_args(argv: Iterable[str] | None) -> CLIArgs:
5558
prog="init",
5659
description=(
5760
"Initialize CrowdSec MCP integration for supported clients "
58-
"(Claude Desktop, ChatGPT Desktop, Visual Studio Code, or stdio)."
61+
"(Claude Desktop, Claude Code, ChatGPT Desktop, Visual Studio Code, or stdio)."
5962
),
6063
)
6164
parser.add_argument(
6265
"target",
63-
choices=("claude-desktop", "chatgpt", "vscode", "stdio"),
66+
choices=("claude-desktop", "claude-code", "chatgpt", "vscode", "stdio"),
6467
help="Client to configure.",
6568
)
6669
parser.add_argument(
@@ -139,6 +142,51 @@ def _configure_claude(args: CLIArgs, server_payload: dict[str, object]) -> None:
139142
)
140143

141144

145+
def _configure_claude_code(args: CLIArgs, server_payload: dict[str, object]) -> None:
146+
runner_command = server_payload["command"]
147+
if not isinstance(runner_command, str):
148+
raise TypeError("Server payload 'command' must be a string.")
149+
runner_args = server_payload.get("args", [])
150+
if not isinstance(runner_args, list):
151+
raise TypeError("Server payload 'args' must be a list.")
152+
153+
claude_invocation = [
154+
"claude",
155+
"mcp",
156+
"add",
157+
"--transport",
158+
"stdio",
159+
"--scope",
160+
"user",
161+
SERVER_LABEL,
162+
"--",
163+
runner_command,
164+
*runner_args,
165+
]
166+
quoted_command = " ".join(shlex.quote(part) for part in claude_invocation)
167+
168+
if args.dry_run:
169+
print(
170+
"Run the following command to register CrowdSec MCP with Claude Code:\n"
171+
f"{quoted_command}"
172+
)
173+
return
174+
175+
if shutil.which("claude") is None:
176+
raise FileNotFoundError(
177+
"The 'claude' CLI is not available on PATH. Install Claude Code CLI and "
178+
f"run:\n{quoted_command}"
179+
)
180+
181+
result = subprocess.run(claude_invocation, check=False)
182+
if result.returncode != 0:
183+
raise RuntimeError(
184+
f"'claude mcp add' failed with exit code {result.returncode}. "
185+
f"Run manually:\n{quoted_command}"
186+
)
187+
print("Registered CrowdSec MCP with Claude Code CLI.")
188+
189+
142190
def _configure_chatgpt(args: CLIArgs, server_payload: dict[str, object]) -> None:
143191
config_path = _resolve_path(args.config_path, _chatgpt_candidates())
144192
_write_mcp_config(

0 commit comments

Comments
 (0)