import { z } from 'zod'; import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import type { RestClient } from '../clients/rest-client.js'; import { formatQueryResponse } from '../utils/response.js'; import { formatToolError, classifyError, getErrorHint } from '../utils/errors.js'; function buildWhereClause(entity: string, searchTerm: string, searchFields?: string[]): string { const fields = searchFields && searchFields.length > 0 ? searchFields : [`${entity}NUM`, `${entity}NAM`]; const conditions = fields.map((field) => `contains(${field},'${searchTerm}')`); return conditions.length === 1 ? conditions[0] : `(${conditions.join(' or ')})`; } export function registerSearchTool(server: McpServer, restClient: RestClient): void { server.registerTool( 'sage_search', { description: 'Search Sage X3 records with flexible text matching. Builds SData where clauses from a search term across common fields.', inputSchema: { entity: z.string(), searchTerm: z.string(), searchFields: z.array(z.string()).optional(), count: z.number().min(1).max(200).optional(), }, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, async (args) => { try { const where = buildWhereClause(args.entity, args.searchTerm, args.searchFields); const result = await restClient.query({ entity: args.entity, where, count: args.count, }); return formatQueryResponse(result.records, result.pagination); } catch (error) { return formatToolError(error, getErrorHint(classifyError(error))); } }, ); } export { buildWhereClause };