Skip to content

Mzizi tools overview

The Mzizi tooling — @nyuchi/mzizi-mcp, @nyuchi/mzizi-cli (the fundi agent SDK + CLI), and @nyuchi/mzizi-skills — is governed by the Bundu Foundation, operated by Nyuchi as part of the open Mzizi project, and consumed by every Nyuchi codebase. It all lives in one monorepo, nyuchi/mzizi-tools.

This section documents how Nyuchi uses them. Upstream product reference lives in bundu-docs.

Also in this section Covers
The DNA double helix The architecture model Mzizi actually serves — nodes, strands, rungs
Registry health Which of the 64 registry tools work, which serve retired data
A2A How long-running runs will be delegated to fundi. Design, not shipped
Package Version Ships as
@nyuchi/mzizi-mcp 0.5.0-beta.6 Cloudflare Worker at mcp.mzizi.dev + an npm stdio bin
@nyuchi/mzizi-cli 0.4.0-beta.1 (last stable 0.3.0) npm — SDK + the fundi bin
@nyuchi/mzizi-skills 0.5.0 npm — 9 skills, data only
@nyuchi/fundi-tester 0.2.0 Cloudflare Worker only. private: truenever published to npm
@nyuchi/bushtrade-mcp 0.2.0 Cloudflare Worker + stdio bin. Not on npm yet; ships manually
@nyuchi/mzizi-console-app 0.2.0-beta.1 Svelte mini-app for the Console. Not on npm yet; ships manually

Versions read from the npm registry and the monorepo on 2026-07-31. Per-package semver: every commit touching a tool is a patch, every merged PR lands a minor, and an open PR carries an X.Y.0-beta.N pre-release of that next minor — which is why the two live tools currently report betas.

Two live MCP surfaces read the same Mzizi document store, and the difference matters:

Endpoint What it is Auth
https://mcp.mzizi.dev/mcp The standalone mzizi-mcp Cloudflare Worker. 64 tools, built at startup from the mcp_tool_registry table WorkOS Connect OAuth PKCE — free signup
https://mzizi.dev/mcp The portal’s canonical document-route MCP — components, collections, database status none (anon read)

The worker is registry-driven: it reads the tool catalogue from the database at startup and dispatches each tool by its kind — a SQL function, an edge function, or a table select. Adding a tool is a database edit, not a code change. Two CORE tools are defined in code rather than the registry (list_collections, get_database_status), plus fundi_status when the fundi worker is configured.

Connect a client:

{
"mcpServers": {
"mzizi": { "type": "http", "url": "https://mcp.mzizi.dev/mcp" }
}
}

An unauthenticated tools/list against mcp.mzizi.dev/mcp returns 401 invalid_token — that is the gate working, not an outage. It also means production is not a usable target for scripted inspection; point the official inspector at the local stdio bin or a wrangler dev instance instead.

The server is listed on the public MCP registry as io.github.nyuchi/mzizi-mcp.

One npm package, @nyuchi/mzizi-cli, containing both the SDK and a CLI whose bin is named fundi.

Terminal window
pnpm add -D @nyuchi/mzizi-cli

Three verbs, plus session commands:

Command Needs Does
fundi explore nothing — offline Reads a small set of disk markers (package.json, tsconfig.json, app/globals.css, tailwind.config.*, components.json) and prints a project snapshot. No model call.
fundi plan <goal...> ANTHROPIC_API_KEY + sign-in Plans the minimal Mzizi-aligned edits. Read-only — prints the steps as a dry run and writes nothing.
fundi chat <message...> ANTHROPIC_API_KEY + sign-in One-shot chat scoped to Mzizi doctrine.
fundi login [--token <jwt>] Saves a WorkOS access token for the gated mzizi-mcp.
fundi logout / fundi whoami Clears, or reports, the saved identity.

Environment the CLI reads (the SDK itself is deliberately env-agnostic — wiring env into options is the caller’s job):

Variable Default
ANTHROPIC_API_KEY required for plan and chat
MZIZI_MCP_URL https://mcp.mzizi.dev/mcp
MZIZI_MODEL claude-sonnet-4-6
WORKOS_ACCESS_TOKEN alternative to fundi login

As a library:

import { createFundi } from '@nyuchi/mzizi-cli';
const fundi = await createFundi({
projectRoot: process.cwd(),
anthropicApiKey: process.env.ANTHROPIC_API_KEY!,
mcpUrl: process.env.MZIZI_MCP_URL, // optional
model: process.env.MZIZI_MODEL, // optional
});
const snapshot = await fundi.explore();
const plan = await fundi.plan('add the Mzizi token layer and a button', snapshot);
await plan.apply({ dryRun: true });

Two safety properties worth knowing before you point it at a repo:

  • Planning is read-only. The agent has six tools; write_file and run_shell are blocked during planning and only reachable through plan.apply({ dryRun: false }).
  • Everything is sandboxed to projectRoot. Any path that escapes it is rejected — neither the planner nor the apply phase can read or write outside the project.

The design-system and engineering doctrine ships as a public npm package of agent skills. Install it into any repo so Claude Code (or Cursor, Copilot, Cline, Windsurf) has the doctrine on hand instead of guessing:

Terminal window
npx skills add @nyuchi/mzizi-skills

Or take the whole toolchain as a Claude Code plugin — the skills, the fundi agent, the registry MCP, and the /mzizi:* commands in one step:

/plugin marketplace add nyuchi/mzizi-tools
/plugin install mzizi@mzizi-tools

Nine skills ship in 0.5.0:

Skill Reach for it when
nyuchi-design Generating any branded interface — minerals, radius, type
bundu-design Cross-brand materials and brand-voice decisions
mukoko-design Producing or exporting mukoko visual identity
simplify Before adding a component or style, and during any refactor
discoverability A shared link shows no preview, or you’re adding a route/site
scaffold-component Authoring a new component into the Mzizi registry
ecosystem-app-setup Bootstrapping a new ecosystem app against the registry
cloudflare-worker-rust Building a Worker in Rust with workers-rs
mcp-server-cloudflare Adding or changing an MCP Worker

The last four were migrated out of the database and out of the nyuchi/mzizi repo during the 0.5.0 cycle, so git is now the single home for every Mzizi skill. Their retired references were corrected on the way in.

Skills are authored in nyuchi/mzizi-tools as mzizi-skills/skills/<name>/SKILL.md — YAML frontmatter carrying name and description, then the body — and listed in mzizi-skills/index.json. That bundle is the single home for skill content: mzizi-tools projects it into the Mzizi skills collection (pnpm skills:sync, disk → DB), and the portal serves what it finds there via /api/v1/skills* and MCP get_skill.

The sync writes through RLS, as authenticated

Section titled “The sync writes through RLS, as authenticated”

This is the part people get wrong, so it is worth stating plainly.

skills:sync authenticates as the authenticated role by minting a short-lived JWT via OAuth 2.0 client_credentials against the WorkOS M2M application — the same issuer Supabase Third-Party Auth trusts. Row-level policies then decide what the sync may write.

There is deliberately no service-role path. The earlier implementation used a service-role key and bypassed RLS entirely; that was removed on purpose. No key outranks the policies.

Two headers do two different jobs, and conflating them is the classic failure:

Header Carries Determines
apikey the publishable (anon) key which project
Authorization Bearer <M2M JWT> which role RLS evaluates

Sending the anon key as both can only ever be the anon role, which is read-only here. A 401 or 403 on write is RLS declining — fix the policy, do not reach for a service-role key to get around it.

  1. Open a PR against nyuchi/mzizi-tools editing mzizi-skills/skills/<name>/SKILL.md.
  2. Adding a skill? Also add an index.json entry (name, file, description) — consumers read the index, so an unlisted skill is invisible.
  3. Bump the version in both mzizi-skills/package.json and index.json; they move in lockstep.
  4. Run pnpm skills:validate from the repo root. It is offline and needs no credentials — which is exactly why it, and not the drift check, gates the publish workflow: a missing secret must never be the reason a broken bundle ships. It catches version drift between the two files, an index entry pointing at a missing file, frontmatter name disagreeing with the index, an unlisted skill directory, and an exports map that would make consumers silently fall back to built-in defaults.
  5. Merge to main. publish-mzizi-skills.yml validates and publishes to npm. The workflow checks the registry first, so a merge without a version bump publishes nothing — bump the version or nothing ships.
  6. An operator runs pnpm skills:sync to project the change into the registry surface. That step needs the WorkOS M2M credentials, not a service-role key.

Every gated surface in the toolchain answers two separate questions, and the answers come from different systems. Getting this split right is the difference between a design that scales and one that quietly leaks a secret into a CLI.

Authentication — how the caller proves identity:

Surface kind Mechanism Examples
Public / customer WorkOS Connect OAuth PKCE — public client, no secret. Always a Worker; each public MCP has its own Connect app mzizi-mcp, bushtrade-mcp
Internal staff / machine WorkOS M2M (client credentials). Only Workers hold the secret fundi /admin/*

Entitlement — what the caller may do:

  • Public / customer → a UCP commerce subscription. Per-user tags do not scale to public consumption.
  • Internalscopes on the M2M token (fundi:admin, and the planned fundi:security / fundi:chaos). These are token scopes, not per-user tags.

The fundi worker is a resource server with no interactive login at all. It validates two things on /admin/*: an inbound M2M token, and a forwarded end-user token in X-Fundi-User-Token so it only ever acts for a real signed-in user. Cron, queue, webhook, and health routes bypass that gate because they are not user-triggered.

When you add a gated surface, ask one question: staff/machine (→ M2M + a claim scope) or public/customer (→ Connect OAuth PKCE + a UCP subscription)? Never gate a public or paid surface with a per-user tag, and never ship an M2M secret in a CLI.

Mzizi ships UI through a shadcn-compatible registry at mzizi.dev, consumed under the @mzizi namespace — mzizi.dev/api/v1/ui/{name}. The fundi CLI and the Mzizi MCP resolver both resolve the same source, so a component pulled by the CLI, by an agent, or by a raw shadcn add all come from one place.

Terminal window
npx shadcn@latest add https://mzizi.dev/api/v1/ui/button

Component naming is a deliberate mix: plain shadcn names for framework-standard primitives (button, dialog, card, …) alongside custom components prefixed by brand — nyuchi-, bundu-, or mzizi-. The prefix signals a brand-specific composite; an unprefixed name is a stock shadcn primitive re-served through the registry.

Honest gaps rather than a promise:

  • Nyuchi-specific workflows against mzizi-mcp — scaffolding a new mini-app, validating component back-links, running the registry health check as part of a release.
  • How to exercise a skill locally before publishing, beyond pnpm skills:validate’s structural checks.
  • Whether Nyuchi-specific skills (ones no external consumer would want) belong in the shared bundle or in a per-repo .claude/skills/.
  • @nyuchi/mzizi-console-app integration from the Console side — it is still pre-1.0 and ships manually.