feat(tools): add SOAP tools (sage_soap_read, sage_soap_query, sage_describe_entity)

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-Claude)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-03-10 17:14:47 +00:00
parent 8861e15019
commit 73e59412b4
6 changed files with 744 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
import { z } from 'zod';
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import type { SoapClient } from '../clients/soap-client.js';
import { formatQueryResponse } from '../utils/response.js';
import { formatToolError, classifyError, getErrorHint } from '../utils/errors.js';
export function registerSoapQueryTool(
server: McpServer,
soapClient: SoapClient,
): void {
server.registerTool(
'sage_soap_query',
{
description:
'Query Sage X3 records via SOAP. Returns a list of records matching criteria. Use for bulk data retrieval via SOAP pools.',
inputSchema: {
publicName: z
.string()
.describe('SOAP publication name, e.g. SIH, SOH, WSBPC, WITM'),
listSize: z
.number()
.min(1)
.max(200)
.optional()
.describe('Maximum number of records to return (1-200, default 20)'),
inputXml: z
.string()
.optional()
.describe('Optional XML filter criteria for the query'),
},
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
},
},
async ({ publicName, listSize, inputXml }) => {
try {
const result = await soapClient.query({ publicName, listSize, inputXml });
if (result.status === 1) {
const records = Array.isArray(result.data) ? result.data : result.data ? [result.data] : [];
return formatQueryResponse(records, {
returned: records.length,
hasMore: false,
});
}
const messages = result.messages.map((m) => m.message).join('; ');
return formatToolError(
new Error(messages || 'SOAP query failed'),
'Check the publicName. Use sage_describe_entity to discover available fields.',
);
} catch (error) {
const classification = classifyError(error);
return formatToolError(error, getErrorHint(classification));
}
},
);
}