SkillRegistry to MCP Bridge (zmodu.ai.mcp)
zmodu.ai.mcp exposes a SkillRegistry as a Model Context Protocol (MCP) stdio server so external LLM hosts (such as Claude Desktop, Cursor, or Codex) can discover and invoke zmodu skills (db.query, kpi.query, approval.request, entity.create, etc.).
Note:
zmodu mcpin the CLI is the code-generation MCP server for project scaffolding.zmodu.ai.mcpis the runtime library bridge for your application’sSkillRegistry.
1. Quick Start
const ai = zmodu.ai;
// 1. Register business, KPI, and action skills
var registry = ai.SkillRegistry.init(allocator, io);
defer registry.deinit();
// Multi-tenant applications MUST declare `db_query_tenant_column` so `db.query`
// scopes queries to `ctx.tenant_id` (otherwise it fails closed with `error.TenantScopeUnavailable`).
try ai.business.registerBusinessSkillsWith(®istry, &.{}, .{
.db_query_tenant_column = "tenant_id",
});
try ai.kpi.registerKpiSkills(®istry);
try ai.actions.registerWriteSkills(®istry);
// 2. Define the session identity and permissions applied to every MCP tool call
const perms = [_][]const u8{"entity:write"};
const ctx = ai.SkillContext{
.allocator = allocator,
.tenant_id = 1,
.permissions = &perms,
};
// 3. Start the stdio MCP server
try ai.mcp.serveStdio(io, allocator, ®istry, ctx);
Runnable example: examples/mcp-server:
cd examples/mcp-server && zig build
cd ../.. && python3 scripts/mcp-client-test.py examples/mcp-server/zig-out/bin/mcp-server
2. Supported MCP Methods
initialize: Negotiates protocol version (2024-11-05) and advertisescapabilities.tools.tools/list: Exports registered skills (name,description, and JSONinputSchemaderived fromTool.parameters), filtered by the session’s permissions.tools/call: Dispatches the tool call throughSkillRegistry.dispatchand returns the JSON result as text content.
3. Security & Tenant Isolation
- Permission filtering on
tools/listandtools/call:serveStdioonly advertises skills thatctx_template.permissionsis authorized to call, andSkillRegistry.dispatchenforcesTool.required_permissionon everytools/call(error.PermissionDenied). For custom filtering, callserveStdioFiltered(io, allocator, ®istry, ctx_template, .{ .allowlist = ..., .permissions = ... }). - Tenant isolation:
ctx_template.tenant_idis passed to every skill invocation.entity.*skills filter by the entity’stenant_column, anddb.querywraps the query withBusinessSkillsConfig.db_query_tenant_column(failing closed witherror.TenantScopeUnavailableiftenant_idis set without a configured column).
4. Programmatic API
ai.mcp.toMcpTools(registry, allocator): Renders the unfiltered MCPtools/listJSON payload.ai.mcp.handleToolCall(registry, ctx, params): Executes a singletools/callrequest.ai.mcp.serveStdio(io, allocator, registry, ctx_template): Runs the stdio JSON-RPC loop with permission filtering.ai.mcp.serveStdioFiltered(io, allocator, registry, ctx_template, filter): Runs the stdio loop with explicit allowlist and permission filters.