Skip to main content
Glama

OpenFGA MCP

ObjectCompletionProvider.php4.83 kB
<?php declare(strict_types=1); namespace OpenFGA\MCP\Completions; use OpenFGA\Models\TupleKey; use OpenFGA\Responses\ReadTuplesResponseInterface; use Override; use PhpMcp\Server\Contracts\SessionInterface; use Throwable; use function array_slice; use function assert; final readonly class ObjectCompletionProvider extends AbstractCompletions { /** * Get completion suggestions for object identifiers from OpenFGA relationship tuples. * * @param string $currentValue * @param SessionInterface $session * @return array<string> */ #[Override] public function getCompletions(string $currentValue, SessionInterface $session): array { // Return common object patterns in offline mode if ($this->isOffline()) { return $this->getCommonObjectPatterns($currentValue); } try { // Try to get store ID from session context $storeId = $this->extractStoreIdFromSession($session); if (null === $storeId) { return $this->getCommonObjectPatterns($currentValue); } // Check if access to this store is restricted if ($this->isRestricted($storeId)) { return []; } // Read relationship tuples to extract objects $objects = []; // Use wildcard tuple (empty strings act as wildcards) to read all tuples $tuple = new TupleKey( user: '', relation: '', object: '', ); $this->client->readTuples( store: $storeId, tuple: $tuple, pageSize: 50, ) ->failure(static function (): void { // If we can't fetch tuples, objects will remain empty }) ->success(static function (mixed $response) use (&$objects): void { assert($response instanceof ReadTuplesResponseInterface); $tuples = $response->getTuples(); foreach ($tuples as $tuple) { $object = $tuple->getKey()->getObject(); if ('' !== $object) { $objects[] = $object; } } }); if ([] === $objects) { return $this->getCommonObjectPatterns($currentValue); } // Remove duplicates and sort $objects = array_unique($objects); sort($objects); // Limit to reasonable number for performance $objects = array_slice($objects, 0, 50); return $this->filterCompletions($objects, $currentValue); } catch (Throwable) { // Handle any unexpected errors gracefully return $this->getCommonObjectPatterns($currentValue); } } /** * Get common object identifier patterns as fallback. * * @param string $currentValue * @return array<string> */ private function getCommonObjectPatterns(string $currentValue): array { // If the value already has a type prefix, provide common ID suggestions if (str_contains($currentValue, ':')) { [$type] = explode(':', $currentValue, 2); // Provide common ID patterns based on the type $suggestions = match ($type) { 'document', 'doc' => [ $type . ':budget', $type . ':plan', $type . ':report', $type . ':proposal', ], 'folder' => [ $type . ':root', $type . ':shared', $type . ':public', $type . ':private', ], 'user' => [ $type . ':alice', $type . ':bob', $type . ':admin', ], 'group' => [ $type . ':admins', $type . ':editors', $type . ':viewers', ], // For unknown types, suggest generic IDs default => [ $type . ':1', $type . ':default', $type . ':main', ], }; return $this->filterCompletions($suggestions, $currentValue); } // If no type prefix, suggest common type prefixes $commonPatterns = [ 'document:', 'doc:', 'folder:', 'user:', 'group:', ]; return $this->filterCompletions($commonPatterns, $currentValue); } }

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