Skip to main content
Glama

Chess Analysis Assistant

by turlockmike
MIT License
4
15
  • Apple
  • Linux
play-move.handler.test.ts5.64 kB
import { describe, it, expect, jest, beforeEach, beforeAll, afterAll } from '@jest/globals'; import { PlayMoveHandler } from '../handlers/play-move.handler.js'; import { ChessEngine } from '../chess-engine.js'; import { ChessImageService } from '../chess-image-service.js'; import { CallToolRequest, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; jest.mock('../chess-image-service.js'); describe('PlayMoveHandler', () => { let handler: PlayMoveHandler; let engine: ChessEngine; let mockImageService: jest.Mocked<ChessImageService>; beforeAll(async () => { engine = new ChessEngine('/opt/homebrew/bin/stockfish'); await engine.init(); }, 30000); afterAll(async () => { await engine.quit(); }, 30000); beforeEach(() => { mockImageService = new ChessImageService() as jest.Mocked<ChessImageService>; mockImageService.generateImage = jest.fn(); handler = new PlayMoveHandler(engine, mockImageService); }); const createRequest = (args: any): CallToolRequest => ({ method: 'tools/call', params: { name: 'play-move', arguments: args } }); describe('handle', () => { it('should validate a legal move from starting position', async () => { const startPos = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'; const move = 'e2e4'; const expectedFen = 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1'; const result = await handler.handle(createRequest({ move })); expect(result.content[0]).toEqual({ type: 'text', text: `Move ${move} is legal. New position: ${expectedFen}` }); expect(result.isError).toBeUndefined(); expect(result.errorCode).toBeUndefined(); }); it('should handle illegal moves', async () => { const move = 'e2e5'; // Illegal pawn move - can't move 3 squares const result = await handler.handle(createRequest({ move })); expect(result.content[0]).toEqual({ type: 'text', text: `Move ${move} is illegal.` }); expect(result.content.length).toBe(1); // No evaluation or image for illegal moves expect(result.isError).toBe(true); expect(result.errorCode).toBe(ErrorCode.InvalidRequest); }); it('should handle invalid move format', async () => { const result = await handler.handle(createRequest({ move: 'invalid' })); expect(result.isError).toBe(true); expect(result.errorCode).toBe(ErrorCode.InvalidRequest); expect(result.content[0].type).toBe('text'); expect(result.content[0].text).toBe('Error: Invalid move format'); }); it('should handle invalid FEN', async () => { const result = await handler.handle(createRequest({ fen: 'invalid-fen', move: 'e2e4' })); expect(result.isError).toBe(true); expect(result.errorCode).toBe(ErrorCode.InvalidRequest); expect(result.content[0].type).toBe('text'); expect(result.content[0].text).toBe('Error: Invalid FEN position'); }); it('should include evaluation when requested', async () => { const move = 'e2e4'; const result = await handler.handle(createRequest({ move, includeEvaluation: true })); expect(result.content[0].type).toBe('text'); expect(result.content[0].text).toContain('legal'); expect(result.content[1].type).toBe('text'); // The exact evaluation may vary, but it should be a reasonable number for e4 expect(result.content[1].text).toMatch(/Evaluation: [-\d.]+ pawns/); expect(result.isError).toBeUndefined(); expect(result.errorCode).toBeUndefined(); }, 10000); it('should include image when requested', async () => { const move = 'e2e4'; const imageBuffer = Buffer.from('fake-image-data'); mockImageService.generateImage.mockResolvedValue(imageBuffer); const result = await handler.handle(createRequest({ move, includeImage: true })); expect(result.content[0].type).toBe('text'); expect(result.content[0].text).toContain('legal'); expect(result.content[1]).toEqual({ type: 'image', data: imageBuffer.toString('base64'), mimeType: 'image/png' }); expect(result.isError).toBeUndefined(); expect(result.errorCode).toBeUndefined(); }); it('should handle custom starting position with FEN', async () => { const fen = 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1'; const move = 'e7e5'; const expectedFen = 'rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq e6 0 2'; const result = await handler.handle(createRequest({ fen, move })); expect(result.content[0].text).toBe(`Move ${move} is legal. New position: ${expectedFen}`); expect(result.isError).toBeUndefined(); expect(result.errorCode).toBeUndefined(); }); it('should detect mate positions in evaluation', async () => { // Scholar's mate position const fen = 'r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR w KQkq - 0 4'; const move = 'h5f7'; // Qxf7# const result = await handler.handle(createRequest({ fen, move, includeEvaluation: true })); expect(result.content[0].type).toBe('text'); expect(result.content[0].text).toContain('legal'); expect(result.content[1].type).toBe('text'); expect(result.content[1].text).toContain('Mate'); expect(result.isError).toBeUndefined(); expect(result.errorCode).toBeUndefined(); }, 15000); }); });

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/turlockmike/chess-mcp'

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