Skip to content

Commit 60c38e9

Browse files
docs: update completion provider documentation
1 parent 2193188 commit 60c38e9

File tree

1 file changed

+126
-13
lines changed

1 file changed

+126
-13
lines changed

README.md

Lines changed: 126 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,11 @@ Completion providers enable MCP clients to offer auto-completion suggestions in
757757

758758
> **Note**: Tools and resources can be discovered via standard MCP commands (`tools/list`, `resources/list`), so completion providers are not needed for them. Completion providers are used only for resource templates (URI variables) and prompt arguments.
759759
760-
Completion providers must implement the `CompletionProviderInterface`:
760+
The `#[CompletionProvider]` attribute supports three types of completion sources:
761+
762+
#### 1. Custom Provider Classes
763+
764+
For complex completion logic, implement the `CompletionProviderInterface`:
761765

762766
```php
763767
use PhpMcp\Server\Contracts\CompletionProviderInterface;
@@ -766,34 +770,143 @@ use PhpMcp\Server\Attributes\{McpResourceTemplate, CompletionProvider};
766770

767771
class UserIdCompletionProvider implements CompletionProviderInterface
768772
{
773+
public function __construct(private DatabaseService $db) {}
774+
769775
public function getCompletions(string $currentValue, SessionInterface $session): array
770776
{
771-
// Return completion suggestions based on current input
772-
$allUsers = ['user_1', 'user_2', 'user_3', 'admin_user'];
773-
774-
// Filter based on what user has typed so far
775-
return array_filter($allUsers, fn($user) => str_starts_with($user, $currentValue));
777+
// Dynamic completion from database
778+
return $this->db->searchUsers($currentValue);
776779
}
777780
}
778781

779782
class UserService
780783
{
781784
#[McpResourceTemplate(uriTemplate: 'user://{userId}/profile')]
782785
public function getUserProfile(
783-
#[CompletionProvider(UserIdCompletionProvider::class)]
786+
#[CompletionProvider(provider: UserIdCompletionProvider::class)] // Class string - resolved from container
784787
string $userId
785788
): array {
786-
// Always validate input even with completion providers
787-
// Users can still pass any value regardless of completion suggestions
788-
if (!$this->isValidUserId($userId)) {
789-
throw new \InvalidArgumentException('Invalid user ID provided');
790-
}
791-
792789
return ['id' => $userId, 'name' => 'John Doe'];
793790
}
794791
}
795792
```
796793

794+
You can also pass pre-configured provider instances:
795+
796+
```php
797+
class DocumentService
798+
{
799+
#[McpPrompt(name: 'document_prompt')]
800+
public function generatePrompt(
801+
#[CompletionProvider(provider: new UserIdCompletionProvider($database))] // Pre-configured instance
802+
string $userId,
803+
804+
#[CompletionProvider(provider: $this->categoryProvider)] // Instance from property
805+
string $category
806+
): array {
807+
return [['role' => 'user', 'content' => "Generate document for user {$userId} in {$category}"]];
808+
}
809+
}
810+
```
811+
812+
#### 2. Simple List Completions
813+
814+
For static completion lists, use the `values` parameter:
815+
816+
```php
817+
use PhpMcp\Server\Attributes\{McpPrompt, CompletionProvider};
818+
819+
class ContentService
820+
{
821+
#[McpPrompt(name: 'content_generator')]
822+
public function generateContent(
823+
#[CompletionProvider(values: ['blog', 'article', 'tutorial', 'guide', 'documentation'])]
824+
string $contentType,
825+
826+
#[CompletionProvider(values: ['beginner', 'intermediate', 'advanced', 'expert'])]
827+
string $difficulty
828+
): array {
829+
return [['role' => 'user', 'content' => "Create a {$difficulty} level {$contentType}"]];
830+
}
831+
}
832+
```
833+
834+
#### 3. Enum-Based Completions
835+
836+
For enum classes, use the `enum` parameter:
837+
838+
```php
839+
enum Priority: string
840+
{
841+
case LOW = 'low';
842+
case MEDIUM = 'medium';
843+
case HIGH = 'high';
844+
case CRITICAL = 'critical';
845+
}
846+
847+
enum Status // Unit enum (no backing values)
848+
{
849+
case DRAFT;
850+
case PUBLISHED;
851+
case ARCHIVED;
852+
}
853+
854+
class TaskService
855+
{
856+
#[McpTool(name: 'create_task')]
857+
public function createTask(
858+
string $title,
859+
860+
#[CompletionProvider(enum: Priority::class)] // String-backed enum uses values
861+
string $priority,
862+
863+
#[CompletionProvider(enum: Status::class)] // Unit enum uses case names
864+
string $status
865+
): array {
866+
return ['id' => 123, 'title' => $title, 'priority' => $priority, 'status' => $status];
867+
}
868+
}
869+
```
870+
871+
#### Manual Registration with Completion Providers
872+
873+
```php
874+
$server = Server::make()
875+
->withServerInfo('Completion Demo', '1.0.0')
876+
877+
// Using provider class (resolved from container)
878+
->withPrompt(
879+
[DocumentHandler::class, 'generateReport'],
880+
name: 'document_report'
881+
// Completion providers are auto-discovered from method attributes
882+
)
883+
884+
// Using closure with inline completion providers
885+
->withPrompt(
886+
function(
887+
#[CompletionProvider(values: ['json', 'xml', 'csv', 'yaml'])]
888+
string $format,
889+
890+
#[CompletionProvider(enum: Priority::class)]
891+
string $priority
892+
): array {
893+
return [['role' => 'user', 'content' => "Export data in {$format} format with {$priority} priority"]];
894+
},
895+
name: 'export_data'
896+
)
897+
898+
->build();
899+
```
900+
901+
#### Completion Provider Resolution
902+
903+
The server automatically handles provider resolution:
904+
905+
- **Class strings** (`MyProvider::class`) → Resolved from PSR-11 container with dependency injection
906+
- **Instances** (`new MyProvider()`) → Used directly as-is
907+
- **Values arrays** (`['a', 'b', 'c']`) → Automatically wrapped in `ListCompletionProvider`
908+
- **Enum classes** (`MyEnum::class`) → Automatically wrapped in `EnumCompletionProvider`
909+
797910
> **Important**: Completion providers only offer suggestions to users in the MCP client interface. Users can still input any value, so always validate parameters in your handlers regardless of completion provider constraints.
798911
799912
### Custom Dependency Injection

0 commit comments

Comments
 (0)