Server
Server
Abstract base class for Model Context Protocol servers.
class Server extends \Hazaar\ControllerExtends: Hazaar\Controller
Publishes public methods marked with #[Tool] as MCP tools over the Streamable HTTP transport, handling protocol framing, header validation, JSON Schema generation and dispatch. Subclasses write tool methods and nothing else.
class Tools extends \Hazaar\Controller\MCP
{
#[Tool('Search the customer database by name or email')]
public function searchCustomers(
#[Param('Name or email fragment to search for')]
string $query
): array {
return Customer::search($query);
}
}Protocol revision 2026-07-28 is stateless — no sessions, no handshake, one POST per request — which maps directly onto PHP's request-per-process execution model. Real-world clients still open every connection with the legacy initialize / notifications/initialized handshake regardless, so this server answers both statelessly: initialize gets a derived response with no session created, and every notification (including notifications/initialized) is acknowledged without being routed through Hazaar\MCP\Server::dispatch.
Two earlier revisions, 2025-06-18 and 2025-11-25, are accepted too (see Hazaar\MCP\Protocol::SUPPORTED_VERSIONS) — real clients still negotiate them. Both are otherwise session/SSE-oriented revisions, but the subset this server implements (initialize, tools/list, tools/call over a single POST) is wire-compatible across all three, so no version-specific branching is needed beyond accepting the version and never claiming the listChanged/session/SSE capabilities those revisions additionally allow for.
Properties
serverName
Server name reported to clients for display and logging.
protected string $serverName = 'hazaar-mcp'Type: string
serverVersion
Server version reported to clients for display and logging.
protected string $serverVersion = '1.0.0'Type: string
instructions
public string $instructionsType: string
allowedOrigins
Origins permitted to call this endpoint.
protected array $allowedOriginsType: array
When empty, only an Origin whose host matches the request host is accepted. Browser-based clients served from a different host need their origin listed here.
listCacheTTL
How long, in milliseconds, clients may cache list results before re-fetching.
protected int $listCacheTTL = 300000Type: int
tools
private array $toolsType: array
Methods
__construct
Constructs the server and registers every #[Tool] method on the concrete subclass.
public __construct(Request $request): voidParameters
| Parameter | Type | Description |
|---|---|---|
$request | Hazaar\Application\Request | the incoming application request |
registerTool
Registers a tool backed by an arbitrary callable.
public registerTool(string $name, callable $handler, ?array $inputSchema, ?string $description): voidReturns: void
Use this from init() for tools whose set is not known until runtime — driven by config, the database, or a plugin registry. Attributed methods cover everything known at author time.
Parameters
| Parameter | Type | Description |
|---|---|---|
$name | string | the tool name the client calls |
$handler | callable | the callable to execute |
$inputSchema | array | JSON Schema for the arguments, or null to derive it from the callable |
$description | string | what the tool does |
getTools
Returns the tools currently registered, keyed by name.
public getTools(): arrayReturns: array
runAction
Handles the request.
protected runAction(string $actionName, array $actionArgs, bool $namedActionArgs): ResponseReturns: Hazaar\Controller\Response
The route action is ignored: this endpoint dispatches on the JSON-RPC method in the request body, the same way Controller\WebDAV dispatches on the HTTP verb.
Parameters
| Parameter | Type | Description |
|---|---|---|
$actionName | string | unused, the JSON-RPC method determines the handler |
$actionArgs | array | unused |
$namedActionArgs | bool | unused |
dispatch
Routes a parsed message to its handler.
protected dispatch(Message $message): arrayReturns: array
Parameters
| Parameter | Type | Description |
|---|---|---|
$message | Hazaar\MCP\Message |
handleInitialize
Answers the legacy initialize handshake statelessly: no session is created, and nothing
protected handleInitialize(Message $message): arrayReturns: array
here depends on a subsequent notifications/initialized ever arriving.
Per the lifecycle spec, a version the client requests is only echoed back when this server actually supports it; otherwise the response names a version it does support (its latest), so a compliant client renegotiates instead of proceeding on a version every subsequent request would then fail with UnsupportedProtocolVersion.
Parameters
| Parameter | Type | Description |
|---|---|---|
$message | Hazaar\MCP\Message |
handleDiscover
Answers server/discover with the supported versions, capabilities and identity.
protected handleDiscover(): arrayReturns: array
The listChanged capability is deliberately not declared: advertising it obliges the server to support subscriptions/listen, which this implementation does not.
handleToolsList
Answers tools/list with every registered tool definition.
protected handleToolsList(): arrayReturns: array
Order follows registration, which is deterministic across requests. That matters: clients cache the list and a stable order improves prompt cache hit rates.
handleToolsCall
Executes tools/call and maps the outcome onto a tool result.
protected handleToolsCall(Message $message): arrayReturns: array
Parameters
| Parameter | Type | Description |
|---|---|---|
$message | Hazaar\MCP\Message |
buildToolResult
Maps a tool's return value onto a tool result payload.
protected buildToolResult(mixed $value): arrayReturns: array
Parameters
| Parameter | Type | Description |
|---|---|---|
$value | mixed |
getServerInfo
Returns the server identity attached to every result.
protected getServerInfo(): arrayReturns: array
validateOrigin
Rejects requests carrying an Origin this server does not accept.
private validateOrigin(): voidReturns: void
Without this check a malicious page could reach a locally-bound server via DNS rebinding.
validateHeaders
Validates the request metadata headers against the request body, where present.
private validateHeaders(Message $message): voidReturns: void
The transport mirrors body fields into headers so intermediaries can route without parsing the body; if the two are allowed to disagree, a gateway and the server can act on different values. A header is only checked when the client sent it — clients that carry method/version purely in the body (no mirrored headers at all) are not required to add them, they just forgo the anti-mismatch defense the headers provide for header-routing intermediaries.
Parameters
| Parameter | Type | Description |
|---|---|---|
$message | Hazaar\MCP\Message |
validateNameHeader
Validates the Mcp-Name header against the tool name in the body, when the client sent one.
private validateNameHeader(string $name): voidReturns: void
Parameters
| Parameter | Type | Description |
|---|---|---|
$name | string |
getRequestHeader
Looks up a request header without regard to case.
private getRequestHeader(string $name): ?stringReturns: string
Request::getHeader() matches the array key exactly, and header names are case-insensitive — MCP-Protocol-Version and Mcp-Protocol-Version are the same header and both appear in the wild.
Parameters
| Parameter | Type | Description |
|---|---|---|
$name | string |
isContentList
Determines whether every element of an array is a content block.
private isContentList(array $value): boolReturns: bool
Parameters
| Parameter | Type | Description |
|---|---|---|
$value | array |
Generated by Hazaar API Doc Generator on Sun, 23 Aug 2026 10:49:44 +0000