Một trong những câu hỏi mà bất kỳ ai bắt đầu build AI agent cho hệ thống thực tế đều gặp phải sớm hay muộn: "Codebase của tôi có 500,000 dòng code, database có hàng triệu record, làm sao nhét hết vào context window của LLM?" Câu trả lời ngắn gọn là: không cần nhét hết. Bài viết này sẽ giải thích cơ chế kỹ thuật đằng sau việc MCP giúp agent "vượt qua" giới hạn context window — không phải bằng cách làm context window lớn hơn, mà bằng cách thay đổi hoàn toàn cách agent tiếp cận dữ liệu.
Vì Sao Context Window Là Nút Thắt Cổ Chai Của AI Agent
Context window (cửa sổ ngữ cảnh) là lượng token (đơn vị văn bản nhỏ nhất mà model xử lý) tối đa mà một LLM có thể "nhìn thấy" trong một lần inference — bao gồm system prompt, lịch sử hội thoại, tài liệu đính kèm, và output sinh ra. Ngay cả với các model hiện đại có context window rất lớn (Claude Opus 4.5/Sonnet 4.5 hỗ trợ tới 200K token tiêu chuẩn, một số cấu hình mở rộng lên 1M token; Gemini 2.5 Pro hỗ trợ tới 1M-2M token), đây vẫn là một tài nguyên hữu hạn và đắt đỏ theo nhiều nghĩa.
Thứ nhất là chi phí tính toán. Cơ chế attention trong Transformer có độ phức tạp gần như bậc hai theo số token đầu vào (dù các kỹ thuật tối ưu như FlashAttention đã cải thiện đáng kể), nghĩa là nhồi càng nhiều token, thời gian xử lý và chi phí API càng tăng nhanh không tuyến tính. Một request với context 150K token có thể tốn gấp nhiều lần một request 20K token, cả về latency (độ trễ phản hồi) lẫn chi phí — với API tính phí theo token, gửi dư thừa 100K token "phòng khi cần" là lãng phí tiền bạc thực sự.
Thứ hai, và quan trọng hơn với chất lượng agent, là hiện tượng "lost in the middle" — nghiên cứu đã chỉ ra rằng LLM có xu hướng chú ý tốt đến thông tin ở đầu và cuối context, nhưng "quên" hoặc xử lý kém chính xác hơn với thông tin nằm ở giữa một context rất dài. Nhồi cả một file log 50MB hay toàn bộ schema database 200 bảng vào context không chỉ tốn token mà còn có thể làm giảm chất lượng suy luận của model, vì phần lớn nội dung đó không liên quan đến câu hỏi hiện tại và trở thành "nhiễu".
Thứ ba, dữ liệu thực tế thường xuyên thay đổi — số dư tài khoản, trạng thái đơn hàng, giá cổ phiếu, kết quả build CI — trong khi context của một cuộc hội thoại thường được thiết lập tại một thời điểm cố định. Nếu bạn nhồi cứng dữ liệu vào prompt, agent sẽ trả lời dựa trên dữ liệu đã cũ ngay khi bạn gửi request.
Kinh nghiệm triển khai cho thấy rất nhiều đội ngũ mới làm agent mắc lỗi "context window overload" — cố gắng giải quyết bài toán thiếu dữ liệu bằng cách nhồi thêm tài liệu vào system prompt, dẫn đến agent vừa chậm, vừa đắt, vừa kém chính xác. MCP giải quyết vấn đề này theo một hướng hoàn toàn khác: thay vì tăng kích thước context, nó cho phép agent truy vấn theo yêu cầu (on-demand).
Mẹo: Khi debug một agent trả lời sai hoặc "quên" thông tin quan trọng, việc đầu tiên nên kiểm tra không phải là "model có đủ thông minh không" mà là "context hiện tại có đang bị nhồi quá nhiều dữ liệu không liên quan không". Dùng công cụ đếm token (như tokenizer của Anthropic hoặc
tiktoken) để đo kích thước thực tế của system prompt và lịch sử hội thoại trước khi kết luận là do model.
MCP Tools Cho Phép Agent Truy Vấn Hệ Thống Bên Ngoài Theo Yêu Cầu
Cơ chế cốt lõi ở đây là: thay vì cung cấp dữ liệu, MCP server cung cấp khả năng lấy dữ liệu dưới dạng tool. Agent chỉ nhìn thấy mô tả của tool (tên, description, tham số) trong context — tốn rất ít token — và chỉ khi cần thông tin cụ thể, nó mới gọi tool đó, nhận về đúng phần dữ liệu liên quan, xử lý xong rồi có thể "quên" (không cần giữ nguyên toàn bộ trong context cho các bước sau).
Lấy ví dụ cụ thể: một MCP server kết nối tới PostgreSQL có thể expose một tool tên query_database với mô tả "Execute a read-only SQL query against the customer database". Khi agent nhận yêu cầu "Cho tôi biết 10 khách hàng có doanh thu cao nhất tháng này", nó không cần biết trước schema của toàn bộ 200 bảng trong database — nó chỉ cần biết tool query_database tồn tại, có thể gọi tool list_tables hoặc describe_table (cũng do server expose) để khám phá schema liên quan, rồi mới viết câu SQL chính xác. Toàn bộ 199 bảng không liên quan không bao giờ chạm vào context.
Đây chính là cách agentic search (tìm kiếm có tính agentic) hoạt động — thay vì retrieval một lần (như RAG truyền thống lấy top-k đoạn văn bản tương tự rồi nhồi hết vào prompt), agent dùng MCP tool để tìm kiếm lặp lại nhiều vòng: thử một truy vấn, xem kết quả, tinh chỉnh truy vấn tiếp theo, giống hệt cách một kỹ sư con người tra cứu tài liệu. Ví dụ prompt thực tế minh họa rõ luồng này:
Ví dụ prompt để dán vào agent có MCP filesystem + database:
Tìm trong codebase function nào đang gọi trực tiếp tới bảng `orders` mà không qua Repository layer, sau đó kiểm tra xem bảng `orders` hiện có bao nhiêu record đang ở trạng thái "pending" quá 7 ngày. Tổng hợp lại thành danh sách file cần sửa và số lượng record bị ảnh hưởng.
Với prompt này, agent sẽ: gọi tool tìm kiếm code (grep_codebase hoặc tương tự) để định vị các file liên quan, đọc nội dung từng file qua resource/tool đọc file, rồi gọi tool query_database để đếm record — tất cả theo yêu cầu, không có bước nào cần nhồi trước toàn bộ codebase hay toàn bộ bảng orders vào context.
Về mặt kỹ thuật, luồng gọi tool trong MCP tuân theo JSON-RPC request/response: model sinh ra một "tool call" (tên tool + tham số dạng JSON), client gửi request tools/call tới MCP server tương ứng, server thực thi và trả về kết quả (content dạng text/image/resource), client đưa kết quả đó vào context như một tool result message, rồi model tiếp tục suy luận dựa trên kết quả mới đó.
Mẹo: Khi thiết kế tool cho MCP server, viết description tool càng cụ thể càng tốt về việc khi nào nên dùng và khi nào không nên dùng — ví dụ "Use this tool only for read-only queries; do not use for tables larger than 1M rows without a WHERE clause". Description mơ hồ là nguyên nhân số một khiến model gọi sai tool hoặc gọi tool không cần thiết, gây lãng phí vòng lặp và tăng latency.
Các Kịch Bản Thực Tế: Điều Gì Trở Nên Khả Thi Với MCP
Khi tách rời được ràng buộc "phải nhồi hết dữ liệu vào context", một loạt kịch bản mà trước đây bất khả thi hoặc rất tốn kém giờ trở nên thực tế:
Agent hỗ trợ code review trên monorepo lớn
Với một monorepo hàng triệu dòng code, không ai nhồi toàn bộ vào context được. Nhưng với MCP server tích hợp Git + filesystem + ctags/LSP, agent có thể: đọc diff của PR, dùng tool tìm kiếm để định vị các hàm bị ảnh hưởng ở nơi khác trong codebase, đọc riêng các file đó, và đưa ra nhận xét review chính xác — tất cả chỉ với vài chục nghìn token context tại một thời điểm, thay vì hàng triệu token.
Trợ lý phân tích dữ liệu kinh doanh theo thời gian thực
Một MCP server kết nối vào data warehouse (Snowflake, BigQuery) cho phép agent trả lời câu hỏi như "Doanh thu quý này so với cùng kỳ năm ngoái tăng/giảm bao nhiêu ở từng khu vực?" bằng cách sinh SQL, chạy qua tool, và phân tích kết quả trả về — luôn dựa trên dữ liệu mới nhất tại thời điểm hỏi, không phải dữ liệu snapshot cũ nhúng cứng trong prompt.
Agent vận hành đa hệ thống (DevOps/SRE)
Một MCP server tích hợp Kubernetes, Datadog, và PagerDuty cho phép agent xử lý một incident: đọc log lỗi mới nhất từ Datadog, kiểm tra trạng thái pod hiện tại trên Kubernetes, tra cứu runbook liên quan, và nếu cần thì tạo/update incident trên PagerDuty — hoàn toàn dựa trên dữ liệu thời gian thực, agent không cần "biết trước" trạng thái hệ thống tại thời điểm training hay tại thời điểm viết prompt.
Trợ lý QA kiểm thử dựa trên trạng thái ứng dụng thực tế
Trong bối cảnh automation test, một agent QA có MCP server kết nối tới Playwright/Selenium hoặc API testing tool có thể đọc DOM hiện tại của trang, thử tương tác, đọc kết quả response API thực tế theo từng bước — thay vì phải viết test case "mù" dựa trên tài liệu tĩnh có thể đã lỗi thời.
Điểm chung của mọi kịch bản trên: agent luôn làm việc với dữ liệu sống (live) và chỉ lấy đúng phần cần thiết, giúp giải quyết được các bài toán mà trước đây đòi hỏi phải fine-tune model riêng hoặc xây dựng pipeline RAG phức tạp.
Mẹo: Khi thiết kế một use case agent mới, hãy tự hỏi "Dữ liệu này có thay đổi theo thời gian không, và agent có cần dữ liệu mới nhất tại thời điểm chạy không?" Nếu câu trả lời là có, đó là dấu hiệu rõ ràng nên dùng MCP tool để lấy trực tiếp thay vì nhúng cứng dữ liệu vào system prompt hay fine-tune.
Cân Nhắc Về Hiệu Năng: Đánh Đổi Giữa Latency và Token
Không có giải pháp nào miễn phí, và MCP cũng có chi phí riêng mà bạn cần cân nhắc kỹ khi thiết kế hệ thống production.
Chi phí latency của mỗi vòng gọi tool
Mỗi lần agent gọi một MCP tool là một round-trip: model sinh tool call → client gửi JSON-RPC request tới server → server xử lý (có thể gồm cả việc gọi ra API bên ngoài hoặc query database) → trả kết quả về → model xử lý tiếp. Với transport stdio (local), overhead giao tiếp gần như không đáng kể (vài millisecond). Nhưng với transport HTTP/Streamable HTTP (remote server), mỗi vòng có thể tốn thêm 50-300ms tùy khoảng cách mạng và độ phức tạp xử lý phía server. Nếu một tác vụ cần agent gọi 10-15 vòng tool liên tiếp (rất phổ biến với agentic search nhiều bước), tổng latency cộng dồn có thể lên tới vài giây tới vài chục giây — chưa kể thời gian inference của chính model giữa mỗi vòng.
Đánh đổi giữa số lượng vòng gọi và kích thước context mỗi vòng
Đây là bài toán tối ưu thực sự: gọi tool với granularity (độ chi tiết) quá nhỏ (ví dụ đọc từng dòng file một) sẽ khiến số vòng gọi tăng vọt, cộng dồn latency network. Ngược lại, tool trả về quá nhiều dữ liệu một lần (ví dụ trả nguyên file 10,000 dòng khi chỉ cần 20 dòng liên quan) sẽ làm phình context, tốn token, và có nguy cơ "lost in the middle" như đã nói ở phần trên.
| Chiến lược | Số vòng gọi tool | Token mỗi vòng | Rủi ro |
|---|---|---|---|
| Granularity quá nhỏ (đọc từng dòng) | Rất nhiều | Rất thấp | Latency cộng dồn cao, chậm tổng thể |
| Granularity quá lớn (trả cả file/bảng) | Ít | Rất cao | Tốn token, giảm chất lượng suy luận |
| Granularity vừa phải (có filter/pagination) | Vừa phải | Vừa phải | Cân bằng tốt nhất trong đa số trường hợp |
Trong thực tế triển khai, các MCP server chất lượng tốt thường thiết kế tool có tham số filter/limit/pagination ngay từ đầu — ví dụ tool search_logs nhận tham số keyword, since, limit thay vì chỉ có get_all_logs. Điều này cho phép model tự điều chỉnh độ chi tiết cần thiết theo từng tình huống, thay vì luôn phải chọn giữa "tất cả" hoặc "không gì cả".
Cache và song song hóa (parallelization)
Một số MCP client hiện đại hỗ trợ gọi nhiều tool song song khi model xác định các tool call độc lập với nhau (không phụ thuộc kết quả của nhau), giúp giảm đáng kể tổng latency so với gọi tuần tự. Ngoài ra, phía server có thể tự implement cache cho các truy vấn lặp lại (ví dụ cache kết quả describe_table trong vài phút) để giảm tải cho hệ thống backend và giảm latency cho các lần gọi sau.
Mẹo: Khi đo hiệu năng một agent dùng MCP, đừng chỉ nhìn vào thời gian phản hồi tổng thể — hãy log riêng thời gian của từng vòng gọi tool (
tools/callrequest → response) để xác định chính xác tool nào đang là bottleneck. Kinh nghiệm thực tế cho thấy phần lớn latency thường tập trung ở 1-2 tool "nặng" (ví dụ query một bảng không có index phù hợp) chứ không dàn đều across tất cả các tool.
Tóm lại, MCP không "làm context window lớn hơn" theo nghĩa kỹ thuật — nó thay đổi cách agent tương tác với dữ liệu, từ "nhồi trước tất cả" sang "lấy đúng thứ cần khi cần". Đánh đổi ở đây là latency network và độ phức tạp thiết kế tool, nhưng lợi ích về tính chính xác, tính thời gian thực, và khả năng mở rộng gần như không giới hạn về quy mô dữ liệu là rất đáng để đầu tư. Ở bài tiếp theo, chúng ta sẽ đi sâu vào kiến trúc kỹ thuật cụ thể của MCP — vai trò của host, client, và server — để hiểu rõ cơ chế bên dưới mọi ví dụ đã nêu ở trên.