feat(hanzo-mcp): repo joins the default surface, on llm limits and typed plan refusals

This commit is contained in:
2026-10-04 16:54:10 -07:00
parent e315b45181
commit 54e7f4fa2b
6 changed files with 46 additions and 11 deletions
@@ -68,6 +68,7 @@ _PREFIX_TO_CATEGORY: dict[str, ToolCategory] = {
"find": ToolCategory.search,
"search": ToolCategory.search,
"git": ToolCategory.vcs,
"repo": ToolCategory.vcs,
"think": ToolCategory.reasoning,
"critic": ToolCategory.reasoning,
"memory": ToolCategory.memory,
@@ -34,7 +34,7 @@ PACKAGE_TOOL_PREFIXES: dict[str, list[str]] = {
"core": ["id"], # Identity axis (hash, uri, ref, verify)
"code": ["code"], # Symbols + Structure axis (parse, transform, summarize)
"shell": ["exec"], # Execution axis
"vcs": ["git"], # History + Diffs axis
"vcs": ["git", "repo"], # History + Diffs axis; repo is the Hanzo git side
"test": ["test"], # Validation axis (check, build, test)
"net": ["fetch"], # Network axis (search, fetch, download, crawl)
"plan": ["plan"], # Orchestration axis (intent, route, compose)
@@ -107,6 +107,7 @@ ESSENTIAL_TOOLS = [
"exec", # Execution (run, background, ps, kill, logs)
"code", # Symbols + Semantics (parse, search, transform, summarize)
"git", # Diffs + History
"repo", # Repositories on Hanzo git linked to GitHub (list, sync now)
"fetch", # Network (get, post, download)
"plan", # Orchestration / intent
# Knowledge persistence
@@ -117,8 +118,8 @@ ESSENTIAL_TOOLS = [
# Agent spawning
"agent",
# Models through Hanzo: completions Enso routes, the catalog with prices,
# feedback (llm); typed questions to Kai (kai_decide). Both are HTTP calls
# to api.hanzo.ai, with nothing heavy to install.
# the plan's limits, feedback (llm); typed questions to Kai (kai_decide).
# Both are HTTP calls to api.hanzo.ai, with nothing heavy to install.
"llm",
"kai_decide",
# Hanzo cloud — one tool projecting every service from the OpenAPI registry.
@@ -143,7 +144,7 @@ HEAVY_TOOLS = [
# now points at the HIP-0300 axis tool that absorbs the legacy split.
UNIX_TOOLS = ["exec"]
BUILD_TOOLS = ["exec"]
VERSION_CONTROL = ["git"]
VERSION_CONTROL = ["git", "repo"]
AI_TOOLS = ["agent", "consensus", "critic", "think", "llm"]
SEARCH_TOOLS = ["code", "fs"]
DATABASE_TOOLS = ["sql_query", "sql_search", "graph_add", "graph_query"]
@@ -77,7 +77,7 @@ class ToolListTool(BaseTool):
("vector", "Semantic search (search/index/stats/clear)"),
],
"ai": [
("llm", "Models through Hanzo: query (Enso routes), models (with prices), feedback"),
("llm", "Models through Hanzo: query (Enso routes), models (search, class, price), limits, feedback"),
("kai_decide", "Typed questions to Kai, Hanzo's decision model"),
("agent", "AI agents (run/start/call/stop/list with A2A support)"),
("swarm", "Parallel agent execution across multiple files"),
+7 -6
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "hanzo-mcp"
version = "0.15.19"
version = "0.15.20"
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"
@@ -18,8 +18,9 @@ classifiers = [
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",
# 2.2.1 is the first release shipping hanzoai.protocols (permissions.py imports it);
# 8.5.624 the first carrying hanzoai.usage, which the llm tools read refusals with
"hanzoai>=8.5.624",
# Core MCP dependencies
"mcp>=1.25.0,<2",
"fastmcp>=2.14.4",
@@ -30,7 +31,7 @@ dependencies = [
"hanzo-async>=0.1.3",
"uvloop>=0.22.1; sys_platform != 'win32'",
# Hanzo tool infrastructure (all tools)
"hanzo-tools>=0.3.8", # 0.3.8 carries extra request headers (Enso's bounds) and DEFAULT_ACTION
"hanzo-tools>=0.3.9", # 0.3.9: a cloud refusal carries its body and headers, send() returns headers
"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
@@ -43,9 +44,9 @@ dependencies = [
# 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.2.1", # 0.2.1 is llm over api.hanzo.ai (Enso) and kai_decide
"hanzo-tools-llm>=0.2.2", # 0.2.2: llm limits, searched models, served/paid-by, typed plan refusals
"hanzo-tools-code>=0.1.0",
"hanzo-tools-vcs>=0.1.0",
"hanzo-tools-vcs>=0.1.3", # 0.1.3 adds repo: repositories on Hanzo git (list, sync now)
"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
@@ -0,0 +1,32 @@
"""The cloud-backed tools ride the default surface of every mode.
A mode disables every registered tool it does not list, so a tool missing from
ESSENTIAL_TOOLS is installed and invisible. llm (completions, the catalog, the
plan's limits), kai_decide and repo (repositories on Hanzo git) are HTTP calls to
api.hanzo.ai, so every mode carries them.
"""
from hanzo_mcp.tools.common.entrypoint_loader import PACKAGE_TOOL_PREFIXES
from hanzo_mcp.tools.common.mode import ModeRegistry
from hanzo_mcp.tools.common.mode_loader import ModeLoader
from hanzo_mcp.tools.common.personality import ESSENTIAL_TOOLS
CLOUD_TOOLS = ("llm", "kai_decide", "repo")
def test_the_cloud_tools_are_essential():
assert set(CLOUD_TOOLS) <= set(ESSENTIAL_TOOLS)
assert PACKAGE_TOOL_PREFIXES["llm"] == ["llm", "kai_decide"]
assert PACKAGE_TOOL_PREFIXES["vcs"] == ["git", "repo"]
def test_every_mode_enables_them():
ModeLoader.initialize_modes()
modes = ModeRegistry.list()
assert modes
for mode in modes:
enabled = ModeLoader.get_enabled_tools_from_mode(force_mode=mode.name)
assert all(enabled.get(t) for t in CLOUD_TOOLS), (
mode.name,
{t: enabled.get(t) for t in CLOUD_TOOLS},
)