Skip to main content
Glama
integration.test.ts6.22 kB
import { SentinelMCPServer } from '../server'; import fetch from 'node-fetch'; // Integration tests - these test the MCP protocol end-to-end describe('Sentinel MCP Integration', () => { let server: SentinelMCPServer; let serverUrl: string; beforeAll(async () => { // Set test environment process.env.SENTINEL_PORT = '8788'; process.env.GODOT_PROJECT_ROOT = '/tmp/test-project'; server = new SentinelMCPServer(); await server.start(); serverUrl = 'http://localhost:8788'; }); afterAll(async () => { // Clean up server if (server) { // Server cleanup would go here } }); describe('MCP Protocol', () => { it('should respond to health check', async () => { const response = await fetch(`${serverUrl}/health`); const data = await response.json(); expect(response.status).toBe(200); expect(data).toHaveProperty('status', 'ok'); expect(data).toHaveProperty('timestamp'); }); it('should list available tools', async () => { const mcpRequest = { method: 'tools/list', id: 'test-1' }; const response = await fetch(`${serverUrl}/mcp`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(mcpRequest) }); const data = await response.json(); expect(response.status).toBe(200); expect(data).toHaveProperty('id', 'test-1'); expect(data).toHaveProperty('result'); expect(data.result).toHaveProperty('tools'); expect(Array.isArray(data.result.tools)).toBe(true); // Check for expected tools const toolNames = data.result.tools.map((tool: any) => tool.name); expect(toolNames).toContain('run_tests'); expect(toolNames).toContain('get_context'); expect(toolNames).toContain('apply_patch'); }); it('should handle tool calls with proper schema validation', async () => { const mcpRequest = { method: 'tools/call', params: { name: 'get_context', arguments: { file: 'res://scripts/test.gd', line: 10, radius: 5 } }, id: 'test-2' }; const response = await fetch(`${serverUrl}/mcp`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(mcpRequest) }); const data = await response.json(); expect(response.status).toBe(200); expect(data).toHaveProperty('id', 'test-2'); // Result will depend on whether the file exists, but should not error expect(data).toHaveProperty('result'); }); it('should handle invalid method gracefully', async () => { const mcpRequest = { method: 'invalid_method', id: 'test-3' }; const response = await fetch(`${serverUrl}/mcp`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(mcpRequest) }); const data = await response.json(); expect(response.status).toBe(200); // MCP errors are still HTTP 200 expect(data).toHaveProperty('id', 'test-3'); expect(data).toHaveProperty('error'); expect(data.error).toHaveProperty('code'); expect(data.error).toHaveProperty('message'); }); it('should handle malformed JSON requests', async () => { const response = await fetch(`${serverUrl}/mcp`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: 'invalid json' }); expect(response.status).toBe(500); }); }); describe('Event System', () => { it('should accept events from Godot emitter', async () => { const eventData = { type: 'script_error', file: 'res://scripts/test.gd', line: 42, message: 'Test error message', timestamp: new Date().toISOString() }; const response = await fetch(`${serverUrl}/events`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(eventData) }); const data = await response.json(); expect(response.status).toBe(200); expect(data).toHaveProperty('received', true); }); it('should reject invalid event format', async () => { const invalidEvent = { invalid: 'data' }; const response = await fetch(`${serverUrl}/events`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(invalidEvent) }); expect(response.status).toBe(400); }); }); }); describe('CLI Integration', () => { // These tests would require mocking the CLI commands // or setting up a test Godot project it.skip('should run sentinel test command', async () => { // This would test the actual CLI functionality // Skipped because it requires a real Godot project }); it.skip('should handle file watching', async () => { // Test the watch command functionality // Skipped because it requires file system setup }); }); describe('Error Parsing Integration', () => { it('should handle real Godot error patterns', () => { // Test with actual Godot 4 error messages const realErrors = [ 'ERROR: Invalid call. Nonexistent function \'get_damage\' in base \'Node\'.\nAt: res://scripts/combat/fighter.gd:45 @ _ready()', 'SCRIPT ERROR: Parse Error at line 67: Expected \')\' after expression\nPath: res://scripts/combat/state_machine.gd', 'SCRIPT ERROR: Invalid get index \'health\' (on base: \'null instance\')\nAt: res://scripts/combat/fighter.gd:89 @ take_damage()' ]; // Import parser here to avoid circular dependencies in tests const { ParserGodot4 } = require('../adapters/parser_godot4'); const parser = new ParserGodot4(); realErrors.forEach(errorText => { const parsed = parser.parseFirstError(errorText); expect(parsed).not.toBeNull(); expect(parsed).toHaveProperty('file'); expect(parsed).toHaveProperty('line'); expect(parsed).toHaveProperty('message'); expect(typeof parsed?.line).toBe('number'); }); }); });

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/Snack-JPG/Godot-Sentinel-MCP'

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