90 lines
4.5 KiB
JavaScript
90 lines
4.5 KiB
JavaScript
import { z } from "zod";
|
|
import { withAuth, getSessionCredentials } from "../../auth/index.js";
|
|
import { handleToolError, validateRequired, handleApiResponse } from "../helpers/errorHandler.js";
|
|
import { AcaiHttpClient } from "../helpers/acaiHttpClient.js";
|
|
import { withAuthParams } from "../helpers/authSchema.js";
|
|
|
|
export function registerListTableRecordsTool(server) {
|
|
server.tool(
|
|
"list_table_records",
|
|
"List or search records in a database table. Returns JSON. Default limit is 50 — request only what you need. Use 'fields' to return only the columns you need (saves tokens). ALWAYS use 'num' as primary key, NEVER 'id'. Upload fields are arrays with urlPath.",
|
|
withAuthParams({
|
|
tableName: z.string().describe("Name of the table (without 'cms_' prefix, e.g., 'productos')"),
|
|
page: z.number().optional().describe("Page number (default: 1)"),
|
|
where: z.string().optional().describe("SQL WHERE clause to filter records (e.g., \"name LIKE '%keyword%'\")"),
|
|
limit: z.number().optional().describe("Max records to return. Default: 50. Use 5-10 for previews, up to 200 max for large exports."),
|
|
fields: z.array(z.string()).optional().describe("Return only these columns (e.g., ['num', 'titulo', 'precio']). Omit to return all columns. Always include 'num' if you need record IDs."),
|
|
truncateText: z.number().optional().describe("Truncate string field values longer than this many chars. Appends '... [truncated, N chars]'. Combine with 'fields' for maximum token savings."),
|
|
}),
|
|
{ readOnlyHint: true, destructiveHint: false },
|
|
withAuth(async ({ tableName, page, where, limit, fields, truncateText }, extra) => {
|
|
try {
|
|
// Validate required parameters
|
|
const validationError = validateRequired({ tableName }, ['tableName'], 'list_table_records');
|
|
if (validationError) return validationError;
|
|
|
|
// Build payload for CMS API
|
|
const credentials = await getSessionCredentials(extra.sessionId);
|
|
const payload = {
|
|
tableName: tableName,
|
|
where: where || "",
|
|
order: "",
|
|
limit: limit || 50,
|
|
options: {}
|
|
};
|
|
|
|
// Send to CMS API via viewer_functions
|
|
const response = await AcaiHttpClient.postCmsApi(
|
|
credentials,
|
|
'get',
|
|
payload,
|
|
credentials.token,
|
|
credentials.tokenHash
|
|
);
|
|
|
|
// Check for API errors
|
|
const apiError = handleApiResponse(response.data, 'list_table_records');
|
|
if (apiError) return apiError;
|
|
|
|
// Post-process: filter fields if requested
|
|
let resultData = response.data;
|
|
if (fields && fields.length > 0 && Array.isArray(resultData?.data)) {
|
|
resultData = {
|
|
...resultData,
|
|
data: resultData.data.map(record =>
|
|
Object.fromEntries(fields.map(f => [f, record[f]]))
|
|
)
|
|
};
|
|
}
|
|
|
|
// Post-process: truncate long text values if requested
|
|
if (truncateText && truncateText > 0 && Array.isArray(resultData?.data)) {
|
|
resultData = {
|
|
...resultData,
|
|
data: resultData.data.map(record => {
|
|
const truncated = {};
|
|
for (const [key, value] of Object.entries(record)) {
|
|
if (typeof value === 'string' && value.length > truncateText) {
|
|
truncated[key] = value.substring(0, truncateText) + `... [truncated, ${value.length} chars]`;
|
|
} else {
|
|
truncated[key] = value;
|
|
}
|
|
}
|
|
return truncated;
|
|
})
|
|
};
|
|
}
|
|
|
|
return {
|
|
content: [{
|
|
type: "text",
|
|
text: JSON.stringify(resultData, null, 2)
|
|
}],
|
|
};
|
|
} catch (error) {
|
|
return handleToolError(error, 'list_table_records', { tableName, page });
|
|
}
|
|
})
|
|
);
|
|
}
|