Tóm tắt: Cài package mcp, khai báo FastMCP("tên"), gắn @mcp.tool() / @mcp.resource("uri") lên hàm Python có type hint + docstring, chạy mcp.run() (mặc định transport stdio). Test bằng MCP Inspector, rồi claude mcp add để Claude Code dùng. Khái niệm MCP xem MCP tổng quan.
Luồng hoạt động
flowchart LR A["server.py (FastMCP)"] --> B["mcp dev / Inspector"] B -->|OK| C["claude mcp add"] C --> D[Claude Code] D -->|"stdio JSON-RPC"| A A -->|"ping / show"| E[(Router)]
Cấu hình
Tạo project
uv init netops-mcp && cd netops-mcp
uv add "mcp[cli]"Server tối thiểu
import ipaddress
import subprocess
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("netops")
DEVICES = {
"pe1-hni": {"mgmt": "198.51.100.11", "role": "pe", "os": "iosxr"},
"pe2-hcm": {"mgmt": "198.51.100.12", "role": "pe", "os": "junos"},
}
@mcp.tool()
def ping(target: str, count: int = 3) -> str:
"""Ping một địa chỉ IPv4/IPv6 từ máy chạy server. Chỉ nhận IP, không nhận hostname."""
ip = ipaddress.ip_address(target) # ValueError nếu không phải IP -> trả lỗi cho model
count = max(1, min(count, 10)) # giới hạn để không treo
out = subprocess.run(
["ping", "-c", str(count), "-W", "1", str(ip)],
capture_output=True, text=True, timeout=30,
)
return out.stdout[-1500:] or out.stderr
@mcp.tool()
def list_devices(role: str | None = None) -> list[dict]:
"""Liệt kê thiết bị trong inventory, lọc theo role (pe, p, rr) nếu có."""
return [
{"name": n, **d} for n, d in DEVICES.items() if role is None or d["role"] == role
]
@mcp.resource("inventory://device/{name}")
def device(name: str) -> dict:
"""Thông tin một thiết bị theo tên."""
return DEVICES[name]
if __name__ == "__main__":
mcp.run() # stdio; HTTP: mcp.run(transport="streamable-http")Điểm cần nhớ:
- Tên hàm thành tên tool, docstring thành description, type hint thành JSON Schema
inputSchema. Viết docstring cho model đọc (xem Thiết kế tool cho agent). - Raise exception trong tool thì client nhận kết quả lỗi (
isError), model có thể tự sửa tham số. - Với
stdio, khôngprint()ra stdout: stdout là kênh JSON-RPC. Log ra stderr (loggingmặc định ghi stderr).
Test bằng MCP Inspector
uv run mcp dev server.py # mở Inspector qua CLI của mcp
npx @modelcontextprotocol/inspector uv run server.py # hoặc chạy Inspector trực tiếpTrong Inspector: Connect → tab Tools → List Tools → chọn ping → nhập target → Run Tool. Tab Resources để thử inventory://device/pe1-hni.
Thêm vào Claude Code
# stdio, scope local (chỉ mình bạn, project hiện tại)
claude mcp add netops -- uv run --directory /opt/netops-mcp server.py
# chia sẻ cho cả team qua file .mcp.json trong repo
claude mcp add netops -s project -- uv run --directory /opt/netops-mcp server.py
# truyền biến môi trường
claude mcp add netbox -e NETBOX_TOKEN=$NETBOX_TOKEN -- uv run netbox-mcp
# server HTTP
claude mcp add --transport http netops https://mcp.example.net/mcp
claude mcp list
claude mcp get netops
claude mcp remove netopsTrong phiên Claude Code, gõ /mcp để xem trạng thái kết nối và danh sách tool.
{
"mcpServers": {
"netops": {
"command": "uv",
"args": ["run", "--directory", "/opt/netops-mcp", "server.py"],
"env": {}
}
}
}Tool chạy với quyền của user chạy server. Chỉ expose lệnh đọc (show, get, ping); nếu cần ghi cấu hình, buộc qua commit confirmed và để Claude Code hỏi xác nhận (không cho vào permissions.allow).
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
/mcp báo failed ngay khi khởi động |
Lệnh sai đường dẫn, thiếu dependency | Chạy y nguyên lệnh trong terminal: uv run --directory ... server.py |
| Kết nối rồi rớt, lỗi parse JSON | Code print() ra stdout |
Bỏ print, dùng logging (stderr) |
| Tool không xuất hiện | Quên () ở @mcp.tool() hoặc server chưa restart |
Sửa decorator, restart Claude Code / reconnect trong /mcp |
| Model truyền sai kiểu tham số | Thiếu type hint, docstring mơ hồ | Thêm type hint, ví dụ giá trị trong docstring |
ModuleNotFoundError: mcp |
Claude Code chạy python hệ thống, không phải venv | Dùng uv run --directory <project> hoặc đường dẫn tuyệt đối tới .venv/bin/python |
| Tool chạy lâu bị timeout | Thiết bị chậm, không giới hạn | Đặt timeout cho subprocess/SSH, trả kết quả gọn |