For dynamic registration, closures, or explicit control, use the ServerBuilder methods before calling build(). Manual registrations take precedence over discovered elements with the same identifier.
Supported Handler Formats:
[ClassName::class, 'methodName']: Class method handlers.InvokableClass::class: Classes with an __invoke method.callable: Closures, static methods, or function names.
Note on Closures: When using closures, the server generates minimal JSON schemas based only on PHP type hints. For detailed schemas, use the #[Schema] attribute or provide a custom $inputSchema in withTool().
use App\Handlers\\EmailHandler;
use PhpMcp\\Schema\\ToolAnnotations;
$server = Server::make()
->withServerInfo('Manual Registration Server', '1.0.0')
// Register a tool with a class method
->withTool(
[EmailHandler::class, 'sendEmail'],
name: 'send_email',
description: 'Send email to user',
annotations: ToolAnnotations::make(title: 'Send Email Tool')
)
// Register an invokable class
->withTool(UserHandler::class)
// Register a closure
->withTool(
function(int $a, int $b): int { return $a + $b; },
name: 'add_numbers'
)
// Register a resource with a closure
->withResource(
function(): array { return ['status' => 'ok']; },
uri: 'config://runtime/status'
)
// Register a resource template
->withResourceTemplate(
[UserHandler::class, 'getUserProfile'],
uriTemplate: 'user://{userId}/profile'
)
// Register a prompt with a closure
->withPrompt(
function(string $topic): array {
return [['role' => 'user', 'content' => "Write about {$topic}"]];
},
name: 'writing_prompt'
)
->build();