Skip to main content
Glama

OpenFGA MCP

AbstractResourcesTest.php16.2 kB
<?php declare(strict_types=1); namespace OpenFGA\MCP\Tests\Unit\Resources; use OpenFGA\MCP\Resources\AbstractResources; use ReflectionClass; use function in_array; beforeEach(function (): void { $this->resources = new TestableResources; }); afterEach(function (): void { // Clean up environment variables unset($_ENV['OPENFGA_MCP_API_URL'], $_ENV['OPENFGA_MCP_API_TOKEN'], $_ENV['OPENFGA_MCP_API_CLIENT_ID'], $_ENV['OPENFGA_MCP_API_RESTRICT'], $_ENV['OPENFGA_MCP_API_STORE'], $_ENV['OPENFGA_MCP_API_MODEL']); putenv('OPENFGA_MCP_API_URL'); putenv('OPENFGA_MCP_API_TOKEN'); putenv('OPENFGA_MCP_API_CLIENT_ID'); putenv('OPENFGA_MCP_API_RESTRICT'); putenv('OPENFGA_MCP_API_STORE'); putenv('OPENFGA_MCP_API_MODEL'); }); describe('AbstractResources', function (): void { describe('class structure', function (): void { it('is an abstract class', function (): void { $reflection = new ReflectionClass(AbstractResources::class); expect($reflection->isAbstract())->toBeTrue(); }); it('is readonly', function (): void { $reflection = new ReflectionClass(AbstractResources::class); expect($reflection->isReadOnly())->toBeTrue(); }); it('has protected methods', function (): void { $reflection = new ReflectionClass(AbstractResources::class); $checkOfflineMode = $reflection->getMethod('checkOfflineMode'); expect($checkOfflineMode->isProtected())->toBeTrue(); $checkRestrictedMode = $reflection->getMethod('checkRestrictedMode'); expect($checkRestrictedMode->isProtected())->toBeTrue(); }); }); describe('checkOfflineMode', function (): void { it('returns null when not in offline mode', function (): void { // Set up online mode $_ENV['OPENFGA_MCP_API_URL'] = 'http://localhost:8080'; $result = $this->resources->testCheckOfflineMode('Test Operation'); expect($result)->toBeNull(); }); it('returns error array when in offline mode (no URL)', function (): void { // Clear all connection settings for offline mode unset($_ENV['OPENFGA_MCP_API_URL'], $_ENV['OPENFGA_MCP_API_TOKEN'], $_ENV['OPENFGA_MCP_API_CLIENT_ID']); $result = $this->resources->testCheckOfflineMode('Test Operation'); expect($result)->toBeArray(); expect($result)->toHaveKey('error'); expect($result['error'])->toContain('❌'); expect($result['error'])->toContain('Test Operation'); expect($result['error'])->toContain('requires a live OpenFGA instance'); expect($result['error'])->toContain('OPENFGA_MCP_API_URL'); }); it('returns error with custom operation name', function (): void { unset($_ENV['OPENFGA_MCP_API_URL'], $_ENV['OPENFGA_MCP_API_TOKEN'], $_ENV['OPENFGA_MCP_API_CLIENT_ID']); $result = $this->resources->testCheckOfflineMode('Fetching authorization models'); expect($result)->toBeArray(); expect($result['error'])->toContain('Fetching authorization models'); }); it('returns error when URL is empty string', function (): void { unset($_ENV['OPENFGA_MCP_API_URL'], $_ENV['OPENFGA_MCP_API_TOKEN'], $_ENV['OPENFGA_MCP_API_CLIENT_ID']); $result = $this->resources->testCheckOfflineMode('Operation'); expect($result)->toBeArray(); expect($result)->toHaveKey('error'); }); it('returns null when token is set without URL', function (): void { // Token with no URL is considered online mode (intent to connect) unset($_ENV['OPENFGA_MCP_API_URL']); $_ENV['OPENFGA_MCP_API_TOKEN'] = 'some-token'; $result = $this->resources->testCheckOfflineMode('Operation'); // Should return null because having a token indicates online mode expect($result)->toBeNull(); }); it('returns null when client ID is set without URL', function (): void { // Client ID with no URL is considered online mode (intent to connect) unset($_ENV['OPENFGA_MCP_API_URL']); $_ENV['OPENFGA_MCP_API_CLIENT_ID'] = 'client-123'; $result = $this->resources->testCheckOfflineMode('Operation'); // Should return null because having a client ID indicates online mode expect($result)->toBeNull(); }); }); describe('checkRestrictedMode', function (): void { describe('when not in restricted mode', function (): void { it('returns null when restricted mode is disabled (default)', function (): void { unset($_ENV['OPENFGA_MCP_API_RESTRICT']); $result = $this->resources->testCheckRestrictedMode('any-store', 'any-model'); expect($result)->toBeNull(); }); it('returns null when restricted mode is explicitly false', function (): void { $_ENV['OPENFGA_MCP_API_RESTRICT'] = 'false'; $result = $this->resources->testCheckRestrictedMode('store-123', 'model-456'); expect($result)->toBeNull(); }); it('returns null for any value other than "true"', function (): void { $_ENV['OPENFGA_MCP_API_RESTRICT'] = 'yes'; $result = $this->resources->testCheckRestrictedMode('store', 'model'); expect($result)->toBeNull(); $_ENV['OPENFGA_MCP_API_RESTRICT'] = '1'; $result = $this->resources->testCheckRestrictedMode('store', 'model'); expect($result)->toBeNull(); $_ENV['OPENFGA_MCP_API_RESTRICT'] = 'TRUE'; $result = $this->resources->testCheckRestrictedMode('store', 'model'); expect($result)->toBeNull(); }); }); describe('when in restricted mode', function (): void { beforeEach(function (): void { $_ENV['OPENFGA_MCP_API_RESTRICT'] = 'true'; }); describe('store restrictions', function (): void { it('returns null when querying the configured store', function (): void { $_ENV['OPENFGA_MCP_API_STORE'] = 'allowed-store'; $result = $this->resources->testCheckRestrictedMode('allowed-store', null); expect($result)->toBeNull(); }); it('returns error when querying a different store', function (): void { $_ENV['OPENFGA_MCP_API_STORE'] = 'allowed-store'; $result = $this->resources->testCheckRestrictedMode('different-store', null); expect($result)->toBeArray(); expect($result)->toHaveKey('error'); expect($result['error'])->toContain('❌'); expect($result['error'])->toContain('restricted mode'); expect($result['error'])->toContain('allowed-store'); expect($result['error'])->toContain('cannot query stores other than'); }); it('returns null when no store restriction is configured', function (): void { unset($_ENV['OPENFGA_MCP_API_STORE']); $result = $this->resources->testCheckRestrictedMode('any-store', null); expect($result)->toBeNull(); }); it('returns null when store ID is null', function (): void { $_ENV['OPENFGA_MCP_API_STORE'] = 'restricted-store'; $result = $this->resources->testCheckRestrictedMode(null, null); expect($result)->toBeNull(); }); it('handles empty string store restriction', function (): void { unset($_ENV['OPENFGA_MCP_API_STORE']); $result = $this->resources->testCheckRestrictedMode('some-store', null); expect($result)->toBeNull(); }); }); describe('model restrictions', function (): void { it('returns null when querying the configured model', function (): void { $_ENV['OPENFGA_MCP_API_MODEL'] = 'allowed-model'; $result = $this->resources->testCheckRestrictedMode(null, 'allowed-model'); expect($result)->toBeNull(); }); it('returns error when querying a different model', function (): void { $_ENV['OPENFGA_MCP_API_MODEL'] = 'allowed-model'; $result = $this->resources->testCheckRestrictedMode(null, 'different-model'); expect($result)->toBeArray(); expect($result)->toHaveKey('error'); expect($result['error'])->toContain('❌'); expect($result['error'])->toContain('restricted mode'); expect($result['error'])->toContain('allowed-model'); expect($result['error'])->toContain('cannot query using authorization models other than'); }); it('returns null when no model restriction is configured', function (): void { unset($_ENV['OPENFGA_MCP_API_MODEL']); $result = $this->resources->testCheckRestrictedMode(null, 'any-model'); expect($result)->toBeNull(); }); it('returns null when model ID is null', function (): void { $_ENV['OPENFGA_MCP_API_MODEL'] = 'restricted-model'; $result = $this->resources->testCheckRestrictedMode(null, null); expect($result)->toBeNull(); }); it('handles empty string model restriction', function (): void { unset($_ENV['OPENFGA_MCP_API_MODEL']); $result = $this->resources->testCheckRestrictedMode(null, 'some-model'); expect($result)->toBeNull(); }); }); describe('combined store and model restrictions', function (): void { it('returns null when both store and model match', function (): void { $_ENV['OPENFGA_MCP_API_STORE'] = 'allowed-store'; $_ENV['OPENFGA_MCP_API_MODEL'] = 'allowed-model'; $result = $this->resources->testCheckRestrictedMode('allowed-store', 'allowed-model'); expect($result)->toBeNull(); }); it('returns error when store does not match', function (): void { $_ENV['OPENFGA_MCP_API_STORE'] = 'allowed-store'; $_ENV['OPENFGA_MCP_API_MODEL'] = 'allowed-model'; $result = $this->resources->testCheckRestrictedMode('wrong-store', 'allowed-model'); expect($result)->toBeArray(); expect($result['error'])->toContain('allowed-store'); }); it('returns error when model does not match', function (): void { $_ENV['OPENFGA_MCP_API_STORE'] = 'allowed-store'; $_ENV['OPENFGA_MCP_API_MODEL'] = 'allowed-model'; $result = $this->resources->testCheckRestrictedMode('allowed-store', 'wrong-model'); expect($result)->toBeArray(); expect($result['error'])->toContain('allowed-model'); }); it('returns store error first when both do not match', function (): void { $_ENV['OPENFGA_MCP_API_STORE'] = 'allowed-store'; $_ENV['OPENFGA_MCP_API_MODEL'] = 'allowed-model'; $result = $this->resources->testCheckRestrictedMode('wrong-store', 'wrong-model'); expect($result)->toBeArray(); // Store check happens first, so we get store error expect($result['error'])->toContain('allowed-store'); expect($result['error'])->not->toContain('allowed-model'); }); it('allows partial restrictions', function (): void { // Only store restricted $_ENV['OPENFGA_MCP_API_STORE'] = 'allowed-store'; unset($_ENV['OPENFGA_MCP_API_MODEL']); $result = $this->resources->testCheckRestrictedMode('allowed-store', 'any-model'); expect($result)->toBeNull(); // Only model restricted unset($_ENV['OPENFGA_MCP_API_STORE']); $_ENV['OPENFGA_MCP_API_MODEL'] = 'allowed-model'; $result = $this->resources->testCheckRestrictedMode('any-store', 'allowed-model'); expect($result)->toBeNull(); }); }); }); describe('edge cases', function (): void { it('handles special characters in store/model names', function (): void { $_ENV['OPENFGA_MCP_API_RESTRICT'] = 'true'; $_ENV['OPENFGA_MCP_API_STORE'] = 'store-with-special_chars.123'; $result = $this->resources->testCheckRestrictedMode('store-with-special_chars.123', null); expect($result)->toBeNull(); $result = $this->resources->testCheckRestrictedMode('different-store', null); expect($result)->toBeArray(); expect($result['error'])->toContain('store-with-special_chars.123'); }); it('handles case-sensitive comparisons', function (): void { $_ENV['OPENFGA_MCP_API_RESTRICT'] = 'true'; $_ENV['OPENFGA_MCP_API_STORE'] = 'MyStore'; // Case must match exactly $result = $this->resources->testCheckRestrictedMode('mystore', null); expect($result)->toBeArray(); expect($result['error'])->toContain('MyStore'); $result = $this->resources->testCheckRestrictedMode('MyStore', null); expect($result)->toBeNull(); }); it('handles whitespace in configuration', function (): void { $_ENV['OPENFGA_MCP_API_RESTRICT'] = 'true'; $_ENV['OPENFGA_MCP_API_STORE'] = ' '; // Space $result = $this->resources->testCheckRestrictedMode('any-store', null); // Space is trimmed by getConfiguredString, becomes empty string expect($result)->toBeNull(); }); }); }); describe('method visibility and inheritance', function (): void { it('provides protected methods to child classes', function (): void { // Use TestableResources instead of anonymous class to avoid Pest crash $childClass = new TestableResources; // Use reflection to verify methods exist $reflection = new ReflectionClass($childClass); $methods = $reflection->getMethods(); $methodNames = array_map(fn ($m) => $m->getName(), $methods); expect(in_array('checkOfflineMode', $methodNames, true))->toBeTrue(); expect(in_array('checkRestrictedMode', $methodNames, true))->toBeTrue(); }); it('methods return expected types', function (): void { $reflection = new ReflectionClass(AbstractResources::class); $checkOfflineMode = $reflection->getMethod('checkOfflineMode'); $returnType = $checkOfflineMode->getReturnType(); expect($returnType)->not->toBeNull(); expect($returnType->allowsNull())->toBeTrue(); $checkRestrictedMode = $reflection->getMethod('checkRestrictedMode'); $returnType = $checkRestrictedMode->getReturnType(); expect($returnType)->not->toBeNull(); expect($returnType->allowsNull())->toBeTrue(); }); }); });

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/evansims/openfga-mcp'

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