OpenCode là một trong những AI coding agent chạy terminal đang được nhiều team engineering ở Việt Nam thử nghiệm thay cho các công cụ closed-source, một phần vì nó mở, nhẹ, và hỗ trợ MCP (Model Context Protocol — giao thức chuẩn hóa cách AI agent kết nối với các nguồn dữ liệu/tool bên ngoài) khá đầy đủ ngay từ core. Nếu bạn đã quen cấu hình MCP trên Claude Code hay Cursor, phần logic sẽ không lạ, nhưng OpenCode có cách tổ chức file cấu hình và một vài hành vi runtime riêng mà nếu không nắm rõ sẽ mất khá nhiều thời gian debug. Bài này đi từ khái niệm, qua cấu hình config.toml cụ thể, tới một workflow thực tế và danh sách lỗi thường gặp — đủ để bạn đưa MCP vào dùng thật trong ngày làm việc, không chỉ demo.
OpenCode Là Gì và Hỗ Trợ MCP Ra Sao?
OpenCode là một AI coding agent dạng CLI (command-line interface), chạy trực tiếp trong terminal, đóng vai trò trung gian giữa bạn, một LLM (large language model — có thể là Claude, GPT, hoặc các model khác tùy provider bạn cấu hình) và codebase của bạn. Khác với các plugin IDE thuần túy chỉ gợi ý code, OpenCode được thiết kế như một agent có thể tự đọc file, chạy shell command, sửa code nhiều file liên tiếp, và — quan trọng với bài này — tự gọi tool từ các MCP server bên ngoài khi cần.
Về mặt kiến trúc, OpenCode đóng vai trò MCP client (bên tiêu thụ tool), còn MCP server là tiến trình độc lập expose ra một tập tool cụ thể (đọc file hệ thống, query database, gọi API bên thứ ba, điều khiển browser...). Khi bạn khai báo một MCP server trong cấu hình, OpenCode sẽ:
- Khởi động (hoặc kết nối tới) server đó khi phiên làm việc bắt đầu.
- Lấy danh sách tool mà server đó công bố (tool discovery), kèm schema tham số của từng tool.
- Đưa danh sách tool này vào context (cửa sổ ngữ cảnh — context window, phần thông tin LLM "nhìn thấy" ở mỗi lượt suy luận) để model biết mình có thể gọi tool nào, khi nào nên gọi.
- Khi model quyết định cần gọi tool (tool calling — cơ chế LLM chủ động yêu cầu thực thi một hàm bên ngoài thay vì tự trả lời bằng text), OpenCode chuyển tiếp lời gọi đó tới đúng MCP server, nhận kết quả, rồi đưa ngược lại vào context cho model tiếp tục suy luận.
OpenCode hỗ trợ hai kiểu MCP server: local (stdio) — server chạy như một tiến trình con trên máy bạn, giao tiếp qua standard input/output — và remote (SSE/HTTP) — server chạy ở nơi khác (có thể là service nội bộ công ty hoặc SaaS bên thứ ba), giao tiếp qua HTTP với cơ chế server-sent events. Local phù hợp cho tool cần quyền truy cập trực tiếp filesystem hoặc process của máy (ví dụ đọc file, chạy Docker), còn remote phù hợp cho các dịch vụ đã có sẵn API, không cần cài gì thêm trên máy dev.
Điểm cần lưu ý: OpenCode không tự "hiểu" tool làm gì chỉ qua tên — nó dựa hoàn toàn vào description và schema mà MCP server công bố. Nếu server viết description mập mờ, model sẽ gọi tool sai ngữ cảnh hoặc bỏ qua tool dù nó thực sự cần dùng.
Mẹo: Trước khi thêm một MCP server lạ vào OpenCode, hãy tự chạy thử server đó độc lập (qua
npxhoặc lệnh command tương ứng) và xem log để chắc nó thực sự khởi động được — tránh trường hợp bạn debug sai hướng, nghĩ lỗi ở OpenCode trong khi server bản thân đã fail từ đầu.
Thêm MCP Server Vào File config.toml Của OpenCode
OpenCode đọc cấu hình MCP từ file config.toml, có thể đặt ở project (ưu tiên cao hơn, chỉ áp dụng cho repo hiện tại) hoặc ở global (~/.config/opencode/config.toml, áp dụng cho mọi project trên máy). Cấu trúc chung dùng section [mcp.servers.<tên-server>], trong đó <tên-server> là identifier bạn tự đặt, sẽ hiển thị trong log và trong danh sách tool.
Khai báo MCP server local (stdio)
Đây là kiểu phổ biến nhất — server chạy như subprocess, nhận lệnh qua command + args:
[mcp.servers.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/Users/alex/projects/my-app"]
[mcp.servers.postgres]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-postgres"]
env = { DATABASE_URL = "postgresql://localhost:5432/my_app_dev" }
[mcp.servers.git-tools]
command = "uvx"
args = ["mcp-server-git", "--repository", "."]
Vài điểm kỹ thuật cần chú ý:
envcho phép truyền biến môi trường riêng cho tiến trình server, tách biệt với env của OpenCode chính — hữu ích khi bạn không muốn credential của server bị lẫn vào context chung.- Với server cần API key nhạy cảm, không hardcode trực tiếp giá trị vào
config.tomlnếu file này được commit vào git. Dùng biến môi trường tham chiếu qua shell trước khi OpenCode khởi động, hoặc dùng cú pháp interpolation nếu OpenCode version bạn dùng hỗ trợ (env = { API_KEY = "${MY_SECRET_API_KEY}" }), và để giá trị thật nằm trong.envkhông commit. - Đường dẫn trong
args(như filesystem server) nên dùng đường dẫn tuyệt đối để tránh lỗi khi OpenCode chạy từ working directory khác dự kiến.
Khai báo MCP server remote (SSE/HTTP)
Với server chạy như dịch vụ HTTP (ví dụ MCP server nội bộ công ty deploy trên server riêng, hoặc SaaS bên thứ ba cung cấp MCP endpoint):
[mcp.servers.internal-search]
type = "sse"
url = "https://mcp.internal.company.com/search/sse"
headers = { Authorization = "Bearer ${INTERNAL_MCP_TOKEN}" }
[mcp.servers.linear]
type = "sse"
url = "https://mcp.linear.app/sse"
headers = { Authorization = "Bearer ${LINEAR_API_KEY}" }
Khác với local server, remote server không cần command/args vì OpenCode chỉ đóng vai trò client HTTP kết nối tới endpoint đã có sẵn. Authorization thường truyền qua headers, và OpenCode sẽ tự duy trì kết nối SSE trong suốt phiên làm việc.
Bật/tắt server theo project
Nếu bạn có nhiều server nhưng chỉ muốn một vài server hoạt động cho project cụ thể, có thể dùng cờ enabled để tắt tạm mà không cần xóa cấu hình:
[mcp.servers.postgres]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-postgres"]
enabled = false
Mẹo: Giữ file
config.tomlở project-level trong git (trừ phần secret), nhưng để giá trị thật của mọi biến nhạy cảm trong.envhoặc secret manager của team — vừa đảm bảo cả team dùng chung cấu hình MCP nhất quán, vừa không rò rỉ credential lên remote repository.
Chạy OpenCode Với MCP Trong Quy Trình Phát Triển Thực Tế
Cấu hình xong không có nghĩa là dùng đúng cách. Giá trị thật của MCP trong OpenCode nằm ở việc gộp nhiều tool khác nhau vào một luồng làm việc liên tục — thay vì bạn tự chuyển qua chuyển lại giữa terminal, database client, và trình duyệt.
Ví dụ một ngày làm việc thực tế: bạn đang fix một bug liên quan tới dữ liệu sai lệch giữa API response và bảng trong Postgres, đồng thời cần tạo lại ticket trên Linear để theo dõi. Với ba MCP server đã khai báo ở trên (filesystem, postgres, linear), một session OpenCode có thể xử lý toàn bộ chuỗi việc này trong cùng một cuộc trò chuyện.
Trước tiên, khởi động OpenCode trong thư mục project:
cd my-app
opencode
Kiểm tra nhanh các MCP server đã kết nối thành công chưa bằng lệnh slash trong session:
/mcp
Kết quả mong đợi liệt kê từng server, trạng thái kết nối, và số tool khả dụng, dạng tương tự:
filesystem ✓ connected (4 tools)
postgres ✓ connected (3 tools)
linear ✓ connected (6 tools)
Ví dụ prompt xử lý bug xuyên nhiều hệ thống
Tôi nghi ngờ có bug ở endpoint GET /api/orders/:id — response trả về
field "total_amount" nhưng dữ liệu hiển thị trên frontend luôn lệch
so với giá trị thật trong DB.
Hãy giúp tôi:
1. Đọc file src/routes/orders.ts để xem logic tính total_amount hiện tại
2. Query trực tiếp bảng "orders" và "order_items" trong Postgres với
order id = 4821, so sánh giá trị total_amount trong DB với logic
tính toán trong code
3. Nếu phát hiện sai lệch, chỉ rõ dòng code gây lỗi (ví dụ thiếu
discount, tính sai thuế, round sai)
4. Đề xuất fix cụ thể, kèm đoạn code sửa
5. Sau khi tôi xác nhận fix đúng, tạo một issue mới trên Linear team
"Backend" với title "Fix incorrect total_amount calculation in
GET /api/orders/:id", mô tả gồm root cause và cách fix
Với prompt này, model sẽ tự điều phối việc gọi tool filesystem để đọc code, tool postgres để query dữ liệu thật, đối chiếu hai nguồn, rồi mới tới bước gọi tool linear để tạo ticket — đúng thứ tự nghiệp vụ, không cần bạn tự chuyển ngữ cảnh giữa các công cụ.
Theo dõi tool call trong lúc chạy
OpenCode hiển thị trực tiếp trong terminal mỗi lần model gọi tool — tên tool, tham số truyền vào, và kết quả trả về (thường được rút gọn nếu quá dài). Đây là chỗ bạn nên quan sát kỹ trong những lượt chạy đầu, để phát hiện sớm nếu model gọi query SQL không như mong đợi (ví dụ quét toàn bảng thay vì filter theo id) trước khi nó lan sang bước tiếp theo.
Mẹo: Với các tool có khả năng gây side-effect thật (tạo ticket, ghi dữ liệu, gọi API production), tách prompt thành hai lượt rõ ràng — lượt đầu chỉ yêu cầu phân tích và đề xuất, lượt hai mới xác nhận cho thực thi — giống ví dụ prompt ở trên có bước "sau khi tôi xác nhận".
Xử Lý Các Lỗi Thường Gặp Khi Cấu Hình MCP Trong OpenCode
Dưới đây là những lỗi hay gặp nhất khi setup MCP trong OpenCode, cùng cách chẩn đoán và fix — dựa trên các pattern lỗi lặp lại nhiều nhất khi làm việc thực tế với nhiều MCP server khác nhau.
Server hiện trạng "failed to connect"
Chạy /mcp thấy server báo ✗ failed. Nguyên nhân thường gặp nhất là câu lệnh trong command/args không tự chạy được độc lập. Debug bằng cách chạy tay chính câu lệnh đó ngoài OpenCode:
npx -y @modelcontextprotocol/server-postgres
Nếu lệnh này tự nó đã lỗi (thiếu package, sai version Node.js, network timeout khi tải package lần đầu), OpenCode chắc chắn cũng fail — sửa ở gốc trước khi quay lại cấu hình.
Tool không hiển thị dù server báo connected
Trường hợp server connect thành công nhưng model "không biết" gọi tool nào liên quan. Thường do:
- Description của tool (do chính MCP server định nghĩa) quá mập mờ, không đủ để model liên hệ với yêu cầu của bạn — thử prompt rõ tên tool hơn để kiểm tra (ví dụ "hãy dùng tool query trong postgres MCP để chạy câu SQL sau...").
- Server giới hạn số tool tối đa expose ra (một số MCP server có cấu hình riêng để bật/tắt nhóm tool) — kiểm tra tài liệu của server đó.
Lỗi authorization với remote MCP server
Với server kiểu SSE/HTTP, lỗi phổ biến là token hết hạn hoặc biến môi trường không được resolve đúng trong headers. Kiểm tra bằng cách in thử giá trị biến môi trường ngay trước khi chạy OpenCode:
echo $LINEAR_API_KEY
Nếu giá trị rỗng, OpenCode sẽ gửi header Authorization: Bearer (rỗng phần token) và server từ chối kết nối — lỗi này rất dễ nhầm thành "server MCP bị lỗi" trong khi thực chất là biến môi trường chưa được load trước khi khởi động OpenCode (ví dụ quên source .env).
Server khởi động chậm khiến timeout
Một số MCP server (đặc biệt server chạy qua npx lần đầu, phải download package) khởi động chậm hơn timeout mặc định của OpenCode. Cách xử lý: chạy trước một lần thủ công để cache package về local, hoặc nếu server hỗ trợ, chuyển sang cài global thay vì gọi qua npx -y mỗi lần.
npm install -g @modelcontextprotocol/server-postgres
Sau đó sửa command trong config.toml để gọi trực tiếp binary đã cài global, tránh chi phí resolve package mỗi lần khởi động session.
Xung đột tên server giữa global và project config
Nếu cùng một tên server (ví dụ postgres) được khai báo khác nhau ở global config.toml và project config.toml, OpenCode sẽ ưu tiên cấu hình project — nhưng nếu bạn quên mất mình đã có cấu hình global, dễ nhầm lẫn vì sao server "chạy không đúng như mình nghĩ". Luôn kiểm tra cả hai file khi debug hành vi lạ.
Mẹo: Khi một MCP server báo lỗi mơ hồ, luôn tách vấn đề thành hai lớp riêng — lớp 1 là "server tự chạy được không" (test độc lập ngoài OpenCode), lớp 2 là "OpenCode có cấu hình đúng để gọi tới nó không" (kiểm tra
config.toml) — tránh lẫn hai lớp lỗi khi chẩn đoán sẽ tiết kiệm rất nhiều thời gian.
Mẹo Hay Khi Làm Việc Với MCP Trong OpenCode
Tổng hợp lại một số kinh nghiệm thực chiến, ngoài các Mẹo đã nêu ở từng phần trên:
Mẹo: Đặt tên server trong
config.tomltheo domain nghiệp vụ (postgres-orders,linear-backend-team) thay vì tên generic (db,tool1) — khi log tool call hiện trong terminal, bạn sẽ đọc hiểu ngay agent đang tương tác với hệ thống nào mà không cần nhớ thứ tự khai báo.Mẹo: Với project lớn có nhiều MCP server, tách riêng một file
config.local.toml(không commit) chỉ chứa server cá nhân bạn cần cho việc đang làm (ví dụ một MCP server thử nghiệm), đểconfig.tomlchính giữ được bộ server chuẩn chung của cả team.Mẹo: Định kỳ chạy lại
/mcpmỗi khi bắt đầu session mới, đặc biệt sau khi update version OpenCode hoặc update package của MCP server — một số bản cập nhật có thể đổi tên tool hoặc thay đổi schema tham số, khiến prompt cũ không còn hoạt động đúng như trước.Mẹo: Viết hẳn một đoạn hướng dẫn ngắn trong file cấu hình project (README hoặc file quy ước riêng của team) mô tả server nào dùng cho mục đích gì, tool tiêu biểu là gì — vì khi có thành viên mới join, họ sẽ hiểu ngay bộ MCP server hiện có phục vụ workflow nào mà không phải dò từng dòng
config.toml.Mẹo: Khi viết prompt giao việc xuyên nhiều MCP server (như ví dụ workflow bug fix ở trên), luôn liệt kê thứ tự bước rõ ràng bằng số — model tuân theo trình tự tool call chính xác hơn hẳn so với việc mô tả yêu cầu chung không có cấu trúc bước.