Skip to main content
Glama

ChatGPT Code MCP

MCP server tự host, expose một workspace code trong sandbox cho bất kỳ MCP client nào — Hermes (Telegram/Discord/CLI), ChatGPT Developer Mode, Claude Code, Cursor — và cho phép client deploy lại chính VPS đó.

Không cần gateway, không cần pairing, không cần dịch vụ bên thứ ba.

Kiến trúc

graph TD
  H["Hermes → Telegram<br/>(bot của bạn)"] -->|stdio hoặc HTTPS+Bearer| S
  G["ChatGPT<br/>Developer Mode"] -->|Streamable HTTP + Bearer| S
  C["Claude Code / Cursor"] -->|stdio| S
  S["src/server.ts<br/>16 MCP tool"] --> X["src/sandbox.ts<br/>allow/block, chống escape"]
  X --> W["workspace code"]
  S --> D["src/deploy.ts<br/>git pull → compose build → up"]
  D --> V["docker trên VPS"]

Mọi tool filesystem đi qua đúng một cửa: resolvePath() trong src/sandbox.ts. Ngoại lệ duy nhất là deploy — nó chạy git/docker trên host, nên mặc định tắt.

Related MCP server: opengpt-connect

Yêu cầu

  • Node.js 22+ (test trên 24)

  • pnpm 10+ (repo pin packageManager: pnpm@10.33.0)

  • ripgrep (rg) — tùy chọn; thiếu thì code_search tự chuyển sang scanner nội bộ

  • Git — cho git_status / git_diff / git_log / deploy

  • Docker + compose — chỉ khi dùng deploy

pnpm install

Chạy local

stdio

pnpm mcp:stdio --workspace-root .

stdout là kênh JSON-RPC; mọi log đi ra stderr.

HTTP

MCP_AUTH_TOKEN=$(openssl rand -hex 32) pnpm mcp:http --port 8787 --workspace-root .
curl -s localhost:8787/healthz

Endpoint MCP: POST/GET/DELETE /mcp. Health: GET /healthz.

Cả hai script nhận --workspace-root có hoặc không có -- phía trước (pnpm 10 forward -- vào script, npm thì cần nó).

Kết nối Hermes

Hermes đọc MCP server từ key mcp_servers trong ~/.hermes/config.yaml. Có hai cách, chọn theo chỗ Hermes chạy.

A. Hermes chạy cùng máy với code — dùng stdio (khuyến nghị)

Đơn giản nhất: không TLS, không token, không tunnel.

mcp_servers:
  code:
    command: 'node'
    args:
      - '/srv/chatgpt-code-mcp/dist/bin/stdio.js'
      - '--workspace-root'
      - '/srv/code'
    env:
      DEPLOY_ENABLED: 'true'
      DEPLOY_REPO_DIR: '/srv/chatgpt-code-mcp'

Hoặc bằng CLI:

hermes mcp add code --command node --args /srv/chatgpt-code-mcp/dist/bin/stdio.js --workspace-root /srv/code

B. Hermes chạy máy khác — dùng HTTP + bearer

mcp_servers:
  code:
    url: 'https://mcp.example.com/mcp'
    headers:
      Authorization: 'Bearer <MCP_AUTH_TOKEN>'
hermes mcp add code --url https://mcp.example.com/mcp

Sau khi sửa config

/reload-mcp

Nếu tool không hiện trong session Telegram đang chạy, restart hẳn process Hermes — cache tool MCP có thể bị stale qua các session sống lâu.

Giới hạn tool cho Hermes

Bot Telegram có thể xoá file và deploy. Nên chỉ bật đúng thứ cần:

mcp_servers:
  code:
    command: 'node'
    args: ['/srv/chatgpt-code-mcp/dist/bin/stdio.js', '--workspace-root', '/srv/code']
    tools:
      include:
        - workspaces_list
        - directory_list
        - file_read
        - code_search
        - file_apply_patch
        - git_diff
        - test_run
        - deploy

Chính doc của Hermes cũng cảnh báo: server có khả năng mutate thì đừng nối vào Telegram/Discord/cron trước khi đã kiểm tra approval gate và đường rollback.

Nhắn thử:

Đọc src/greeting.ts rồi sửa greet trả về "Hello, <name>! Welcome to MCP.", chạy test, xong thì deploy.

Kết nối ChatGPT

ChatGPT chỉ nhận remote MCP qua HTTPS, nên phải có TLS (xem phần VPS bên dưới hoặc tunnel):

cloudflared tunnel --url http://127.0.0.1:8787

Rồi Settings → Connectors → Advanced → Developer mode, thêm https://<host>/mcp + bearer token.

  • Developer Mode bắt buộc để dùng tool ghi; mọi write action đều hỏi xác nhận.

  • Khi chưa bật Developer Mode, ChatGPT reject connector thiếu tool search + fetch. Server này có đủ cả hai nên được chấp nhận ở cả hai chế độ.

Deploy lên VPS

Server phải chạy trên máy có code. Nó không có agent từ xa — nó chính là thứ đọc filesystem.

Cần deploy: dist/ đã build + node_modules prod + workspace + MCP_AUTH_TOKEN + TLS terminator. Không cần tsx/typescript trên VPS.

Cách 1: Docker compose (khuyến nghị)

git clone <repo> /srv/chatgpt-code-mcp && cd /srv/chatgpt-code-mcp
cp .env.example .env && $EDITOR .env     # MCP_AUTH_TOKEN, WORKSPACE_DIR
$EDITOR Caddyfile                        # đổi mcp.example.com thành domain thật
docker compose up -d --build
curl -s localhost:8787/healthz

File

Vai trò

Dockerfile

Multi-stage: build dist/, runtime alpine có git, ripgrep, docker-cli, tini, chạy non-root node

compose.yaml

Service mcp (bind 127.0.0.1:8787) + caddy (TLS 80/443)

Caddyfile

Reverse proxy có flush_interval -1bắt buộc, thiếu nó Caddy buffer SSE và session MCP treo

.env.example

Mọi env, kèm ghi chú

Workspace mount :ro mặc định. Muốn agent sửa được code thì bỏ :ro.

Cách 2: systemd (không Docker)

pnpm install --frozen-lockfile && pnpm build
sudo cp deploy/chatgpt-code-mcp.service /etc/systemd/system/
sudo $EDITOR /etc/systemd/system/chatgpt-code-mcp.service   # thay PLACEHOLDER
sudo install -m 600 .env.example /etc/chatgpt-code-mcp.env
sudo $EDITOR /etc/chatgpt-code-mcp.env
sudo systemctl daemon-reload && sudo systemctl enable --now chatgpt-code-mcp

Unit đã có NoNewPrivileges, PrivateTmp, ProtectSystem=full, ProtectHome, và ReadWritePaths chỉ mở đúng workspace.

Bật deploy

DEPLOY_ENABLED=true
DEPLOY_HOST_REPO_DIR=/srv/chatgpt-code-mcp
DEPLOY_SERVICES=mcp
DOCKER_GID=$(getent group docker | cut -d: -f3)

Rồi bỏ comment hai volume /repo/var/run/docker.sock trong compose.yaml.

Container có docker socket = quyền tương đương root trên host. Chỉ mount khi bạn chấp nhận rằng ai giữ MCP_AUTH_TOKEN (hoặc điều khiển được bot Hermes) đều deploy được máy này. Với stdio + systemd thì không cần socket — process đã chạy trên host.

deploy chạy: git -c safe.directory=<repo> pull --ff-onlydocker compose build <services>docker compose up -d <services>. Dừng ở bước đầu tiên khác 0 và trả về log của đúng bước lỗi.

Workspace

Một thư mục thành workspace khi có .code-agent.json. --workspace-root nhận chính thư mục đó, hoặc thư mục cha (mọi con cấp 1 có marker đều được nhận). Lặp --workspace-root nhiều lần, hoặc set MCP_WORKSPACE_ROOTS (; trên Windows, : trên POSIX).

Config đọc lại mỗi lần gọi workspaces_list → thêm workspace không cần restart.

{
  "name": "chatgpt-code-mcp-sample",
  "allowedPaths": ["src/**", "test/**", "package.json", "tsconfig.json", "README.md", ".code-agent.json"],
  "blockedPaths": [".env*", "secrets/**", "**/*.key", "**/*.pem", "node_modules/**"],
  "commands": { "test": "pnpm test", "build": "pnpm build", "typecheck": "pnpm typecheck" },
  "maxFileBytes": 512000,
  "writable": true,
  "commandTimeoutMs": 120000
}

Field

Mặc định

Ý nghĩa

name

tên thư mục

Id workspace dùng trong tool args

allowedPaths

["**"]

Glob được phép đọc/ghi

blockedPaths

[]

Glob bị chặn — cộng thêm vào hard-block, không thay thế

commands

{}

Whitelist cho test_run; client chỉ truyền key

maxFileBytes

512000

Chặn đọc/ghi file quá lớn

writable

true

false → workspace read-only qua MCP

commandTimeoutMs

120000

Trần timeout của test_run

Schema strict: field lạ báo lỗi config thay vì bỏ qua im lặng. Dockerfile/compose.yaml cố ý không nằm trong allowlist — agent sửa code, không sửa hạ tầng.

Tool

Tool

Đọc/Ghi

Mô tả

workspaces_list

đọc

Workspace, policy, command key, vấn đề config

directory_list

đọc

Duyệt cây, depth 1–5; symlink được báo nhưng không đi theo

file_read

đọc

Nội dung + sha256 toàn file + totalLines; hỗ trợ startLine/endLine; file binary bị từ chối

code_search

đọc

ripgrep (fallback scanner nội bộ), hỗ trợ regex, glob, caseSensitive

search / fetch

đọc

Dạng citation ChatGPT yêu cầu

file_create

ghi

Tạo file, overwrite mặc định false

file_apply_patch

ghi

Patch oldText/newText, khoá bằng expectedSha256

file_move

ghi

Đổi tên/di chuyển, fallback copy khi EXDEV

file_delete

ghi

Xoá file thường (không xoá thư mục)

git_status

đọc

Branch, ahead/behind, file — đã lọc theo allowlist (hiddenCount)

git_diff

đọc

Diff working tree hoặc staged, cắt theo maxLines

git_log

đọc

--oneline, tối đa 50 commit

commands_list

đọc

Command key workspace cho phép

test_run

ghi

Chạy command đã whitelist; exit code khác 0 trả về như dữ liệu, không phải lỗi tool

deploy

ghi

git pull → compose build → up. Tắt mặc định, cần DEPLOY_ENABLED=true

Resource: workspace://{name}/config trả policy đã resolve dưới dạng JSON.

Mọi tool có annotations (readOnlyHint, destructiveHint) để client tự gate write action. deploy được đánh destructiveHint: true.

Quy trình sửa file

file_apply_patch dùng optimistic locking:

  1. file_read → lấy sha256

  2. file_apply_patch với expectedSha256 đó

  3. Hash lệch → CONFLICT, không ghi gì; đọc lại rồi patch lại

Trong một lần gọi, các edit là all-or-nothing. oldText không khớp → NO_MATCH; khớp nhiều chỗ mà không replaceAllAMBIGUOUS. Ghi ra file tạm cùng thư mục rồi rename.

Model bảo mật

Sandbox path (src/sandbox.ts) — mọi tool filesystem qua resolvePath():

  • Path phải tương đối. Tuyệt đối và drive letter (C:/…) → INVALID

  • .. vượt root → ESCAPE

  • Symlink/junction được realpath trước khi check → link ra ngoài → ESCAPE

  • Match glob case-insensitive: SECRETS/x cũng bị chặn trên Windows/macOS

  • Chặn theo cả tổ tiên: secrets/** chặn luôn chính secrets

  • Ngoài allowedPathsNOT_ALLOWED; writable: false + ghi → READ_ONLY

  • Hard-block không thể tắt bằng config: .git/**, .env, .env.*, node_modules/**, **/*.pem, **/*.key, **/*.p12, **/*.pfx, **/id_rsa*, **/id_ed25519*, **/.npmrc, **/.git-credentials, **/.aws/**, **/.ssh/**

code_search lọc lại từng hit của ripgrep bằng isAllowed(), vì ripgrep không biết policy.

Thực thi commandtest_run nhận key của commands, không nhận command string. argv lấy từ .code-agent.json, spawn shell: false, stdin: ignore, timeout có trần. Không có đường nào để client nội suy chuỗi vào shell.

deploy — tên service phải khớp ^[a-zA-Z0-9_.-]+$ và không bắt đầu bằng - (chặn smuggle argv kiểu --privileged). safe.directory chỉ mở cho đúng DEPLOY_REPO_DIR, không dùng wildcard *.

HTTPMCP_AUTH_TOKEN bật bearer auth, so sánh timingSafeEqual. Bind ngoài loopback mà không có token → in cảnh báo và exit 1. Body giới hạn 4 MB. Mỗi session một McpServer riêng.

Ngân sách output — payload mỗi tool cắt ở 60k ký tự trên biên giới dòng; test_run giữ 20k ký tự cuối mỗi stream; deploy giữ 8k/step và gói tin nhắn ≤ 3.5k.

Đừng commit token, .env, private key vào repo.

Phát triển

pnpm typecheck   # tsc --noEmit (gồm cả test)
pnpm test        # node --test, 60 test
pnpm build       # tsc -p tsconfig.build.json → dist/ (chỉ src, không test)
pnpm start       # node dist/bin/http.js

File

Nội dung

src/config.ts

Schema + loader .code-agent.json, hard-block list, khám phá workspace

src/sandbox.ts

Glob → regex, allow/block/traverse, resolvePath, assertRegularFile

src/registry.ts

Tập workspace đang expose, refresh, resolve theo tên

src/result.ts

Cắt output, ok/okJson/fail, guard() để lỗi không phá connection

src/deploy.ts

Pipeline git + docker compose, không bao giờ throw

src/server.ts

createMcpServer(), workspaces_list, resource config, resolveRoots()

src/tools/

fs.ts, search.ts, git.ts, exec.ts, deploy.ts

src/bin/

stdio.ts, http.ts

deploy/

systemd unit

Thêm tool mới: viết registerXxxTools(server, registry), lấy workspace bằng registry.get(args.workspace), resolve path bằng resolvePath(), bọc handler trong guard(), rồi gọi từ createMcpServer().

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    D
    maintenance
    An experimental MCP server that enables AI assistants to interact with VS Code workspaces through file operations, code execution, and Git management. It also provides tools for Docker integration, project scaffolding, and secure command execution using project-specific configurations.
    76
    8 npm
    3
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Gives any MCP-compatible AI chat or agent a safe, model-neutral coding runtime with file read/search, structured multi-file patches, command execution, interactive sessions, and git operations, all confined to a single workspace and gated by permission modes.
    Apache 2.0
  • A
    license
    C
    quality
    B
    maintenance
    Local-first MCP runtime for coding agents with bounded workspace access, content-preconditioned writes, AST search, LSP navigation and diagnostics, and Git status/diff. Designed to give coding agents useful repository access without treating unrestricted shell access as the default integration boundary.
    2
    13
    2
    MIT