1010use PhpMcp \Schema \Resource ;
1111use PhpMcp \Schema \ResourceTemplate ;
1212use PhpMcp \Schema \Tool ;
13+ use PhpMcp \Server \Contracts \CompletionProviderInterface ;
1314use PhpMcp \Server \Exception \DefinitionException ;
1415use PhpMcp \Server \Support \Handler ;
1516use PhpMcp \Server \Support \UriTemplateMatcher ;
@@ -55,6 +56,30 @@ class Registry implements EventEmitterInterface
5556 'prompts ' => '' ,
5657 ];
5758
59+ /**
60+ * Stores completion providers.
61+ * Structure:
62+ * [
63+ * 'ref/prompt' => [ // Ref Type
64+ * 'prompt_name_1' => [ // Element Name/URI
65+ * 'argument_name_A' => 'ProviderClassFQCN_For_Prompt1_ArgA',
66+ * 'argument_name_B' => 'ProviderClassFQCN_For_Prompt1_ArgB',
67+ * ],
68+ * 'prompt_name_2' => [ //... ],
69+ * ],
70+ * 'ref/resource' => [ // Ref Type (for URI templates)
71+ * 'resource_template_uri_1' => [ // Element URI Template
72+ * 'uri_variable_name_X' => 'ProviderClassFQCN_For_Template1_VarX',
73+ * ],
74+ * ],
75+ * ]
76+ * @var array<string, array<string, array<string, class-string<ArgumentCompletionProviderInterface>>>>
77+ */
78+ private array $ completionProviders = [
79+ 'ref/prompt ' => [],
80+ 'ref/resource ' => [],
81+ ];
82+
5883 private bool $ notificationsEnabled = true ;
5984
6085 public function __construct (
@@ -307,6 +332,23 @@ public function registerPrompt(Prompt $prompt, Handler $handler, bool $isManual
307332 $ this ->checkAndEmitChange ('prompts ' , $ this ->prompts );
308333 }
309334
335+ /**
336+ * @param 'ref/prompt'|'ref/resource' $refType
337+ * @param string $identifier Name for prompts, URI template for resource templates
338+ * @param string $argument The argument name to register the completion provider for.
339+ * @param class-string<CompletionProviderInterface> $providerClass
340+ */
341+ public function registerCompletionProvider (string $ refType , string $ identifier , string $ argument , string $ providerClass ): void
342+ {
343+ if (!in_array ($ refType , ['ref/prompt ' , 'ref/resource ' ])) {
344+ $ this ->logger ->warning ("Invalid refType ' {$ refType }' for completion provider registration. " );
345+ return ;
346+ }
347+
348+ $ this ->completionProviders [$ refType ][$ identifier ][$ argument ] = $ providerClass ;
349+ $ this ->logger ->debug ("Registered completion provider for {$ refType } ' {$ identifier }', argument ' {$ argument }' " , ['provider ' => $ providerClass ]);
350+ }
351+
310352 public function enableNotifications (): void
311353 {
312354 $ this ->notificationsEnabled = true ;
@@ -505,6 +547,36 @@ public function getResource(string $uri, bool $includeTemplates = true): ?array
505547 return null ;
506548 }
507549
550+ /** @return array{
551+ * resourceTemplate: ResourceTemplate,
552+ * handler: Handler,
553+ * variables: array<string, string>,
554+ * }|null */
555+ public function getResourceTemplate (string $ uriTemplate ): ?array
556+ {
557+ $ registration = $ this ->resourceTemplates [$ uriTemplate ] ?? null ;
558+ if (!$ registration ) {
559+ return null ;
560+ }
561+
562+ try {
563+ $ matcher = new UriTemplateMatcher ($ uriTemplate );
564+ $ variables = $ matcher ->getVariables ();
565+ } catch (\InvalidArgumentException $ e ) {
566+ $ this ->logger ->warning ('Invalid resource template encountered during matching ' , [
567+ 'template ' => $ registration ['resourceTemplate ' ]->uriTemplate ,
568+ 'error ' => $ e ->getMessage (),
569+ ]);
570+ return null ;
571+ }
572+
573+ return [
574+ 'resourceTemplate ' => $ registration ['resourceTemplate ' ],
575+ 'handler ' => $ registration ['handler ' ],
576+ 'variables ' => $ variables ,
577+ ];
578+ }
579+
508580 /** @return array{prompt: Prompt, handler: Handler}|null */
509581 public function getPrompt (string $ name ): ?array
510582 {
@@ -514,24 +586,35 @@ public function getPrompt(string $name): ?array
514586 /** @return array<string, Tool> */
515587 public function getTools (): array
516588 {
517- return array_map (fn ($ registration ) => $ registration ['tool ' ], $ this ->tools );
589+ return array_map (fn ($ registration ) => $ registration ['tool ' ], $ this ->tools );
518590 }
519591
520592 /** @return array<string, Resource> */
521593 public function getResources (): array
522594 {
523- return array_map (fn ($ registration ) => $ registration ['resource ' ], $ this ->resources );
595+ return array_map (fn ($ registration ) => $ registration ['resource ' ], $ this ->resources );
524596 }
525597
526598 /** @return array<string, Prompt> */
527599 public function getPrompts (): array
528600 {
529- return array_map (fn ($ registration ) => $ registration ['prompt ' ], $ this ->prompts );
601+ return array_map (fn ($ registration ) => $ registration ['prompt ' ], $ this ->prompts );
530602 }
531603
532604 /** @return array<string, ResourceTemplate> */
533605 public function getResourceTemplates (): array
534606 {
535- return array_map (fn ($ registration ) => $ registration ['resourceTemplate ' ], $ this ->resourceTemplates );
607+ return array_map (fn ($ registration ) => $ registration ['resourceTemplate ' ], $ this ->resourceTemplates );
608+ }
609+
610+ /**
611+ * @param 'ref/prompt'|'ref/resource' $refType
612+ * @param string $elementIdentifier Name for prompts, URI template for resource templates
613+ * @param string $argumentName
614+ * @return class-string<ArgumentCompletionProviderInterface>|null
615+ */
616+ public function getCompletionProvider (string $ refType , string $ identifier , string $ argument ): ?string
617+ {
618+ return $ this ->completionProviders [$ refType ][$ identifier ][$ argument ] ?? null ;
536619 }
537620}
0 commit comments