mcpengine/servers/twilio/src/tool-registry.ts
Jake Shore f3c4cd817b Add all MCP servers + factory infra to MCPEngine — 2026-02-06
=== NEW SERVERS ADDED (7) ===
- servers/closebot — 119 tools, 14 modules, 4,656 lines TS (Stage 7)
- servers/google-console — Google Search Console MCP (Stage 7)
- servers/meta-ads — Meta/Facebook Ads MCP (Stage 8)
- servers/twilio — Twilio communications MCP (Stage 8)
- servers/competitor-research — Competitive intel MCP (Stage 6)
- servers/n8n-apps — n8n workflow MCP apps (Stage 6)
- servers/reonomy — Commercial real estate MCP (Stage 1)

=== FACTORY INFRASTRUCTURE ADDED ===
- infra/factory-tools — mcp-jest, mcp-validator, mcp-add, MCP Inspector
  - 60 test configs, 702 auto-generated test cases
  - All 30 servers score 100/100 protocol compliance
- infra/command-center — Pipeline state, operator playbook, dashboard config
- infra/factory-reviews — Automated eval reports

=== DOCS ADDED ===
- docs/MCP-FACTORY.md — Factory overview
- docs/reports/ — 5 pipeline evaluation reports
- docs/research/ — Browser MCP research

=== RULES ESTABLISHED ===
- CONTRIBUTING.md — All MCP work MUST go in this repo
- README.md — Full inventory of 37 servers + infra docs
- .gitignore — Updated for Python venvs

TOTAL: 37 MCP servers + full factory pipeline in one repo.
This is now the single source of truth for all MCP work.
2026-02-06 06:32:29 -05:00

214 lines
5.7 KiB
TypeScript

/**
* Tool registry with annotations, safety tiers, and pack management.
* Supports MCP tool annotations spec + custom metadata for lazy loading.
*/
import { z } from 'zod';
// Safety tiers — controls confirmation behavior
export type SafetyTier = 'green' | 'yellow' | 'red';
// Tool annotation metadata
export interface ToolAnnotations {
/** Tool only reads data, no side effects */
readOnlyHint?: boolean;
/** Tool may perform destructive actions (delete, release) */
destructiveHint?: boolean;
/** Tool is idempotent — safe to retry */
idempotentHint?: boolean;
/** Tool may cost real money (Twilio charges) */
costHint?: boolean;
/** Human-readable cost estimate */
estimatedCost?: string;
}
// Our extended tool metadata
export interface ToolMeta {
name: string;
description: string;
category: string;
pack: string;
safety: SafetyTier;
annotations: ToolAnnotations;
inputSchema: z.ZodType<any>;
_meta?: {
labels: {
category: string;
access: "read" | "write" | "delete";
complexity: "simple" | "complex" | "batch";
};
};
isApp?: boolean;
/** Tier 1 = always loaded, Tier 2 = lazy loaded */
tier: 1 | 2;
}
export interface RegisteredTool extends ToolMeta {
handler: (params: any) => Promise<ToolResult>;
}
export interface ToolResult {
content: Array<{
type: 'text' | 'resource';
text?: string;
resource?: {
uri: string;
mimeType: string;
text: string;
};
}>;
isError?: boolean;
structuredContent?: {
type: 'html';
html: string;
};
}
/**
* Central registry for all tools across all packs.
*/
export class ToolRegistry {
private tools = new Map<string, RegisteredTool>();
private activePacks = new Set<string>();
private onToolsChanged?: () => void;
/** Set callback for when tools list changes (lazy loading) */
setOnToolsChanged(callback: () => void) {
this.onToolsChanged = callback;
}
/** Register a single tool */
register(tool: RegisteredTool): void {
this.tools.set(tool.name, tool);
}
/** Register all tools from a pack */
registerPack(packName: string, tools: RegisteredTool[]): void {
for (const tool of tools) {
this.tools.set(tool.name, { ...tool, pack: packName });
}
this.activePacks.add(packName);
}
/** Activate a lazy-loaded pack and notify client */
activatePack(packName: string, tools: RegisteredTool[]): void {
if (this.activePacks.has(packName)) return; // Already loaded
this.registerPack(packName, tools);
this.onToolsChanged?.();
}
/** Deactivate a pack (unload tools) */
deactivatePack(packName: string): void {
if (!this.activePacks.has(packName)) return;
for (const [name, tool] of this.tools) {
if (tool.pack === packName) {
this.tools.delete(name);
}
}
this.activePacks.delete(packName);
this.onToolsChanged?.();
}
/** Get a tool by name */
get(name: string): RegisteredTool | undefined {
return this.tools.get(name);
}
/** Get all currently registered tools (for tools/list response) */
getAll(): RegisteredTool[] {
return Array.from(this.tools.values());
}
/** Get tools for a specific pack */
getByPack(packName: string): RegisteredTool[] {
return Array.from(this.tools.values()).filter(t => t.pack === packName);
}
/** Get all active pack names */
getActivePacks(): string[] {
return Array.from(this.activePacks);
}
/** Check if a pack is loaded */
isPackActive(packName: string): boolean {
return this.activePacks.has(packName);
}
/** Convert to MCP tools/list format */
toMCPToolsList(): Array<{
name: string;
description: string;
inputSchema: any;
_meta?: any;
annotations?: Record<string, any>;
}> {
return this.getAll().map(tool => {
const schema = tool.inputSchema instanceof z.ZodType
? zodToJsonSchema(tool.inputSchema)
: tool.inputSchema;
return {
name: tool.name,
description: tool.description,
inputSchema: schema,
_meta: tool._meta,
annotations: {
...tool.annotations,
category: tool.category,
safety: tool.safety,
},
};
});
}
}
/** Convert Zod schema to JSON Schema (simplified) */
function zodToJsonSchema(schema: z.ZodType<any>): Record<string, any> {
if (schema instanceof z.ZodObject) {
const shape = schema.shape;
const properties: Record<string, any> = {};
const required: string[] = [];
for (const [key, value] of Object.entries(shape)) {
const zodValue = value as z.ZodType<any>;
properties[key] = zodFieldToJsonSchema(zodValue);
if (!(zodValue instanceof z.ZodOptional)) {
required.push(key);
}
}
return {
type: 'object',
properties,
...(required.length > 0 ? { required } : {}),
};
}
return { type: 'object' };
}
function zodFieldToJsonSchema(field: z.ZodType<any>): Record<string, any> {
if (field instanceof z.ZodOptional) {
return zodFieldToJsonSchema(field.unwrap());
}
if (field instanceof z.ZodString) {
return { type: 'string', description: field.description };
}
if (field instanceof z.ZodNumber) {
return { type: 'number', description: field.description };
}
if (field instanceof z.ZodBoolean) {
return { type: 'boolean', description: field.description };
}
if (field instanceof z.ZodArray) {
return { type: 'array', items: zodFieldToJsonSchema(field.element), description: field.description };
}
if (field instanceof z.ZodEnum) {
return { type: 'string', enum: field.options, description: field.description };
}
if (field instanceof z.ZodObject) {
return zodToJsonSchema(field);
}
return { type: 'string' };
}