Here's the PR summary:
---
## Enforce semver validation for `MCPApp` versioning
### Problem
`MCPApp.__init__` accepted any string as `version` with no validation.
Invalid versions like `"1.0.0dev"` or `"latest"` silently propagated to
the Engine, where `compareToolVersions` fell back to lexicographic
`strings.Compare` instead of `semver.Compare` — causing incorrect
ordering (e.g. `1.10.0 < 1.9.0`).
### Solution
Validate and normalize `version` at `MCPApp` instantiation time using
the same acceptance rules as Go's `golang.org/x/mod/semver v0.31.0` (the
exact version used by the Engine).
### Changes
**`arcade_mcp_server/_validation.py`** (new file)
- Shared regex constants: `SEMVER_PATTERN` (semver.org spec),
`SHORT_VERSION_PATTERN`, `MAJOR_ONLY_PATTERN`
**`arcade_mcp_server/mcp_app.py`**
- Added `_validate_version()` mirroring the existing `_validate_name()`
pattern
- Added `version` property + setter (validates on mutation too)
- `__init__` now stores `self._version` via `_validate_version()`
**`arcade_mcp_server/settings.py`**
- Added `@field_validator("version")` on `ServerSettings` — covers the
`MCP_SERVER_VERSION` env var path
- Fixed default from `"0.1.0dev"` → `"0.1.0"` (the old default was
itself invalid)
**`pyproject.toml`** — bumped `arcade-mcp-server` `1.17.4` → `1.17.5`
### Normalization pipeline
All inputs are normalized to canonical `MAJOR.MINOR.PATCH` before
storage:
| Input | Stored as |
|-------|-----------|
| `v1.0.0` | `1.0.0` |
| `1.0` / `v1.0` | `1.0.0` |
| `1` / `v1` | `1.0.0` |
### Verification
Validated against `golang.org/x/mod/semver v0.31.0` (Engine's exact
pinned version) — 40/40 accept/reject cases match. The Engine's own
`store_test.go` uses `"1.0"` and `"1.1"` as `ToolkitVersion` values,
confirming short forms are intentionally supported.
### Breaking change
Any user currently passing a non-semver version string (e.g.
`"1.0.0dev"`, `"latest"`) will get a `ValueError` on upgrade. This is
intentional — those versions were silently causing incorrect tool
ordering in the Engine.
Closes TOO-518
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Introduces stricter version validation/normalization that will raise
errors for previously-accepted non-semver inputs (including via env
vars), which may break existing consumers depending on lax version
strings.
>
> **Overview**
> **Enforces semver for server versioning** across both `MCPApp` and
`ServerSettings`, rejecting invalid strings and normalizing accepted
inputs (e.g., stripping leading `v`, expanding `1`/`1.2` to
`1.0.0`/`1.2.0`).
>
> Adds shared `normalize_version` logic in
`arcade_mcp_server/_validation.py`, updates `MCPApp` to validate on init
and via a new `version` property/setter, and adds a Pydantic `version`
validator so `MCP_SERVER_VERSION` is checked. Defaults are updated from
`0.1.0dev` to `0.1.0`, tests are expanded to cover accept/reject cases,
and the package version is bumped to `1.17.5`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
2ceabacb25372e67eef9720b901c1ee2b214868f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Eric Gustin <34000337+EricGustin@users.noreply.github.com>
45 lines
1.3 KiB
TOML
45 lines
1.3 KiB
TOML
[build-system]
|
|
requires = ["hatchling>=1.25"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[project]
|
|
name = "arcade-mcp-server"
|
|
version = "1.17.5"
|
|
description = "Model Context Protocol (MCP) server framework for Arcade.dev"
|
|
readme = "README.md"
|
|
authors = [{ name = "Arcade.dev" }]
|
|
license = { text = "MIT" }
|
|
classifiers = [
|
|
"Development Status :: 5 - Production/Stable",
|
|
"Intended Audience :: Developers",
|
|
"License :: OSI Approved :: MIT License",
|
|
"Programming Language :: Python :: 3",
|
|
"Programming Language :: Python :: 3.10",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Programming Language :: Python :: 3.13",
|
|
]
|
|
requires-python = ">=3.10"
|
|
dependencies = [
|
|
"arcade-core>=4.4.2,<5.0.0",
|
|
"arcade-serve>=3.2.0,<4.0.0",
|
|
"arcade-tdk>=3.6.0,<4.0.0",
|
|
"arcadepy>=1.5.0",
|
|
"pydantic>=2.0.0",
|
|
"fastapi>=0.100.0",
|
|
"uvicorn>=0.30.0",
|
|
"watchfiles>=0.18.0", # included with uvicorn, but listed to be explicit
|
|
"sse-starlette>=2.0.0",
|
|
"starlette>=0.37.0",
|
|
"anyio>=4.0.0",
|
|
"python-dotenv>=1.0.0",
|
|
"pydantic-settings>=2.10.1",
|
|
"joserfc>=1.5.0",
|
|
"httpx>=0.27.0,<1.0.0",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
dev = ["pytest>=8.0.0", "pytest-asyncio>=0.23.0", "mypy>=1.0.0", "ruff>=0.1.0"]
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["arcade_mcp_server"]
|