MCP Prompts là phần của Model Context Protocol dùng để cung cấp các “prompt mẫu” có tham số cho AI client. Khác với MCP Tools, prompt không trực tiếp thực thi nghiệp vụ; nó tạo ra một hoặc nhiều message có cấu trúc để client đưa vào mô hình. Với GraphQL plugin, MCP Prompts được tích hợp qua cùng MCP endpoint với tools/resources, giúp admin hoặc AI agent gọi prompt theo tên, truyền tham số, rồi nhận lại nội dung hướng dẫn đã được chuẩn hóa.

Kiến trúc tương thích với GraphQL plugin

GraphQL plugin expose MCP server qua endpoint:
GET  /graphql/mcp
POST /graphql/mcp
Endpoint GET trả thông tin server, protocol version và danh sách method hỗ trợ, trong đó có:
prompts/list
prompts/get
completion/complete
Endpoint POST nhận JSON-RPC 2.0 request. Khi request hợp lệ, plugin sẽ map method MCP sang event nội bộ bằng hậu tố:
{method}_mcp_method_event
Ví dụ:
prompts/list -> prompts/list_mcp_method_event
prompts/get  -> prompts/get_mcp_method_event
Luồng tổng quát:
sequenceDiagram
    participant Client as MCP Client
    participant Server as GraphQL MCP Server
    participant Registry as Event Handler Registry
    participant Prompt as Prompt Handler

    Client->>Server: POST /graphql/mcp method=prompts/list
    Server->>Registry: Tìm prompt schema handlers
    Registry-->>Server: Danh sách prompt metadata
    Server-->>Client: JSON-RPC result.prompts

    Client->>Server: POST /graphql/mcp method=prompts/get
    Server->>Registry: Tìm handler theo prompt name
    Registry->>Prompt: Gọi với arguments
    Prompt-->>Server: description + messages
    Server-->>Client: JSON-RPC result

Cơ chế đăng ký Prompt

Một MCP Prompt tương thích với GraphQL plugin cần có 2 handler:
{prompt_name}_mcp_prompt_schema_event
{prompt_name}_mcp_prompt_event
Trong đó:
  • *_mcp_prompt_schema_event trả metadata để hiện trong prompts/list.
  • *_mcp_prompt_event nhận arguments và trả nội dung prompt khi client gọi prompts/get.
Tên prompt phải duy nhất. Plugin scan các event handler singleton, lấy phần trước suffix làm prompt_name, rồi dùng tên đó để map request.

Cấu trúc Prompt Schema

Prompt schema nên trả về object có dạng:
{
  "name": "generate_checkout_link",
  "title": "Generate Checkout Link",
  "description": "Generates a direct checkout link for one or more products.",
  "arguments": [
    {
      "name": "product_codes",
      "description": "Comma-separated product code(s).",
      "required": true
    },
    {
      "name": "quantities",
      "description": "Comma-separated quantities matching product_codes.",
      "required": false
    }
  ]
}
Các field quan trọng:
  • name: tên prompt client dùng trong prompts/get.
  • title: tên dễ đọc cho UI.
  • description: mô tả prompt làm gì.
  • arguments: danh sách tham số, mỗi tham số có name, description, required.

Cấu trúc Prompt Result

Khi client gọi prompts/get, handler trả về kết quả dạng MCP prompt message:
{
  "description": "Generate a direct checkout link for the given product(s).",
  "messages": [
    {
      "role": "user",
      "content": {
        "type": "text",
        "text": "Generate a direct checkout link using the following rules..."
      }
    }
  ]
}
messages có thể chứa một hoặc nhiều message. Với prompt đơn giản, một message role user là đủ.

Ví dụ request prompts/list

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "prompts/list",
  "params": {}
}
Kết quả:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "prompts": [
      {
        "name": "generate_checkout_link",
        "title": "Generate Checkout Link",
        "description": "Generates a direct checkout link for one or more products.",
        "arguments": []
      }
    ]
  }
}

Ví dụ request prompts/get

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "prompts/get",
  "params": {
    "name": "generate_checkout_link",
    "arguments": {
      "product_codes": "book-a,book-b",
      "quantities": "1,2",
      "clear_shopping_cart": "true"
    }
  }
}
Kết quả là prompt đã được dựng sẵn:
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "description": "Generate a direct checkout link for the given product(s).",
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "Generate a direct checkout link using the following rules:n..."
        }
      }
    ]
  }
}

Mẫu cài đặt Prompt

Một prompt mới nên được cài theo cặp handler sau.
Schema handler:
@EzySingleton
public class MyPromptSchemaEventHandler
    extends AbstractEventHandler<Map<String, Object>, Object> {

    public static final String PROMPT_NAME = "my_prompt";

    @Override
    public Object handleEventData(Map<String, Object> data) {
        return EzyMapBuilder.mapBuilder()
            .put("name", PROMPT_NAME)
            .put("title", "My Prompt")
            .put("description", "Creates a reusable prompt for a specific workflow.")
            .put("arguments", Arrays.asList(
                EzyMapBuilder.mapBuilder()
                    .put("name", "input")
                    .put("description", "Main input value.")
                    .put("required", true)
                    .toMap()
            ))
            .toMap();
    }

    @Override
    public String getEventName() {
        return PROMPT_NAME + "_mcp_prompt_schema_event";
    }
}
Prompt handler:
@EzySingleton
public class MyPromptEventHandler
    extends AbstractEventHandler<Map<String, Object>, Object> {

    @Override
    public Object handleEventData(Map<String, Object> arguments) {
        String input = (String) arguments.get("input");

        String text = "Use this input to complete the workflow:nn" + input;

        return EzyMapBuilder.mapBuilder()
            .put("description", "Prompt for my workflow.")
            .put("messages", Collections.singletonList(
                EzyMapBuilder.mapBuilder()
                    .put("role", "user")
                    .put("content", EzyMapBuilder.mapBuilder()
                        .put("type", "text")
                        .put("text", text)
                        .toMap()
                    )
                    .toMap()
            ))
            .toMap();
    }

    @Override
    public String getEventName() {
        return MyPromptSchemaEventHandler.PROMPT_NAME + "_mcp_prompt_event";
    }
}

Tương thích với GraphQL plugin

Để prompt hoạt động tốt với GraphQL plugin, nên tuân thủ các nguyên tắc sau:
  • Prompt name dùng snake_case, ngắn, ổn định.
  • Schema handler và prompt handler phải dùng cùng một PROMPT_NAME.
  • Không thực thi tác vụ có side effect trong prompt handler; nếu cần thực thi nghiệp vụ, dùng MCP Tool.
  • Prompt handler chỉ nên dựng message, hướng dẫn, query mẫu, mutation mẫu hoặc quy trình gọi tool/schema.
  • Nếu prompt cần đọc schema GraphQL lớn, hãy hướng dẫn client dùng MCP Tool tải schema về file thay vì nhúng toàn bộ schema vào prompt.
  • Với tham số bắt buộc, validate trong prompt handler nếu cần, vì schema chỉ mô tả cho client chứ không tự chặn request.

Completion cho tham số Prompt

GraphQL plugin cũng có completion/complete. Cơ chế completion tìm handler theo key:
{ref_name}_{argument_name}_mcp_completion_event
Với prompt, ref_name thường là prompt name. Ví dụ muốn gợi ý giá trị cho argument product_codes của prompt generate_checkout_link, handler completion nên có event name:
generate_checkout_link_product_codes_mcp_completion_event
Response completion nên có dạng:
{
  "completion": {
    "values": ["book-a", "book-b"],
    "total": 2,
    "hasMore": false
  }
}

Bảo mật

MCP endpoint của GraphQL plugin yêu cầu authenticated admin request. Khi server nhận request, access token admin được đưa vào params, và nếu có arguments thì cũng được đưa vào arguments.
Điều này cho phép prompt hoặc tool handler dùng token khi cần gọi các tài nguyên admin/web có kiểm soát quyền. Tuy vậy, prompt handler không nên in token ra message trả về.

Checklist cài đặt

  • Tạo schema handler trả name, title, description, arguments.
  • Tạo prompt handler trả description, messages.
  • Đặt event name đúng suffix:
    • _mcp_prompt_schema_event
    • _mcp_prompt_event
  • Đăng ký handler dưới dạng singleton để plugin scan được.
  • Test bằng prompts/list.
  • Test bằng prompts/get với đủ arguments.
  • Nếu cần autocomplete, thêm completion handler theo {prompt_name}_{argument_name}_mcp_completion_event.

Kết luận

MCP Prompts trong GraphQL plugin được thiết kế theo hướng rất nhẹ: prompt không cần đăng ký qua file cấu hình riêng, mà được phát hiện tự động từ event handler singleton. Chỉ cần triển khai đúng cặp schema/result handler và đặt event name theo convention, prompt sẽ xuất hiện trong prompts/list và dùng được qua prompts/get. Cách này giúp mở rộng workflow cho AI client mà vẫn giữ ranh giới rõ ràng giữa “gợi ý/ngữ cảnh” của prompt và “hành động thực thi” của tool.