Skip to content

Commit 4b4b40f

Browse files
Merge pull request #51 from netboxlabs/feat/src-layout-and-semantic-release
feat!: restructure to src/ layout and add semantic release
2 parents 925c0d2 + 7e10b68 commit 4b4b40f

20 files changed

+401
-60
lines changed

.github/workflows/release.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Release
2+
3+
permissions:
4+
contents: write
5+
issues: write
6+
pull-requests: write
7+
8+
on:
9+
workflow_dispatch:
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
token: ${{ secrets.GITHUB_TOKEN }}
20+
21+
- name: Install uv
22+
uses: astral-sh/setup-uv@v3
23+
with:
24+
version: "latest"
25+
26+
- name: Set up Python
27+
uses: actions/setup-python@v5
28+
with:
29+
python-version: "3.13"
30+
31+
- name: Install dependencies
32+
run: uv sync
33+
34+
- name: Python Semantic Release
35+
uses: python-semantic-release/python-semantic-release@v10
36+
with:
37+
github_token: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/test.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Test
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [main]
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
12+
services:
13+
netbox:
14+
image: netboxcommunity/netbox:latest
15+
env:
16+
SKIP_SUPERUSER: true
17+
ports:
18+
- 8000:8080
19+
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- name: Install uv
24+
uses: astral-sh/setup-uv@v3
25+
with:
26+
version: "latest"
27+
28+
- name: Set up Python
29+
uses: actions/setup-python@v5
30+
with:
31+
python-version: "3.13"
32+
33+
- name: Install dependencies
34+
run: uv sync
35+
36+
- name: Run tests
37+
run: uv run pytest -v
38+
env:
39+
NETBOX_URL: http://localhost:8000
40+
NETBOX_TOKEN: ${{ secrets.NETBOX_TOKEN }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,8 @@ logs/
8585
*.bak
8686
*.swp
8787
*.swo
88+
89+
# Git worktrees
90+
.worktrees/
91+
8892
.plans/*

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ ENV PATH="/app/.venv/bin:$PATH"
3333

3434
EXPOSE 8000
3535

36-
CMD ["python", "-u", "server.py"]
36+
CMD ["netbox-mcp-server"]

README.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# NetBox MCP Server
22

3+
> **⚠️ Breaking Change in v1.0.0**: The project structure has changed.
4+
> If upgrading from v0.1.0, update your configuration:
5+
> - Change `uv run server.py` to `uv run netbox-mcp-server`
6+
> - Update Claude Desktop/Code configs to use `netbox-mcp-server` instead of `server.py`
7+
> - Docker users: rebuild images with updated CMD
8+
> - See [CHANGELOG.md](CHANGELOG.md) for full details
9+
310
This is a simple read-only [Model Context Protocol](https://modelcontextprotocol.io/) server for NetBox. It enables you to interact with your data in NetBox directly via LLMs that support MCP.
411

512
## Tools
@@ -26,7 +33,7 @@ This is a simple read-only [Model Context Protocol](https://modelcontextprotocol
2633
pip install -e .
2734
```
2835

29-
3. Verify the server can run: `NETBOX_URL=https://netbox.example.com/ NETBOX_TOKEN=<your-api-token> uv run server.py`
36+
3. Verify the server can run: `NETBOX_URL=https://netbox.example.com/ NETBOX_TOKEN=<your-api-token> uv run netbox-mcp-server`
3037

3138
4. Add the MCP server to your LLM client. See below for some examples with Claude.
3239

@@ -40,7 +47,7 @@ Add the server using the `claude mcp add` command:
4047
claude mcp add --transport stdio netbox \
4148
--env NETBOX_URL=https://netbox.example.com/ \
4249
--env NETBOX_TOKEN=<your-api-token> \
43-
-- uv --directory /path/to/netbox-mcp-server run server.py
50+
-- uv --directory /path/to/netbox-mcp-server run netbox-mcp-server
4451
```
4552

4653
**Important notes:**
@@ -61,7 +68,7 @@ For HTTP transport, first start the server manually:
6168
NETBOX_URL=https://netbox.example.com/ \
6269
NETBOX_TOKEN=<your-api-token> \
6370
TRANSPORT=http \
64-
uv run server.py
71+
uv run netbox-mcp-server
6572
```
6673

6774
Then add the running server to Claude Code:
@@ -91,7 +98,7 @@ Add the server configuration to your Claude Desktop config file. On Mac, edit `~
9198
"--directory",
9299
"/path/to/netbox-mcp-server",
93100
"run",
94-
"server.py"
101+
"netbox-mcp-server"
95102
],
96103
"env": {
97104
"NETBOX_URL": "https://netbox.example.com/",
@@ -176,7 +183,7 @@ For local Claude Desktop or Claude Code usage with stdio transport:
176183
"mcpServers": {
177184
"netbox": {
178185
"command": "uv",
179-
"args": ["--directory", "/path/to/netbox-mcp-server", "run", "server.py"],
186+
"args": ["--directory", "/path/to/netbox-mcp-server", "run", "netbox-mcp-server"],
180187
"env": {
181188
"NETBOX_URL": "https://netbox.example.com/",
182189
"NETBOX_TOKEN": "<your-api-token>"
@@ -198,10 +205,10 @@ export TRANSPORT=http
198205
export HOST=127.0.0.1
199206
export PORT=8000
200207

201-
uv run server.py
208+
uv run netbox-mcp-server
202209

203210
# Or using CLI arguments
204-
uv run server.py \
211+
uv run netbox-mcp-server \
205212
--netbox-url https://netbox.example.com/ \
206213
--netbox-token <your-api-token> \
207214
--transport http \
@@ -237,11 +244,11 @@ LOG_LEVEL=INFO
237244
All configuration options can be overridden via CLI arguments:
238245

239246
```bash
240-
uv run server.py --help
247+
uv run netbox-mcp-server --help
241248

242249
# Common examples:
243-
uv run server.py --log-level DEBUG --no-verify-ssl # Development
244-
uv run server.py --transport http --port 9000 # Custom HTTP port
250+
uv run netbox-mcp-server --log-level DEBUG --no-verify-ssl # Development
251+
uv run netbox-mcp-server --transport http --port 9000 # Custom HTTP port
245252
```
246253

247254
## Docker Usage

claude.md

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,20 @@ A read-only [Model Context Protocol](https://modelcontextprotocol.io/) server th
1818

1919
```text
2020
.
21-
├── server.py # Main MCP server with tool definitions
22-
├── netbox_client.py # NetBox REST API client abstraction
23-
├── pyproject.toml # Dependencies and project metadata
24-
├── README.md # User-facing documentation
25-
├── SECURITY.md # Security policy and reporting
26-
└── LICENSE # Apache 2.0 license
21+
├── src/
22+
│ └── netbox_mcp_server/
23+
│ ├── __init__.py # Package initialization with __version__
24+
│ ├── __main__.py # Entry point for module execution
25+
│ ├── server.py # Main MCP server with tool definitions
26+
│ ├── netbox_client.py # NetBox REST API client abstraction
27+
│ ├── netbox_types.py # NetBox object type mappings
28+
│ └── config.py # Settings and logging configuration
29+
├── tests/ # Test suite
30+
├── .github/workflows/ # CI/CD automation
31+
├── pyproject.toml # Dependencies and project metadata
32+
├── README.md # User-facing documentation
33+
├── CHANGELOG.md # Auto-generated release notes
34+
└── LICENSE # Apache 2.0 license
2735
```
2836

2937
**Design Pattern**: Clean separation between MCP server logic (`server.py`) and NetBox API client (`netbox_client.py`) to support future plugin-based implementations.
@@ -35,13 +43,16 @@ A read-only [Model Context Protocol](https://modelcontextprotocol.io/) server th
3543
uv sync
3644

3745
# Run the server locally (requires env vars)
38-
NETBOX_URL=https://netbox.example.com/ NETBOX_TOKEN=<token> uv run server.py
46+
NETBOX_URL=https://netbox.example.com/ NETBOX_TOKEN=<token> uv run netbox-mcp-server
47+
48+
# Alternative: module execution
49+
uv run -m netbox_mcp_server
3950

4051
# Add to Claude Code (for development/testing)
4152
claude mcp add --transport stdio netbox \
4253
--env NETBOX_URL=https://netbox.example.com/ \
4354
--env NETBOX_TOKEN=<token> \
44-
-- uv --directory /path/to/netbox-mcp-server run server.py
55+
-- uv --directory /path/to/netbox-mcp-server run netbox-mcp-server
4556
```
4657

4758
## Development Philosophy
@@ -57,6 +68,23 @@ claude mcp add --transport stdio netbox \
5768
- **Functional where clear**: Use functional, stateless approaches when they improve clarity
5869
- **Clean core logic**: Keep business logic clean; push implementation details to the edges
5970

71+
## Version Management
72+
73+
This project uses [python-semantic-release](https://python-semantic-release.readthedocs.io/) for automated version management. Versions are automatically determined from commit messages following [Conventional Commits](https://www.conventionalcommits.org/).
74+
75+
**Release triggers:**
76+
77+
- `feat:` commits trigger minor version bumps (1.0.0 → 1.1.0)
78+
- `fix:` and `perf:` commits trigger patch version bumps (1.0.0 → 1.0.1)
79+
- Commits with `BREAKING CHANGE:` in the body trigger major version bumps (1.0.0 → 2.0.0)
80+
- `docs:`, `test:`, `chore:`, `ci:`, `refactor:` commits are logged but don't trigger releases
81+
82+
**Workflow:**
83+
84+
- Merge to `main` automatically triggers release analysis
85+
- If commits warrant a release, version is bumped and CHANGELOG updated
86+
- GitHub Release is created with auto-generated release notes
87+
6088
## Code Standards
6189

6290
### Python Conventions
@@ -260,7 +288,6 @@ Currently no automated test suite. When adding tests:
260288
-**NEVER commit directly to `main`** - Always use feature branches
261289
-**DO keep commits professional and concise** and focused on the change
262290

263-
264291
## Decision Heuristics
265292

266293
### When to Add a New Tool

pyproject.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
15
[project]
26
name = "netbox-mcp-server"
37
version = "0.1.0"
@@ -12,8 +16,28 @@ dependencies = [
1216
"pydantic-settings>=2.0",
1317
]
1418

19+
[project.scripts]
20+
netbox-mcp-server = "netbox_mcp_server.server:main"
21+
1522
[dependency-groups]
1623
dev = [
1724
"pytest>=8.4.2",
1825
"pytest-cov>=7.0.0",
26+
"python-semantic-release>=10.4.1",
1927
]
28+
29+
[tool.semantic_release]
30+
version_toml = ["pyproject.toml:project.version"]
31+
version_variables = ["src/netbox_mcp_server/__init__.py:__version__"]
32+
branch = "main"
33+
upload_to_vcs_release = true
34+
build_command = "uv build"
35+
tag_format = "v{version}"
36+
37+
[tool.semantic_release.commit_parser_options]
38+
allowed_tags = ["feat", "fix", "docs", "chore", "refactor", "test", "ci", "perf"]
39+
minor_tags = ["feat"]
40+
patch_tags = ["fix", "perf"]
41+
42+
[tool.semantic_release.changelog]
43+
changelog_file = "CHANGELOG.md"

src/netbox_mcp_server/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""NetBox MCP Server - Read-only MCP server for NetBox infrastructure data."""
2+
3+
__version__ = "0.1.0" # Auto-managed by semantic-release
4+
5+
__all__ = ["NetBoxRestClient", "NETBOX_OBJECT_TYPES", "Settings"]
6+
7+
from netbox_mcp_server.netbox_client import NetBoxRestClient
8+
from netbox_mcp_server.netbox_types import NETBOX_OBJECT_TYPES
9+
from netbox_mcp_server.config import Settings

src/netbox_mcp_server/__main__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Entry point for python -m netbox_mcp_server execution."""
2+
3+
from netbox_mcp_server.server import main
4+
5+
if __name__ == "__main__":
6+
main()
File renamed without changes.

0 commit comments

Comments
 (0)