clawdbot-workspace/meta-ads-mcp/fix-tier2-tools.js

101 lines
3.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Batch fix for tier-2 tool modules
* Converts from server.tool() API to registry.registerTool() API
*/
const fs = require('fs');
const path = require('path');
const files = [
'src/tools/audiences.ts',
'src/tools/budget.ts',
'src/tools/catalog.ts',
'src/tools/competitive.ts',
'src/tools/experiments.ts',
'src/tools/leads.ts',
];
function convertFile(filePath) {
console.log(`Converting ${filePath}...`);
let content = fs.readFileSync(filePath, 'utf8');
// 1. Replace imports
content = content.replace(
/import type { McpServer } from "@modelcontextprotocol\/sdk\/server\/mcp\.js";/g,
''
);
content = content.replace(
/interface MetaApiClient \{[^}]+\}/gs,
''
);
// Add ToolRegistry import if not present
if (!content.includes('import type { ToolRegistry }')) {
content = content.replace(
/(import { z } from "zod";)/,
'$1\nimport type { ToolRegistry } from "../server.js";'
);
}
// Remove ToolAnnotations from imports if present
content = content.replace(
/,\s*ToolAnnotations/g,
''
);
// 2. Replace function signature
content = content.replace(
/export function register\(server: McpServer, client: MetaApiClient\): void \{/g,
(match, offset) => {
// Get the function name from the file
const baseName = path.basename(filePath, '.ts');
const functionName = 'register' + baseName.charAt(0).toUpperCase() + baseName.slice(1).replace(/-([a-z])/g, (g) => g[1].toUpperCase()) + 'Tools';
return `export function ${functionName}(registry: ToolRegistry): void {\n const client = registry.getClient();`;
}
);
// 3. Convert server.tool() calls to registry.registerTool()
// This regex handles the basic structure
content = content.replace(
/const\s+(\w+Annotations):\s*ToolAnnotations\s*=\s*(\{[^}]+\});[\s\n]+server\.tool\(\s*"([^"]+)",\s*"([^"]+)",\s*(\{[^}]+\}),\s*async\s*\(params\)\s*=>\s*\{/gs,
(match, annotationsVar, annotations, toolName, description, schema) => {
return `registry.registerTool({\n name: "${toolName}",\n description: "${description}",\n inputSchema: z.object(${schema}),\n annotations: ${annotations},\n handler: async (args) => {\n const params = args as any;`;
}
);
// 4. Fix tool closing - replace "),\n annotationsVar\n );" with "},\n });"
content = content.replace(
/\},\s*\w+Annotations\s*\);/g,
'};\n\n return {\n content: [{\n type: \'text\',\n text: JSON.stringify(result, null, 2),\n }],\n };\n },\n });'
);
// Fix client.get calls to add type cast
content = content.replace(
/client\.get<([^>]+)>\(([^,]+),\s*([^)]+)\)/g,
'client.get<$1>($2, $3 as Record<string, unknown>)'
);
fs.writeFileSync(filePath, content, 'utf8');
console.log(` ✓ Converted ${filePath}`);
}
// Convert all files
for (const file of files) {
const filePath = path.join(__dirname, file);
if (fs.existsSync(filePath)) {
try {
convertFile(filePath);
} catch (error) {
console.error(` ✗ Error converting ${file}:`, error.message);
}
} else {
console.error(` ✗ File not found: ${filePath}`);
}
}
console.log('\nDone! Please review the changes and run npx tsc --noEmit to check.');