Files
zeekay 41533d452a
Hanzo CI/CD / test (linux-amd64) (push) Skipped
Hanzo CI/CD / test (linux-arm64) (push) Skipped
Hanzo CI/CD / test-advisory (push) Skipped
publish / publish (push) Successful in 2m14s
Hanzo CI/CD / test-amd64 (push) Successful in 6m17s
Hanzo CI/CD / cicd (push) Successful in 4m15s
CI/CD / cicd (push) Successful in 10m38s
hanzo-mcp 1.1.30 for every platform the CLI ships, and 2.4.20 takes --project-dir
The release lane built Linux alone, so hanzo.sh offered macOS and
Windows a server nobody had built, and `hanzo dev` there fell back to
nothing. It now cross-builds linux, windows and darwin for both
architectures from the one Linux pool with Zig and a pinned macOS SDK,
the way the CLI's release does, one target at a time. Zig comes from its
own checksummed tarball, not pip.

`hanzo dev` hands its server `--project-dir`, the native spelling. The
npm build read it as stray arguments and exited, so a machine whose
PATH found the npm `hanzo-mcp` first ran every session without the
toolset. It now takes the flag as an allowed root.

Claude-Session: https://claude.ai/code/session_01M8RoubcPN71KgJuZ8LdBUL
2026-10-14 20:51:41 -07:00

65 lines
2.2 KiB
TypeScript

/**
* Shared helper utilities for Hanzo Kai MCP Cookbook recipes.
*/
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { createMCPServer } from "../dist/index.js";
export interface RecipeResult {
recipe: string;
tool: string;
success: boolean;
latency_ms?: number;
output: any;
explanation: string;
}
/**
* Creates an in-process MCP client connected directly to the Hanzo MCP server.
* Enables zero-overhead execution for recipes and automated test suites.
*/
export async function createRecipeClient() {
// Kai is reached as every client reaches it: api.hanzo.ai with HANZO_API_KEY, or LOCAL_KAI_URL for a local `kai serve`.
const server = await createMCPServer({ name: "kai-cookbook-server", version: "2.4.20" });
// Call tools directly via server handlers or in-memory transport
return {
server,
async callTool(name: string, args: Record<string, any>) {
const tool = server.tools.find((t: any) => t.name === name);
if (!tool) throw new Error(`Tool '${name}' not found on server`);
const start = performance.now();
const res = await tool.handler(args);
const elapsed = performance.now() - start;
if (res.isError) {
return {
isError: true,
error: res.content?.[0]?.text || "Unknown error",
latency_ms: elapsed
};
}
let parsed = {};
try {
parsed = JSON.parse(res.content?.[0]?.text || "{}");
} catch {
parsed = { raw: res.content?.[0]?.text };
}
return {
isError: false,
data: parsed,
latency_ms: elapsed
};
}
};
}
export function logRecipe(result: RecipeResult) {
console.log(`\n======================================================`);
console.log(`📖 Recipe: ${result.recipe}`);
console.log(`🛠️ Tool: ${result.tool}`);
console.log(`⚡ Latency: ${result.latency_ms?.toFixed(2)} ms`);
console.log(`📝 Output:\n${JSON.stringify(result.output, null, 2)}`);
console.log(`💡 ${result.explanation}`);
console.log(`======================================================\n`);
}