234 Commits
Author SHA1 Message Date
zeekay 7374804405 hanzo-mcp 0.15.21: the active mode is the whole manifest, and a flood of output has a ceiling
The default surface was 34 tools, 61 KB, ~15,300 tokens of schema in every
prompt of every agent. The mode system already names what a session should
carry, but only the tools register_all_tools enumerates obeyed it: zsh,
curl, playwright and the helpers (ps, npx, uvx, jq, wget, cdp, open) stayed
on in every mode. A mode now decides every discovered tool, the `hanzo`
mode lists what a coding agent calls every few steps (18 tools, 32 KB,
~8,000 tokens), and the rest is a name away: HANZO_MCP_ENABLED_TOOLS=a,b
or =all, `tool enable`, or `mode`.

hanzo-tools-shell 0.6.6: run_shell kept every byte a foreground command
wrote until the command ended. `yes` for thirty seconds is gigabytes. It
keeps the first 16 MiB per stream and drains the rest.

The tests' session-wide patch of asyncio.create_subprocess_exec handed
every shell command a stream that never reached EOF; the first test to run
one read it in a loop until the machine was out of memory (22 GB, killed).
The patch is now opt-in and its process has exited.

bench/latency.py measures the cold start, the tools/list bill and the common
calls through a real MCP client over stdio. Interleaved rounds, wall and CPU
seconds, p50 over 6 cold starts:

                         cold wall  cold CPU  tools  bytes   ~tokens
  installed 0.15.18      9.34 s     10.46 s   30     52,601  13,150
  main 0.15.20           1.52 s      1.13 s   34     61,287  15,321
  this                   0.96 s      1.06 s   18     32,222   8,055

The installed environment's 9 s is its hanzoai 8.5.156, whose package init
imports the whole generated cloud client; hanzo-mcp >= 0.15.20 requires
hanzoai >= 8.5.624, which loads it lazily. Per-call latency is spawn-bound
(zsh 17.6 ms, git status 33 ms, fs.read 2.5 ms at p50) and moves with the
machine's load; no call path changed.
2026-10-12 08:47:57 -07:00
zeekay 54e7f4fa2b feat(hanzo-mcp): repo joins the default surface, on llm limits and typed plan refusals 2026-10-04 16:54:10 -07:00
zooqueenandHanzo Dev 5c0cc67e39 Put llm and kai_decide on the default hanzo-mcp surface
Every mode disables a registered tool it does not list, and llm was
listed nowhere but HEAVY_TOOLS, written when it pulled a 100 MB client.
It is an HTTP call to api.hanzo.ai now, so llm and kai_decide join the
essential set every personality carries, and the llm package maps to the
two tools it ships.

hanzo-mcp 0.15.19, on hanzo-tools 0.3.8 and hanzo-tools-llm 0.2.1.

Co-authored-by: Hanzo Dev <[email protected]>
2026-10-04 13:55:32 -07:00
zeekay ad606c7611 The browser tool takes a seat on the embedded ZAP router
hanzo-mcp said HELLO as consumer:hanzo-mcp/<pid> to a separate zapd
daemon, which the router that replaced it refuses as bad_id. Every
process that speaks ZAP now embeds the router (zapd 1.1 on PyPI) and the
kernel lock elects one; hanzo-mcp stands for it at startup and takes the
seat mcp/hanzo-<pid>. A browser is a browser/<host>/<name> node, found
by engine or name and reached with Node.call, and the extension's
command codec is unchanged.

hanzo-mcp pair prints the code the extension's popup takes. The daemon
spawn and socket probing are gone, and so is the zap-proto dependency.
2026-09-30 06:56:52 -07:00
zeekay 82a090d0ba hanzo-tools and hanzo-mcp stay on mcp 1.x
hanzo_tools.core imports mcp.server.FastMCP, which mcp 2 removed, so a
fresh resolve that picks mcp 2.2.0 fails at import. The published
hanzo-mcp 0.15.17 already declares mcp<2; the tree now says the same,
and hanzo-tools, which owns the import, says it too.

Claude-Session: https://claude.ai/code/session_01Dc8DXc3fEQCRHUa6XWK4Ku
2026-09-29 12:41:52 -07:00
zeekay af78255a39 devserver: running dev servers as MCP nodes
An agent editing a web app needs the dev server's own view of it: which
routes exist, and whether the last edit broke the build. Next 16 serves
that over MCP at /_next/mcp, and Vite-based frameworks can with
vite-plugin-mcp, but nothing here found those endpoints.

index finds Next, Vite, Nuxt, Remix, React Router, Astro and SvelteKit
dev servers from each process's argv, cwd and listening ports, and lists
the tools of the MCP each serves. call runs one. errors returns current
build and runtime errors: Next's get_errors, after opening the app in the
browser tool, since Next reports only what a connected session reported;
otherwise Vite's error overlay, console errors and page errors, read
through the same browser tool.

discover() returns the servers as plain records, the shape a devserver
node will take. hanzo-mcp depends on the package so the tool ships.

Claude-Session: https://claude.ai/code/session_01Dc8DXc3fEQCRHUa6XWK4Ku
2026-09-29 12:37:53 -07:00
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
zeekay 90e00d9bb7 State a version once
A version written into a manifest is written into every manifest that wants it,
which is how eslint came to exist in a hundred and four forms across this estate
and how a package came to resolve twice at run time. The catalog moves the number
out of the manifest: a manifest names the package, the workspace names the
version.

Four are held below their latest because the newer release cannot be used, and
the reason is recorded rather than the version alone: @noble/hashes 2 renamed
every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package
that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels
3 points its types condition at the bundle.
2026-08-29 13:46:58 -07:00
zeekay 4662534cd9 Regenerate: the AI surface says what it answers
288 of hanzoai/ai's 294 operations now declare a response, against 1 before.
GET /v1/models, POST /v1/chat/completions, /v1/embeddings, /v1/messages —
every address a client actually calls — used to reach this client untyped,
because cloud's relay carried an operation's sentence and dropped the shapes
it named. It carries both now.

Fleet-wide the document goes from 69% to 81% of operations declaring what
comes back, which is where the ~208 new models here come from.
2026-08-28 15:53:34 -07:00
zeekay 369b525882 fix(tools): a screenshot arrives downscaled, with the full capture on disk 2026-08-27 08:45:44 -07:00
zeekay 02f2ec2014 hanzo-mcp: the README documents the server that exists
The quickstart called create_mcp_server, server.register_*_tools and
server.tools.read — no such names. The real surface is the hanzo-mcp
command, its flags, and HanzoMCPServer; the tools come from whichever
hanzo-tools-* packages are installed, through the hanzo.tools entry
point. Verified against --version, --help and the constructor.

Drop the three *_COMPLETE.md status reports, MODULAR_ARCHITECTURE.md
(a proposal), COMPREHENSIVE_DOCUMENTATION.md (claims 70+ tools over a
package with seven) and SEARCH_GUIDE.md (documents an ffind tool that
does not exist).

SECURITY_PATCH.md named files and lines for three findings in 0.8.13;
all three are addressed in 0.15.15 — the shell escaper it flagged is
gone with its module, permissions.py refuses .. and ~ before resolving,
and the third asked for a token the server minted, persisted to
~/.hanzo/mcp_token and never once checked. That token is gone too: auth
is IAM's, and a credential nothing verifies reads as a gate that is not
there.
2026-08-23 12:31:08 -07:00
zooqueen 95cf0799f9 the browser transport is the zapd consumer, and only that
hanzo_mcp.zap_server imported hanzo_tools.browser.zap_server, which does not
exist — the module could not be imported at all. Its caller swallowed that in
`except ImportError: return`, so _start_zap_server() ran on every `run()` and
started nothing, and the HANZO_NO_ZAP switch guarded a path that never had an
effect either way.

The browser tool reaches Chrome through the native host -> zapd -> the socket
at ~/.zap/run/zapd.sock, where hanzo-mcp is a consumer (hanzo_tools.browser
.zapd_consumer). That is the transport, so the WebSocket server and its mDNS
discovery go, along with _normalize_mcp_result, which existed to shape results
for that wire and had no other caller.
2026-08-18 23:13:53 -07:00
zeekay bcbea8ce31 drop a script that existed to hold a key
openai_api_check.py was not a test — pytest never collected it, nothing imported
it, and its whole body was a hand-run connectivity probe against a vendor with
the credential written in as a literal. There is nothing to keep.

The value it carried must still be rotated: it is in this repo's history and the
history is public.
2026-08-14 16:52:07 -07:00
zeekay ef4f774da5 the credential comes from the environment
This script carried its key as a literal. A key in a source file is a key in
every clone of that file, and this repo mirrors publicly, so the value must be
rotated independently of this change — removing it from the tip does not remove
it from history.

Reads OPENROUTER_API_KEY and exits with a clear message when it is unset.
2026-08-14 16:51:14 -07:00
zeekayandHanzo Dev 3f14aa2970 Point every Discord invite at the current Hanzo server (discord.gg/CJCyAsm9Vr)
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 21:48:55 -07:00
zeekayandHanzo Dev e89a367a6d fix(mcp): the default mode disabled the unified hanzo tool
0.15.13 shipped the 166-service surface switched off. `tools/list` against a
clean install returned 40 tools with no `hanzo`, and the server logged
"unified `hanzo` tool unavailable — keeping per-service tools enabled".

The import was fine; the mode gate was not. register_all_tools() asks
is_tool_enabled("hanzo", True), which returns tool_config["hanzo"] whenever the
key exists rather than falling back to the default. ModeLoader builds that
config by disabling every TOOL_REGISTRY key and re-enabling only the active
mode's tools. TOOL_REGISTRY has "hanzo"; the default personality's list did
not — so the "True" default was never reached and the tool was explicitly off.

Two things broke together, because the per-service cloud tools are retired only
once `hanzo` is enabled: the unified surface was absent AND the ten tools it
replaces were still mounted. The exact state 929e103e set out to end.

`hanzo` belongs in ESSENTIAL_TOOLS. It is an axis like fs or git — the single
seam to the platform — not a mode-specific extra. It stays out of
ESSENTIAL_SYSTEM_TOOLS so it remains disableable.

Verified in a clean uv venv from built wheels only (no editable, no PYTHONPATH):
tools/list now returns 31 tools including `hanzo`, and api/auth/billing/commerce/
iam/ingress/kms/mpc/paas/team are correctly gone (40 - 10 + 1). The tool answers
hanzo(service="services") with 166 services read live from
https://api.hanzo.ai/v1/openapi.json.

A test now pins the gate where it is actually decided. It fails against the
installed 0.15.13 (3 of 4) and passes against 0.15.14 — an import-level check
cannot catch this, because the import succeeds.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 21:08:44 -07:00
zeekayandHanzo Dev 0178264695 deps: floor hanzo-tools at the version that actually has HanzoCloud
The unified `hanzo` tool imports HanzoCloud from hanzo_tools.core, which
hanzo-tools first shipped in 0.3.3 — but nothing in the dependency graph
required it. hanzo-tools-api asked for `hanzo-tools-core>=0.1.0`, an empty
shim whose own floor is hanzo-tools>=0.3.2, and 0.3.2 has no cloud.py at all.
A resolver was therefore free to satisfy every constraint and still produce an
install where `from hanzo_tools.core import HanzoCloud` raises ImportError.
That is exactly what happened: the legacy-tool gate logged "unified hanzo tool
not importable" and fell back, and the dev venv had to install hanzo-tools
editable to get a working `hanzo`.

Name the real dependency at the real floor:
- hanzo-tools-api: hanzo-tools-core>=0.1.0 -> hanzo-tools>=0.3.4. It imports
  hanzo_tools.core directly, so it must depend on the package that owns it;
  the >=0.1.0 shim floor also still admitted the shadowing duplicate.
- hanzo-tools-vector: hanzo-tools>=0.3.0 -> >=0.3.4 (cloud_vector.py).
- hanzo-mcp: hanzo-tools>=0.3.2 -> >=0.3.4, hanzo-tools-api>=0.3.1 -> >=0.3.2.

Metadata only, on versions not yet published. No version bumps.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 20:44:05 -07:00
zeekayandHanzo Dev d0c125f571 tools: generate the hanzo surface from cloud's OpenAPI registry; delete the vector fake
The `hanzo` dispatcher hand-listed 10 services in SERVICE_TOOL_PATHS, so the
other ~150 cloud products were unreachable until someone cut a Python release.
Project the surface from cloud's /v1/openapi.json instead: cloud tags every
operation with its product (the first path segment after /v1/), so that document
already IS a service/action catalog. 166 services are now reachable, and a newly
mounted app is callable the moment cloud serves it.

Still exactly one MCP tool — agents degrade badly with hundreds — now shaped
hanzo(service, action, params, method), with `services` listing the catalog and
an empty action listing a service's actions.

Delete the local Infinity vector store (3,546 lines). It shipped no embedder, so
its only possible output was random vectors: it ranked "Bananas are yellow" above
an auth document for the query "authentication oauth jwt". A previous fix put the
mock behind HANZO_VECTOR_ALLOW_MOCK, but a fake that a flag can re-enable is
still a fake, and a tool that lies to an agent is worse than a missing one. The
package keeps only the cloud-backed VectorTool, and a test now fails if any
module in it imports `random`.

Make the legacy-tool gate honest: hide the per-service tools only once the
unified tool genuinely imports. It does not import against released hanzo-tools
(HanzoCloud is newer), and disabling them unconditionally would have left no
cloud tools at all.

- spec.py: catalog projection, cache keyed per spec source, stale cache beats
  failing a call. HANZO_OPENAPI_URL decouples catalog from target so a partial
  local host can be driven with the full registry.
- HanzoCloud.call: one generic seam for the verbs the spec names (PUT/PATCH/
  DELETE); auth also resolves the hanzo CLI's IAM session, memoized.
- 40 new tests covering action naming, template binding, method inference,
  param split, and cache fallback.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 20:25:54 -07:00
zeekayandHanzo Dev 8f3d611abf fix: complete the TypeScript 7 tsconfig migration
The first pass left three classes of config that BOTH tsc 5.9 and tsc 7
reject. Each was proven against both compilers before changing:

  TS5090  A `paths` target must be relative once `baseUrl` is gone. The
          first pass skipped the "./" prefix wherever baseUrl pointed at
          the config's own directory, reasoning it was semantically
          equivalent. It is not — without baseUrl a non-relative target
          is rejected outright, by 5.9 as well as 7.

  TS5110  `moduleResolution: node16` requires `module: node16`. The first
          pass mapped commonjs projects to node16 resolution alone, which
          BROKE those configs for the current toolchain. Both are now set.

  TS5102  `downlevelIteration` is also removed in TS7; it was missing from
          the dead-flag list.

Verified: repos that tsc 7 previously refused (base-studio, js-sdk, kv-js)
now report zero config errors on tsc 7 AND tsc 5.9.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 17:56:08 -07:00
zeekayandHanzo Dev 5a5702ec43 build: migrate tsconfig to TypeScript 7 (native compiler)
TypeScript 7 is the native Go compiler and removes `baseUrl` and
`moduleResolution: node|node10`. Both appear here, so `tsc` from TS7
refuses the config outright (TS5102 / TS5108) and cannot typecheck.

`paths` targets resolve relative to `baseUrl` when it is set and relative
to the tsconfig file otherwise. Every `baseUrl` folded here already
pointed at the config's own directory, so dropping it moves nothing and
the targets are left byte-identical. Where a baseUrl pointed elsewhere,
each affected target was rewritten as join(baseUrl, target).

`moduleResolution` was chosen from the declared `module`: commonjs ->
node16, esnext/preserve -> bundler. Configs whose `module` is unset or
exotic were left alone rather than guessed at.

The result is accepted by BOTH toolchains, so nothing has to upgrade
TypeScript in lockstep. Verified on hanzo/chat packages/api: tsc 5.9
779 -> 778 errors (no regression), and tsc 7.0.2 now runs the project
in 2s where it previously refused the config.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 14:18:30 -07:00
zeekay 85bf05c796 feat(mcp): native MCP ImageContent — tools return images the client can SEE
HIP-0300 tools serialize results to JSON text, which flattened images into
useless base64-in-text. Add a ToolImage value type + one converter in
BaseTool.register: any ToolImage anywhere in a result becomes a real
mcp.types.ImageContent block; text-only results stay byte-for-byte JSON.
Emitters wired: fs read of image files, browser screenshots (bidi+playwright).
This gives hanzo-mcp vision parity with zai-mcp — an agent with native vision
(Claude) sees pixels directly, no per-task vision tool needed.

Also decomplect the core-package collision that caused this class of bug:
hanzo-tools-core shipped a DUPLICATE hanzo_tools/core/ that nondeterministically
shadowed canonical hanzo-tools (dropping ToolImage, the sophisticated register,
etc. — same shadow class as the 0.3.0 error-reexport gap). Finish the
'merge core into hanzo-tools' refactor: move id_tool into hanzo-tools, make
hanzo-tools-core a pure empty metapackage. Now ONE package owns hanzo_tools.core.

Versions: hanzo-tools 0.3.2, -core 0.3.1 (shim), -browser 0.5.9, -fs 0.3.4,
hanzo-mcp 0.15.12 (floors bumped). Verified: fs read PNG -> [text, image];
fs stat -> [text]; 29 tools intact; 9 tests pass.
2026-07-03 00:45:49 -07:00
zeekay f34b5535d1 test(hanzo-mcp): guard every hanzo.tools entry point imports cleanly
Regression guard for the hanzo-tools 0.3.0 core re-export gap that silently
dropped fs/exec/code/git/fetch/agent, leaving hanzo-mcp with only 13 tools.
Fails loudly if any entry point stops loading or the core error contract
(ToolError/ConflictError/InvalidParamsError/NotFoundError) regresses.
2026-07-02 23:57:21 -07:00
zeekay fc76d8dc3c fix(hanzo-mcp): 'tool list' crash on @property descriptions (v0.15.11)
DynamicToolRegistry stored getattr(tool_class, 'description'), which for a
class-level @property returns the property DESCRIPTOR (not a str). 'tool list'
then did len(config.description) → 'object of type property has no len()',
breaking the entire tool-catalog command. Add _extract_tool_description
(mirrors _extract_tool_name): resolve a @property via a cheap instance, else
coerce to str, always returns str. Plus a defensive isinstance guard in the
list display path. Regression test covers property/unevaluable-property/plain/
absent + asserts every registered entry's description is len()-safe. 2 passed.
2026-07-02 23:00:52 -07:00
zeekay f6c516868c feat(cli,mcp): complete S3 control surface — hanzo s3 + s3 MCP tool
Closes the last gap in the one-way Hanzo control surface. IAM/KMS/PaaS
already had both CLI subcommands and MCP tools; S3 had neither.

- hanzo s3: buckets/mb/rb/ls/stat/rm/presign over hanzo_s3 (MinIO) client,
  creds from env (inject from KMS, never plaintext). Registered in the
  unified hanzo CLI alongside iam/kms/paas.
- hanzo-tools-s3: S3Tool MCP tool (same action-dispatch pattern as PaaSTool),
  exported via the hanzo.tools entry point; s3 added to loader prefix map.
- uv workspace: map hanzo-cli/iam/kms/s3 + tools-s3 to local sources so the
  unified CLI resolves on-disk packages (fixes hanzo_iam ImportError from a
  stale published 1.29.0 wheel shadowing local 1.30.0).

Tests: 7 CLI + 14 MCP, all green.
2026-06-24 13:50:24 -07:00
zeekay 7b21dba882 hanzo-mcp 0.15.10: harden tool floors (shell>=0.6.5, core>=0.3.0) so the pre-ToolError core can't resolve
Root cause of dead shell-exec: stale installs froze hanzo-tools-core 0.2.0 (no ToolError)
before 0.3.0 published, shadowing hanzo_tools.core and crashing the shell package import.
Floors now exclude it; a fresh/upgraded install always lands the consistent set.
2026-06-23 11:55:07 -07:00
zeekay 490d0b4a84 release: hanzo-tools-browser 0.5.8 + hanzo-mcp 0.15.9 (Firefox BiDi driving) 2026-06-20 13:04:39 -07:00
248e5e0ea9 fix(browser-mcp): migrate CDP bridge → zapd consumer; disk authoritative (#35)
* fix(browser-mcp): migrate CDP bridge -> zapd consumer; make disk authoritative

The MCP runtime kept pulling the buggy published wheel (hanzo-tools-browser
0.5.7) from PyPI instead of the migrated on-disk source, so every restart
re-broke the `cdp` tool. Reinstate `cdp` as a zapd-native tool, finish the
bridge->zapd migration (delete dead bridge/server modules + their tests), bump
to 0.5.8 and pin hanzo-mcp >=0.5.8, add the package to the uv workspace/sources
so disk is authoritative. 9/9 browser tests pass.

Pairs with the hanzoai/extension bridge->zapd migration (separate, still
uncommitted). The ~/.claude.json MCP invocation was also pointed at the local
editable source (machine config, not in this repo).

(cherry picked from commit 11b4d4ea8a5570d6fb0e51079fa445dba3713f71)

* fix(browser): drop dead lifecycle.py (in-process zap_server/cdp_bridge are gone)

lifecycle.py only wrapped the removed in-process ZAP server + CDP bridge; nothing
imports it under the zapd-consumer model. One way: transport is zapd_consumer,
tools are browser/cdp/playwright.

---------

Co-authored-by: hanzo-dev <[email protected]>

Co-authored-by: Antje Worring <[email protected]>

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-16 22:12:07 -07:00
zeekay 1f07cdab33 hanzo-tools-config 0.2.1: ship fixed ConfigTool, floor it in hanzo-mcp
Published 0.2.0 predates 2cb7eb03: its ConfigTool passed
permission_manager positionally into BaseTool.__init__(self), so the
'config' tool failed registration on every server start (and 0.2.0
lacked WorkspaceTool entirely). The fix has sat unreleased on main —
same stranded-fix pattern as hanzoai.protocols. hanzo-mcp now floors
hanzo-tools-config>=0.2.1.
2026-06-10 20:07:33 -07:00
zeekay 8a89329f35 hanzo-mcp 0.15.8: require hanzoai>=2.2.1, never silence stderr
Floor hanzoai at 2.2.1 — the first release that actually ships
hanzoai.protocols, which permissions.py imports.

Drop the stderr→devnull redirect in stdio mode. The MCP stdio protocol
rides stdout alone; stderr is the channel clients log for diagnostics.
Silencing it turned the missing-module crash into a zero-byte mystery —
the client log literally suggests printing to stderr while the server
was throwing tracebacks into devnull. Run-loop failures also log with
exc_info so the traceback reaches the client log.
2026-06-10 20:03:53 -07:00
zeekay 2508eff135 hanzo-mcp 0.15.7: floor hanzo-tools-browser at >=0.5.7
0.5.6 of hanzo-tools-browser shipped with a missing register() method
on CdpTool that crashed MCP startup. 0.5.7 fixes it. Floor bumped to
0.5.7 so pip/uv refuse to resolve the broken intermediate version.
2026-06-10 10:39:35 -07:00
zeekay d5a9494ffd hanzo-mcp 0.15.6: drop unscoped console scripts that polluted ~/.local/bin
Removes three console scripts that should never have been declared at the
top-level shell namespace from hanzo-mcp:

  hanzo-dev      — name-collided with the canonical Rust Codex-fork CLI
                   at /opt/homebrew/bin/hanzo-dev (~/work/hanzo/dev).
  hanzo-plugin   — unscoped; if needed, belongs in its own package.
  hanzo-unified  — vague + unscoped.

Modules remain importable (hanzo_mcp.dev_tools, .cli_plugin,
.unified_backend) so any user-facing entry point can ship from its own
package later. Only hanzo-mcp + hanzo-mcp-dev stay as scripts here.

Also bumps the hanzo-tools-browser floor to >=0.5.5 so the CdpTool alias
(mcp__hanzo__cdp) is guaranteed alongside mcp__hanzo__browser on every
hanzo-mcp install.
2026-06-10 08:33:06 -07:00
zooqueenandHanzo Dev 2c26efdb84 hanzo-tools-browser: vendor ZAP wire constants, advertise on bind host
Two fixes for the canonical ZAP server:

1. Vendor the wire format (ZAP_MAGIC, MSG_*, MAX_MESSAGE_SIZE,
   encode/decode) inside hanzo_tools/browser/zap_server.py instead of
   importing from the external ``zap.protocol`` module — the published
   ``zap-protocol`` package on PyPI is now a ``zap-schema`` stub that
   doesn't expose those symbols, so the import chain breaks for any
   fresh install. Inlining ~40 lines keeps the spec self-contained and
   matches the TS reference at extension/packages/browser/src/shared/zap.ts.

2. Pass ``host=self.host`` to ``zap_mdns.publish`` so the advertised
   address matches the bound address. Default behaviour advertised the
   outbound LAN IP via ``_local_ip()`` while the WebSocket was bound to
   127.0.0.1; clients dialled the LAN IP and got ECONNREFUSED.

Drops the broken ``zap-protocol>=0.2.1`` dependency from both
hanzo-mcp and hanzo-tools-browser pyprojects — no longer needed.

Co-authored-by: Hanzo Dev <[email protected]>
2026-05-18 22:24:47 -07:00
zeekay f6c4d06f7a hanzo-mcp 0.15.5: ESSENTIAL_TOOLS = HIP-0300 axis surface
Replaces the legacy per-operation tool list (read/write/edit/tree/dag/
zsh/shell/open) in PersonalityRegistry.ESSENTIAL_TOOLS with the six
HIP-0300 axes:

  fs    bytes + paths    (read, write, edit, list, stat, apply_patch, search_text)
  exec  execution        (run, background, ps, kill, logs)
  code  symbols          (parse, search, transform, summarize)
  git   diffs + history
  fetch network          (get, post, download)
  plan  orchestration

Action-routed dispatch on top, not split tools — one tool per axis.
Keeps memory/think/critic/agent/config/mode/tool unchanged.
2026-05-14 23:39:39 -07:00
zeekay 572dcd68f2 decomplect: HIP-0300 wire surface is the only public contract
The MCP wire (what tools/list reports) ships exactly one tool per axis:
fs, exec, code, git, fetch, plan — action-routed. The per-action classes
(ReadTool, WriteTool, EditTool, …) stay importable for in-process
read-only sandboxing (swarm sub-agents) but are NOT on the wire.

PyPI 0.3.1 of hanzo-tools-fs shipped the legacy split (7 tools) while
the local 0.3.1 source had already migrated to TOOLS=[FsTool]. Same
version number, two different contracts — the source of the
'Python MCP surfaces 32 tools, Node MCP surfaces 13' divergence
that breaks contract parity. Bumping to 0.3.2 publishes the
HIP-0300 surface for the first time.

- pkg/hanzo-tools-fs 0.3.1 → 0.3.2: TOOLS=[FsTool]; legacy classes
  importable; dropped 'Edit = EditTool' alias; cleaner __init__.
- pkg/hanzo-tools-shell 0.6.3 → 0.6.4: bump only (source already
  TOOLS=_get_detected_shell_tools()).
- pkg/hanzo-tools-code 0.1.0 → 0.1.1: bump only (TOOLS=[CodeTool]).
- pkg/hanzo-tools-vcs  0.1.0 → 0.1.1: bump only (TOOLS=[GitTool]).
- pkg/hanzo-tools-net  0.1.0 → 0.1.1: bump only (TOOLS=[FetchTool]).
- pkg/hanzo-tools-plan 0.1.0 → 0.1.1: bump only (TOOLS=[PlanTool]).
- pkg/hanzo-tools-agent 0.3.1 → 0.3.2: 'Edit' alias is gone — call
  EditTool by its real name in swarm_tool.py.
- pkg/hanzo-mcp 0.15.3 → 0.15.4: gets the HIP-0300-clean wire when
  consumed via 'uvx --refresh-package hanzo-tools-fs hanzo-mcp serve'.
2026-05-13 13:51:48 -07:00
zeekay 2ecbd28aa5 style: black --target-version py312 (CI format-check fix)
No semantic changes — pure black reformat across the four files touched
in 55b55146 (hanzo-mcp 0.15.3 + hanzo-tools-browser 0.5.4).
2026-05-10 17:22:07 -07:00
zeekay c1da01a98b hanzo-mcp 0.15.3 + hanzo-tools-browser 0.5.4: ZAP TextContent normalization, mDNS-only discovery
hanzo-mcp (0.15.1 -> 0.15.3):
- _normalize_mcp_result() collapses FastMCP list[TextContent] to parsed JSON
  for ZAP MSG_RESPONSE serialization
- Closes the "TextContent not JSON serializable" bug surfaced when driving
  the Hanzo extension from agent via tools/call
- Bump hanzo-tools-browser[playwright] floor to 0.5.4

hanzo-tools-browser (0.5.2 -> 0.5.4):
- mDNS-only ZAP discovery via _hanzo._tcp.local. (HIP-0069); no port pool,
  no lockfile, OS-assigned ports advertised by hanzo-zap-mdns
- zap_server.py: refactor for unique server_id + retract on stop
- Test suite trimmed to the new wire contract

Patch-bump both packages.
2026-05-10 17:17:13 -07:00
zeekay 8ac68b91e3 chore: untrack node_modules, improve .gitignore 2026-04-18 17:15:22 -07:00
zeekay 69279a9151 fix: ruff lint auto-fixes across hanzo-mcp and tests 2026-04-01 20:48:58 -07:00
zeekay ffe73447a3 security: fix 3 HIGH + 3 MEDIUM findings from red team review
- H-1: guard negative abs_off in obj_bytes() (buffer read bypass)
- H-2: remove CERT_NONE from ZapClient TLS (MITM protection)
- H-3: add MAX_MESSAGE_SIZE check in ZapServer (OOM DoS)
- M-5: log exceptions instead of bare pass in server
- L-1: validate ZAP version in Message.parse()
- L-2: wrap req_id at u32 boundary in CloudClient
2026-03-31 20:57:16 -07:00
zeekay 7e47625094 fix: lint — ruff format and fix for hanzo-tools-ui and hanzo-mcp 2026-03-27 20:00:21 -07:00
zeekay c0e7414b42 feat: enable ui tool in hanzo-mcp with local-first component reading
Add hanzo-tools-ui to workspace members and hanzo-mcp dependencies so
the ui tool is actually discoverable at runtime. Add LocalUIClient that
reads components directly from ~/work/hanzo/ui when available, falling
back to GitHub API. Adds list_packages and read_file actions. Fixes
GitHub config components_path to match actual repo layout (pkg/ui/primitives).
2026-03-27 18:50:09 -07:00
zeekay 2c8c6a6f55 feat(memory): add namespace/key support + BlueRedChannel coordination class
- SQLite backend: namespace, key, tags, TTL, append support
- PluginMemoryService: full parity with TypeScript/Rust (list, stats, clear, tag, history, export/import)
- BlueRedChannel class for blue-red agent coordination protocol
- 30/30 tests passing
2026-03-24 18:03:30 -07:00
zeekay 867bda8090 rebrand: fix insights host URL and remove redundant env var fallback 2026-03-13 18:03:09 -07:00
zeekay 20778ab5c8 rebrand: PostHog→Insights in MCP analytics 2026-03-13 16:52:56 -07:00
zeekay df275b96f8 refactor(hanzo-mcp): clean up ZAP server bridge 2026-03-13 16:52:56 -07:00
zeekay c287c1eaf8 fix(zap): replace websockets with native ZAP TCP transport
- Rewrite zap_server.py to use asyncio TCP (not websockets library)
- ZAP server now speaks native binary protocol over raw TCP
- Wire format: [magic:4][type:1][length:4 BE][JSON payload]
- Remove websockets from ide optional dependency
- Fix type annotations: any -> Any, dict -> dict[str, Any]
- Add proper frame reading with asyncio.StreamReader.readexactly()
- Support MAX_MESSAGE_SIZE (16MB) limit per ZAP spec
2026-03-12 16:23:41 -07:00
zeekay 985bb9fedc chore(hanzo-mcp): bump version to 0.15.0
HIP-0300 bidirectional action sync release:
- Full action parity across Python/TS/Rust implementations
- 13 unified tools with complete action coverage
2026-03-12 15:39:28 -07:00
zeekay 6548975fd9 fix: ruff format MCP files + update required tool count to 21 2026-03-12 01:40:46 -07:00
zeekay 997b7b91fb fix: resolve mypy errors and update shell tool count in tests
- Fix type shadowing in forgiving_edit.py (needle_lines int/list conflict)
- Add return type annotations to prompts functions
- Fix change_type indexing for None case in utils.py
- Fix commit.message bytes/str handling in utils.py
- Add proper dict typing for tree entries in utils.py
- Update shell tool count from 8 to 9 in test assertions
2026-03-12 01:30:57 -07:00
zeekay e602907141 fix: resolve all ruff lint errors (F401, F841, E741, I001)
Remove unused imports, fix unsorted import blocks, rename ambiguous
variable, and remove unused local variable assignment.
2026-03-12 01:12:30 -07:00