Lộ trình học›MCP›Introduction to MCP Mở bản đồ

7.5 · Test server với MCP Inspector

Bài viếtCơ bản20 phút đọc

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):

Sau bài này, bạn sẽ
  1. Khởi chạy MCP Inspector bằng lệnh mcp dev và connect tới server của bạn
  2. Điều hướng UI Inspector — Tools tab, Resources tab, Prompts tab
  3. Test một tool: nhập input, chạy, verify output
  4. Chạy nhiều tool liên tiếp và verify state persistence giữa các lần gọi
  5. 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 uv project)
  • Có file mcp_server.py từ 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 InitializeRequest tớ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ứ:

  1. isError: false — tool chạy thành công
  2. content có data đúng
  3. 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à:

  • ValueError từ 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: true vớ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.md
  • old_str: implementation
  • new_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ụ:

  1. list_documents() → thấy doc
  2. read_doc_contents(doc_id) → đọc nội dung
  3. edit_document(doc_id, old, new) → sửa
  4. read_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ƯuNhượcKhi dùng
MCP InspectorBrowser UI, immediate feedback, xem schema/output JSONManual, không automatedDev iteration, debug
Unit test (pytest)Automated, CI-friendly, test logic PythonBypass protocol, không test serializationBusiness logic cốt lõi
Integration test (custom client)Test full protocol pathSetup phức tạp, slowRelease 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:

  1. Viết tool đầu tiên, chạy mcp dev
  2. Paste real-world API response vào Inspector để test parsing
  3. Iterate description cho đến khi Claude gọi tool đúng (test qua Claude Desktop song song)
  4. 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:

  1. Dev tool run_sql(query)
  2. Test query đơn giản trong Inspector: SELECT 1
  3. Test query thực tế phức tạp với JOIN, aggregation
  4. Test sai syntax (cách handle lỗi SQL?)
  5. 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:

  1. Dev tool gen_image(prompt, style)
  2. Inspector test prompt ngắn, prompt dài, prompt có đặc biệt
  3. Verify URL return valid, ảnh load được
  4. Thử style values 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:

  1. Test tool verify_token(token) với token hợp lệ
  2. Test với token hết hạn
  3. Test với token malformed
  4. Test với token signature sai
  5. 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:

  1. Connect MCP server tới Jira dev instance
  2. Test tool search_issues(jql) với JQL thật
  3. Verify rate limit xử lý đúng (expect isError: true với message rõ)
  4. 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:

  1. Run read_doc_contents với doc_id = "plan.md". Note content.
  2. Run edit_document với: — doc_id = "plan.md" — old_str = "outline" (hoặc từ nào có trong content) — new_str = "sketch"
  3. Run read_doc_contents lạ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

Những điều cốt lõi
  • 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

Bạn đã hoàn thành bài này chưa?Tiến độ lưu trên trình duyệt của bạn.

Khóa học cùng lộ trình