# Khoá MCP Advanced Topics của Anthropic: học sampling và transport, rồi tự kiểm lại theo đặc tả

> Khoá học này cho bạn bản đồ của MCP khi lên production. Những quy tắc bắt buộc trong đặc tả, như stdout sạch, kiểm tra Origin hay có người duyệt sampling, thì bạn vẫn phải tự cài và tự test.

Bản gốc: https://fdetimes.net/vi/sach-khoa-hoc/khoa-hoc-model-context-protocol-advanced-topics-anthropic/

Ngày 19/04/2026, một issue được mở trên kho Python SDK của MCP. Nội dung khá ngắn: server Streamable HTTP đã cấu hình `stateless_http=True` mà vẫn chấp nhận `GET /mcp`, lệch so với đặc tả. Lỗi không lớn, nhưng cho thấy ngay thư viện chính thức cũng có chỗ chưa làm đúng đặc tả.

Đó cũng là cách nên đọc khoá "Model Context Protocol: Advanced Topics" của Anthropic, đăng trên Anthropic Academy (nền tảng Skilljar). Khoá học xoay quanh giao tiếp server-client, cơ chế transport và những điều cần lưu ý khi triển khai production. Trang khoá học chỉ ghi © 2026, không nêu ngày phát hành hay thời lượng.

Với một FDE, đây là những câu hỏi thật ở chỗ khách hàng. Server MCP chạy ở đâu? Ai giữ key của mô hình? Chuyện gì xảy ra khi bạn đặt nó sau load balancer? Khoá học trả lời được phần lớn. Phần còn lại bạn phải tự làm theo đặc tả.

## Ai nên học, và học theo thứ tự nào?

Khoá học yêu cầu biết trước Python, lập trình async, JSON/HTTP và kiến thức cơ bản về SSE. Nếu bạn chưa quen viết code async trong Python, hãy học phần đó trước. Nếu không, các bài về transport sẽ khó theo vì bạn phải vừa học giao thức vừa học cú pháp.

Thứ tự hợp lý là học xong khoá, rồi đọc hai trang Sampling và Transports của đặc tả bản 2025-06-18, sau đó mới mở issue SDK nói trên. Học theo thứ tự này, bạn đi từ hiểu khái niệm sang đọc quy tắc bắt buộc, rồi tới chỗ code thật còn chưa khớp với quy tắc. Ba ý dưới đây đáng giữ lại nhất.

## Server mượn mô hình của client

Theo khoá học, sampling là cơ chế để MCP server yêu cầu gọi mô hình ngôn ngữ thông qua client đang kết nối với nó. Đặc tả MCP nói rõ cái lợi: server dùng được khả năng AI mà không cần API key riêng, còn client giữ quyền kiểm soát truy cập, chọn mô hình và cấp quyền.

Server cũng không chỉ định cứng tên mô hình. Nó cho client biết mình coi trọng chi phí, tốc độ hay chất lượng của mô hình đến đâu, kèm vài gợi ý tên mô hình. Đặc tả nhấn mạnh rằng gợi ý chỉ để tham khảo, quyết định cuối cùng thuộc về client.

Thử hình dung bạn dựng một server tóm tắt ticket hỗ trợ cho khách hàng. Nhờ sampling, bạn không phải xin khách cấp thêm một key riêng cho server, và đội bảo mật của họ vẫn tự quyết dùng mô hình nào.

Nhưng đặc tả có kèm một khuyến nghị: lúc nào cũng nên có một người được quyền từ chối yêu cầu sampling. Nếu bạn là người viết client, bước duyệt này là việc của bạn.

## stdout chỉ dành cho message MCP

Đặc tả định nghĩa hai transport chuẩn là stdio và Streamable HTTP, và khuyến nghị client hỗ trợ stdio khi có thể. Với stdio có một quy tắc bắt buộc: server không được ghi ra stdout bất cứ thứ gì không phải message MCP hợp lệ. Log phải đi qua stderr.

Lỗi này rất dễ mắc khi bạn tự viết server. Chỉ cần một dòng `print` để debug là luồng message bị lẫn rác, và client nhận được dữ liệu nó không hiểu. Vì thế, việc đầu tiên nên làm khi khởi tạo server là cấu hình logger, trước khi viết bất kỳ tool nào:

```python
import logging, sys

logging.basicConfig(stream=sys.stderr, level=logging.INFO)
log = logging.getLogger("mcp-server")
log.info("server khởi động")  # đi ra stderr, không chạm vào stdout
```

Kết quả mong đợi: mọi dòng log hiện ở stderr, còn stdout chỉ chứa message MCP. Muốn chắc chắn, hãy cố ý thêm một lệnh `print("debug")` rồi xem client phản ứng thế nào, để lần sau bạn nhận ra triệu chứng ngay.

## State quyết định cách bạn mở rộng

Phần giá trị nhất của khoá học là dạy chọn transport theo yêu cầu triển khai, chức năng cần có và giới hạn mở rộng, kèm khi nào nên dùng stateless HTTP để mở rộng ngang sau load balancer.

Theo đặc tả, session trong Streamable HTTP là tuỳ chọn. Server có thể cấp ID qua header `Mcp-Session-Id` khi khởi tạo, và từ đó client phải gửi lại ID này ở mọi request.

Thử hình dung khách hàng chạy ba instance sau một load balancer. Instance A cấp session và giữ state, nhưng request tiếp theo lại rơi vào instance B, vốn không biết gì về session đó. Chạy stateless thì tránh được chuyện này, nhưng không miễn phí.

Khoá học chỉ ra rằng các cờ cấu hình ảnh hưởng tới request do server khởi tạo và tới khả năng streaming. Sampling chính là server chủ động gửi yêu cầu, nên bạn cần kiểm tra nó còn chạy được trong cấu hình đã chọn hay không.

**Điểm mấu chốt:** Học khoá giúp bạn biết giao thức; tự test theo đặc tả mới cho biết hệ thống của bạn chạy thế nào.

Có hai quy tắc nữa nên đưa thẳng vào bộ test, mỗi quy tắc một lệnh riêng để khi request bị từ chối, bạn biết chắc quy tắc nào đã chặn nó. Thay địa chỉ dưới đây bằng server của bạn.

Lệnh đầu tiên kiểm tra chỗ lệch mà issue SDK nêu ra: gửi `GET` vào server đang chạy `stateless_http=True`, không kèm header nào khác.

```bash
curl -i -X GET http://localhost:8000/mcp
```

Issue trên đề xuất server stateless trả về mã 405 cho request này. Nếu server của bạn vẫn nhận request bình thường, hãy ghi lại và chặn nó ở tầng của bạn, thay vì tin rằng thư viện đã xử lý đúng.

Lệnh thứ hai kiểm tra quy tắc bắt buộc về header `Origin`, thứ server Streamable HTTP phải xác thực trên mọi kết nối để chống tấn công DNS rebinding. Dùng `POST` để không lẫn với phép thử `GET` ở trên:

```bash
curl -i -X POST http://localhost:8000/mcp \
  -H "Origin: http://evil.example" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"ping"}'
```

Kết quả bạn cần thấy là request bị từ chối. Sau đó chạy lại đúng lệnh này nhưng bỏ dòng `Origin`: nếu chỉ bản có Origin lạ bị chặn, bạn biết phần kiểm tra Origin đang hoạt động chứ không phải request bị lỗi vì lý do khác.

## Biến khoá học thành bằng chứng trong CV

Đừng chỉ ghi chứng chỉ hoàn thành khoá học vào CV; hãy kèm một repo nhỏ chứng minh bạn đã làm thật.

Dựng một server chạy được cả stdio lẫn Streamable HTTP, có log ra stderr, có test từ chối Origin lạ, có cấu hình stateless chạy sau hai instance, và một client có bước duyệt sampling.

Trong README, viết một đoạn ngắn giải thích vì sao bạn chọn stateful hay stateless.

Khi đọc mô tả công việc FDE có nhắc tới MCP, agent integration hay production deployment, đó chính là đoạn bạn nên mang vào phỏng vấn. Hãy chuẩn bị kể lại các đánh đổi, chẳng hạn vì sao session ID làm khó load balancer, chứ không chỉ liệt kê API bạn đã gọi.

Nhiều người sẽ học xong khoá này. Số người từng tự gửi `GET /mcp` vào server của mình để xem nó trả về gì sẽ ít hơn nhiều.

**Thử ngay tuần này:**

- Viết một MCP server stdio nhỏ, cho toàn bộ log ra stderr, rồi thêm một lệnh print vào stdout để xem client phản ứng ra sao.
- Chạy server Streamable HTTP với stateless_http=True, gửi riêng một GET /mcp và riêng một POST mang Origin lạ, ghi lại server trả về gì cho từng request.
- Thêm vào client một bước duyệt hoặc từ chối mỗi yêu cầu sampling trước khi gọi mô hình.

## Nguồn

- [Model Context Protocol: Advanced Topics (Anthropic Academy)](https://anthropic.skilljar.com/model-context-protocol-advanced-topics)

- [Sampling - Model Context Protocol Specification (2025-06-18)](https://modelcontextprotocol.io/specification/2025-06-18/client/sampling)

- [Transports - Model Context Protocol Specification (2025-06-18)](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports)

- [Return 405 on GET when stateless_http=True (Issue #2474, modelcontextprotocol/python-sdk)](https://github.com/modelcontextprotocol/python-sdk/issues/2474)
