Files
python-sdk/pkg/hanzo-mcp/pyproject.toml
zeekay eab5541a89 Stop handing a model the secrets the fleet withholds
Nine per-service packages registered a hanzo.tools entry point and sat in
hanzo-mcp's default dependencies, so installing it put them in a model's tool
list beside the unified tool and without its filter.

hanzo-tools-kms offered inject, which lists a path and reads every secret at it.
hanzo-tools-iam offered create_user, delete_user and the token and session reads.
cloud withholds all of them from an agent; these were a second way to the same
API, so the rule held on one path and not the other.

The auto-registration is withdrawn, not the packages: they stay importable for a
human at a CLI, which is where reading a secret is a legitimate act. An agent
reaches all eight through the unified tool, verified against the live document.

mpc keeps its registration because the fleet has no equivalent, and auth keeps
its because it reads the caller's own claims rather than another identity's.
2026-08-30 20:08:02 -07:00

263 lines
7.6 KiB
TOML

[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "hanzo-mcp"
version = "0.15.16"
description = "The Zen of Hanzo MCP: One server to rule them all. The ultimate MCP that orchestrates all others."
readme = "README.md"
requires-python = ">=3.12"
license = { text = "MIT" }
authors = [{ name = "Hanzo Industries Inc", email = "[email protected]" }]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
keywords = ["mcp", "claude", "hanzo", "code", "agent"]
dependencies = [
# Hanzo AI core SDK (canonical types, config, session, MCP client)
# 2.2.1 is the first release shipping hanzoai.protocols (permissions.py imports it)
"hanzoai>=2.2.1",
# Core MCP dependencies
"mcp>=1.25.0",
"fastmcp>=2.14.4",
"pydantic>=2.12.5",
"pydantic-settings>=2.12.0",
"typing-extensions>=4.13.0",
# Unified async I/O (aiofiles + uvloop auto-installed on Linux/macOS, graceful fallback)
"hanzo-async>=0.1.3",
"uvloop>=0.22.1; sys_platform != 'win32'",
# Hanzo tool infrastructure (all tools)
"hanzo-tools>=0.3.6", # 0.3.6 carries capture(): downscaled inline, full-res on disk
"hanzo-tools-fs>=0.3.4", # 0.3.4 returns image files as native MCP ImageContent
"hanzo-tools-shell>=0.6.5", # 0.6.5 pairs with hanzo-tools>=0.3.0 (ToolError)
"hanzo-tools-core>=0.3.1", # 0.3.1 is the EMPTY shim — no longer shadows canonical hanzo-tools.core
"hanzo-tools-browser[playwright]>=0.5.11", # 0.5.11 screenshots downscale before they reach the wire
"hanzo-tools-memory>=0.2.0",
"hanzo-tools-todo>=0.1.0",
"hanzo-tools-reasoning>=0.1.0",
"hanzo-tools-lsp>=0.1.0",
"hanzo-tools-computer>=0.5.5", # 0.5.5 screenshots downscale before they reach the wire
# 0.2.1 fixes ConfigTool passing permission_manager positionally into BaseTool.__init__
"hanzo-tools-config>=0.2.1",
"hanzo-tools-refactor>=0.1.0",
"hanzo-tools-llm>=0.1.0",
"hanzo-tools-code>=0.1.0",
"hanzo-tools-vcs>=0.1.0",
"hanzo-tools-net>=0.1.0",
"hanzo-tools-agent>=0.3.1",
"hanzo-tools-api>=0.3.2", # 0.3.2 is the unified `hanzo` tool projected from cloud's OpenAPI registry
# The fleet is reached through the unified `hanzo` tool (hanzo-tools-api),
# which offers what cloud offers an AGENT — it withholds an operation whose
# name discloses a bearer secret, or whose mutating verb acts on identity or
# authority. The per-service packages that used to be installed here carried
# no such filter: hanzo-tools-kms handed a model `inject`, which reads every
# secret at a path, and hanzo-tools-iam handed it create_user/delete_user and
# the token and session reads. They remain installable for a human at a CLI.
"hanzo-tools-auth>=0.1.0",
"hanzo-tools-mpc>=0.1.0",
"hanzo-tools-ui>=0.1.0",
"hanzo-persona>=1.0.0",
]
# For local development, install hanzo-tools-* packages from pkg/
# pip install -e ../hanzo-tools ../hanzo-tools-fs etc.
# Or when published, add them back as dependencies
[project.urls]
"Homepage" = "https://github.com/hanzoai/mcp"
"Bug Tracker" = "https://github.com/hanzoai/mcp/issues"
"Documentation" = "https://mcp.hanzo.ai"
[project.optional-dependencies]
# NOTE: hanzo-tools-* packages are installed separately from pkg/
# Use: pip install -e ../hanzo-tools -e ../hanzo-tools-fs etc.
# When published to PyPI, these extras will work:
# filesystem = ["hanzo-tools-fs>=0.1.0"]
# shell = ["hanzo-tools-shell>=0.1.0"]
# etc.
# Memory tools with full backend support
memory = [
"hanzo-tools-memory[full]>=0.2.2",
"sqlite-vec>=0.1.0",
"fastembed>=0.4.0",
]
# Interactive REPL with multi-language Jupyter kernels
repl = [
"hanzo-tools-repl>=0.1.0",
"jupyter-client>=8.6.0",
"ipykernel>=6.29.0",
]
# IDE integration (VS Code, Cursor, JetBrains)
ide = [
"hanzo-tools-ide>=0.1.0",
]
# Full interactive suite (REPL + IDE + Browser)
interactive = [
"hanzo-mcp[repl,ide]",
"hanzo-tools-browser>=0.2.1",
]
# Development
dev = [
"watchdog>=3.0.0",
"pytest>=7.0.0",
"pytest-cov>=4.1.0",
"ruff>=0.14.0",
"black>=23.3.0",
"mypy>=1.10.0",
"types-aiofiles>=23.2.0",
"types-psutil>=5.9.5",
"types-setuptools>=69.5.0",
]
docs = ["sphinx>=8.0.0", "sphinx-rtd-theme>=3.0.0", "myst-parser>=4.0.0", "sphinx-copybutton>=0.5.0"]
test = [
"pytest>=7.0.0",
"pytest-cov>=4.1.0",
"pytest-mock>=3.10.0",
"pytest-asyncio>=0.26.0,<1.0.0",
]
performance = [
"ujson>=5.7.0",
"orjson>=3.9.0",
]
publish = ["twine>=4.0.2", "build>=1.0.3"]
[project.scripts]
hanzo-mcp = "hanzo_mcp.cli:main"
hanzo-mcp-dev = "hanzo_mcp.dev_server:run_dev_server"
[tool.setuptools.packages.find]
where = ["."]
include = ["hanzo_mcp*"]
[tool.setuptools.package-data]
hanzo_mcp = ["py.typed"]
[tool.basedpyright]
include = ["hanzo_mcp"]
[tool.pytest.ini_options]
# Configuration for pytest
addopts = "--no-header --no-summary -p asyncio"
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
# Note: --cov-fail-under=96.3 will be added after achieving target coverage
markers = [
"asyncio: mark test as using asyncio",
"requires_hanzo_agents: mark test as requiring hanzo-agents SDK",
"requires_memory_tools: mark test as requiring hanzo-memory package",
"slow: mark test as slow running",
"integration: mark test as integration test",
]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
[tool.pytest_asyncio]
mode = "auto"
default_loop_scope = "function"
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_any_generics = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
show_error_codes = true
show_column_numbers = true
pretty = true
# Per-module options
[[tool.mypy.overrides]]
module = [
"bashlex.*",
"grep_ast.*",
"libtmux.*",
"llm.*",
"nbformat.*",
"ffind.*",
"fastmcp.*",
"mcp.*",
"hanzo_agents.*",
"hanzo_memory.*",
"personalities.*",
]
ignore_missing_imports = true
[tool.coverage.run]
source = ["hanzo_mcp"]
omit = [
"*/tests/*",
"*/__pycache__/*",
"*/site-packages/*",
"*/venv/*",
"*/migrations/*",
]
[tool.coverage.report]
precision = 2
show_missing = true
skip_covered = false
fail_under = 96.3
exclude_lines = [
"pragma: no cover",
"def __repr__",
"if self.debug:",
"if __name__ == .__main__.:",
"raise AssertionError",
"raise NotImplementedError",
"if TYPE_CHECKING:",
"@abstractmethod",
]
[tool.coverage.html]
directory = "htmlcov"
[tool.ruff]
exclude = [
".git",
".venv",
"venv",
"__pycache__",
"build",
"dist",
"*.egg-info",
"node_modules",
"vscode-extension",
]
[tool.ruff.lint]
select = ["E", "F", "I", "B"]
ignore = [
"E501", # Line too long
"B017", # Blind exception test
"B023", # Function definition loop variable
"B904", # Raise without from in except
"E741", # Ambiguous variable name
"E402", # Module level import not at top
"F401", # Unused imports (handled by tests themselves)
"F821", # Undefined name (tests may have conditional imports)
"F841", # Local variable assigned but never used
"B007", # Loop control variable not used
]
[tool.ruff.lint.per-file-ignores]
"tests/*" = ["F401", "F821", "F841", "B007"] # Relax rules for test files
"*/__init__.py" = ["F401"] # Allow unused imports in __init__.py