andrew-dataverse-mcp
Version:
A Model Context Protocol server for Microsoft Dataverse with comprehensive CRUD operations
152 lines (151 loc) • 8.61 kB
JavaScript
// Import tool definitions
import { createRecordTool } from '../src/tools/createRecord.js';
import { readRecordTool } from '../src/tools/readRecord.js';
import { queryRecordsTool } from '../src/tools/queryRecords.js';
import { updateRecordTool } from '../src/tools/updateRecord.js';
import { deleteRecordTool } from '../src/tools/deleteRecord.js';
import { listTablesTool } from '../src/tools/listTables.js';
describe('MCP Server Integration', () => {
describe('Tool Definitions', () => {
it('should have correct tool definitions', () => {
// Test createRecordTool
expect(createRecordTool.name).toBe('dataverse_create_record');
expect(createRecordTool.description).toContain('Create a new record');
expect(createRecordTool.inputSchema.required).toEqual(['table', 'data']);
// Test readRecordTool
expect(readRecordTool.name).toBe('dataverse_read_record');
expect(readRecordTool.description).toContain('Read a single record');
expect(readRecordTool.inputSchema.required).toEqual(['table', 'id']);
// Test queryRecordsTool
expect(queryRecordsTool.name).toBe('dataverse_query_records');
expect(queryRecordsTool.description).toContain('Query multiple records');
expect(queryRecordsTool.inputSchema.required).toEqual(['table']);
// Test updateRecordTool
expect(updateRecordTool.name).toBe('dataverse_update_record');
expect(updateRecordTool.description).toContain('Update an existing record');
expect(updateRecordTool.inputSchema.required).toEqual(['table', 'id', 'data']);
// Test deleteRecordTool
expect(deleteRecordTool.name).toBe('dataverse_delete_record');
expect(deleteRecordTool.description).toContain('Delete a record');
expect(deleteRecordTool.inputSchema.required).toEqual(['table', 'id']);
// Test listTablesTool
expect(listTablesTool.name).toBe('dataverse_list_tables');
expect(listTablesTool.description).toContain('List all available tables');
expect(listTablesTool.inputSchema.required).toEqual([]);
});
it('should have proper input schema types', () => {
// Test createRecordTool schema
expect(createRecordTool.inputSchema.properties?.table?.type).toBe('string');
expect(createRecordTool.inputSchema.properties?.data?.type).toBe('object');
// Test readRecordTool schema
expect(readRecordTool.inputSchema.properties?.table?.type).toBe('string');
expect(readRecordTool.inputSchema.properties?.id?.type).toBe('string');
expect(readRecordTool.inputSchema.properties?.select?.type).toBe('string');
// Test queryRecordsTool schema
expect(queryRecordsTool.inputSchema.properties?.table?.type).toBe('string');
expect(queryRecordsTool.inputSchema.properties?.filter?.type).toBe('string');
expect(queryRecordsTool.inputSchema.properties?.top?.type).toBe('number');
// Test updateRecordTool schema
expect(updateRecordTool.inputSchema.properties?.table?.type).toBe('string');
expect(updateRecordTool.inputSchema.properties?.id?.type).toBe('string');
expect(updateRecordTool.inputSchema.properties?.data?.type).toBe('object');
// Test deleteRecordTool schema
expect(deleteRecordTool.inputSchema.properties?.table?.type).toBe('string');
expect(deleteRecordTool.inputSchema.properties?.id?.type).toBe('string');
});
});
describe('Tool Schema Validation', () => {
it('should have valid JSON schemas', () => {
const tools = [
createRecordTool,
readRecordTool,
queryRecordsTool,
updateRecordTool,
deleteRecordTool,
listTablesTool,
];
tools.forEach(tool => {
expect(tool.inputSchema).toBeDefined();
expect(tool.inputSchema.type).toBe('object');
expect(tool.inputSchema.properties).toBeDefined();
expect(Array.isArray(tool.inputSchema.required)).toBe(true);
});
});
it('should have descriptive field descriptions', () => {
// Check that all tools have meaningful descriptions for their parameters
expect(createRecordTool.inputSchema.properties?.table?.description).toContain('table');
expect(createRecordTool.inputSchema.properties?.data?.description).toContain('data');
expect(readRecordTool.inputSchema.properties?.id?.description).toContain('GUID');
expect(readRecordTool.inputSchema.properties?.select?.description).toContain('columns');
expect(queryRecordsTool.inputSchema.properties?.filter?.description).toContain('OData');
expect(queryRecordsTool.inputSchema.properties?.top?.description).toContain('Maximum');
expect(updateRecordTool.inputSchema.properties?.data?.description).toContain('update');
expect(deleteRecordTool.inputSchema.properties?.id?.description).toContain('delete');
});
});
describe('Tool Parameter Validation', () => {
it('should require correct parameters for each tool', () => {
// Create record requires table and data
expect(createRecordTool.inputSchema.required).toContain('table');
expect(createRecordTool.inputSchema.required).toContain('data');
// Read record requires table and id
expect(readRecordTool.inputSchema.required).toContain('table');
expect(readRecordTool.inputSchema.required).toContain('id');
// Query records only requires table
expect(queryRecordsTool.inputSchema.required).toContain('table');
expect(queryRecordsTool.inputSchema.required).not.toContain('filter');
// Update record requires table, id, and data
expect(updateRecordTool.inputSchema.required).toContain('table');
expect(updateRecordTool.inputSchema.required).toContain('id');
expect(updateRecordTool.inputSchema.required).toContain('data');
// Delete record requires table and id
expect(deleteRecordTool.inputSchema.required).toContain('table');
expect(deleteRecordTool.inputSchema.required).toContain('id');
// List tables requires no parameters
expect(listTablesTool.inputSchema.required).toHaveLength(0);
});
it('should have optional parameters marked correctly', () => {
// Read record has optional select and expand
expect(readRecordTool.inputSchema.required).not.toContain('select');
expect(readRecordTool.inputSchema.required).not.toContain('expand');
expect(readRecordTool.inputSchema.properties?.select).toBeDefined();
expect(readRecordTool.inputSchema.properties?.expand).toBeDefined();
// Query records has many optional parameters
const queryOptionalParams = ['select', 'filter', 'orderby', 'top', 'skip', 'expand', 'count'];
queryOptionalParams.forEach(param => {
expect(queryRecordsTool.inputSchema.required).not.toContain(param);
expect(queryRecordsTool.inputSchema.properties?.[param]).toBeDefined();
});
});
});
describe('Tool Names and Consistency', () => {
it('should have consistent naming convention', () => {
const tools = [
createRecordTool,
readRecordTool,
queryRecordsTool,
updateRecordTool,
deleteRecordTool,
listTablesTool,
];
tools.forEach(tool => {
expect(tool.name).toMatch(/^dataverse_/);
expect(tool.name).not.toContain(' ');
expect(tool.name).toBe(tool.name.toLowerCase());
});
});
it('should have unique tool names', () => {
const tools = [
createRecordTool,
readRecordTool,
queryRecordsTool,
updateRecordTool,
deleteRecordTool,
listTablesTool,
];
const names = tools.map(tool => tool.name);
const uniqueNames = new Set(names);
expect(uniqueNames.size).toBe(names.length);
});
});
});