memran/marwa-mcp is a small PHP 8.2 library for building Model Context Protocol servers in Marwa Framework or standalone PHP apps.
It supports JSON-RPC 2.0, stdio, HTTP POST, tool/resource/prompt registries, permission checks, and PSR-3 logging.
composer require memran/marwa-mcpvendor/bin/marwa-mcpClaude Desktop or Cursor can then start the server over stdio.
{
"mcpServers": {
"marwa": {
"command": "php",
"args": ["vendor/bin/marwa-mcp"]
}
}
}Use the bundled example:
php -S 127.0.0.1:8080 -t examples/http/public<?php
declare(strict_types=1);
use Marwa\MCP\JsonRpcHandler;
use Marwa\MCP\ServerFactory;
use Marwa\MCP\HttpTransport;
require __DIR__ . '/../../../vendor/autoload.php';
$server = ServerFactory::createDefault();
$transport = new HttpTransport(new JsonRpcHandler($server));
$transport->emit();Example request:
curl -X POST http://127.0.0.1:8080/mcp.php \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'<?php
declare(strict_types=1);
use Marwa\MCP\JsonRpcHandler;
use Marwa\MCP\ServerFactory;
use Marwa\MCP\HttpTransport;
final class McpController
{
public function __invoke(): void
{
$server = ServerFactory::createDefault();
$transport = new HttpTransport(new JsonRpcHandler($server));
$transport->emit();
}
}<?php
declare(strict_types=1);
use Marwa\MCP\ToolInterface;
use Marwa\MCP\ToolResult;
final class GreetingTool implements ToolInterface
{
public function name(): string
{
return 'greeting';
}
public function description(): string
{
return 'Greets a user by name.';
}
public function schema(): array
{
return [
'type' => 'object',
'properties' => [
'name' => ['type' => 'string'],
],
'required' => ['name'],
];
}
public function call(array $arguments): ToolResult
{
return ToolResult::text('Hello ' . $arguments['name']);
}
}Register it:
$server->tools()->register(new GreetingTool());<?php
declare(strict_types=1);
use Marwa\MCP\ResourceInterface;
use Marwa\MCP\ResourceResult;
final class StatusResource implements ResourceInterface
{
public function uri(): string
{
return 'marwa://status';
}
public function name(): string
{
return 'Status';
}
public function description(): string
{
return 'Application status.';
}
public function read(): ResourceResult
{
return new ResourceResult($this->uri(), '{"ok":true}', 'application/json');
}
}<?php
declare(strict_types=1);
use Marwa\MCP\PromptInterface;
use Marwa\MCP\PromptResult;
final class ReviewPrompt implements PromptInterface
{
public function name(): string
{
return 'review_code';
}
public function description(): string
{
return 'Ask the assistant to review code.';
}
public function arguments(): array
{
return [['name' => 'code', 'required' => true]];
}
public function get(array $arguments): PromptResult
{
return PromptResult::userText($this->description(), 'Review this code: ' . $arguments['code']);
}
}The optional provider is intentionally minimal and avoids framework lock-in:
use Marwa\MCP\McpServiceProvider;
(new McpServiceProvider())->register($container);It registers:
marwa.mcp.server
marwa.mcp.handler
marwa.mcp.http
Your container must expose a set(string $id, mixed $value): void method. If it exposes get(Psr\Log\LoggerInterface::class), that logger is used.
Supported MCP methods:
initialize
tools/list
tools/call
resources/list
resources/read
prompts/list
prompts/get
ping
server_info
echo
marwa://server/info
marwa://tools
marwa_debug_help
marwa_module_generator
Do not expose unsafe tools by default. This package intentionally ships without shell execution and raw SQL tools.
Use a custom PermissionPolicyInterface in production:
use Marwa\MCP\PermissionPolicyInterface;
final class ProductionPolicy implements PermissionPolicyInterface
{
public function allowsMethod(string $method): bool
{
return in_array($method, ['initialize', 'tools/list', 'tools/call'], true);
}
public function allowsTool(string $name): bool
{
return in_array($name, ['ping', 'server_info'], true);
}
public function allowsResource(string $uri): bool
{
return false;
}
public function allowsPrompt(string $name): bool
{
return false;
}
}Recommended production controls:
- Whitelist methods, tools, resources, and prompts.
- Validate every tool argument using the declared schema.
- Never put secrets into resource contents.
- Send logs to STDERR or a PSR-3 logger, never stdout for stdio MCP.
- Hide stack traces from client responses.
- Add authentication and audit logging at the HTTP boundary.
composer install
composer test
composer analyse
composer cs-checkMIT. See LICENSE.