Skip to main content
Glama

OpenFGA MCP

ConfigurationParser.php8.24 kB
<?php declare(strict_types=1); namespace OpenFGA\MCP; use Psr\Log\{LoggerInterface, NullLogger}; use function gettype; use function in_array; use function is_array; use function is_bool; use function is_string; use function sprintf; use function strlen; final readonly class ConfigurationParser { /** * @var array<string, string> List of all supported configuration keys and their types */ private const array SUPPORTED_CONFIG = [ // Core OpenFGA Connection 'OPENFGA_MCP_API_URL' => 'string', 'OPENFGA_MCP_API_TOKEN' => 'string', 'OPENFGA_MCP_API_CLIENT_ID' => 'string', 'OPENFGA_MCP_API_CLIENT_SECRET' => 'string', 'OPENFGA_MCP_API_ISSUER' => 'string', 'OPENFGA_MCP_API_AUDIENCE' => 'string', // Security & Access Control 'OPENFGA_MCP_API_WRITEABLE' => 'bool', 'OPENFGA_MCP_API_RESTRICT' => 'bool', 'OPENFGA_MCP_API_STORE' => 'string', 'OPENFGA_MCP_API_MODEL' => 'string', // Transport Configuration (rarely set via query params but supported) 'OPENFGA_MCP_TRANSPORT' => 'string', 'OPENFGA_MCP_TRANSPORT_HOST' => 'string', 'OPENFGA_MCP_TRANSPORT_PORT' => 'int', 'OPENFGA_MCP_TRANSPORT_SSE' => 'bool', 'OPENFGA_MCP_TRANSPORT_STATELESS' => 'bool', // Debug & Logging 'OPENFGA_MCP_DEBUG' => 'bool', ]; private LoggerInterface $logger; public function __construct(?LoggerInterface $logger = null) { $this->logger = $logger ?? new NullLogger; } /** * Parse JSON configuration and apply to $_ENV. * * @param string $jsonConfig JSON-encoded configuration string * @return ConfigurationResult Result object with status and details */ public function parseAndApply(string $jsonConfig): ConfigurationResult { $errors = []; $appliedKeys = []; $appliedValues = []; // Decode JSON $config = json_decode($jsonConfig, true); if (JSON_ERROR_NONE !== json_last_error()) { $errors[] = sprintf('Invalid JSON: %s', json_last_error_msg()); return new ConfigurationResult(false, $errors, $appliedKeys, $appliedValues); } if (! is_array($config)) { $errors[] = 'Configuration must be a JSON object'; return new ConfigurationResult(false, $errors, $appliedKeys, $appliedValues); } // Process each configuration value /** @var mixed $value */ foreach ($config as $key => $value) { // Check if key is supported if (! isset(self::SUPPORTED_CONFIG[$key])) { $this->logger->warning('Unsupported configuration key', ['key' => $key]); continue; // Skip unsupported keys silently } // Validate and convert value based on expected type $expectedType = self::SUPPORTED_CONFIG[$key]; $processedValue = $this->processValue($value, $expectedType, $key, $errors); if (null !== $processedValue) { // Apply to $_ENV (highest precedence) $_ENV[$key] = $processedValue; $appliedKeys[] = $key; $appliedValues[$key] = $processedValue; $this->logger->debug('Configuration value set', [ 'key' => $key, 'type' => $expectedType, 'value' => $this->maskSensitiveValue($key, $processedValue), ]); } } // Validate configuration combinations $this->validateConfigurationCombinations($appliedValues, $errors); return new ConfigurationResult( [] === $errors, $errors, $appliedKeys, $appliedValues, ); } /** * Mask sensitive values for logging. * * @param string $key Configuration key * @param string $value Configuration value * @return string Masked value if sensitive, original otherwise */ private function maskSensitiveValue(string $key, string $value): string { $sensitiveKeys = [ 'OPENFGA_MCP_API_TOKEN', 'OPENFGA_MCP_API_CLIENT_SECRET', ]; if (in_array($key, $sensitiveKeys, true) && 4 < strlen($value)) { return substr($value, 0, 4) . str_repeat('*', min(12, strlen($value) - 4)); } return $value; } /** * Process and validate a single configuration value. * * @param mixed $value The raw value from JSON * @param string $expectedType The expected type (string, int, bool) * @param string $key The configuration key (for error messages) * @param array<string> $errors Array to collect error messages * @return string|null Processed value or null if invalid */ private function processValue(mixed $value, string $expectedType, string $key, array &$errors): ?string { switch ($expectedType) { case 'string': if (! is_string($value) && ! is_numeric($value)) { $errors[] = sprintf('%s must be a string, %s given', $key, gettype($value)); return null; } return (string) $value; case 'int': if (! is_numeric($value)) { $errors[] = sprintf('%s must be numeric, %s given', $key, gettype($value)); return null; } return (string) (int) $value; case 'bool': if (is_bool($value)) { return $value ? 'true' : 'false'; } if (is_string($value) && in_array(strtolower($value), ['true', 'false', '1', '0'], true)) { return in_array(strtolower($value), ['true', '1'], true) ? 'true' : 'false'; } if (is_numeric($value)) { return ((bool) $value) ? 'true' : 'false'; } $errors[] = sprintf('%s must be a boolean, %s given', $key, gettype($value)); return null; default: $errors[] = sprintf('Unknown type %s for key %s', $expectedType, $key); return null; } } /** * Validate that certain configuration combinations are valid. * * @param array<string, string> $config Applied configuration values * @param array<string> $errors Array to collect error messages */ private function validateConfigurationCombinations(array $config, array &$errors): void { // If OAuth2 client credentials are provided, all related fields must be present $hasClientId = isset($config['OPENFGA_MCP_API_CLIENT_ID']) && '' !== $config['OPENFGA_MCP_API_CLIENT_ID']; $hasClientSecret = isset($config['OPENFGA_MCP_API_CLIENT_SECRET']) && '' !== $config['OPENFGA_MCP_API_CLIENT_SECRET']; $hasIssuer = isset($config['OPENFGA_MCP_API_ISSUER']) && '' !== $config['OPENFGA_MCP_API_ISSUER']; $hasAudience = isset($config['OPENFGA_MCP_API_AUDIENCE']) && '' !== $config['OPENFGA_MCP_API_AUDIENCE']; if (($hasClientId || $hasClientSecret) && (! $hasClientId || ! $hasClientSecret || ! $hasIssuer || ! $hasAudience)) { $errors[] = 'OAuth2 client credentials require all of: OPENFGA_MCP_API_CLIENT_ID, OPENFGA_MCP_API_CLIENT_SECRET, OPENFGA_MCP_API_ISSUER, OPENFGA_MCP_API_AUDIENCE'; } // If restricted mode is enabled, store and model must be provided $isRestricted = isset($config['OPENFGA_MCP_API_RESTRICT']) && 'true' === $config['OPENFGA_MCP_API_RESTRICT']; if ($isRestricted) { $hasStore = isset($config['OPENFGA_MCP_API_STORE']) && '' !== $config['OPENFGA_MCP_API_STORE']; $hasModel = isset($config['OPENFGA_MCP_API_MODEL']) && '' !== $config['OPENFGA_MCP_API_MODEL']; if (! $hasStore || ! $hasModel) { $errors[] = 'Restricted mode requires both OPENFGA_MCP_API_STORE and OPENFGA_MCP_API_MODEL to be set'; } } } }

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