aki-mcp-sv: Đưa Filesystem & Shell Cục Bộ Lên Web Qua MCP

Claude Desktop mang đến một capability mạnh: cho phép AI trực tiếp đọc/ghi file và chạy lệnh trên filesystem thật. Nhưng do bản chất là native app, quota sử dụng bị khoá cứng vào một device ID mà người dùng không kiểm soát được. aki-mcp-sv giải quyết giới hạn này bằng cách chạy một MCP server ngay trên máy, tự host ra internet qua Tailscale Funnel (bọc HTTPS, xác thực OAuth 2.1), rồi add ngược vào claude.ai hoặc ChatGPT dưới dạng custom connector. Kết quả là truy cập local shell/file ngay trên trình duyệt, tính vào quota bản web, không khoá device, không cần cài desktop client.


Luồng kết nối: Tailscale Funnel + OAuth 2.1

gatekeeper.js là cổng public duy nhất. mcp-hub thật chỉ lắng nghe trên loopback, nên admin API nội bộ (/api/*, không xác thực) không bao giờ lộ ra internet dù gatekeeper.js có bị lỗi.


Whitelist thay vì blocklist

!IMPORTANT Khác với Desktop Commander, MCP terminal server phổ biến nhất cho Claude Desktop (dùng blocklist, chỉ chạy nội bộ qua stdio, và tài liệu chính chủ khuyến cáo không expose ra internet), aki-mcp-sv chọn whitelist deny-by-default ngay từ đầu vì mục tiêu thiết kế là mở ra internet công khai. Cơ chế này cho 4 tính chất: fail-safe (lệnh lạ tự động bị chặn), bề mặt tấn công tối thiểu, giới hạn tới cấp subcommand (git chỉ được phép status/log/diff/show), và mặc định read-only.

shell-mcp.js thực thi lệnh qua execFile, không qua shell thật, nên ký tự nối lệnh như ;, &&, | bị chặn ở tầng thực thi thay vì lọc chuỗi, tránh toàn bộ lớp command injection dựa trên string parsing.

!WARNING "Mặc định read-only" không phải lý thuyết suông: bản 1.1.0 vẫn giữ findsort trong allowlist mặc định, dù flag riêng của hai lệnh phá vỡ read-only (find -delete/-exec, sort -o <path>) và execFile không chặn được vì nguy hiểm nằm ở chính argv của binary chứ không phải ở shell. Bản 1.2.0 đóng lỗ hổng này (issue #2) bằng cách bỏ hẳn hai lệnh khỏi mặc định thay vì vá từng flag; find_path/search_content của arm search thay đúng nhu cầu tra cứu read-only mà hai lệnh đó từng phục vụ.


OAuth 2.1: Claude và Gemini dán tay, ChatGPT và Grok tự đăng ký

claude.ai mặc định thử Dynamic Client Registration (DCR) trước khi kết nối. aki-mcp-sv không quảng cáo endpoint đó cho Claude; client_id/client_secret được sinh một lần khi chạy npm start, người dùng dán tay vào ô Advanced settings, đúng cơ chế pre-registered client credentials mà tài liệu Anthropic công nhận là cách hợp lệ để bỏ qua DCR. Gemini dùng chung cơ chế này: nó tái sử dụng đúng client confidential của Claude, không tự đăng ký.

ChatGPT và Grok làm ngược lại: cả hai tự đăng ký qua POST /register (RFC 7591) như public client (token_endpoint_auth_method: none), mỗi bên một redirect URI riêng được allowlist sẵn (chatgpt.com, grok.com/connectors-oauth-exchange-code/). Cả bốn flow đều phải vượt qua màn hình passphrase 10 ký tự (~50 bit entropy, không có nút Approve trần vì /authorize là endpoint public) và PKCE S256 trước khi lấy được token.

!NOTE Gemini xác thực OAuth thành công nhưng qua kiểm thử thực tế 2026-08-09 chưa điều khiển tool MCP ổn định (kết nối khoẻ, gọi tool không đáng tin). Claude, ChatGPT và Grok là ba client đáng tin cậy hiện tại.


Kiro CLI: arm đọc (ghi đã gỡ ở 1.3.0)

Bản 1.2.0 thêm kiro-mcp.js. kiro_read (--trust-tools=fs_read) giữ nguyên; kiro_write bị gỡ ở 1.3.0 — ghi file đi qua filesystem MCP của session đang kết nối. Model khoá claude-sonnet-4.5. 1.2.1 live-verify với kiro-cli 2.16.2 và sửa merge server thiếu trên install cũ.

Cập nhật 1.3.0–1.4.0 (trusted dirs, allowlist chips, panel multi-client tabs, search_content -iE): xem aki-mcp-sv 1.4.0.


Không phải mcp-remote, không phải SaaS

Nhìn rộng ra, phần lớn MCP server hiện có rơi vào ba nhóm không giải quyết cùng bài toán với aki-mcp-sv:

NhómĐại diệnVấn đề giải quyết
Chỉ chạy nội bộDesktop Commander, server-filesystem chính thức của AnthropicKhông thiết kế để expose ra internet
Bridge/proxy, không phải servermcp-remote (geelen)Relay stdio↔HTTP/SSE tới một MCP server từ xa đã tồn tại sẵn, tự nó không cấp quyền filesystem/shell nào
SaaS chạy trên cloud của bên thứ baComposio, Smithery-hosted MCPMiddleman gọi API bên thứ ba (GitHub, Slack...), không đụng vào filesystem/shell máy cá nhân
Tự host, tự exposeaki-mcp-svChạy trên máy của bạn, tự expose qua Tailscale Funnel, toàn quyền kiểm soát hạ tầng

6 bản release trong 3 ngày

  • v1.0.0 (2026-08-07): bản public đầu tiên, xoá sạch path đặc thù máy tác giả.
  • v1.0.1 (2026-08-07): gộp allowlist của search và shell thành một danh sách duy nhất, tránh lệch pha giữa hai bản sao.
  • v1.0.2 (2026-08-08): rút gọn README, dọn 46 dấu gạch em dash thừa.
  • v1.1.0 (2026-08-08): thêm connector ChatGPT (tự đăng ký qua RFC 7591, đóng góp qua PR của contributor capybara/okdev888), thống nhất kiến trúc cho Windows/Linux/macOS, sửa lỗi log phiên kết nối bị tràn.
  • v1.2.0 (2026-08-09): thêm connector Gemini và Grok, thêm arm Kiro CLI, nén instruction prompt dưới 1.500 ký tự, đóng lỗ hổng read-only mặc định của shell allowlist (issue #2).
  • v1.2.1 (2026-08-09): sửa lỗi redirect_uri khiến Gemini/Grok không kết nối được, Kiro arm thật sự triển khai được cho install cũ, đổi tên connector sang OS-neutral.

Giới hạn

!NOTE Không xoay vòng refresh token cho Claude, chấp nhận được vì đây là confidential client (có client_secret). Restart npm start làm mất toàn bộ session đang cấp vì token chỉ sống trong RAM. Không rate-limit /authorize, chấp nhận được nhờ entropy ~50 bit của passphrase khiến brute-force không khả thi. Gemini xác thực được nhưng chưa điều khiển tool đáng tin cậy.

Yêu cầu: Node.js, tài khoản Tailscale đã bật Funnel (miễn phí trên mọi gói). Sau khi kết nối, mỗi client gọi được 20 tool MCP qua 5 nhóm: filesystem__*, search__find_path/search__search_content, shell__run_cmd, agy__agy_run, kiro__kiro_read/kiro__kiro_write.