UNPKG

@toolprint/mcp-graphql-forge

Version:

MCP server that exposes GraphQL APIs to AI tools through automatic schema introspection and tool generation

147 lines 6.85 kB
import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { createMockGraphQLServer } from './fixtures/mock-server.js'; import { writeFileSync, unlinkSync, existsSync, readFileSync } from 'fs'; import { join } from 'path'; import { mockIntrospectionResult } from './fixtures/introspection-result.js'; describe('Server Configuration and Initialization', () => { const mockServer = createMockGraphQLServer(4003); const testSchemaPath = join(process.cwd(), 'test-server-schema.json'); beforeAll(async () => { await mockServer.start(); writeFileSync(testSchemaPath, JSON.stringify(mockIntrospectionResult, null, 2)); }); afterAll(async () => { await mockServer.stop(); if (existsSync(testSchemaPath)) { unlinkSync(testSchemaPath); } }); describe('Schema Loading Strategies', () => { it('should load schema from file when available', () => { expect(existsSync(testSchemaPath)).toBe(true); const schemaData = JSON.parse(readFileSync(testSchemaPath, 'utf-8')); expect(schemaData.__schema).toBeDefined(); expect(schemaData.__schema.types).toBeInstanceOf(Array); }); it('should fall back to introspection when file does not exist', async () => { const nonExistentPath = join(process.cwd(), 'non-existent-schema.json'); expect(existsSync(nonExistentPath)).toBe(false); }); }); describe('GraphQL Operation Building', () => { function buildGraphQLOperation(type, operationName, variables) { const variableDeclarations = Object.keys(variables || {}) .map(key => `$${key}: String`) .join(', '); const variableUsage = Object.keys(variables || {}) .map(key => `${key}: $${key}`) .join(', '); return ` ${type} ${operationName}Operation${variableDeclarations ? `(${variableDeclarations})` : ''} { ${operationName}${variableUsage ? `(${variableUsage})` : ''} } `; } it('should build correct query operations', () => { const query = buildGraphQLOperation('query', 'user', { id: '123' }); expect(query).toContain('query userOperation($id: String)'); expect(query).toContain('user(id: $id)'); }); it('should build correct mutation operations', () => { const mutation = buildGraphQLOperation('mutation', 'createUser', { input: { name: 'John', email: 'john@example.com' } }); expect(mutation).toContain('mutation createUserOperation($input: String)'); expect(mutation).toContain('createUser(input: $input)'); }); it('should handle operations with no variables', () => { const query = buildGraphQLOperation('query', 'users', {}); expect(query).toContain('query usersOperation'); expect(query).toContain('users'); expect(query).not.toContain('$'); }); it('should handle operations with multiple variables', () => { const query = buildGraphQLOperation('query', 'users', { limit: 10, offset: 0, searchTerm: 'john' }); expect(query).toContain('$limit: String'); expect(query).toContain('$offset: String'); expect(query).toContain('$searchTerm: String'); expect(query).toContain('limit: $limit'); expect(query).toContain('offset: $offset'); expect(query).toContain('searchTerm: $searchTerm'); }); }); describe('Tool Execution Logic', () => { it('should correctly identify query tools', () => { const toolName = 'query_user'; const isQuery = toolName.startsWith('query_'); const isMutation = toolName.startsWith('mutation_'); expect(isQuery).toBe(true); expect(isMutation).toBe(false); const operationName = toolName.replace(/^(query_|mutation_)/, ''); expect(operationName).toBe('user'); }); it('should correctly identify mutation tools', () => { const toolName = 'mutation_createUser'; const isQuery = toolName.startsWith('query_'); const isMutation = toolName.startsWith('mutation_'); expect(isQuery).toBe(false); expect(isMutation).toBe(true); const operationName = toolName.replace(/^(query_|mutation_)/, ''); expect(operationName).toBe('createUser'); }); it('should reject unknown tool names', () => { const toolName = 'unknown_operation'; const isQuery = toolName.startsWith('query_'); const isMutation = toolName.startsWith('mutation_'); expect(isQuery).toBe(false); expect(isMutation).toBe(false); expect(() => { if (!isQuery && !isMutation) { throw new Error(`Unknown tool: ${toolName}`); } }).toThrow('Unknown tool: unknown_operation'); }); }); describe('Error Handling', () => { it('should handle GraphQL client errors gracefully', () => { const mockError = new Error('GraphQL execution error'); const errorResponse = { content: [ { type: 'text', text: `Error executing query_user: ${mockError.message}` } ], isError: true }; expect(errorResponse.isError).toBe(true); expect(errorResponse.content[0].text).toContain('GraphQL execution error'); }); it('should handle network errors gracefully', () => { const networkError = new Error('Network error: ECONNREFUSED'); const errorResponse = { content: [ { type: 'text', text: `Error executing mutation_createUser: ${networkError.message}` } ], isError: true }; expect(errorResponse.isError).toBe(true); expect(errorResponse.content[0].text).toContain('ECONNREFUSED'); }); it('should handle unknown errors gracefully', () => { const unknownError = 'String error instead of Error object'; const errorMessage = typeof unknownError === 'object' && unknownError !== null && 'message' in unknownError ? unknownError.message : 'Unknown error'; expect(errorMessage).toBe('Unknown error'); }); }); }); //# sourceMappingURL=server.test.js.map