MCP Completion là phần mở rộng của Model Context Protocol giúp server trả về gợi ý tự động hoàn thành cho tham số của prompt hoặc resource. Thay vì bắt người dùng nhớ chính xác mã sản phẩm, tên template, URI, locale hay loại dữ liệu, MCP client có thể gọi completion/complete trong lúc người dùng đang nhập và hiển thị danh sách gợi ý giống autocomplete trong IDE. Theo MCP spec 2025-11-25, completion dùng request completion/complete, nhận ref, argument, có thể kèm context.arguments, và trả về completion.values, total, hasMore. Tham khảo: MCP Completion spec.

Kiến trúc tổng quát

Trong GraphQL plugin, MCP server expose endpoint JSON-RPC tại:
POST /graphql/mcp
Method completion/complete đã được route qua hệ thống event handler. GraphQL plugin không bắt bạn sửa dispatcher cho từng completion mới; bạn chỉ cần tạo thêm một event handler có tên đúng quy ước.
sequenceDiagram
    participant Client as MCP Client
    participant MCP as GraphQL MCP Endpoint
    participant Router as MCP Method Handler
    participant Completion as Completion Handler

    Client->>MCP: completion/complete(ref, argument)
    MCP->>Router: completion/complete_mcp_method_event
    Router->>Router: tạo key = refName + "_" + argumentName
    Router->>Completion: <key>_mcp_completion_event
    Completion-->>Router: completion.values
    Router-->>MCP: CompleteResult
    MCP-->>Client: JSON-RPC result

Quy ước tương thích với GraphQL plugin

GraphQL plugin tìm completion handler bằng suffix:
_mcp_completion_event
Khi client gửi request completion, plugin tạo key theo công thức:
<refName>_<argumentName>
Sau đó plugin tìm event handler có event name:
<refName>_<argumentName>_mcp_completion_event
Trong đó:
ref.type = "ref/prompt"   -> refName = ref.name
ref.type = "ref/resource" -> refName = ref.uri
argumentName             -> argument.name
Ví dụ prompt tên create_article, argument tên category thì completion handler cần trả về:
create_article_category_mcp_completion_event

Cài đặt completion cho một prompt argument

Giả sử bạn có prompt create_article và muốn autocomplete argument category.
@EzySingleton
public class CreateArticleCategoryMcpCompletionEventHandler
    extends AbstractEventHandler<Map<String, Object>, Object> {

    @Override
    public Object handleEventData(Map<String, Object> argument) {
        String value = argument != null
            ? (String) argument.getOrDefault("value", "")
            : "";

        List<String> values = findCategories(value);

        return EzyMapBuilder.mapBuilder()
            .put(
                "completion",
                EzyMapBuilder.mapBuilder()
                    .put("values", values)
                    .put("total", values.size())
                    .put("hasMore", Boolean.FALSE)
                    .toMap()
            )
            .toMap();
    }

    private List<String> findCategories(String keyword) {
        return Arrays.asList("news", "tutorial", "release-note")
            .stream()
            .filter(it -> it.startsWith(keyword))
            .limit(100)
            .collect(Collectors.toList());
    }

    @Override
    public String getEventName() {
        return "create_article_category_mcp_completion_event";
    }
}

Request kiểm thử

Sau khi restart plugin, có thể gọi thử:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "completion/complete",
  "params": {
    "ref": {
      "type": "ref/prompt",
      "name": "create_article"
    },
    "argument": {
      "name": "category",
      "value": "tu"
    }
  }
}
Response kỳ vọng:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "completion": {
      "values": ["tutorial"],
      "total": 1,
      "hasMore": false
    }
  }
}

Lưu ý tương thích

Nếu không tìm thấy handler, GraphQL plugin trả completion rỗng:
{
  "completion": {
    "values": [],
    "total": 0,
    "hasMore": false
  }
}
MCP spec yêu cầu server có completion nên khai báo capability completions. Vì vậy, để client strict nhận biết tính năng này ngay từ initialize, nên đảm bảo response capabilities có thêm:
{
  "capabilities": {
    "completions": {}
  }
}
Hiện flow completion của GraphQL plugin truyền argument vào handler. Vì vậy handler đọc trực tiếp argument.nameargument.value; nếu muốn dùng context.arguments để gợi ý theo các argument đã chọn trước đó, cần mở rộng dispatcher để truyền thêm context hoặc gộp context vào dữ liệu gửi cho handler.

Kết luận

Để cài MCP Completion tương thích với GraphQL plugin, phần quan trọng nhất là giữ đúng quy ước event name:
<refName>_<argumentName>_mcp_completion_event
Handler chỉ cần trả đúng shape completion.values, total, hasMore. Với cách này, mỗi prompt hoặc resource có thể bổ sung autocomplete độc lập, không cần sửa danh sách method MCP hay cơ chế route chung của plugin.