php-sdk/examples/server/oauth-keycloak/McpElements.php
2026-04-26 12:39:27 +02:00

132 lines
4.3 KiB
PHP

<?php
/*
* This file is part of the official PHP MCP SDK.
*
* A collaboration between Symfony and the PHP Foundation.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Mcp\Example\Server\OAuthKeycloak;
use Mcp\Capability\Attribute\McpPrompt;
use Mcp\Capability\Attribute\McpResource;
use Mcp\Capability\Attribute\McpTool;
use Mcp\Server\RequestContext;
/**
* MCP elements for the OAuth Keycloak example.
*
* These tools demonstrate a protected MCP server.
* All requests must include a valid OAuth bearer token.
*/
final class McpElements
{
/**
* Confirms the user is authenticated.
*
* The fact that this tool executes means the request passed OAuth validation.
*
* @return array<string, mixed>
*/
#[McpTool(
name: 'get_auth_status',
description: 'Confirm authentication status - only accessible with valid OAuth token'
)]
public function getAuthStatus(RequestContext $context): array
{
$meta = $context->getRequest()->getMeta() ?? [];
$oauth = isset($meta['oauth']) && \is_array($meta['oauth']) ? $meta['oauth'] : [];
$claims = isset($oauth['oauth.claims']) && \is_array($oauth['oauth.claims']) ? $oauth['oauth.claims'] : [];
$scopes = isset($oauth['oauth.scopes']) && \is_array($oauth['oauth.scopes']) ? $oauth['oauth.scopes'] : [];
return [
'authenticated' => true,
'provider' => 'Keycloak',
'message' => 'You have successfully authenticated with OAuth!',
'timestamp' => date('c'),
'user' => [
'subject' => $oauth['oauth.subject'] ?? ($claims['sub'] ?? null),
'username' => $claims['preferred_username'] ?? null,
'name' => $claims['name'] ?? null,
'email' => $claims['email'] ?? null,
'issuer' => $claims['iss'] ?? null,
'audience' => $claims['aud'] ?? null,
'scopes' => $scopes,
'expires_at' => isset($claims['exp']) && is_numeric($claims['exp'])
? date('c', (int) $claims['exp'])
: null,
],
'note' => 'This endpoint is protected by JWT validation. If you see this, your token was valid.',
];
}
/**
* Simulates calling a protected external API.
*
* @return array<string, mixed>
*/
#[McpTool(
name: 'call_protected_api',
description: 'Simulate calling a protected external API endpoint'
)]
public function callProtectedApi(
string $endpoint,
string $method = 'GET',
): array {
// In a real implementation, you would:
// 1. Use token exchange to get a token for the downstream API
// 2. Or use client credentials with the user's context
// 3. Make the actual HTTP call to the protected API
return [
'status' => 'success',
'message' => \sprintf('Simulated %s request to %s', $method, $endpoint),
'simulated_response' => [
'data' => 'This is simulated data from the protected API',
'timestamp' => date('c'),
],
];
}
/**
* Returns the current server time and status.
*
* @return array<string, mixed>
*/
#[McpResource(
uri: 'server://status',
name: 'server_status',
description: 'Current server status (protected resource)',
mimeType: 'application/json'
)]
public function getServerStatus(): array
{
return [
'status' => 'healthy',
'timestamp' => date('c'),
'php_version' => \PHP_VERSION,
'memory_usage_mb' => round(memory_get_usage(true) / 1024 / 1024, 2),
'protected' => true,
];
}
/**
* A greeting prompt.
*/
#[McpPrompt(
name: 'greeting',
description: 'Generate a greeting message'
)]
public function greeting(string $style = 'formal'): string
{
return match ($style) {
'casual' => 'Hey there! Welcome to the protected MCP server!',
'formal' => 'Good day. Welcome to the OAuth-protected MCP server.',
'friendly' => 'Hello! Great to have you here!',
default => 'Welcome to the MCP server!',
};
}
}