This repository was archived by the owner on Nov 12, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathPromptPass.php
More file actions
95 lines (80 loc) · 3.3 KB
/
Copy pathPromptPass.php
File metadata and controls
95 lines (80 loc) · 3.3 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
88
89
90
91
92
93
94
95
<?php
declare(strict_types=1);
namespace Ecourty\McpServerBundle\DependencyInjection\CompilerPass;
use Ecourty\McpServerBundle\Attribute\AsPrompt;
use Ecourty\McpServerBundle\IO\Prompt\PromptResult;
use Ecourty\McpServerBundle\Prompt\Argument;
use Ecourty\McpServerBundle\Service\PromptRegistry;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* PromptPass is a compiler pass that processes MCP server prompts.
*
* It validates the class and method signatures.
*/
class PromptPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
$promptRegistry = $container->getDefinition(PromptRegistry::class);
foreach ($container->getDefinitions() as $definition) {
$class = $definition->getClass();
try {
if ($class === null || class_exists($class) === false) {
continue;
}
} catch (\Throwable) {
continue;
}
$refClass = new \ReflectionClass($class);
$attributes = $refClass->getAttributes(AsPrompt::class);
if (\count($attributes) === 0) {
continue;
}
if (\count($attributes) > 1) {
throw new \LogicException(\sprintf(
'Multiple AsPrompt attributes found on class "%s". Only one is allowed.',
$class,
));
}
if ($refClass->hasMethod('__invoke') === false) {
throw new \LogicException(\sprintf(
'Class "%s" must implement the __invoke method to be used as a prompt.',
$class,
));
}
$invokeMethodParameters = $refClass->getMethod('__invoke')->getParameters();
if (\count($invokeMethodParameters) > 1) {
throw new \LogicException(\sprintf(
'Class "%s" must have a maximum of one parameter in the __invoke method to be used as a prompt.',
$class,
));
}
$returnType = $refClass->getMethod('__invoke')->getReturnType();
if ($returnType?->getName() !== PromptResult::class) { // @phpstan-ignore method.notFound
throw new \LogicException(\sprintf(
'The __invoke method in class "%s" must return an instance of %s.',
$class,
PromptResult::class,
));
}
/** @var AsPrompt|null $attr */
$attr = $attributes[0]->newInstance();
if ($attr === null) {
throw new \LogicException(\sprintf(
'Failed to instantiate AsPrompt attribute for class "%s".',
$class,
));
}
$definition
->addTag(name: 'mcp_server.prompt', attributes: [
'name' => $attr->name,
]);
$promptRegistry->addMethodCall(method: 'addPromptDefinition', arguments: [
$attr->name,
$attr->description,
array_map(fn (Argument $argument) => $argument->toArray(), $attr->getArguments()),
]);
}
}
}