1. Go to this page and download the library: Download milpa/mcp-server library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
milpa / mcp-server example snippets
use Milpa\McpServer\JsonRpcService;
use Milpa\ToolRuntime\Contracts\ToolContext;
use Milpa\ToolRuntime\ToolRegistry;
use Psr\Log\NullLogger;
$registry = new ToolRegistry(new NullLogger());
// ... register tools on $registry, e.g. via ToolScanner ...
$rpc = new JsonRpcService($registry);
$ctx = new ToolContext(principal: 'user:42', channel: 'mcp', scopes: ['notes:read']);
$response = $rpc->handle([
'jsonrpc' => '2.0',
'method' => 'tools/call',
'params' => ['name' => 'list_notes', 'arguments' => ['page' => 1]],
'id' => 1,
], $ctx);
// $response is a JSON-RPC 2.0 response array, or null. json_encode() an array response onto
// whatever transport your host terminates (an HTTP POST body, a stdio pipe, ...); a null
// response means the request was a notification and your transport MUST write nothing at all
// — see "Recipes" below.
use Milpa\Events\InterceptionSlot;
use Milpa\McpServer\Events\McpRequestEvent;
use Milpa\McpServer\Events\McpRespondedEvent;
use Milpa\McpServer\JsonRpcService;
// A cache plugin: short-circuit tools/call for a known-idempotent tool + args pair.
$dispatcher->subscribe('mcp.request', function (string $eventName, array $payload): void {
$event = $payload['event']; // McpRequestEvent
/** @var InterceptionSlot $slot */
$slot = $payload['slot'];
if ($event->getMethod() === 'tools/call') {
$cached = $cache->get($event->getParams());
if ($cached !== null) {
$slot->shortCircuit($cached); // the tool never actually runs
}
}
});
// An audit plugin: log the outcome of every dispatched method, cache hit or not.
$dispatcher->subscribe('mcp.responded', function (string $eventName, array $payload): void {
/** @var McpRespondedEvent $event */
$event = $payload['event'];
$logger->info('mcp method responded', [
'method' => $event->getMethod(),
'ok' => !isset($event->getResponse()['error']),
]);
});
$rpc = new JsonRpcService($registry, $dispatcher);
use Milpa\McpServer\Auth\Principal;
use Milpa\McpServer\Auth\TokenValidatorInterface;
final class DatabaseTokenValidator implements TokenValidatorInterface
{
public function validate(string $token, ?string $ip = null): ?Principal
{
$record = $this->tokens->findValidByToken($token); // your own store, your own rules
if ($record === null) {
return null;
}
$record->recordUsage($ip); // optional side effect, entirely up to the implementation
return new Principal(
id: "user:{$record->ownerId()}",
displayName: $record->ownerName(),
scopes: $record->scopes(),
extra: ['token_prefix' => $record->prefix()],
);
}
}
use Milpa\ToolRuntime\Contracts\ToolContext;
$ctx = ToolContext::mcp(
requestId: (string) ($request['id'] ?? uniqid('mcp-', true)),
principal: 'stdio', // any non-empty string satisfies