Rename packages for PyPI: winegard-birdcage + mcbirdcage
Core library published as winegard-birdcage (import stays `birdcage`). MCP server renamed birdcage-mcp → mcbirdcage, matching mcserial pattern. Both packages live on PyPI — `uvx mcbirdcage` works out of the box.
This commit is contained in:
parent
b98a5482fa
commit
5a26dce075
20 changed files with 122 additions and 92 deletions
|
|
@ -3,22 +3,33 @@ requires = ["hatchling"]
|
|||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "birdcage-mcp"
|
||||
name = "mcbirdcage"
|
||||
version = "2026.02.17"
|
||||
description = "FastMCP server for Winegard satellite dish control"
|
||||
description = "MCP server for Winegard satellite dish control via serial"
|
||||
license = "MIT"
|
||||
requires-python = ">=3.11"
|
||||
authors = [{name = "Ryan Malloy", email = "ryan@supported.systems"}]
|
||||
keywords = ["mcp", "satellite", "antenna", "winegard", "amateur-radio"]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Science/Research",
|
||||
"Topic :: Scientific/Engineering",
|
||||
"Topic :: Communications :: Ham Radio",
|
||||
]
|
||||
dependencies = [
|
||||
"birdcage",
|
||||
"winegard-birdcage",
|
||||
"fastmcp>=2.0",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://git.supported.systems/warehack.ing/birdcage"
|
||||
Documentation = "https://birdcage.warehack.ing"
|
||||
|
||||
[project.scripts]
|
||||
birdcage-mcp = "birdcage_mcp.server:main"
|
||||
mcbirdcage = "mcbirdcage.server:main"
|
||||
|
||||
[tool.uv.sources]
|
||||
birdcage = { path = "..", editable = true }
|
||||
winegard-birdcage = { path = "..", editable = true }
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py311"
|
||||
|
|
@ -28,7 +39,7 @@ src = ["src"]
|
|||
select = ["E", "F", "I", "UP", "B", "SIM"]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/birdcage_mcp"]
|
||||
packages = ["src/mcbirdcage"]
|
||||
|
||||
[dependency-groups]
|
||||
dev = ["pytest>=9.0.2", "pytest-asyncio>=1.3.0"]
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
"""birdcage-mcp: FastMCP server for Winegard satellite dish control."""
|
||||
1
mcp/src/mcbirdcage/__init__.py
Normal file
1
mcp/src/mcbirdcage/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
"""mcbirdcage: MCP server for Winegard satellite dish control via serial."""
|
||||
|
|
@ -7,7 +7,7 @@ from contextlib import asynccontextmanager
|
|||
|
||||
from fastmcp import FastMCP
|
||||
|
||||
from birdcage_mcp.state import BirdcageState
|
||||
from mcbirdcage.state import BirdcageState
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -67,8 +67,8 @@ mcp = FastMCP(
|
|||
)
|
||||
|
||||
# Register tool modules
|
||||
from birdcage_mcp import prompts, resources # noqa: E402, F401
|
||||
from birdcage_mcp.tools import ( # noqa: E402
|
||||
from mcbirdcage import prompts, resources # noqa: E402, F401
|
||||
from mcbirdcage.tools import ( # noqa: E402
|
||||
connection,
|
||||
console,
|
||||
movement,
|
||||
|
|
@ -88,5 +88,5 @@ prompts.register(mcp)
|
|||
|
||||
|
||||
def main():
|
||||
print("birdcage-mcp v2026.02.17", file=sys.stderr)
|
||||
print("mcbirdcage v2026.02.17", file=sys.stderr)
|
||||
mcp.run()
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from fastmcp import Context
|
||||
|
||||
from birdcage_mcp.state import BirdcageState
|
||||
from mcbirdcage.state import BirdcageState
|
||||
|
||||
|
||||
def register(mcp):
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from fastmcp import Context
|
||||
|
||||
from birdcage_mcp.state import BirdcageState
|
||||
from mcbirdcage.state import BirdcageState
|
||||
|
||||
# Commands that are dangerous at the root menu level.
|
||||
_BLOCKED_ROOT_COMMANDS = {"q"}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from fastmcp import Context
|
||||
|
||||
from birdcage_mcp.state import BirdcageState
|
||||
from mcbirdcage.state import BirdcageState
|
||||
|
||||
|
||||
def _require_device(state: BirdcageState):
|
||||
|
|
@ -4,7 +4,7 @@ from dataclasses import asdict
|
|||
|
||||
from fastmcp import Context
|
||||
|
||||
from birdcage_mcp.state import BirdcageState
|
||||
from mcbirdcage.state import BirdcageState
|
||||
|
||||
|
||||
def _require_craft(state: BirdcageState):
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from fastmcp import Context
|
||||
|
||||
from birdcage_mcp.state import BirdcageState
|
||||
from mcbirdcage.state import BirdcageState
|
||||
|
||||
|
||||
def _require_device(state: BirdcageState):
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from fastmcp import Context
|
||||
|
||||
from birdcage_mcp.state import BirdcageState
|
||||
from mcbirdcage.state import BirdcageState
|
||||
|
||||
|
||||
def _require_device(state: BirdcageState):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
"""Shared fixtures for birdcage-mcp tests.
|
||||
"""Shared fixtures for mcbirdcage tests.
|
||||
|
||||
Uses FastMCP's run_server_async to spin up a real MCP server backed by
|
||||
DemoDevice + DemoCraftClient. No serial hardware, no subprocesses.
|
||||
|
|
@ -13,7 +13,7 @@ from fastmcp import Client, FastMCP
|
|||
from fastmcp.client.transports import StreamableHttpTransport
|
||||
from fastmcp.utilities.tests import run_server_async
|
||||
|
||||
from birdcage_mcp.state import BirdcageState
|
||||
from mcbirdcage.state import BirdcageState
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
|
|
@ -36,8 +36,8 @@ async def _test_lifespan(server: FastMCP):
|
|||
|
||||
def _build_server() -> FastMCP:
|
||||
"""Build a FastMCP server with all tools registered."""
|
||||
from birdcage_mcp import prompts, resources
|
||||
from birdcage_mcp.tools import (
|
||||
from mcbirdcage import prompts, resources
|
||||
from mcbirdcage.tools import (
|
||||
connection,
|
||||
console,
|
||||
movement,
|
||||
|
|
|
|||
84
mcp/uv.lock
generated
84
mcp/uv.lock
generated
|
|
@ -81,48 +81,6 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl", hash = "sha256:d16c9bbc61ea14637596c5f6fbff2ee99cbe3573e46a716401734ef50c3060c2", size = 1333658, upload-time = "2025-12-13T06:50:28.266Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "birdcage"
|
||||
version = "2026.2.12.1"
|
||||
source = { editable = "../" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "pyserial" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "click", specifier = ">=8.0" },
|
||||
{ name = "pyserial", specifier = ">=3.5" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "birdcage-mcp"
|
||||
version = "2026.2.17"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "birdcage" },
|
||||
{ name = "fastmcp" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "birdcage", editable = "../" },
|
||||
{ name = "fastmcp", specifier = ">=2.0" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "pytest", specifier = ">=9.0.2" },
|
||||
{ name = "pytest-asyncio", specifier = ">=1.3.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cachetools"
|
||||
version = "7.0.1"
|
||||
|
|
@ -774,6 +732,33 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mcbirdcage"
|
||||
version = "2026.2.17"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "fastmcp" },
|
||||
{ name = "winegard-birdcage" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "fastmcp", specifier = ">=2.0" },
|
||||
{ name = "winegard-birdcage", editable = "../" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "pytest", specifier = ">=9.0.2" },
|
||||
{ name = "pytest-asyncio", specifier = ">=1.3.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mcp"
|
||||
version = "1.26.0"
|
||||
|
|
@ -1668,6 +1653,21 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winegard-birdcage"
|
||||
version = "2026.2.17"
|
||||
source = { editable = "../" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "pyserial" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "click", specifier = ">=8.0" },
|
||||
{ name = "pyserial", specifier = ">=3.5" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.23.0"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue