MCP vs API: có thực sự cần MCP không?
Cập nhật: 2026-07-20
Mục lục
- 1. API là gì, và thực tế khi tích hợp thủ công
- 2. Thêm LLM vào bài toán: model không tự gọi API
- 3. Bài toán nhân bản: 2 app × 10 service
- 4. MCP giải quyết thế nào: MCP Client, MCP Server và Discovery
- 5. Một vòng round-trip hoàn chỉnh với MCP
- 6. MCP có thay thế API không?
- 7. Câu hỏi lớn nhất: đã có API docs thì cần MCP làm gì?
- 8. Khác biệt thực sự giữa 2 approach
- 9. Hai cảnh báo: context cost và API keys
- 10. Khi nào dùng MCP, khi nào dùng API trực tiếp
1. API là gì, và thực tế khi tích hợp thủ công
Bạn đã bao giờ tự hỏi: khi một ứng dụng "gọi" tới Slack, Jira, hay Gmail, thực chất chuyện gì đang xảy ra phía sau? Câu trả lời nằm ở API — cách hai chương trình nói chuyện với nhau. Ví dụ cụ thể: chương trình A cần đọc message từ Slack (chương trình B). Slack expose một endpoint — chỉ là một URL, kiểu api.slack.com/messages. Chương trình A gửi request tới URL này, Slack trả về response chứa data. Cách này rất rõ ràng và dễ đoán — với phần mềm thông thường, đây là lựa chọn hoàn hảo.
Nhưng thực tế quan trọng là: chính developer phải xây dựng từng API integration này, và cũng chính developer viết luôn rule cho việc khi nào gọi API nào — deploy xong thì gọi Slack send-message endpoint, ai đó hỏi message hôm qua thì gọi history endpoint, việc này xảy ra thì gọi Slack, việc kia xảy ra thì gọi Jira.
Trong thực tế production, app không chỉ nói chuyện với Slack. Nó có thể nói chuyện với 10 service: Slack để cảnh báo, Gmail để gửi mail, Jira cho ticket, Notion cho tài liệu, database riêng để lưu user record, và vài service khác tương tự. Với mỗi service trong 10 service đó, developer phải viết cùng một loại logic: authentication, API call, xử lý lỗi, retry khi API call fail.
2. Thêm LLM vào bài toán: model không tự gọi API
Giờ nâng cấp chương trình A: thêm một LLM vào để ứng dụng có thể "suy nghĩ" và ra quyết định theo tình huống, thay vì developer phải quyết định trước mọi trường hợp.
Đây là điểm mấu chốt giúp mọi thứ còn lại trong bài dễ hiểu hơn: model không trực tiếp gọi API. Model chỉ nói cho ứng dụng biết nó muốn thực hiện hành động gì, còn ứng dụng — phần mềm bình thường nằm ngoài model — mới là bên thực sự thực hiện hành động đó.
Cụ thể diễn ra như sau: ứng dụng đưa cho model thông tin về những việc nó có thể làm, ví dụ gửi message Slack, tạo ticket Jira, truy vấn database. Model đọc tình huống và viết lại một message, kiểu: "Gọi Slack endpoint, kênh on-call, gửi text 'payment service đang down'." Sau đó, chính logic ứng dụng — code bình thường do developer viết — mới thực sự thực hiện API call đó. Model chỉ nói phải làm gì, ứng dụng mới là bên thực thi API call thật.
💡 Hình dung như thế này: giống hành khách gọi xe qua app — hành khách chỉ nói muốn đi đâu, còn tài xế mới là người thực sự cầm vô lăng và lái xe tới đó. Model đóng vai hành khách, ứng dụng đóng vai tài xế.
Về cơ bản, tình huống không thay đổi gì cả: developer vẫn phải viết tay cả 10 API integration. Thêm model vào không loại bỏ bất kỳ API call nào — model chỉ quyết định gọi API nào, còn developer vẫn phải xây dựng từng API call.
3. Bài toán nhân bản: 2 app × 10 service
Giờ hình dung tổ chức xây thêm một app thứ hai — app chat hỗ trợ khách hàng, cũng chạy bằng LLM. Model của app support này đọc chat của khách hàng và quyết định các việc như: "Cái này cần tạo ticket Jira", "cái kia cần trả lời qua email".
App support này cần truy cập lại đúng 10 service ở trên — từ đầu. Vậy là team lại viết Gmail integration lần nữa, Jira integration lần nữa, cả 10 cái, cho app thứ hai. App đầu tiên viết 10 API integration, app thứ hai lại viết thêm 10 API integration nữa. Hai app × 10 service = 20 đống integration code mà team phải viết và maintain. Sang năm tổ chức xây thêm app tiếp theo, con số này thành 30 API integration.
Câu hỏi dẫn tới MCP chính là: làm sao để không ai phải hardcode các API call này vào từng app nữa?
4. MCP giải quyết thế nào: MCP Client, MCP Server và Discovery
Cách hoạt động: mỗi app có một thành phần chuẩn gọi là MCP client. Mỗi service — Slack, Gmail, Jira, Notion, database — có một chương trình nhỏ đứng cạnh nó gọi là MCP server. MCP client và MCP server nói chung một ngôn ngữ, nên client nào cũng có thể nói chuyện với server nào.
Đếm lại: 2 app nghĩa là 2 MCP client, 10 service nghĩa là 10 MCP server. 2 + 10 = 12 thành phần cần xây, thay vì 20 integration riêng lẻ như trước. App thứ ba sang năm chỉ đơn giản là tái sử dụng lại 10 server sẵn có, chỉ cần thêm 1 client mới.
(Về thuật ngữ chính thức: ứng dụng được gọi là MCP Host, và Host tạo một MCP Client riêng cho mỗi server nó kết nối — nên số client thực tế theo spec sẽ nhiều hơn 1/app nếu app nói chuyện với nhiều server cùng lúc. Cách đếm "1 client/app" ở trên là góc nhìn đơn giản hóa để dễ hình dung mức giảm tải, không phải con số tuyệt đối theo spec — xem Nguồn tham khảo.)
Trong thực tế còn tốt hơn nữa, vì với các sản phẩm phổ biến, MCP server thường đã có sẵn — ví dụ Slack tự xây và host MCP server chính thức của họ. Nhưng với database nội bộ hay tool riêng của team, team vẫn phải tự xây server đó. Còn client thì hầu hết team lấy sẵn từ một AI framework, không cần viết từ đầu.
Một MCP server có thể cung cấp nhiều action. Ví dụ server Slack sẽ công bố rằng nó có thể gửi message, đọc lịch sử một kênh, và tìm kiếm message cũ.
Chi tiết quan trọng (đây là phần hay bị hiểu nhầm): MCP client bên trong app kết nối tới từng server trong 10 server, và hỏi xem server đó có những action nào — quá trình này gọi là discovery. App sau đó đưa danh sách action này cho model, và model chọn action phù hợp với task. Developer không còn phải hardcode từng quyết định — model chọn từ những action mà app cho phép nó dùng. Nói cách khác: đưa cho model một hộp công cụ đã dán nhãn, để model tự chọn.
💡 Hình dung như thế này: mỗi MCP server giống một nhà hàng có sẵn thực đơn riêng. MCP client bước vào từng nhà hàng, xin xem thực đơn (discovery), rồi mang cả chồng thực đơn đó ra cho khách (model) chọn món — khách không cần biết bếp nấu món đó ra sao, chỉ cần chọn đúng món trên thực đơn.
5. Một vòng round-trip hoàn chỉnh với MCP
Ví dụ cụ thể để không còn gì mơ hồ: khách hàng nhắn cho app support "Thanh toán của tôi bị fail 2 lần." App support lấy message này, cộng với danh sách action đã discover được từ tất cả MCP server trước đó, gửi hết cho model.
Model đọc toàn bộ và viết lại: "Chạy action Jira, tạo ticket. Title: payment failing. Priority: high." Lưu ý: model chỉ mới viết text — chưa có gì thực sự xảy ra cả.
App đưa request đó cho MCP client của nó. Client gửi request tới Jira MCP server — server Jira là thành phần duy nhất thực sự nói chuyện với Jira. Nó gọi API bình thường của Jira, đúng API vốn đã tồn tại từ trước, và ticket được tạo ra. Jira trả lời với số ticket. Câu trả lời này đi ngược lại từ MCP server → MCP client → app, và đến trước mặt model dưới dạng plain text. Model đọc và viết câu trả lời cuối: "Tôi đã tạo ticket #42 cho vấn đề thanh toán."
Ai làm gì trong toàn bộ chuỗi này: model chỉ quyết định và trả lời; client và server chỉ chuyển tiếp message; còn API gốc của Jira mới thực sự làm việc — y hệt như nó vẫn luôn làm.
6. MCP có thay thế API không?
Không. Nếu hệ thống đã có API sẵn, MCP server đứng ở phía trước API đó như một lớp phiên dịch, còn API vẫn nằm nguyên chỗ cũ. MCP không phải là thứ thay thế API — MCP là một lớp giao tiếp chung hướng tới AI (AI-facing layer), đứng phía trước API.
7. Câu hỏi lớn nhất: đã có API docs thì cần MCP làm gì?
Đây là thắc mắc phổ biến nhất: "Tại sao tôi cần MCP, trong khi API docs đã có sẵn? Tôi có thể đưa thẳng OpenAPI spec cho AI agent, để agent tự tìm ra cần gọi API nào." Câu hỏi này hợp lý — cách đó hoàn toàn khả thi và sẽ chạy được. Nhưng dùng MCP server vẫn có một số lợi thế.
Để thấy rõ lợi thế đó, hãy cho cả hai approach cùng làm một task: team có kênh Slack tên incident. Cần một AI agent lấy message của hôm qua trong kênh đó và viết một bản tóm tắt ngắn. Nếu là bạn, việc này chỉ mất khoảng 1 phút: mở Slack, tìm kênh, đọc message, tóm tắt.
Trước khi so sánh, nhắc lại bí mật ở phần trước: model không thể tự gọi API, nó chỉ viết ra thứ nó muốn làm. Phần mềm nằm ngoài model phải nhận request đó và thực sự thực hiện. Phần mềm thực sự gọi API này cần một cái tên — gọi nó là execution layer, vì nó thực thi bất cứ điều gì model yêu cầu. Cả hai approach dưới đây — dùng API docs và dùng MCP — thực chất là hai cách khác nhau để xây dựng execution layer này.
💡 Hình dung như thế này: giống việc sửa nhà. Approach 1 là tự đi mua vật liệu, tự thuê thợ, tự giám sát từng công đoạn — làm được, nhưng lần sau sửa nhà khác lại phải làm lại từ đầu. Approach 2 là thuê nhà thầu trọn gói đã có sẵn đội thợ và quy trình chuẩn — chỉ cần đưa yêu cầu, họ tự lo phần còn lại.
Approach 1 — Đi thẳng qua API
Đưa cho agent hai thứ: toàn bộ tài liệu API của Slack, và một sandbox — một "căn phòng khóa" nơi agent có thể chạy code Python, có sẵn credential Slack bên trong.
- Bước 1: Model đọc docs. Slack có hàng trăm API method, toàn bộ spec API được nhồi vào context của model để nó biết cần viết code gì để gọi API.
- Bước 2: Model viết code Python. Đây là chỗ bắt đầu phát sinh vấn đề nhỏ: API của Slack không hiểu tên kênh
incident— nó cần channel ID. Nên code phải tra cứu kênh trước để lấy ID, rồi mới gọi API lấy lịch sử message, rồi phải đổi từ "yesterday" sang đúng định dạng thời gian mà Slack yêu cầu. Message trả về lại toàn user ID thô, nên code có thể còn phải đổi ID đó thành tên đọc được. Một script Python, nhưng bên dưới là nhiều API call phải nối đúng thứ tự. - Bước 3: Sandbox chạy script đó. Message sạch được trả về cho model, và model viết bản tóm tắt.
Kết quả: chạy được, hoàn toàn. Với một ứng dụng đơn lẻ, cách này ổn. Nhưng để ý: agent viết code, team setup credential, team vận hành sandbox, và khi script hoặc sandbox hỏng, team phải sửa — không phải model. Đó là một Slack integration thật sự, và ai đó phải maintain nó. Ứng dụng có thể lưu lại code đó để tái dùng sau này. Nhưng ngay khi một AI app thứ hai cũng cần Slack, team phải quyết định: chia sẻ integration này bằng cách nào đó, hoặc xây lại từ đầu.
Approach 2 — Dùng MCP
Làm cùng task, nhưng lần này không đưa bất kỳ tài liệu nào cho agent. Kết nối ứng dụng với một Slack MCP server. MCP server đóng vai trò một execution layer làm sẵn, đứng trước Slack. Server đã hiểu sẵn API của Slack, và nó cung cấp cho model một menu ngắn các action viết riêng cho AI application: tìm kênh, đọc message từ một kênh, tìm message theo ngày, gửi message.
Model nhìn menu này và chọn action phù hợp — trong trường hợp này, model chọn "đọc message từ một kênh". MCP server lo phần còn lại: tra channel ID, đổi định dạng thời gian, phân trang (pagination), authentication. Server trả về message sạch, dễ đọc, và model viết bản tóm tắt. Model của chúng ta không hề chạm vào bất kỳ API method cấp thấp nào của Slack.
Điểm khác biệt quan trọng: toàn bộ kiến thức đặc thù của Slack giờ nằm gọn trong một thành phần có thể tái sử dụng — chính là MCP server.
Nói ngắn gọn: ở approach trực tiếp, model đọc tài liệu, và code tuỳ chỉnh của team — một phần do chính agent viết ra — chính là execution layer. Ở approach MCP, model đọc một menu action, và MCP server chính là execution layer.
8. Khác biệt thực sự giữa 2 approach
Có thể phản biện rằng approach trực tiếp cũng chia sẻ được: xây một internal Slack service, đặt nó trước tất cả ứng dụng, xong. Đó là một thiết kế hoàn toàn hợp lý. Nhưng để ý: lúc đó chính là đã tự phát minh ra một format riêng để mô tả action, gửi request, và trả kết quả. MCP chính là ý tưởng đó — chỉ khác là format của nó là công khai (public), và các AI application tương thích đã sẵn sàng "nói" format đó. Tại sao phải tự thiết kế lại thứ đã có sẵn? Giống như tự thiết kế một database riêng trong khi Postgres đã có sẵn.
Quay lại câu hỏi gốc: tại sao không đưa thẳng OpenAPI spec cho model? Hoàn toàn được. Và giờ đã rõ điều đó mang lại gì: nó giúp agent biết những API call nào khả dụng, nhưng không xây execution layer. Vẫn cần phần mềm giữ credential, thực hiện request, xử lý lỗi, và trả kết quả về cho model. Có thể tự xây phần đó — nhưng cái MCP mang lại chính là một execution layer chuẩn (standard).
Còn một khác biệt thứ hai: cần hỏi API docs gốc được viết cho ai. API method thô được viết cho developer — nó chứa rất nhiều chi tiết nhỏ mà developer phải tự nối lại (chain up) để ra kết quả. MCP server có thể gói toàn bộ những chi tiết đó thành một action với tên rõ ràng. Và khi Slack đổi một API method bên dưới, MCP server hosted sẵn chỉ cần sửa một chỗ duy nhất — không cần nhồi lại API method mới vào AI agent.
Thêm một điểm nữa: OpenAPI chỉ mô tả web API. File local, terminal, database — không có tài liệu OpenAPI nào cho những thứ này cả. Tất cả những thứ đó đều có thể có MCP server riêng.
9. Hai cảnh báo: context cost và API keys
MCP không giải quyết được mọi thứ. Hai lưu ý cần biết:
- Context cost: vấn đề này ảnh hưởng cả hai approach. Tài liệu API có thể rất lớn, load hết vào có thể lấp đầy context của model và tốn nhiều token. MCP cũng gặp vấn đề tương tự nếu app load hết mọi action từ mọi server đã kết nối. Các AI app mới hơn giờ có thể tìm kiếm đúng action cần dùng và chỉ load những action cần cho task hiện tại — tiết kiệm token, để dành chỗ cho phần hội thoại thật.
- API keys: API key giống như mật khẩu — model không bao giờ nên nhìn thấy nó. Execution layer nằm ngoài model mới là nơi lưu key và dùng nó để kết nối service. MCP có thể hỗ trợ login, phân quyền, và yêu cầu approval trước khi chạy một action rủi ro. Nhưng developer vẫn phải tự thiết lập đúng những cơ chế bảo vệ đó.
10. Khi nào dùng MCP, khi nào dùng API trực tiếp
- Nếu đang xây một ứng dụng chỉ gọi vài API operation đã biết rõ, một thử nghiệm nhanh, hay một task one-off — direct integration hoàn toàn hợp lý.
- Tương tự nếu chưa có MCP server hữu ích nào tồn tại, hoặc server có sẵn không cung cấp đúng action cần dùng. Nhiều team vẫn chạy direct integration an toàn, tái sử dụng được, mà không cần MCP — và điều đó hoàn toàn ổn.
- MCP bắt đầu đáng giá khi nhiều AI application cùng cần dùng chung hệ thống.
Cần nhớ: MCP không cho model thêm bất kỳ khả năng mới nào. Mọi thứ bên dưới vẫn là API và code bình thường như cũ. Thứ MCP mang lại là một standard — và standard chính là thứ giúp 10 ứng dụng chia sẻ chung một execution layer, thay vì mỗi ứng dụng phải tự xây một cái.
Câu chốt lại: AI model không bao giờ tự thực thi API call — execution layer xung quanh nó mới làm việc đó. Có thể tự xây execution layer đó cho một ứng dụng. Hoặc dùng MCP khi cần một execution layer chuẩn mà nhiều AI application có thể discover và tái sử dụng. Với một ứng dụng đơn lẻ, direct integration có thể đơn giản hơn. Nhưng khi cùng một khả năng cần phục vụ nhiều AI application và nhiều hệ thống — đó chính xác là lúc MCP phát huy tác dụng.
Nguồn tham khảo
Nguồn gốc: MCP vs API Explained: Do You Really Need MCP? — kênh KodeKloud
Ghi chú kỹ thuật (fact-check bổ sung):
- Ứng dụng gọi API MCP chính thức là "MCP Host", tạo 1 MCP Client riêng cho mỗi MCP Server kết nối — truy cập 2026-07-20, MCP Architecture overview
- Cơ chế "discovery" đúng thuật ngữ chính thức là "Tool Discovery" qua
tools/list— truy cập 2026-07-20, MCP Architecture overview - Slack MCP server chính thức, do Slack tự xây và host, GA từ 17/2/2026 — 17/2/2026, Slack Developer Docs changelog