Skip to content

Commit c03a123

Browse files
committed
refactor: introduce server driver abstraction and enhance transport configuration
1 parent bfaf605 commit c03a123

File tree

13 files changed

+282
-21
lines changed

13 files changed

+282
-21
lines changed

src/McpServer/Action/Resources/ListResourcesAction.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Butschster\ContextGenerator\Application\Logger\LoggerPrefix;
88
use Butschster\ContextGenerator\Config\Loader\ConfigLoaderInterface;
99
use Butschster\ContextGenerator\Config\Registry\ConfigRegistryAccessor;
10-
use Butschster\ContextGenerator\McpServer\McpConfig;
10+
use Butschster\ContextGenerator\McpServer\Config\McpConfig;
1111
use Butschster\ContextGenerator\McpServer\Registry\McpItemsRegistry;
1212
use Butschster\ContextGenerator\McpServer\Routing\Attribute\Get;
1313
use Mcp\Types\ListResourcesResult;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Config;
6+
7+
/**
8+
* HTTP Transport configuration DTO
9+
*/
10+
final readonly class HttpTransportConfig
11+
{
12+
public function __construct(
13+
public string $host = 'localhost',
14+
public int $port = 8080,
15+
public string $sessionStore = 'file',
16+
public ?string $sessionStorePath = null,
17+
public bool $corsEnabled = true,
18+
public array $corsOrigins = ['*'],
19+
public int $maxRequestSize = 10485760, // 10MB
20+
) {}
21+
22+
/**
23+
* Get the full server address
24+
*/
25+
public function getAddress(): string
26+
{
27+
return "http://{$this->host}:{$this->port}";
28+
}
29+
30+
/**
31+
* Get session store configuration array
32+
*/
33+
public function getSessionStoreConfig(): array
34+
{
35+
return [
36+
'type' => $this->sessionStore,
37+
'path' => $this->sessionStorePath,
38+
];
39+
}
40+
41+
/**
42+
* Get HTTP options array for the runner
43+
*/
44+
public function toHttpOptions(): array
45+
{
46+
return [
47+
'enable_sse' => true,
48+
];
49+
}
50+
}
Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace Butschster\ContextGenerator\McpServer;
5+
namespace Butschster\ContextGenerator\McpServer\Config;
66

77
use Spiral\Core\InjectableConfig;
88

@@ -12,6 +12,18 @@ final class McpConfig extends InjectableConfig
1212

1313
protected array $config = [
1414
'document_name_format' => '[{path}] {description}',
15+
'transport' => [
16+
'type' => 'stdio',
17+
'http' => [
18+
'host' => 'localhost',
19+
'port' => 8080,
20+
'session_store' => 'file',
21+
'session_store_path' => null,
22+
'cors_enabled' => true,
23+
'cors_origins' => ['*'],
24+
'max_request_size' => 10485760,
25+
],
26+
],
1527
'common_prompts' => [
1628
'enable' => true,
1729
],
@@ -51,6 +63,31 @@ public function getDocumentNameFormat(string $path, string $description, string
5163
);
5264
}
5365

66+
public function getTransportType(): string
67+
{
68+
return $this->config['transport']['type'] ?? 'stdio';
69+
}
70+
71+
public function isHttpTransport(): bool
72+
{
73+
return $this->getTransportType() === 'http';
74+
}
75+
76+
public function getHttpTransportConfig(): HttpTransportConfig
77+
{
78+
$http = $this->config['transport']['http'] ?? [];
79+
80+
return new HttpTransportConfig(
81+
host: $http['host'] ?? 'localhost',
82+
port: (int) ($http['port'] ?? 8080),
83+
sessionStore: $http['session_store'] ?? 'file',
84+
sessionStorePath: $http['session_store_path'] ?? null,
85+
corsEnabled: (bool) ($http['cors_enabled'] ?? true),
86+
corsOrigins: $http['cors_origins'] ?? ['*'],
87+
maxRequestSize: (int) ($http['max_request_size'] ?? 10485760),
88+
);
89+
}
90+
5491
public function isFileOperationsEnabled(): bool
5592
{
5693
return $this->config['file_operations']['enable'] ?? false;

src/McpServer/Console/MCPServerCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use Butschster\ContextGenerator\McpServer\Projects\ProjectServiceInterface as ProjectService;
1717
use Butschster\ContextGenerator\McpServer\ProjectService\ProjectServiceFactory;
1818
use Butschster\ContextGenerator\McpServer\ProjectService\ProjectServiceInterface;
19-
use Butschster\ContextGenerator\McpServer\ServerRunnerInterface;
19+
use Butschster\ContextGenerator\McpServer\Server\RunnerInterface;
2020
use Butschster\ContextGenerator\McpServer\Tool\Command\CommandExecutor;
2121
use Butschster\ContextGenerator\McpServer\Tool\Command\CommandExecutorInterface;
2222
use Monolog\Level;
@@ -142,7 +142,7 @@ public function __invoke(
142142
]),
143143
],
144144
),
145-
scope: static function (ServerRunnerInterface $factory) use ($app): void {
145+
scope: static function (RunnerInterface $factory) use ($app): void {
146146
$factory->run(name: \sprintf('%s %s', $app->name, $app->version));
147147
},
148148
);

src/McpServer/McpServerBootloader.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use Butschster\ContextGenerator\McpServer\Action\Tools\ListToolsAction;
3232
use Butschster\ContextGenerator\McpServer\Action\Tools\Prompts\GetPromptToolAction;
3333
use Butschster\ContextGenerator\McpServer\Action\Tools\Prompts\ListPromptsToolAction;
34+
use Butschster\ContextGenerator\McpServer\Config\McpConfig;
3435
use Butschster\ContextGenerator\McpServer\Console\MCPServerCommand;
3536
use Butschster\ContextGenerator\McpServer\Projects\Actions\ProjectsListToolAction;
3637
use Butschster\ContextGenerator\McpServer\Projects\Actions\ProjectSwitchToolAction;
@@ -46,6 +47,9 @@
4647
use Butschster\ContextGenerator\McpServer\Routing\Handler\Tools\ToolsHandlerInterface;
4748
use Butschster\ContextGenerator\McpServer\Routing\McpResponseStrategy;
4849
use Butschster\ContextGenerator\McpServer\Routing\RouteRegistrar;
50+
use Butschster\ContextGenerator\McpServer\Server\Runner;
51+
use Butschster\ContextGenerator\McpServer\Server\RunnerInterface;
52+
use Butschster\ContextGenerator\McpServer\Server\ServerDriverFactory;
4953
use Butschster\ContextGenerator\McpServer\Tool\McpToolBootloader;
5054
use League\Route\Router;
5155
use League\Route\Strategy\StrategyInterface;
@@ -81,6 +85,18 @@ public function init(EnvironmentInterface $env): void
8185
McpConfig::CONFIG,
8286
[
8387
'document_name_format' => $env->get('MCP_DOCUMENT_NAME_FORMAT', '[{path}] {description}'),
88+
'transport' => [
89+
'type' => $env->get('MCP_TRANSPORT', 'stdio'),
90+
'http' => [
91+
'host' => $env->get('MCP_HTTP_HOST', 'localhost'),
92+
'port' => (int) $env->get('MCP_HTTP_PORT', 8080),
93+
'session_store' => $env->get('MCP_HTTP_SESSION_STORE', 'file'),
94+
'session_store_path' => $env->get('MCP_HTTP_SESSION_STORE_PATH'),
95+
'cors_enabled' => (bool) $env->get('MCP_HTTP_CORS_ENABLED', true),
96+
'cors_origins' => \array_filter(\explode(',', $env->get('MCP_HTTP_CORS_ORIGINS', '*'))),
97+
'max_request_size' => (int) $env->get('MCP_HTTP_MAX_REQUEST_SIZE', 10485760),
98+
],
99+
],
84100
'file_operations' => [
85101
'enable' => (bool) $env->get('MCP_FILE_OPERATIONS', !$isCommonProject),
86102
'write' => (bool) $env->get('MCP_FILE_WRITE', true),
@@ -128,9 +144,9 @@ public function defineSingletons(): array
128144
ToolsHandlerInterface::class => ToolsHandler::class,
129145

130146
// Server infrastructure
131-
ServerRunnerInterface::class => function (
147+
RunnerInterface::class => function (
132148
McpConfig $config,
133-
ServerRunner $factory,
149+
Runner $factory,
134150
ConfigLoaderInterface $loader,
135151
) {
136152
$loader->load();
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Server\Driver;
6+
7+
use Butschster\ContextGenerator\McpServer\Config\HttpTransportConfig;
8+
use Mcp\Server\HttpServerRunner;
9+
use Mcp\Server\InitializationOptions;
10+
use Mcp\Server\Server as McpServer;
11+
use Mcp\Server\Transport\Http\HttpMessage;
12+
use Psr\Log\LoggerInterface;
13+
use Swoole\Http\Request;
14+
use Swoole\Http\Response;
15+
use Swoole\Http\Server;
16+
17+
final readonly class HttpServerDriver implements ServerDriverInterface
18+
{
19+
public function __construct(
20+
private HttpTransportConfig $httpConfig,
21+
private LoggerInterface $logger,
22+
) {}
23+
24+
public function run(McpServer $server, InitializationOptions $initOptions): void
25+
{
26+
$runner = new HttpServerRunner(
27+
server: $server,
28+
initOptions: $initOptions,
29+
httpOptions: $this->httpConfig->toHttpOptions(),
30+
logger: $this->logger,
31+
);
32+
33+
$this->startSwooleServer($runner);
34+
}
35+
36+
private function startSwooleServer(HttpServerRunner $runner): void
37+
{
38+
$http = new Server($this->httpConfig->host, $this->httpConfig->port);
39+
40+
$http->on('request', function (Request $request, Response $response) use ($runner): void {
41+
$requestMessage = $this->createHttpMessage($request);
42+
$result = $runner->handleRequest($requestMessage);
43+
44+
$response->end($result->getBody());
45+
});
46+
47+
$http->start();
48+
}
49+
50+
private function createHttpMessage(Request $request): HttpMessage
51+
{
52+
$requestMessage = new HttpMessage();
53+
54+
// Set headers
55+
foreach ($request->header as $key => $value) {
56+
$requestMessage->setHeader($key, $value);
57+
}
58+
59+
// Set query parameters
60+
if ($request->get) {
61+
$requestMessage->setQueryParams($request->get);
62+
}
63+
64+
// Set body
65+
if ($request->post) {
66+
$requestMessage->setBody(\json_encode($request->post));
67+
}
68+
69+
// Set method
70+
$requestMessage->setMethod($request->server['request_method']);
71+
72+
return $requestMessage;
73+
}
74+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Server\Driver;
6+
7+
use Mcp\Server\InitializationOptions;
8+
use Mcp\Server\Server as McpServer;
9+
10+
interface ServerDriverInterface
11+
{
12+
/**
13+
* Run the server with the specified configuration
14+
*/
15+
public function run(McpServer $server, InitializationOptions $initOptions): void;
16+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Butschster\ContextGenerator\McpServer\Server\Driver;
6+
7+
use Mcp\Server\Server as McpServer;
8+
use Mcp\Server\ServerRunner;
9+
use Psr\Log\LoggerInterface;
10+
11+
final readonly class StdioServerDriver implements ServerDriverInterface
12+
{
13+
public function __construct(
14+
private LoggerInterface $logger,
15+
) {}
16+
17+
public function run(McpServer $server, mixed $initOptions): void
18+
{
19+
$runner = new ServerRunner(
20+
server: $server,
21+
initOptions: $initOptions,
22+
logger: $this->logger,
23+
);
24+
25+
// For STDIO, run continuous loop
26+
$runner->run();
27+
}
28+
}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
namespace Butschster\ContextGenerator\McpServer;
5+
namespace Butschster\ContextGenerator\McpServer\Server;
66

77
use Butschster\ContextGenerator\Application\AppScope;
88
use Butschster\ContextGenerator\Application\Logger\HasPrefixLoggerInterface;
@@ -17,7 +17,7 @@
1717
use Spiral\Core\ScopeInterface;
1818

1919
#[Singleton]
20-
final class ServerRunner implements ServerRunnerInterface
20+
final class Runner implements RunnerInterface
2121
{
2222
/**
2323
* @var array<class-string>
@@ -51,6 +51,7 @@ public function run(string $name): void
5151
PromptsHandlerInterface $promptsHandler,
5252
ResourcesHandlerInterface $resourcesHandler,
5353
ToolsHandlerInterface $toolsHandler,
54+
ServerDriverFactory $driverFactory,
5455
) use ($name): void {
5556
// Register all classes with MCP item attributes. Should be before registering controllers!
5657
$registry->registerMany($this->actions);
@@ -64,6 +65,7 @@ public function run(string $name): void
6465
promptsHandler: $promptsHandler,
6566
resourcesHandler: $resourcesHandler,
6667
toolsHandler: $toolsHandler,
68+
driverFactory: $driverFactory,
6769
))->run($name);
6870
},
6971
);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
declare(strict_types=1);
44

5-
namespace Butschster\ContextGenerator\McpServer;
5+
namespace Butschster\ContextGenerator\McpServer\Server;
66

7-
interface ServerRunnerInterface
7+
interface RunnerInterface
88
{
99
/**
1010
* Create a new McpServer instance with attribute-based routing

0 commit comments

Comments
 (0)