MCP chuyển sang stateless core ngày 28/7/2026: hướng dẫn migration server, session, OAuth và observability
Playbook chuyển MCP server sang stateless core từ ngày 28/7/2026: phân loại state, idempotency, session, OAuth, tool safety, retry, observability, canary và rollback.
Ngày 28/7/2026 đánh dấu một mốc đáng chú ý đối với hệ sinh thái Model Context Protocol khi GitHub MCP Server chuyển trọng tâm sang giao thức stateless theo thông báo trong GitHub Changelog. Với đội ngũ đang vận hành MCP server nội bộ, đây không chỉ là thay đổi cách truyền request. Stateless làm thay đổi cách lưu session, cấp quyền, xử lý retry, thiết kế tool, quan sát lỗi và mở rộng hạ tầng.
Nhiều MCP server ban đầu được xây như một ứng dụng hội thoại nhỏ: kết nối được mở lâu, tiến trình giữ context trong memory, token gắn với session, tool dựa vào trạng thái của request trước. Mô hình này dễ thử nghiệm nhưng khó chạy ổn định khi có nhiều instance, autoscaling, failover hoặc client thay đổi kết nối. Chỉ cần request tiếp theo rơi vào pod khác, trạng thái ngầm có thể mất và hành động trở nên không xác định.
Stateless core không có nghĩa hệ thống không được lưu bất kỳ dữ liệu nào. Nó có nghĩa mỗi request phải mang đủ thông tin hoặc tham chiếu rõ ràng để server xử lý mà không phụ thuộc vào memory riêng của một tiến trình trước đó. State vẫn tồn tại, nhưng được đặt vào kho có chủ đích, có định danh, thời hạn, quyền truy cập và khả năng kiểm toán. Bài viết này trình bày playbook migration thực tế cho đội sản phẩm, từ inventory đến canary và rollback.
1. Stateless core là gì và không phải là gì?

Trong kiến trúc stateless, một instance bất kỳ có thể xử lý request hợp lệ vì dữ liệu cần thiết nằm trong request, token, resource URI hoặc kho trạng thái dùng chung. Instance không cần biết client đã nói gì với một instance khác nếu thông tin đó không được truyền hoặc lưu rõ ràng. Điều này giúp load balancer phân phối request tự do, giảm phụ thuộc sticky session và làm failover đơn giản hơn.
Stateless không đồng nghĩa mọi tool đều là pure function. Tool tạo issue, gửi email, cập nhật database hoặc publish nội dung vẫn có side effect. Điều cần thay đổi là side effect phải được quản lý bằng idempotency key, transaction, optimistic concurrency, audit log và trạng thái tác vụ bền vững. Server không được dựa vào biến cục bộ như lastCreatedRecord để biết đối tượng nào cần cập nhật.
Stateless cũng không loại bỏ session ở lớp sản phẩm. Người dùng vẫn có cuộc hội thoại, job dài hoặc workflow nhiều bước. Tuy nhiên, session phải trở thành một thực thể rõ: session ID, owner, scope, version, expiry và dữ liệu được phép lưu. Client gửi session ID hoặc continuation token; server đọc state từ kho được kiểm soát, không từ memory ngẫu nhiên của process.
2. Vì sao MCP server stateful dễ hỏng khi mở rộng?

Một server stateful thường hoạt động tốt ở môi trường local vì chỉ có một tiến trình và một người dùng. Khi chạy nhiều replica, request có thể đi vào instance khác. Nếu không có sticky session, context mất. Nếu bật sticky session, một instance quá tải hoặc chết sẽ làm session gián đoạn. Việc deploy phiên bản mới cũng khó vì state trong memory không thể di chuyển an toàn.
State ngầm còn gây lỗi retry. Client hoặc gateway có thể gửi lại request khi timeout dù server đã thực hiện side effect. Nếu server chỉ nhớ trong memory rằng thao tác đã hoàn thành, retry vào instance khác sẽ tạo bản ghi trùng, gửi email hai lần hoặc charge hai lần. Khi không có idempotency bền vững, hệ thống không phân biệt request mới với request lặp.
Quan sát cũng trở nên khó. Log ở một pod chứa phần đầu workflow, pod khác chứa phần sau. Không có correlation ID và state version, kỹ sư không tái dựng được chuỗi hành động. Stateless buộc đội ngũ xác định identity của request, task và resource, từ đó telemetry trở nên có cấu trúc hơn.
3. Bước đầu tiên: lập state inventory

Trước khi sửa code, hãy liệt kê mọi state mà server đang giữ. Chia thành sáu nhóm: authentication state; conversation hoặc session context; resource state; job state; cache; và state phục vụ giao diện. Với từng mục, ghi nơi lưu hiện tại, owner, dữ liệu nhạy cảm, thời gian sống, cách khôi phục và hậu quả nếu mất.
Ví dụ, access token nằm trong object session là authentication state; danh sách file người dùng vừa chọn là workflow state; kết quả tìm kiếm gần nhất có thể là cache; ID của draft vừa tạo là resource state; tiến độ ingest media là job state. Không nên gom tất cả vào một JSON session lớn vì quyền, retention và consistency của từng loại khác nhau.
Sau inventory, phân loại state nào có thể loại bỏ, state nào client phải gửi lại, state nào chuyển sang database hoặc queue, và state nào chỉ cần cache có thể mất. Đây là bước tiết kiệm nhất. Nhiều biến được giữ trong memory chỉ vì code ban đầu thuận tiện, không phải vì sản phẩm thực sự cần.
4. Thiết kế request envelope có đủ ngữ cảnh
Mỗi request nên có request ID duy nhất, actor identity, organization hoặc tenant, tool name, input đã validate, idempotency key khi có side effect, correlation ID, policy version và optional session reference. Các trường này giúp server xử lý độc lập và liên kết telemetry.
Không tin hoàn toàn metadata do client gửi. Actor và scope phải được suy ra hoặc kiểm chứng từ token. Tenant phải khớp quyền. Tool input cần schema validation, giới hạn kích thước, allowlist URL và kiểm tra kiểu dữ liệu. Request ID chỉ phục vụ trace; idempotency key phải có namespace và ràng buộc với actor, tool cùng payload hash.
Response nên có status rõ, result hoặc error chuẩn hóa, resource reference, retryability, state version và audit reference. Khi thao tác chuyển sang asynchronous job, server trả job ID và endpoint hoặc resource để client kiểm tra, thay vì giữ kết nối và state trong process.
5. Idempotency là điều kiện bắt buộc cho tool có side effect
Idempotency nghĩa cùng một yêu cầu hợp lệ được gửi lại sẽ không tạo side effect thứ hai ngoài ý muốn. Server lưu idempotency key cùng actor, operation, payload hash, trạng thái và kết quả. Khi nhận lại, nếu payload giống và thao tác đã hoàn thành, trả kết quả cũ; nếu đang chạy, trả trạng thái; nếu payload khác, từ chối conflict.
Không dùng request ID ngẫu nhiên do server tạo sau khi nhận request làm idempotency key, vì retry sẽ có ID khác. Key phải ổn định cho cùng ý định, thường do client tạo hoặc được dẫn xuất từ workflow step. Đặt TTL phù hợp với nguy cơ duplicate; các thao tác tài chính hoặc publish có thể cần retention dài hơn.
Idempotency không thay thế transaction. Khi tạo nhiều bản ghi, cần transaction hoặc saga để tránh trạng thái nửa chừng. Record idempotency cũng phải được ghi atomically với side effect hoặc theo outbox pattern, nếu không crash giữa hai bước vẫn tạo duplicate.
6. Optimistic concurrency và version hóa tài nguyên
Trong workflow nhiều bước, resource có thể bị người khác hoặc agent khác sửa giữa lúc đọc và cập nhật. Stateless server không nên giả định bản ghi vẫn như cũ. Mỗi update cần expected version hoặc updatedAt. Nếu mismatch, trả conflict và yêu cầu client đọc lại hoặc hợp nhất thay đổi.
Preview-apply là pattern đặc biệt hữu ích với thao tác rủi ro. Client gửi thay đổi dự kiến; server tạo diff, risk, confirmation text và preview hash. Khi apply, client phải gửi đúng hash và expectedUpdatedAt. Nếu dữ liệu thay đổi hoặc payload khác, apply bị từ chối. Điều này chống thao tác mơ hồ và race condition.
Version hóa schema cũng cần rõ. Tool definition, request contract, resource schema và policy đều có version. Server nên hỗ trợ cửa sổ tương thích, cảnh báo client cũ và đo tỷ lệ request theo version trước khi loại bỏ.
7. Session và continuation token nên được thiết kế lại ra sao?

Nếu workflow cần nhiều bước, tạo session record tối thiểu: session ID không đoán được, actor, tenant, purpose, createdAt, expiresAt, state version và references. Không lưu toàn bộ prompt, secret hoặc file thô nếu không cần. Dữ liệu nhạy cảm nên nằm ở kho chuyên dụng, session chỉ giữ reference có scope.
Continuation token có thể chứa state tối thiểu đã ký hoặc một opaque ID trỏ đến server-side state. Token tự chứa giúp giảm lookup nhưng khó revoke, giới hạn kích thước và cần bảo vệ dữ liệu. Opaque token dễ thu hồi, kiểm soát retention và cập nhật state. Lựa chọn phụ thuộc mức nhạy cảm và yêu cầu latency.
Mọi session cần expiry và cleanup. Không để session vĩnh viễn vì tạo data graveyard và tăng bề mặt tấn công. Khi hết hạn, client nhận lỗi có thể xử lý và hướng dẫn khởi tạo lại, không phải lỗi 500 không rõ nguyên nhân.
8. OAuth cho MCP stateless: tách authorization khỏi process

Authorization code, PKCE, token exchange, refresh và resource authorization phải hoạt động độc lập với instance. State parameter và PKCE verifier cần được ràng buộc an toàn, có TTL và chống replay. Token không nên nằm trong memory của một pod duy nhất nếu request tiếp theo có thể đến pod khác.
Access token nên ngắn hạn, audience cụ thể, scope tối thiểu và không được ghi vào log. Refresh token cần lưu mã hóa hoặc dùng token broker. Với on-behalf-of flow, server phải giữ liên kết audit giữa người dùng, client, MCP server và downstream resource. Không chuyển token của một hệ thống sang hệ thống khác nếu audience không phù hợp.
OAuth state và session sản phẩm là hai khái niệm khác nhau. OAuth state dùng bảo vệ flow authorization; session sản phẩm dùng duy trì workflow. Trộn chúng làm tăng rủi ro và khó revoke. Mỗi lớp cần ID, TTL và storage riêng.
9. Tool contract phải tự mô tả và an toàn khi retry
Mỗi tool cần mô tả mục đích, input schema, output schema, side effect, quyền cần thiết, timeout, retry policy và error taxonomy. Tool đọc dữ liệu có thể retry tự do hơn tool ghi. Tool gửi email hoặc publish phải dùng idempotency và có bước confirmation khi tác động lớn.
Không tạo tool quá tổng quát như execute_admin_action với JSON tự do. Tool hẹp giúp model hiểu đúng, policy dễ kiểm soát và log có ý nghĩa. Nếu cần nhiều operation, dùng enum rõ và validation theo operation. Không cho model tự đưa SQL, shell hoặc URL tùy ý vào backend.
Output nên trả reference ổn định thay vì dựa vào thứ tự. Ví dụ create draft trả draft ID, editor URL và updatedAt. Bước tiếp theo dùng ID đó, không dùng “bản nháp vừa tạo”. Đây chính là cách loại state ngầm khỏi hội thoại.
10. Job dài, queue và outbox

Ingest file, crawl, render hoặc batch update không nên giữ request mở quá lâu. Server tạo job record, enqueue và trả accepted. Worker lấy job theo lease, cập nhật progress, heartbeat và result. Nếu worker chết, lease hết hạn và job có thể retry theo chính sách.
Side effect gửi ra ngoài nên dùng transactional outbox: ghi thay đổi nội bộ và event vào cùng transaction; worker sau đó gửi event. Pattern này tránh trường hợp database đã cập nhật nhưng message không được gửi, hoặc message gửi rồi database rollback.
Job cần cancellation, deadline và retry budget. Không retry vô hạn lỗi validation hoặc permission. Phân biệt transient, permanent và unknown. Mỗi retry phải giữ correlation ID và tăng attempt count để quan sát vòng lặp.
11. Observability cho MCP stateless

Metric tối thiểu gồm request rate, success rate, latency, error theo tool, auth failure, policy denial, idempotency hit, conflict, retry, queue depth và job duration. Trace cần nối client request, MCP tool call, downstream API, database, queue và worker. Log có cấu trúc chứa request ID, actor pseudonymous ID, tenant, tool, resource ID và state version.
Không log prompt, token hoặc toàn bộ payload mặc định. Dùng field allowlist và redaction trước khi dữ liệu rời tiến trình. Trace sampling nên giữ lỗi và tác vụ rủi ro cao, giảm tỷ lệ ở request thành công thông thường. Audit log phải tách khỏi log vận hành và có retention phù hợp.
Dashboard cần gắn runbook. Idempotency conflict tăng dẫn đến kiểm tra client key; auth failure tăng sau deploy dẫn đến kiểm tra audience và clock skew; latency tăng ở downstream dẫn đến circuit breaker; queue depth tăng dẫn đến scale worker hoặc giảm intake.
12. Security boundary và prompt injection

MCP tool thường kết nối dữ liệu có giá trị nên phải coi mọi nội dung từ web, issue, document hoặc user upload là không tin cậy. Model có thể đọc một câu yêu cầu bỏ qua policy hoặc gửi secret. Server phải thực thi authorization ở tool, không dựa vào model tự tuân thủ.
URL fetch phải chống SSRF bằng allowlist scheme, DNS/IP validation, redirect limit, MIME và size check. File ingest cần magic-byte, checksum và antivirus khi phù hợp. Tool ghi phải xác nhận tenant, resource ownership và expected version. Secrets chỉ được cấp tại thời điểm cần và không trả về model nếu không cần.
Policy engine nên quyết định actor nào được gọi tool nào trên resource nào, với tham số và điều kiện gì. Policy decision cần log version và reason. Khi policy thay đổi, canary và rollback như code.
13. Kế hoạch migration 21 ngày
Ngày 1–3: inventory state, tool và auth; vẽ data flow; đo baseline. Ngày 4–6: thêm request ID, correlation ID, schema validation và error taxonomy mà chưa đổi hành vi. Ngày 7–9: triển khai idempotency store và optimistic concurrency cho tool ghi.
Ngày 10–12: chuyển session quan trọng sang kho dùng chung, thêm TTL và cleanup; tách OAuth state. Ngày 13–15: chuyển job dài sang queue, thêm retry budget, outbox và progress. Ngày 16–17: chạy multi-instance test, kill pod, network fault và duplicate request.
Ngày 18–19: canary một nhóm client, theo dõi success, latency, conflict và duplicate. Ngày 20: tăng traffic nếu đạt tiêu chí. Ngày 21: loại sticky dependency, giữ rollback và lập báo cáo hậu kiểm. Không tắt stateful path trước khi session cũ hết hạn hoặc có cơ chế chuyển đổi.
14. Test matrix bắt buộc
- Cùng request gửi hai lần đồng thời.
- Server hoàn thành side effect nhưng response bị mất.
- Pod chết giữa transaction và response.
- Request tiếp theo rơi vào instance khác.
- Session hết hạn trong workflow.
- Access token hết hạn và refresh thất bại.
- Resource bị sửa sau preview.
- Queue giao job nhiều lần.
- Downstream timeout hoặc trả 429.
- Prompt chứa yêu cầu vượt quyền.
- URL redirect tới private IP.
- Client dùng contract version cũ.
- Rollback phiên bản server khi job mới đang chạy.
Mỗi test cần expected result và bằng chứng trong telemetry. Không chỉ kiểm tra response; phải xác nhận không có duplicate, audit đầy đủ và state cuối đúng.
15. Những sai lầm phổ biến
Sai lầm đầu tiên là chỉ bỏ sticky session rồi gọi hệ thống stateless. Nếu context vẫn nằm trong memory, lỗi chỉ trở nên ngẫu nhiên hơn. Sai lầm thứ hai là chuyển toàn bộ session JSON vào Redis mà không phân loại; hệ thống có thể scale nhưng vẫn khó bảo mật và kiểm toán.
Sai lầm tiếp theo là retry mọi lỗi, dùng idempotency key không gắn payload, giữ token quá lâu, log toàn bộ input, dùng tool quá rộng và không version contract. Một lỗi nguy hiểm khác là coi stateless như lý do để client gửi mọi dữ liệu nhạy cảm trong mỗi request.
Migration tốt phải giảm coupling, làm state rõ ràng và cải thiện khả năng phục hồi. Nếu chỉ chuyển nơi lưu state nhưng không thêm identity, version, TTL và policy, lợi ích sẽ hạn chế.
Checklist go-live
- State inventory đã được owner duyệt.
- Mọi tool ghi có idempotency.
- Update dùng expected version.
- Session có TTL, owner và scope.
- OAuth state tách khỏi session sản phẩm.
- Token có audience và scope tối thiểu.
- Job dài chạy qua queue có retry budget.
- Tool schema hẹp và validate server-side.
- SSRF, file và secret controls hoạt động.
- Trace nối request, tool và downstream.
- Audit log không chứa secret.
- Canary có tiêu chí dừng.
- Rollback đã được diễn tập.
Câu hỏi thường gặp
Có cần xóa hoàn toàn session không?
Không. Cần loại phụ thuộc vào memory cục bộ của instance. Session hợp lệ nếu là thực thể rõ, có storage, TTL, quyền và version.
Redis có đủ để chuyển sang stateless không?
Redis có thể là một thành phần, nhưng không tự giải quyết idempotency, consistency, auth, retention hay audit. Phải thiết kế theo loại state và rủi ro.
Tool chỉ đọc có cần idempotency key không?
Thông thường không bắt buộc, nhưng vẫn cần request ID, timeout, cache policy và chống truy cập vượt quyền. Tool đọc có thể gây chi phí hoặc rate limit nên retry vẫn phải có budget.
Đọc thêm trên VietBoost
- Thiết kế MCP và AI Agent an toàn cho production
- Quy trình kiểm thử và security review trước production
Nguồn tham khảo
- GitHub Changelog tháng 7/2026
- Model Context Protocol Specification
- RFC 9700 OAuth 2.0 Security Best Current Practice
- OpenTelemetry Documentation
Kết luận
Chuyển MCP server sang stateless core là cơ hội làm rõ toàn bộ hợp đồng vận hành: request mang gì, state nằm đâu, ai được gọi tool, retry có an toàn không và lỗi được quan sát thế nào. Hãy bắt đầu bằng state inventory, sau đó ưu tiên idempotency, optimistic concurrency, OAuth đúng boundary và telemetry. Khi mỗi request có thể được xử lý bởi bất kỳ instance nào mà vẫn giữ đúng quyền và kết quả, hệ thống mới thực sự sẵn sàng cho production.



