22c8e915e9
Clean control and invisible junk from tool result text fields to reduce token waste while preserving readable Unicode. Add an MCP_TEXT_SANITIZATION toggle and regression tests for enabled and disabled behavior.
83 lines
2.5 KiB
PHP
83 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace RedMCP;
|
|
|
|
use RuntimeException;
|
|
|
|
final class McpEnvironment
|
|
{
|
|
/**
|
|
* @return array{redmine_url:string,redmine_api_key:string,mcp_server_token:?string,mcp_debug_log:?string,mcp_text_sanitization:bool}
|
|
*/
|
|
public static function load(string $envFile): array
|
|
{
|
|
$env = self::loadFile($envFile);
|
|
$apiKey = getenv('REDMINE_API_KEY') ?: getenv('REDMNINE_API_KEY') ?: ($env['REDMINE_API_KEY'] ?? $env['REDMNINE_API_KEY'] ?? null);
|
|
if (!is_string($apiKey) || trim($apiKey) === '') {
|
|
throw new RuntimeException('REDMINE_API_KEY is required in the environment or redMCP/.env');
|
|
}
|
|
|
|
return [
|
|
'redmine_url' => rtrim((string) (getenv('REDMINE_URL') ?: ($env['REDMINE_URL'] ?? 'http://192.168.50.170')), '/'),
|
|
'redmine_api_key' => $apiKey,
|
|
'mcp_server_token' => self::optionalString(getenv('MCP_SERVER_TOKEN') ?: ($env['MCP_SERVER_TOKEN'] ?? null)),
|
|
'mcp_debug_log' => self::optionalString(getenv('MCP_DEBUG_LOG') ?: ($env['MCP_DEBUG_LOG'] ?? null)),
|
|
'mcp_text_sanitization' => self::boolSetting(getenv('MCP_TEXT_SANITIZATION') ?: ($env['MCP_TEXT_SANITIZATION'] ?? null), true),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<string,string>
|
|
*/
|
|
private static function loadFile(string $path): array
|
|
{
|
|
if (!is_file($path)) {
|
|
return [];
|
|
}
|
|
|
|
$values = [];
|
|
foreach (file($path, FILE_IGNORE_NEW_LINES) ?: [] as $line) {
|
|
$line = trim($line);
|
|
if ($line === '' || str_starts_with($line, '#') || !str_contains($line, '=')) {
|
|
continue;
|
|
}
|
|
[$key, $value] = explode('=', $line, 2);
|
|
$values[trim($key)] = trim(trim($value), "\"'");
|
|
}
|
|
|
|
return $values;
|
|
}
|
|
|
|
private static function optionalString(mixed $value): ?string
|
|
{
|
|
if (!is_string($value) || trim($value) === '') {
|
|
return null;
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
private static function boolSetting(mixed $value, bool $default): bool
|
|
{
|
|
if (!is_string($value)) {
|
|
return $default;
|
|
}
|
|
|
|
$normalized = strtolower(trim($value));
|
|
if ($normalized === '') {
|
|
return $default;
|
|
}
|
|
|
|
if (in_array($normalized, ['1', 'true', 'yes', 'on'], true)) {
|
|
return true;
|
|
}
|
|
if (in_array($normalized, ['0', 'false', 'no', 'off'], true)) {
|
|
return false;
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
}
|