Skip to content

Conversation

@pushpak1300
Copy link
Member

@pushpak1300 pushpak1300 commented Dec 5, 2025

This PR adds support for the MCP completion utility, allowing servers to provide IDE-like autocompletion suggestions for Prompt arguments and Resource template variables.

Completions are opt-in. MCP servers will not enable this by default. To turn it on, add the capability in your server class:

protected function boot(): void
{
    $this->addCapability(self::CAPABILITY_COMPLETION);
}

How It Works

  1. Opt-in per primitive: Prompts and Resources implement SupportsCompletion interface
  2. Context-aware: Access current argument values via $context array parameter
  3. Lazy resolution: Completion strategies (fromArray, fromEnum, fromCallback) resolve at call time with user input
  4. Built-in helpers: Filter completions with CompletionHelper::filterByPrefix()

Completion Strategies

// Direct array (immediate, no filtering)
CompletionResponse::from(['php', 'python', 'javascript']);

// Single value
CompletionResponse::from('php');

// List with prefix filtering (lazy)
CompletionResponse::fromArray(['php', 'python', 'javascript']);

// Enum values (lazy)
CompletionResponse::fromEnum(StatusEnum::class);

// Callback (deferred execution)
CompletionResponse::fromCallback(fn (string $value) => 
    DB::table('tags')->where('name', 'like', "$value%")->pluck('name')->all()
);

// Empty result
CompletionResponse::empty();

Usage Example

class TaskPrompt extends Prompt implements SupportsCompletion
{
    public function complete(string $argument, string $value, array $context): CompletionResponse
    {
        return match ($argument) {
            'assignee' => CompletionResponse::from(['alice', 'bob', 'charlie']),
            'priority' => CompletionResponse::fromEnum(Priority::class),
            'category' => CompletionResponse::fromArray(['backend', 'frontend', 'infra']),
            'tag' => CompletionResponse::fromCallback(
                fn ($v) => DB::table('tags')->where('name', 'like', "$v%")->pluck('name')->all()
            ),
            'status' => $context['priority'] === 'high'
                ? CompletionResponse::make(['in-progress', 'blocked'])
                : CompletionResponse::fromArray(['pending', 'in-progress', 'completed']),
            default => CompletionResponse::empty(),
        };
    }
}

Resource Template Completion

class UserFileResource extends Resource implements HasUriTemplate, SupportsCompletion
{
    public function uriTemplate(): UriTemplate
    {
        return new UriTemplate('file://users/{userId}/files/{fileId}');
    }

    public function complete(string $argument, string $value, array $context): CompletionResponse
    {
        return match ($argument) {
            'userId' => CompletionResponse::fromArray(['user-1', 'user-2']),
            'fileId' => $context['userId'] 
                ? CompletionResponse::fromArray($this->getFilesForUser($context['userId']))
                : CompletionResponse::empty(),
            default => CompletionResponse::empty(),
        };
    }
}

Testing

MyServer::completion(LanguagePrompt::class, 'language', 'py')
    ->assertHasCompletions(['python'])
    ->assertCompletionCount(1);

MyServer::completion(TaskPrompt::class, 'status', '', ['priority' => 'high'])
    ->assertHasCompletions(['in-progress', 'blocked']);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants