basecamp-cli-mcp 0.6.0__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.
- basecamp_cli_mcp-0.6.0/.gitignore +7 -0
- basecamp_cli_mcp-0.6.0/PKG-INFO +161 -0
- basecamp_cli_mcp-0.6.0/README.md +148 -0
- basecamp_cli_mcp-0.6.0/pyproject.toml +38 -0
- basecamp_cli_mcp-0.6.0/src/basecamp_cli_mcp/__init__.py +6 -0
- basecamp_cli_mcp-0.6.0/src/basecamp_cli_mcp/cli.py +80 -0
- basecamp_cli_mcp-0.6.0/src/basecamp_cli_mcp/data/tools.json +18543 -0
- basecamp_cli_mcp-0.6.0/src/basecamp_cli_mcp/generator.py +168 -0
- basecamp_cli_mcp-0.6.0/src/basecamp_cli_mcp/help_parser.py +169 -0
- basecamp_cli_mcp-0.6.0/src/basecamp_cli_mcp/runner.py +189 -0
- basecamp_cli_mcp-0.6.0/src/basecamp_cli_mcp/server.py +102 -0
- basecamp_cli_mcp-0.6.0/src/basecamp_cli_mcp/setup_cmd.py +142 -0
- basecamp_cli_mcp-0.6.0/tests/conftest.py +10 -0
- basecamp_cli_mcp-0.6.0/tests/fixtures/cards_create_help.txt +31 -0
- basecamp_cli_mcp-0.6.0/tests/fixtures/projects_list_help.txt +23 -0
- basecamp_cli_mcp-0.6.0/tests/fixtures/todos_complete_help.txt +25 -0
- basecamp_cli_mcp-0.6.0/tests/fixtures/todos_create_help.txt +28 -0
- basecamp_cli_mcp-0.6.0/tests/test_help_parser.py +79 -0
- basecamp_cli_mcp-0.6.0/tests/test_runner.py +198 -0
- basecamp_cli_mcp-0.6.0/tests/test_server.py +39 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: basecamp-cli-mcp
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: MCP server that wraps the basecamp CLI.
|
|
5
|
+
Project-URL: Homepage, https://github.com/FutureWorkshops/basecamp-cli-mcp
|
|
6
|
+
Project-URL: Source, https://github.com/FutureWorkshops/basecamp-cli-mcp
|
|
7
|
+
Author-email: Matt Brooke-Smith <matt@futureworkshops.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: basecamp,mcp,model-context-protocol
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Requires-Dist: mcp>=1.2
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# basecamp-cli-mcp
|
|
15
|
+
|
|
16
|
+
A Model Context Protocol (MCP) server that wraps the [`basecamp`](https://github.com/basecamp/cli)
|
|
17
|
+
CLI. Every non-shortcut CLI action (`projects list`, `todos create`, `cards update`, etc.) is
|
|
18
|
+
exposed as an MCP tool, so MCP-compatible clients (Claude Code, Claude Desktop, etc.) can
|
|
19
|
+
drive Basecamp directly.
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- Python ≥ 3.11
|
|
24
|
+
- The `basecamp` CLI on `PATH`, already authenticated (`basecamp setup`) — see [First-time setup](#first-time-setup) below to do both in one command
|
|
25
|
+
- [`uv`](https://docs.astral.sh/uv/) for the recommended install
|
|
26
|
+
|
|
27
|
+
## First-time setup
|
|
28
|
+
|
|
29
|
+
If you don't have the `basecamp` CLI installed yet:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
uvx basecamp-cli-mcp setup
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This checks for the `basecamp` binary, runs the official installer (`curl -fsSL https://basecamp.com/install-cli | bash`) after a y/N prompt if it's missing, then runs `basecamp setup` to walk you through OAuth.
|
|
36
|
+
|
|
37
|
+
On macOS, after auth completes it offers to:
|
|
38
|
+
|
|
39
|
+
1. Add `basecamp` to your `claude_desktop_config.json` (with a timestamped backup of any existing file).
|
|
40
|
+
2. Restart Claude Desktop.
|
|
41
|
+
|
|
42
|
+
Both steps prompt y/N. macOS and Linux only for the install/auth — on Windows the command prints the PowerShell installer and exits. The Claude Desktop step is macOS-only.
|
|
43
|
+
|
|
44
|
+
## Run
|
|
45
|
+
|
|
46
|
+
The fastest way — no install step at all:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
uvx basecamp-cli-mcp
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`uvx` resolves the package, runs it in an ephemeral isolated env, and exec's it on stdin/stdout.
|
|
53
|
+
|
|
54
|
+
To install permanently:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
uv tool install basecamp-cli-mcp
|
|
58
|
+
basecamp-cli-mcp
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Add to Claude Code
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
claude mcp add basecamp -- uvx basecamp-cli-mcp
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Add to Claude Desktop (`claude_desktop_config.json`)
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"mcpServers": {
|
|
72
|
+
"basecamp": {
|
|
73
|
+
"command": "uvx",
|
|
74
|
+
"args": ["basecamp-cli-mcp"]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If `uvx` isn't on Desktop's `PATH` (it strips most of your shell `PATH`), use the absolute path — `which uvx` from your shell.
|
|
81
|
+
|
|
82
|
+
### Filtering tools
|
|
83
|
+
|
|
84
|
+
By default the server exposes all 250+ tools. Most agents only need a handful, and a smaller
|
|
85
|
+
catalog speeds up tool selection. Filter with `--include` / `--exclude` (fnmatch globs against
|
|
86
|
+
tool names; both flags repeatable):
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
basecamp-cli-mcp --include 'cards_*' --include 'todos_*'
|
|
90
|
+
basecamp-cli-mcp --include '*' --exclude 'webhooks_*' --exclude 'templates_*'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Register multiple profiles in `claude_desktop_config.json` and turn them on per task:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"basecamp-cards": {
|
|
99
|
+
"command": "uvx",
|
|
100
|
+
"args": ["basecamp-cli-mcp", "--include", "cards_*", "--include", "projects_list"]
|
|
101
|
+
},
|
|
102
|
+
"basecamp-todos": {
|
|
103
|
+
"command": "uvx",
|
|
104
|
+
"args": ["basecamp-cli-mcp", "--include", "todos_*", "--include", "projects_list"]
|
|
105
|
+
},
|
|
106
|
+
"basecamp-full": {
|
|
107
|
+
"command": "uvx",
|
|
108
|
+
"args": ["basecamp-cli-mcp"]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `BASECAMP_BIN`
|
|
115
|
+
|
|
116
|
+
If the `basecamp` CLI isn't on the spawned process's `PATH` (a real risk under Claude Desktop), set:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
"env": { "BASECAMP_BIN": "/absolute/path/to/basecamp" }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## How it works
|
|
123
|
+
|
|
124
|
+
Tool schemas are pre-generated and committed to `src/basecamp_cli_mcp/data/tools.json` (shipped
|
|
125
|
+
inside the wheel as package data). At runtime the server loads that file and registers one MCP
|
|
126
|
+
tool per entry. Each tool:
|
|
127
|
+
|
|
128
|
+
1. Builds `argv` from positional arguments and flags defined in the schema.
|
|
129
|
+
2. Shells out: `basecamp <group> <action> <args...> --json`.
|
|
130
|
+
3. Returns the parsed `data` field from the CLI's `{ok, data}` envelope to the MCP client.
|
|
131
|
+
|
|
132
|
+
Shortcut commands (`todo`, `done`, `card`, `comment`, etc.) are intentionally excluded — their
|
|
133
|
+
underlying actions (`todos_create`, `cards_create`, …) are already exposed.
|
|
134
|
+
|
|
135
|
+
## Regenerating tool schemas
|
|
136
|
+
|
|
137
|
+
After upgrading the `basecamp` CLI:
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
uv run basecamp-cli-mcp generate
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Review the diff in `src/basecamp_cli_mcp/data/tools.json` and commit. The generator reads
|
|
144
|
+
`basecamp commands --json` and parses `basecamp <group> <action> --help` for each action.
|
|
145
|
+
|
|
146
|
+
## Development
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
uv sync
|
|
150
|
+
uv run pytest
|
|
151
|
+
uv build # wheel + sdist into dist/
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Layout:
|
|
155
|
+
|
|
156
|
+
- `src/basecamp_cli_mcp/server.py` — wires up the MCP server from `data/tools.json`
|
|
157
|
+
- `src/basecamp_cli_mcp/runner.py` — builds argv and shells out
|
|
158
|
+
- `src/basecamp_cli_mcp/generator.py` — regenerates `data/tools.json`
|
|
159
|
+
- `src/basecamp_cli_mcp/help_parser.py` — parses `--help` text into a schema
|
|
160
|
+
- `src/basecamp_cli_mcp/cli.py` — entrypoint (`basecamp-cli-mcp`)
|
|
161
|
+
- `src/basecamp_cli_mcp/data/tools.json` — generated tool schemas (committed)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# basecamp-cli-mcp
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server that wraps the [`basecamp`](https://github.com/basecamp/cli)
|
|
4
|
+
CLI. Every non-shortcut CLI action (`projects list`, `todos create`, `cards update`, etc.) is
|
|
5
|
+
exposed as an MCP tool, so MCP-compatible clients (Claude Code, Claude Desktop, etc.) can
|
|
6
|
+
drive Basecamp directly.
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Python ≥ 3.11
|
|
11
|
+
- The `basecamp` CLI on `PATH`, already authenticated (`basecamp setup`) — see [First-time setup](#first-time-setup) below to do both in one command
|
|
12
|
+
- [`uv`](https://docs.astral.sh/uv/) for the recommended install
|
|
13
|
+
|
|
14
|
+
## First-time setup
|
|
15
|
+
|
|
16
|
+
If you don't have the `basecamp` CLI installed yet:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
uvx basecamp-cli-mcp setup
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This checks for the `basecamp` binary, runs the official installer (`curl -fsSL https://basecamp.com/install-cli | bash`) after a y/N prompt if it's missing, then runs `basecamp setup` to walk you through OAuth.
|
|
23
|
+
|
|
24
|
+
On macOS, after auth completes it offers to:
|
|
25
|
+
|
|
26
|
+
1. Add `basecamp` to your `claude_desktop_config.json` (with a timestamped backup of any existing file).
|
|
27
|
+
2. Restart Claude Desktop.
|
|
28
|
+
|
|
29
|
+
Both steps prompt y/N. macOS and Linux only for the install/auth — on Windows the command prints the PowerShell installer and exits. The Claude Desktop step is macOS-only.
|
|
30
|
+
|
|
31
|
+
## Run
|
|
32
|
+
|
|
33
|
+
The fastest way — no install step at all:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
uvx basecamp-cli-mcp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`uvx` resolves the package, runs it in an ephemeral isolated env, and exec's it on stdin/stdout.
|
|
40
|
+
|
|
41
|
+
To install permanently:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
uv tool install basecamp-cli-mcp
|
|
45
|
+
basecamp-cli-mcp
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Add to Claude Code
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
claude mcp add basecamp -- uvx basecamp-cli-mcp
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Add to Claude Desktop (`claude_desktop_config.json`)
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"basecamp": {
|
|
60
|
+
"command": "uvx",
|
|
61
|
+
"args": ["basecamp-cli-mcp"]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If `uvx` isn't on Desktop's `PATH` (it strips most of your shell `PATH`), use the absolute path — `which uvx` from your shell.
|
|
68
|
+
|
|
69
|
+
### Filtering tools
|
|
70
|
+
|
|
71
|
+
By default the server exposes all 250+ tools. Most agents only need a handful, and a smaller
|
|
72
|
+
catalog speeds up tool selection. Filter with `--include` / `--exclude` (fnmatch globs against
|
|
73
|
+
tool names; both flags repeatable):
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
basecamp-cli-mcp --include 'cards_*' --include 'todos_*'
|
|
77
|
+
basecamp-cli-mcp --include '*' --exclude 'webhooks_*' --exclude 'templates_*'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Register multiple profiles in `claude_desktop_config.json` and turn them on per task:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"mcpServers": {
|
|
85
|
+
"basecamp-cards": {
|
|
86
|
+
"command": "uvx",
|
|
87
|
+
"args": ["basecamp-cli-mcp", "--include", "cards_*", "--include", "projects_list"]
|
|
88
|
+
},
|
|
89
|
+
"basecamp-todos": {
|
|
90
|
+
"command": "uvx",
|
|
91
|
+
"args": ["basecamp-cli-mcp", "--include", "todos_*", "--include", "projects_list"]
|
|
92
|
+
},
|
|
93
|
+
"basecamp-full": {
|
|
94
|
+
"command": "uvx",
|
|
95
|
+
"args": ["basecamp-cli-mcp"]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `BASECAMP_BIN`
|
|
102
|
+
|
|
103
|
+
If the `basecamp` CLI isn't on the spawned process's `PATH` (a real risk under Claude Desktop), set:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
"env": { "BASECAMP_BIN": "/absolute/path/to/basecamp" }
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## How it works
|
|
110
|
+
|
|
111
|
+
Tool schemas are pre-generated and committed to `src/basecamp_cli_mcp/data/tools.json` (shipped
|
|
112
|
+
inside the wheel as package data). At runtime the server loads that file and registers one MCP
|
|
113
|
+
tool per entry. Each tool:
|
|
114
|
+
|
|
115
|
+
1. Builds `argv` from positional arguments and flags defined in the schema.
|
|
116
|
+
2. Shells out: `basecamp <group> <action> <args...> --json`.
|
|
117
|
+
3. Returns the parsed `data` field from the CLI's `{ok, data}` envelope to the MCP client.
|
|
118
|
+
|
|
119
|
+
Shortcut commands (`todo`, `done`, `card`, `comment`, etc.) are intentionally excluded — their
|
|
120
|
+
underlying actions (`todos_create`, `cards_create`, …) are already exposed.
|
|
121
|
+
|
|
122
|
+
## Regenerating tool schemas
|
|
123
|
+
|
|
124
|
+
After upgrading the `basecamp` CLI:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
uv run basecamp-cli-mcp generate
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Review the diff in `src/basecamp_cli_mcp/data/tools.json` and commit. The generator reads
|
|
131
|
+
`basecamp commands --json` and parses `basecamp <group> <action> --help` for each action.
|
|
132
|
+
|
|
133
|
+
## Development
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
uv sync
|
|
137
|
+
uv run pytest
|
|
138
|
+
uv build # wheel + sdist into dist/
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Layout:
|
|
142
|
+
|
|
143
|
+
- `src/basecamp_cli_mcp/server.py` — wires up the MCP server from `data/tools.json`
|
|
144
|
+
- `src/basecamp_cli_mcp/runner.py` — builds argv and shells out
|
|
145
|
+
- `src/basecamp_cli_mcp/generator.py` — regenerates `data/tools.json`
|
|
146
|
+
- `src/basecamp_cli_mcp/help_parser.py` — parses `--help` text into a schema
|
|
147
|
+
- `src/basecamp_cli_mcp/cli.py` — entrypoint (`basecamp-cli-mcp`)
|
|
148
|
+
- `src/basecamp_cli_mcp/data/tools.json` — generated tool schemas (committed)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "basecamp-cli-mcp"
|
|
3
|
+
version = "0.6.0"
|
|
4
|
+
description = "MCP server that wraps the basecamp CLI."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "Matt Brooke-Smith", email = "matt@futureworkshops.com" }]
|
|
9
|
+
keywords = ["mcp", "basecamp", "model-context-protocol"]
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
"mcp>=1.2",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Homepage = "https://github.com/FutureWorkshops/basecamp-cli-mcp"
|
|
17
|
+
Source = "https://github.com/FutureWorkshops/basecamp-cli-mcp"
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
basecamp-cli-mcp = "basecamp_cli_mcp.cli:main"
|
|
21
|
+
|
|
22
|
+
[build-system]
|
|
23
|
+
requires = ["hatchling"]
|
|
24
|
+
build-backend = "hatchling.build"
|
|
25
|
+
|
|
26
|
+
[tool.hatch.build.targets.wheel]
|
|
27
|
+
packages = ["src/basecamp_cli_mcp"]
|
|
28
|
+
|
|
29
|
+
[tool.hatch.build.targets.sdist]
|
|
30
|
+
include = ["src/basecamp_cli_mcp", "tests", "README.md", "LICENSE"]
|
|
31
|
+
|
|
32
|
+
[dependency-groups]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=8",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[tool.pytest.ini_options]
|
|
38
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import asyncio
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from importlib.resources import files
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from . import __version__
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main(argv: list[str] | None = None) -> int:
|
|
14
|
+
parser = argparse.ArgumentParser(
|
|
15
|
+
prog="basecamp-cli-mcp",
|
|
16
|
+
description="MCP server that wraps the basecamp CLI.",
|
|
17
|
+
)
|
|
18
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
19
|
+
parser.add_argument(
|
|
20
|
+
"--include",
|
|
21
|
+
action="append",
|
|
22
|
+
default=None,
|
|
23
|
+
metavar="PATTERN",
|
|
24
|
+
help=(
|
|
25
|
+
"Only expose tools whose name matches PATTERN (fnmatch glob). "
|
|
26
|
+
"Repeatable. Example: --include 'cards_*' --include 'todos_*'."
|
|
27
|
+
),
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"--exclude",
|
|
31
|
+
action="append",
|
|
32
|
+
default=None,
|
|
33
|
+
metavar="PATTERN",
|
|
34
|
+
help="Hide tools whose name matches PATTERN. Repeatable. Applied after --include.",
|
|
35
|
+
)
|
|
36
|
+
sub = parser.add_subparsers(dest="command")
|
|
37
|
+
|
|
38
|
+
gen = sub.add_parser("generate", help="Regenerate data/tools.json from the basecamp CLI.")
|
|
39
|
+
gen.add_argument(
|
|
40
|
+
"--output",
|
|
41
|
+
type=Path,
|
|
42
|
+
default=None,
|
|
43
|
+
help="Path to write tools.json (default: in-tree data/tools.json next to this package).",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
sub.add_parser(
|
|
47
|
+
"setup",
|
|
48
|
+
help="Install the basecamp CLI (if missing) and run `basecamp setup` to authenticate.",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
args = parser.parse_args(argv)
|
|
52
|
+
|
|
53
|
+
if args.command == "generate":
|
|
54
|
+
return _generate(args.output)
|
|
55
|
+
|
|
56
|
+
if args.command == "setup":
|
|
57
|
+
from .setup_cmd import run as run_setup
|
|
58
|
+
|
|
59
|
+
return run_setup()
|
|
60
|
+
|
|
61
|
+
from . import server
|
|
62
|
+
|
|
63
|
+
asyncio.run(server.run(include=args.include, exclude=args.exclude))
|
|
64
|
+
return 0
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _generate(output: Path | None) -> int:
|
|
68
|
+
from .generator import Generator
|
|
69
|
+
|
|
70
|
+
tools = Generator().generate()
|
|
71
|
+
if output is None:
|
|
72
|
+
output = Path(str(files("basecamp_cli_mcp") / "data" / "tools.json"))
|
|
73
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
74
|
+
output.write_text(json.dumps(tools, indent=2) + "\n", encoding="utf-8")
|
|
75
|
+
print(f"Wrote {len(tools)} tools to {output}", file=sys.stderr)
|
|
76
|
+
return 0
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
raise SystemExit(main())
|