-
Notifications
You must be signed in to change notification settings - Fork 64
Expand file tree
/
Copy pathMcpServerPass.php
More file actions
87 lines (73 loc) · 4.01 KB
/
McpServerPass.php
File metadata and controls
87 lines (73 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php
declare(strict_types=1);
namespace PhpMcp\Server\Bridge\Symfony\DependencyInjection\Compiler;
use PhpMcp\Server\Attributes\McpPrompt;
use PhpMcp\Server\Attributes\McpResource;
use PhpMcp\Server\Attributes\McpResourceTemplate;
use PhpMcp\Server\Attributes\McpTool;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Reference;
class McpServerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
$serverBuilderDefinition = $container->getDefinition('mcp_server.server_builder');
$mcpElements = [];
foreach ($container->findTaggedServiceIds('mcp_server.server_element') as $serviceId => $tags) {
$definition = $container->findDefinition($serviceId);
$mcpElements[$definition->getClass()] = new Reference($serviceId);
$reflectionClass = new \ReflectionClass($definition->getClass());
foreach ([McpPrompt::class, McpResource::class, McpResourceTemplate::class, McpTool::class] as $attributeClass) {
if ([] !== $reflectionAttributes = $reflectionClass->getAttributes($attributeClass, \ReflectionAttribute::IS_INSTANCEOF)) {
if (!$reflectionClass->hasMethod('__invoke')) {
throw new LogicException(sprintf('The class "%s" has attribute "%s" but method "__invoke" is missing, please declare it.', $definition->getClass(), $attributeClass));
}
$this->mapElements($attributeClass, $serverBuilderDefinition, [$definition->getClass(), '__invoke'], $reflectionAttributes[0]->getArguments());
break;
}
foreach ($reflectionClass->getMethods() as $reflectionMethod) {
if ([] !== $reflectionAttributes = $reflectionMethod->getAttributes($attributeClass, \ReflectionAttribute::IS_INSTANCEOF)) {
$this->mapElements($attributeClass, $serverBuilderDefinition, [$definition->getClass(), $reflectionMethod->getName()], $reflectionAttributes[0]->getArguments());
}
}
}
}
$serverBuilderDefinition->addMethodCall('withContainer', [ServiceLocatorTagPass::register($container, $mcpElements)]);
}
private function mapElements(string $attributeClass, Definition $serverBuilderDefinition, array $handler, array $attributeArgs): void
{
match ($attributeClass) {
McpPrompt::class => $serverBuilderDefinition->addMethodCall('withPrompt', [
$handler,
$attributeArgs['name'] ?? null,
$attributeArgs['description'] ?? null,
]),
McpResource::class => $serverBuilderDefinition->addMethodCall('withResource', [
$handler,
$attributeArgs['uri'] ?? null,
$attributeArgs['name'] ?? null,
$attributeArgs['description'] ?? null,
$attributeArgs['mimeType'] ?? null,
$attributeArgs['size'] ?? null,
$attributeArgs['annotations'] ?? [],
]),
McpResourceTemplate::class => $serverBuilderDefinition->addMethodCall('withResourceTemplate', [
$handler,
$attributeArgs['uriTemplate'] ?? null,
$attributeArgs['name'] ?? null,
$attributeArgs['description'] ?? null,
$attributeArgs['mimeType'] ?? null,
$attributeArgs['annotations'] ?? [],
]),
McpTool::class => $serverBuilderDefinition->addMethodCall('withTool', [
$handler,
$attributeArgs['name'] ?? null,
$attributeArgs['description'] ?? null,
]),
};
}
}