Hãy tưởng tượng bạn vừa viết tool edit_document từ Bài 7.4. Làm sao test? Cách truyền thống (anti-pattern):
- Khởi chạy MCP Inspector bằng lệnh mcp dev và connect tới server của bạn
- Điều hướng UI Inspector — Tools tab, Resources tab, Prompts tab
- Test một tool: nhập input, chạy, verify output
- Chạy nhiều tool liên tiếp và verify state persistence giữa các lần gọi
- Dùng Inspector như một công cụ debug chính trong development workflow
Mở đầu: Cái bẫy "test bằng print statement"
if __name__ == "__main__":
# Test hack
from mcp_server import edit_document
edit_document("report.pdf", "old text", "new text")
print(docs["report.pdf"])
mcp.run()
Vấn đề:
- Gọi function trực tiếp → bỏ qua toàn bộ protocol layer
- Không biết schema SDK gen có đúng không
- Không test được validation pydantic
- Không thấy được format
CallToolResult - Không thử được edge case (doc_id sai, input empty, v.v.)
Cách tốt: MCP Inspector.
Inspector là browser-based testing tool tích hợp trong MCP Python SDK. Nó là một MCP Client đặc biệt — UI web cho phép bạn:
- Connect tới server như một client thật
- Liệt kê tools/resources/prompts server expose
- Xem JSON schema tự động gen
- Chạy tool với input tùy ý
- Xem output JSON raw, bao gồm cả error format
Nghĩ về Inspector như Postman cho MCP. Trước khi code client thật, bạn dùng Inspector verify server hoạt động đúng.
David Soria Parra (đồng tác giả MCP) thường nói Inspector là lý do tại sao build MCP server trở nên nhanh như vậy: bạn không phải rời terminal để tạo test harness riêng.
Starting Inspector
Chuẩn bị
- Đã hoàn thành Bài 7.3 (setup
uvproject) - Có file
mcp_server.pytừ Bài 7.4 với ít nhất 1 tool
Lệnh khởi động
uv run mcp dev mcp_server.py
(Hoặc chỉ mcp dev mcp_server.py nếu bạn đã activate venv.)
Output tương tự:
Starting MCP Inspector on http://127.0.0.1:6274
Connected to server: DocumentMCP
Inspector proxy running on port 6277
Mở browser tới http://127.0.0.1:6274 và bạn thấy UI Inspector.
Mẹo: Nếu cổng 6274 đã dùng, Inspector tự chuyển sang cổng khác. Check terminal output để biết cổng chính xác.
UI overview
┌─────────────────────────────────────────────────────────┐
│ MCP Inspector [Connect] [⚙] │
├─────────────────────────────────────────────────────────┤
│ │
│ [Resources] [Tools] [Prompts] [Resource Templates] │
│ │
│ ┌─────────────────┬───────────────────────────────┐ │
│ │ │ │ │
│ │ List of tools │ Tool detail + input form │ │
│ │ ───────────── │ │ │
│ │ ► read_doc... │ Name: read_doc_contents │ │
│ │ edit_doc... │ Description: Read the... │ │
│ │ list_docs │ │ │
│ │ │ Input: │ │
│ │ │ doc_id: [ ] │ │
│ │ │ │ │
│ │ │ [Run Tool] │ │
│ │ │ │ │
│ └─────────────────┴───────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Output │ │
│ │ ────────────────────────────────────────────── │ │
│ │ { "isError": false, │ │
│ │ "content": [ │ │
│ │ { "type": "text", │ │
│ │ "text": "This deposition covers..." } │ │
│ │ ] } │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
Lưu ý: Inspector UI đang phát triển liên tục. Version bạn dùng có thể trông khác chút ít, nhưng 3 concept cốt lõi (Connect, tab navigation, run tool) vẫn nhất quán.
Workflow cơ bản — 3 bước test một tool
Bước 1: Click "Connect"
Ngay sau khi mở UI, trạng thái là "Disconnected". Click nút Connect ở góc phải trên để khởi tạo session MCP.
Inspector sẽ:
- Gửi
InitializeRequesttới server - Nhận lại capabilities (server hỗ trợ tools/resources/prompts nào)
- Đổi trạng thái thành "Connected"
- Populate các tab với items có sẵn
Nếu fail:
- Check terminal xem server có start được không
- Check port conflict
- Restart
mcp dev
Bước 2: Vào tab Tools, list & select
Click tab Tools → click List Tools. Bạn thấy danh sách tool server expose, ví dụ:
► read_doc_contents
edit_document
list_documents
Click read_doc_contents. Panel phải hiện chi tiết:
Name: read_doc_contents
Description: Read the full text contents of a document...
Input Schema:
doc_id (string) required
Description: Exact document ID, e.g. 'deposition.md'
Đây là schema SDK tự gen từ type hints + Field trong code của bạn. Verify:
- Tên tool đúng?
- Description hiện đầy đủ, không bị truncate?
- Required fields đúng?
- Type correct?
Nếu sai → quay lại code sửa decorator/type hints.
Bước 3: Run tool với input
Trong form input, nhập doc_id = "deposition.md". Click Run Tool.
Output xuất hiện:
{
"isError": false,
"content": [
{
"type": "text",
"text": "This deposition covers the testimony of Angela Smith, P.E."
}
]
}
Verify 3 thứ:
isError: false— tool chạy thành côngcontentcó data đúng- Type là
"text"(với tool text output)
Nếu thấy isError: true → đọc content[0].text để biết lỗi gì. Thường là:
ValueErrortừ code của bạn (doc_id không tồn tại)- Type mismatch (SDK không parse được input)
- Exception không handle
Test edge cases
Đây là nơi Inspector shine — bạn không phải viết test harness để thử edge case.
Edge case 1: Input invalid
Nhập doc_id = "không_tồn_tại.md".
Output:
{
"isError": true,
"content": [
{ "type": "text",
"text": "Error: Doc with id 'không_tồn_tại.md' not found. Call list_docs() to see available IDs." }
]
}
Verify:
- Error được return đúng (không crash server)
- Message hữu ích cho model/user
- Gợi ý cách fix (
Call list_docs())
Edge case 2: Input trống
Để trống doc_id, click Run.
Tùy SDK, bạn có thể thấy:
- Validation error từ Pydantic: "Field required"
- Hoặc
isError: truevới message lỗi
Đây là lý do dùng Field(description=...) — Pydantic validate trước khi vào function.
Edge case 3: Unicode / ký tự đặc biệt
Nhập doc_id = "deposition.md 🎉" (có emoji).
Output sẽ báo không tìm thấy — expected. Inspector cho bạn thử nhanh để verify encoding không gây bug nào.
Test tool interactions (chain)
Mạnh hơn test đơn lẻ: chain nhiều tool để verify state management.
Scenario: Edit rồi Read
Bước 1 — Click edit_document, nhập:
doc_id:plan.mdold_str:implementationnew_str:execution
Click Run. Kết quả empty content (tool không return gì) nhưng isError: false → thành công.
Bước 2 — Quay lại read_doc_contents, nhập doc_id = "plan.md".
Click Run. Output:
{
"isError": false,
"content": [{ "type": "text",
"text": "The plan outlines the steps for the project's execution." }]
}
Notice: "implementation" đã thành "execution". State persists giữa các tool call vì cùng 1 session.
Tại sao điều này quan trọng
Trong app thật, Claude sẽ chain nhiều tool call. Ví dụ:
list_documents()→ thấy docread_doc_contents(doc_id)→ đọc nội dungedit_document(doc_id, old, new)→ sửaread_doc_contents(doc_id)→ verify đã sửa
Nếu state không persist, Claude sẽ confused. Inspector test pattern này trước khi tích hợp vào CLI chat.
Bảng so sánh: Ba cách test MCP server
| Phương pháp | Ưu | Nhược | Khi dùng |
|---|---|---|---|
| MCP Inspector | Browser UI, immediate feedback, xem schema/output JSON | Manual, không automated | Dev iteration, debug |
| Unit test (pytest) | Automated, CI-friendly, test logic Python | Bypass protocol, không test serialization | Business logic cốt lõi |
| Integration test (custom client) | Test full protocol path | Setup phức tạp, slow | Release qualification |
Thực tế: dùng cả 3. Inspector cho 90% dev time, unit test cho core logic, integration test trước release lớn.
Ví dụ thực chiến: Inspector-driven development
Tình huống
Bạn vừa viết tool summarize_documents(doc_ids: list[str]) — tóm tắt nhiều docs đồng thời.
Bước 1: Code + Run
Code tool, save. Trong terminal khác đã chạy mcp dev.
Mẹo: mcp dev có hot-reload. Save file → Inspector refresh automatic. Không cần restart.
Bước 2: Happy path
Trong Inspector, run với:
doc_ids = ["deposition.md", "plan.md"]
Output OK? Content format đúng?
Bước 3: Edge case 1 — empty list
doc_ids = []
Bạn muốn behavior gì? Error hay trả summary rỗng? Thử cả hai cách, pick cái có UX tốt hơn.
Bước 4: Edge case 2 — ID không tồn tại
doc_ids = ["real.md", "fake.md"]
Tool xử lý thế nào? Skip fake.md và summary real.md? Hay error cả batch?
Decide consciously. Update tool description reflect behavior đã chọn.
Bước 5: Stress test
doc_ids = ["a.md", "b.md", ..., "z.md"](26 docs)
Quá chậm? Crash? Memory spike? Fix nếu cần, hoặc document limit (max 10 docs per call).
Kết quả
Trong ~10 phút, bạn đã test ~5 edge case. Không viết 1 dòng test code. Đây là tốc độ Inspector cho phép.
Ví dụ theo ngành — Dev workflow với Inspector
Internal tooling team
Scenario: Build MCP server wrap internal REST API.
Workflow:
- Viết tool đầu tiên, chạy
mcp dev - Paste real-world API response vào Inspector để test parsing
- Iterate description cho đến khi Claude gọi tool đúng (test qua Claude Desktop song song)
- Khi Inspector test pass → commit
Thế mạnh: Feedback loop 30 giây thay vì deploy → test full stack.
Data team
Scenario: SQL tool cho analyst.
Workflow:
- Dev tool
run_sql(query) - Test query đơn giản trong Inspector:
SELECT 1 - Test query thực tế phức tạp với JOIN, aggregation
- Test sai syntax (cách handle lỗi SQL?)
- Test query chậm (timeout behavior?)
Thế mạnh: Verify safety (write-block, timeout) trước khi give analyst access.
Creative tools dev
Scenario: Image generation MCP server.
Workflow:
- Dev tool
gen_image(prompt, style) - Inspector test prompt ngắn, prompt dài, prompt có đặc biệt
- Verify URL return valid, ảnh load được
- Thử
stylevalues khác nhau: "photorealistic", "oil painting", "3d render"
Thế mạnh: Qualitative test loại này khó automate — Inspector cho human verify nhanh.
Security team
Scenario: Auth MCP server.
Workflow:
- Test tool
verify_token(token)với token hợp lệ - Test với token hết hạn
- Test với token malformed
- Test với token signature sai
- Verify không leak thông tin nhạy cảm trong error message
Thế mạnh: Check security boundaries một cách thủ công trước khi audit formal.
Enterprise integration
Scenario: Wrap Jira/Confluence internal.
Workflow:
- Connect MCP server tới Jira dev instance
- Test tool
search_issues(jql)với JQL thật - Verify rate limit xử lý đúng (expect
isError: truevới message rõ) - Test pagination (large result set)
Thế mạnh: Test tích hợp thật-thật trong vài phút.
Anti-patterns — Những sai lầm cần tránh
Skip Inspector, test thẳng trong Claude Desktop
- Sai lầm
- Paste MCP server vào Claude Desktop config, restart Claude, prompt thử.
- Tại sao là sai
- Feedback loop dài (restart Claude Desktop), khó isolate lỗi (Claude có thể sửa lỗi tool qua prompt, che mất bug thật).
- Cách đúng
- Inspector trước cho qualification cơ bản. Claude Desktop sau cho end-to-end UX test.
Chỉ test happy path
- Sai lầm
- Run tool 1 lần với input đẹp, thấy output OK → "done".
- Tại sao là sai
- Claude sẽ gọi tool với đủ kiểu input trong production. Bug edge case = bug production.
- Cách đúng
- Ít nhất 3 test case: happy, edge (empty/large/special), error (invalid input).
Ignore isError: false nhưng content trống
Sai lầm:
@mcp.tool(...)
def do_thing():
if some_condition:
return # empty return → content rỗng, isError=false
Inspector show empty output nhưng isError: false. Bạn thấy "no error" và pass.
- Tại sao là sai
- Claude nhận empty response, không biết nên làm gì tiếp.
- Cách đúng
- Luôn return gì đó meaningful hoặc raise exception rõ ràng.
Không test với data realistic
- Sai lầm
- Test với
doc_id = "a.md", content 5 ký tự. Production data có docs 100KB. - Tại sao là sai
- Performance issue, memory issue, truncation issue không lộ.
- Cách đúng
- Tạo fixture data realistic size (500-5000 từ mỗi doc).
Không verify schema gen
- Sai lầm
- Bỏ qua việc xem JSON schema trong Inspector. Chỉ click Run thử input.
- Tại sao là sai
- Schema sai → Claude không biết truyền gì → tool không được gọi đúng cách.
- Cách đúng
- Mỗi tool mới, verify schema trong Inspector có đúng required fields, types, descriptions.
Dùng Inspector prod
- Sai lầm
- Deploy MCP Inspector lên production server public.
- Tại sao là sai
- Inspector là dev tool, không có auth mạnh. Expose = cho phép bất kỳ ai chạy tool.
- Cách đúng
- Inspector chỉ local dev. Production dùng real MCP client có auth.
Mẹo nâng cao
Mẹo 1: Inspector với log debug
Khi tool fail mysteriously:
mcp = FastMCP("DocumentMCP", log_level="DEBUG")
Output terminal sẽ in mọi JSON-RPC message. Đối chiếu với Inspector để thấy exact request/response.
Mẹo 2: mcp dev --port
Default port 6274. Đổi nếu conflict:
uv run mcp dev mcp_server.py --port 7000
Mẹo 3: Two servers side-by-side
Test 2 version server cùng lúc:
Terminal 1:
uv run mcp dev old_server.py --port 6274
Terminal 2:
uv run mcp dev new_server.py --port 6275
Mở 2 tab browser để so sánh output same input.
Mẹo 4: Inspector output → test fixture
Copy JSON output từ Inspector → save vào file test:
{
"isError": false,
"content": [...]
}
Dùng fixture này trong unit test để verify wire format không thay đổi.
Áp dụng ngay
Bài tập 1: Chạy Inspector (~10 phút)
- Bước 1
- Mở terminal trong project MCP.
- Bước 2
- Chạy:
uv run mcp dev mcp_server.py
- Bước 3
- Mở browser tới URL in ra trong terminal.
- Bước 4
- Click Connect. Verify status đổi thành "Connected".
- Bước 5
- Click tab Tools → List Tools. Ghi lại:
- Số lượng tool hiện ra: ___________
- Tool name: ___________
- Schema có description đầy đủ không? ___________
Bài tập 2: Run 3 test case (~10 phút)
Với tool read_doc_contents:
Test 1: Happy path
- Input:
doc_id = "deposition.md" - Output:
_______________ isError:_______________
Test 2: Error path
- Input:
doc_id = "nonexistent.md" - Output:
_______________ isError:_______________- Error message có informative không?
_______________
Test 3: Special char
- Input:
doc_id = "deposition.md "(trailing space) - Output:
_______________ - Tool handle thế nào?
_______________
Bài tập 3 (thử thách): Chain tools (~10 phút)
Chạy sequence:
- Run
read_doc_contentsvớidoc_id = "plan.md". Note content. - Run
edit_documentvới: —doc_id = "plan.md"—old_str = "outline"(hoặc từ nào có trong content) —new_str = "sketch" - Run
read_doc_contentslại với"plan.md". Verify đã đổi.
Ghi lại:
- State có persist giữa 3 calls không? ___________
- Edit tool return gì? ___________
- Nếu bạn đóng Inspector và mở lại, state còn không? ___________ (hint: no, vì server restart)
Tóm tắt bài học
- Inspector = Postman cho MCP — Browser-based testing tool built-in với SDK, cho phép test tool không cần viết client thật.
- 3 bước cơ bản — Connect → List & Select tool → Run với input → Check output JSON.
- Test edge case là bắt buộc — Happy path chỉ cover 30% bug. Invalid input, empty, special chars, large data mới lộ vấn đề.
- Verify schema gen — Đọc JSON schema Inspector show để catch bug decorator/type hint ngay, trước khi lỗi lan sang client.
- Chain để test state — Run nhiều tool liên tiếp để verify behavior như Claude sẽ làm trong real session.
Tài liệu tham khảo
- MCP Inspector docs
- MCP Python SDK CLI commands
- "Debugging MCP servers" — community tips on GitHub discussions