Skip to main content
Glama
backward-compatibility.e2e.test.ts11.8 kB
/** * E2E Backward Compatibility Test * * Verifies that deprecated tool names (kebab-case and noun-verb patterns) * continue to work via the alias system until their planned removal in v2.0.0. * * This ensures existing integrations won't break during the transition period. */ import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest'; import { E2ETestBase } from '../setup.js'; import { E2EAssertions } from '../utils/assertions.js'; import { CompanyFactory } from '../fixtures/index.js'; import type { McpToolResponse } from '../types/index.js'; import { callUniversalTool, validateTestEnvironment, } from '../utils/enhanced-tool-caller.js'; import { startTestSuite, endTestSuite } from '../utils/logger.js'; import { resolveToolName } from '@/config/tool-aliases.js'; function asToolResponse(response: unknown): McpToolResponse { return response as McpToolResponse; } describe.skipIf( !process.env.ATTIO_API_KEY || process.env.SKIP_E2E_TESTS === 'true' )('Backward Compatibility E2E', () => { let testCompanyId: string; beforeAll(async () => { startTestSuite('backward-compatibility'); const envValidation = await validateTestEnvironment(); if (!envValidation.valid) { console.warn('⚠️ Test environment warnings:', envValidation.warnings); } await E2ETestBase.setup({ requiresRealApi: true, cleanupAfterTests: true, timeout: 120000, }); console.error('🚀 Starting Backward Compatibility E2E'); // Create a test company for operations const companyResponse = asToolResponse( await callUniversalTool('create_record', { resource_type: 'companies', record_data: CompanyFactory.create() as any, }) ); E2EAssertions.expectMcpSuccess(companyResponse); const company = E2EAssertions.expectMcpData(companyResponse); testCompanyId = company.id.record_id; }, 120000); afterAll(async () => { // Cleanup test company if (testCompanyId) { await callUniversalTool('delete_record', { resource_type: 'companies', record_id: testCompanyId, }); } endTestSuite(); console.error('✅ Backward Compatibility E2E completed'); }, 60000); describe('Alias Resolution System', () => { it('should resolve kebab-case alias to snake_case target', () => { const resolution = resolveToolName('search-records'); expect(resolution.name).toBe('search_records'); expect(resolution.alias).toBeDefined(); expect(resolution.alias?.alias).toBe('search-records'); expect(resolution.alias?.definition.target).toBe('search_records'); expect(resolution.alias?.definition.removal).toBe('v2.0.0'); expect(resolution.alias?.definition.reason).toContain('#1039'); }); it('should resolve noun-verb alias to verb-first target', () => { const resolution = resolveToolName('records_search'); expect(resolution.name).toBe('search_records'); expect(resolution.alias).toBeDefined(); expect(resolution.alias?.alias).toBe('records_search'); expect(resolution.alias?.definition.target).toBe('search_records'); expect(resolution.alias?.definition.removal).toBe('v2.0.0'); }); it('should return canonical name unchanged', () => { const resolution = resolveToolName('search_records'); expect(resolution.name).toBe('search_records'); expect(resolution.alias).toBeUndefined(); }); }); describe('CRUD Tool Aliases', () => { it('should work with kebab-case create-record alias', async () => { const companyData = CompanyFactory.create() as any; const kebabResponse = asToolResponse( await callUniversalTool('create-record', { resource_type: 'companies', record_data: companyData, }) ); E2EAssertions.expectMcpSuccess(kebabResponse); const company = E2EAssertions.expectMcpData(kebabResponse); E2EAssertions.expectCompanyRecord(company); // Cleanup await callUniversalTool('delete_record', { resource_type: 'companies', record_id: company.id.record_id, }); }, 60000); it('should work with kebab-case get-record-details alias', async () => { const kebabResponse = asToolResponse( await callUniversalTool('get-record-details', { resource_type: 'companies', record_id: testCompanyId, }) ); E2EAssertions.expectMcpSuccess(kebabResponse); const company = E2EAssertions.expectMcpData(kebabResponse); expect(company.id.record_id).toBe(testCompanyId); }, 60000); it('should work with kebab-case update-record alias', async () => { const kebabResponse = asToolResponse( await callUniversalTool('update-record', { resource_type: 'companies', record_id: testCompanyId, record_data: { description: 'Updated via kebab-case alias', }, }) ); E2EAssertions.expectMcpSuccess(kebabResponse); }, 60000); }); describe('Search Tool Aliases', () => { it('should work with kebab-case search-records alias', async () => { const kebabResponse = asToolResponse( await callUniversalTool('search-records', { resource_type: 'companies', limit: 5, }) ); E2EAssertions.expectMcpSuccess(kebabResponse); const data = E2EAssertions.expectMcpData(kebabResponse); expect(data).toHaveProperty('records'); }, 60000); it('should work with noun-verb records_search alias', async () => { const nounVerbResponse = asToolResponse( await callUniversalTool('records_search', { resource_type: 'companies', limit: 5, }) ); E2EAssertions.expectMcpSuccess(nounVerbResponse); const data = E2EAssertions.expectMcpData(nounVerbResponse); expect(data).toHaveProperty('records'); }, 60000); it('should produce identical results for all search name variants', async () => { const params = { resource_type: 'companies', limit: 3 }; const [canonicalResponse, kebabResponse, nounVerbResponse] = await Promise.all([ callUniversalTool('search_records', params), callUniversalTool('search-records', params), callUniversalTool('records_search', params), ]); // All should succeed E2EAssertions.expectMcpSuccess(asToolResponse(canonicalResponse)); E2EAssertions.expectMcpSuccess(asToolResponse(kebabResponse)); E2EAssertions.expectMcpSuccess(asToolResponse(nounVerbResponse)); // All should return records const canonicalData = E2EAssertions.expectMcpData( asToolResponse(canonicalResponse) ); const kebabData = E2EAssertions.expectMcpData( asToolResponse(kebabResponse) ); const nounVerbData = E2EAssertions.expectMcpData( asToolResponse(nounVerbResponse) ); expect(canonicalData).toHaveProperty('records'); expect(kebabData).toHaveProperty('records'); expect(nounVerbData).toHaveProperty('records'); }, 60000); }); describe('Advanced Operation Aliases', () => { it('should work with kebab-case advanced-search alias', async () => { const kebabResponse = asToolResponse( await callUniversalTool('advanced-search', { resource_type: 'companies', filters: [ { attribute: 'name', operator: 'contains', value: 'Test', }, ], }) ); E2EAssertions.expectMcpSuccess(kebabResponse); }, 60000); it('should work with noun-verb records_search_advanced alias', async () => { const nounVerbResponse = asToolResponse( await callUniversalTool('records_search_advanced', { resource_type: 'companies', filters: [ { attribute: 'name', operator: 'contains', value: 'Test', }, ], }) ); E2EAssertions.expectMcpSuccess(nounVerbResponse); }, 60000); }); describe('Metadata Tool Aliases', () => { it('should work with noun-verb records_get_attributes alias', async () => { const nounVerbResponse = asToolResponse( await callUniversalTool('records_get_attributes', { resource_type: 'companies', }) ); E2EAssertions.expectMcpSuccess(nounVerbResponse); const data = E2EAssertions.expectMcpData(nounVerbResponse); expect(data).toHaveProperty('attributes'); }, 60000); it('should work with noun-verb records_discover_attributes alias', async () => { const nounVerbResponse = asToolResponse( await callUniversalTool('records_discover_attributes', { resource_type: 'companies', }) ); E2EAssertions.expectMcpSuccess(nounVerbResponse); }, 60000); }); describe('Batch Operation Aliases', () => { it('should work with kebab-case batch-operations alias', async () => { const kebabResponse = asToolResponse( await callUniversalTool('batch-operations', { resource_type: 'companies', operations: [ { operation: 'create', record_data: CompanyFactory.create() as any, }, ], }) ); E2EAssertions.expectMcpSuccess(kebabResponse); // Cleanup created company const data = E2EAssertions.expectMcpData(kebabResponse); if (data.results?.[0]?.data?.id?.record_id) { await callUniversalTool('delete_record', { resource_type: 'companies', record_id: data.results[0].data.id.record_id, }); } }, 60000); it('should work with noun-verb records_batch alias', async () => { const nounVerbResponse = asToolResponse( await callUniversalTool('records_batch', { resource_type: 'companies', operations: [ { operation: 'create', record_data: CompanyFactory.create() as any, }, ], }) ); E2EAssertions.expectMcpSuccess(nounVerbResponse); // Cleanup created company const data = E2EAssertions.expectMcpData(nounVerbResponse); if (data.results?.[0]?.data?.id?.record_id) { await callUniversalTool('delete_record', { resource_type: 'companies', record_id: data.results[0].data.id.record_id, }); } }, 60000); }); describe('Note Tool Aliases', () => { it('should work with kebab-case create-note alias', async () => { const kebabResponse = asToolResponse( await callUniversalTool('create-note', { resource_type: 'companies', record_id: testCompanyId, title: 'Test note via kebab-case alias', content: 'This note was created using the kebab-case alias', }) ); E2EAssertions.expectMcpSuccess(kebabResponse); }, 60000); it('should work with kebab-case list-notes alias', async () => { const kebabResponse = asToolResponse( await callUniversalTool('list-notes', { resource_type: 'companies', record_id: testCompanyId, }) ); E2EAssertions.expectMcpSuccess(kebabResponse); const data = E2EAssertions.expectMcpData(kebabResponse); expect(data).toHaveProperty('notes'); }, 60000); }); describe('Diagnostic Tool Aliases', () => { it('should work with kebab-case smithery-debug-config alias', async () => { const kebabResponse = asToolResponse( await callUniversalTool('smithery-debug-config', {}) ); E2EAssertions.expectMcpSuccess(kebabResponse); }, 60000); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kesslerio/attio-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server