andrew-dataverse-mcp
Version:
A Model Context Protocol server for Microsoft Dataverse with comprehensive CRUD operations
113 lines (112 loc) • 4.39 kB
JavaScript
import { validateTableName, validateODataQuery, validatePositiveInteger, validateNonNegativeInteger } from '../utils/validation.js';
import { createLogger } from '../utils/logger.js';
const logger = createLogger('QueryRecordsTool');
export const queryRecordsTool = {
name: 'dataverse_query_records',
description: 'Query multiple records from a Dataverse table with OData filters',
inputSchema: {
type: 'object',
properties: {
table: {
type: 'string',
description: 'The name of the Dataverse table (e.g., "contacts", "accounts")',
},
select: {
type: 'string',
description: 'Comma-separated list of columns to select (optional)',
},
filter: {
type: 'string',
description: 'OData filter expression (optional, e.g., "firstname eq \'John\'")',
},
orderby: {
type: 'string',
description: 'OData orderby expression (optional, e.g., "createdon desc")',
},
top: {
type: 'number',
description: 'Maximum number of records to return (optional)',
},
skip: {
type: 'number',
description: 'Number of records to skip (optional)',
},
expand: {
type: 'string',
description: 'Related entities to expand (optional)',
},
count: {
type: 'boolean',
description: 'Include total count in response (optional)',
},
},
required: ['table'],
},
};
export async function handleQueryRecords(args, dataverseService) {
try {
logger.info('Processing query records request');
// Validate inputs
const table = validateTableName(args.table, 'table');
const select = args.select ? String(args.select).trim() : undefined;
const expand = args.expand ? String(args.expand).trim() : undefined;
const count = args.count ? Boolean(args.count) : undefined;
// Validate OData query parameters
const filter = args.filter ? validateODataQuery(String(args.filter).trim(), 'filter') : undefined;
const orderby = args.orderby ? validateODataQuery(String(args.orderby).trim(), 'orderby') : undefined;
// Validate numeric parameters
const top = args.top ? validatePositiveInteger(args.top, 'top') : undefined;
const skip = args.skip ? validateNonNegativeInteger(args.skip, 'skip') : undefined;
logger.debug(`Querying records from table: ${table}`);
// Query the records
const response = await dataverseService.queryRecords({
table,
select,
filter,
orderby,
top,
skip,
expand,
count,
});
const recordCount = response.value?.length || 0;
const totalCount = response['@odata.count'];
let successMessage = `Successfully retrieved ${recordCount} records from table '${table}'`;
if (totalCount !== undefined) {
successMessage += ` (total available: ${totalCount})`;
}
logger.info(successMessage);
// Format the response
let resultText = `${successMessage}:\n\n`;
if (response.value && response.value.length > 0) {
resultText += JSON.stringify(response.value, null, 2);
}
else {
resultText += 'No records found matching the criteria.';
}
// Add pagination info if available
if (response['@odata.nextLink']) {
resultText += '\n\nNote: More records are available. Use skip parameter to retrieve additional pages.';
}
return {
content: [
{
type: 'text',
text: resultText,
},
],
};
}
catch (error) {
const errorMessage = `Failed to query records: ${error instanceof Error ? error.message : 'Unknown error'}`;
logger.error(errorMessage, error);
return {
content: [
{
type: 'text',
text: errorMessage,
},
],
};
}
}