KB-282F

GPT MCP Server Design - Phase 1 Rev3

11 min read Revision 1
gpt-mcpphase1rev3designfastmcp2026-05-13

GPT MCP Server Design — Phase 1 Rev3

Date: 2026-05-13 Author: Opus (Claude) Status: PENDING GPT REVIEW Revision: Rev3 (sửa 8 điểm Rev1 + 6 điểm Rev2)


1. Tổng quan

Xây GPT-specific FastMCP server trên VPS để ChatGPT kết nối qua Developer Mode custom connector. Thay thế GPT Actions/OpenAPI direct đã chứng minh không ổn định (ClientResponseError, request không tới VPS).

Quyết định đã thống nhất:

  • Build trên VPS, container riêng
  • FastMCP / Python 3.11+
  • KHÔNG đụng Claude MCP hiện tại
  • KHÔNG dùng GPT Actions cũ
  • ChatGPT kết nối qua Developer Mode → No Auth → secret path URL
  • Full CRUD code, write bật/tắt qua env var
  • Phase 1: validation + log + soft-delete approach
  • Không expose shell / raw SQL / hard-delete / arbitrary filesystem

2. Kiến trúc

ChatGPT (Developer Mode, No Auth)
    ↓ HTTPS
https://vps.incomexsaigoncorp.vn/gpt-mcp/<SECRET>/mcp
    ↓ nginx reverse proxy (strip secret path)
http://127.0.0.1:8100/mcp/
    ↓ FastMCP Streamable HTTP
GPT MCP Server container (gpt-mcp)
    ↓ REST HTTP (internal Docker network)
http://agent-data:8888/api/...
    ↓
AgentData container (existing, unchanged)

Chốt: GPT MCP server gọi AgentData bằng REST HTTP nội bộ. Không dùng MCP client nội bộ. Lý do: đơn giản, debug bằng curl được, không MCP-over-MCP.


3. Auth — Secret path (temporary Phase 1)

  • ChatGPT UI chọn No Auth
  • Secret nhúng trong URL path segment
  • Nginx filter: chỉ match đúng secret path → proxy tới FastMCP
  • URL không match → 404 tự nhiên
  • Đây là temporary capability URL cho Phase 1 nội bộ, KHÔNG phải production auth
  • Roadmap Phase 3/4: đánh giá chuyển OAuth 2.1 / Mixed Auth

Secret management

  • Secret lấy từ .env file trên VPS (không commit)
  • Nginx config render từ template bởi deploy.sh
  • Rendered config file: permission 600, owner root:root
  • Không commit rendered config
  • Không in secret thật ra report/chat
  • Rotate: đổi env → chạy deploy.sh → cập nhật ChatGPT connector URL

4. Tool set

Read tools (luôn bật)

Tool AgentData REST Method Params
healthCheck() /api/health GET
searchKnowledge(query) /api/chat POST {"query": str}
listDocuments(path) /api/kb/list?path=... GET path: str = "knowledge/"
getDocument(document_id) /api/documents/{path} GET document_id: str
getDocumentFull(path) /api/documents/{path}?full=true GET path: str
batchRead(paths, full) /api/documents/batch POST {"paths": list, "full": bool}

Write tools (chỉ register khi ENABLE_WRITE=true)

Tool AgentData REST Method Params
createDocument(path, content, title?, tags?) /api/documents POST {"path": str, "content": str, "title": str|None, "tags": list|None}
updateDocument(path, content, title?, tags?) /api/documents/{path} PUT {"content": str, "title": str|None, "tags": list|None}
patchDocument(path, old_str, new_str) /api/documents/{path} PATCH {"old_str": str, "new_str": str}

Không expose Phase 1

  • deleteDocument — chưa verify soft/hard
  • shell, raw SQL, filesystem, qdrant/postgres admin

Conditional registration

if os.environ.get("ENABLE_WRITE", "false").lower() == "true":
    # register write tools

Khi ENABLE_WRITE=false: write tools KHÔNG xuất hiện trong tools/list.


5. Mapping evidence

Source: AgentData MCP tool definitions verified qua tool_search trong Claude chat 2026-05-13.

search_knowledge

  • Input: {"query": "string" (required), "session_id": "string" (optional)}
  • Test: search_knowledge("test connection health check")
  • Output: text response + "Sources:" với document paths
  • Không có top_k — GPT prompt gốc sai, đã sửa

list_documents

  • Input: {"path": "string" (optional)}
  • Test: list_documents("knowledge/current-state/reports/")
  • Output: "Documents in '...' (50 items):" + list "- path [tags]"
  • Không có limit/offset — GPT prompt gốc sai, đã sửa

get_document

  • Input: {"document_id": "string" (required)}
  • Test: get_document("knowledge/current-state/reports/agentdata-gpt-action-401-auth-fix-2026-05-13.md")
  • Output: truncated content (500 chars) + "[Truncated: showing 500/2631 chars]"

upload_document (= createDocument)

  • Input: {"content": "string", "path": "string", "tags": ["string"] optional, "title": "string" optional}
  • Mapping: POST /api/documents

update_document

  • Input: {"content": "string", "path": "string", "tags": ["string"] optional, "title": "string" optional}
  • Mapping: PUT /api/documents/{path}

patch_document

  • Input: {"path": "string", "old_str": "string", "new_str": "string"}
  • Output: 404 if not found, 409 if old_str ambiguous
  • Mapping: PATCH /api/documents/{path}

batch_read

  • Input: {"paths": ["string"] (max 20), "full": boolean (default false)}
  • Mapping: POST /api/documents/batch

Lưu ý: REST endpoint/method/body mapping dựa trên tool definitions + GPT prompt gốc. Phase 2 bước đầu sẽ curl test từng endpoint nội bộ để xác nhận 100%.


6. Nginx config

Template (nginx-gpt-mcp.conf.template)

# GPT MCP Server route — DO NOT commit rendered version
# Log format: NO path/query logged (secret protection)
log_format gpt_mcp_log '$remote_addr - [$time_local] "GPT_MCP $request_method" '
                        '$status $body_bytes_sent "$http_user_agent" '
                        '$request_id $upstream_response_time';

location /gpt-mcp/__GPT_MCP_SECRET__/mcp {
    proxy_pass http://127.0.0.1:8100/mcp;
    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Request-ID $request_id;
    proxy_set_header Connection '';

    access_log /var/log/nginx/gpt-mcp-access.log gpt_mcp_log;
}

Route matching

  • Prefix location (không có =): match /mcp, /mcp/, /mcp/anything
  • proxy_pass có URI component /mcp: nginx thay thế location prefix
  • Phase 2 sẽ test cả /mcp/mcp/ với curl, chốt kết quả thực tế

Deploy script (deploy.sh)

#!/bin/bash
set -euo pipefail
source /opt/incomex/gpt-mcp/.env
sed "s|__GPT_MCP_SECRET__|${GPT_MCP_SECRET}|g" \
    /opt/incomex/gpt-mcp/nginx-gpt-mcp.conf.template \
    > /etc/nginx/conf.d/gpt-mcp.conf
chmod 600 /etc/nginx/conf.d/gpt-mcp.conf
chown root:root /etc/nginx/conf.d/gpt-mcp.conf
nginx -t && nginx -s reload
echo "GPT MCP nginx route deployed (secret redacted)"

7. Docker

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY server.py agentdata_client.py validation.py ./
CMD ["python", "server.py"]
# requirements.txt
fastmcp>=2.0
httpx>=0.27
python-dotenv>=1.0

Port: 8100 internal. Không expose external — chỉ nginx proxy.


8. Env vars

# .env.example (commit được)
GPT_MCP_SECRET=change_me_64_random_chars
AGENTDATA_BASE_URL=http://agent-data:8888
ENABLE_WRITE=false
LOG_LEVEL=INFO
REQUEST_TIMEOUT_SECONDS=30

9. Validation

  • path phải bắt đầu bằng knowledge/ — no path traversal (..)
  • content max 100KB
  • tags max 20 items, mỗi tag max 100 chars (type: list[str] | None = None)
  • paths trong batchRead max 20 items
  • query max 500 chars
  • All write tool params use | None = None for optional fields

10. Logging (app level)

Mỗi tool call log:

  • timestamp, request_id, tool_name, status, duration_ms
  • upstream_status, upstream_duration_ms
  • auth_present (true/false), payload_size, response_size
  • Không log: secret/token, full document content nếu dài

11. Error layers (3 cho Phase 1)

  • auth_error — nginx 404 (secret path không match)
  • validation_error — input không hợp lệ (trả 400 trong MCP response)
  • upstream_error — AgentData timeout/error (trả error trong MCP response kèm upstream status)

12. Files

/opt/incomex/gpt-mcp/
├── server.py                      # FastMCP server + tool definitions
├── agentdata_client.py            # httpx REST client for AgentData
├── validation.py                  # Input validation
├── Dockerfile
├── requirements.txt
├── .env.example                   # template (commit OK)
├── .env                           # secret thật (VPS only, NO commit)
├── nginx-gpt-mcp.conf.template   # nginx template (commit OK)
├── deploy.sh                      # render nginx config + reload
└── test_mcp_client.py             # MCP client test script

13. Test plan (Phase 2)

Step 1: Verify AgentData REST endpoints nội bộ

docker exec gpt-mcp curl -s http://agent-data:8888/api/health
docker exec gpt-mcp curl -s http://agent-data:8888/api/kb/list?path=knowledge/

Nếu endpoint khác → sửa mapping, báo cáo.

Step 2: Test nginx route

curl -v https://vps.incomexsaigoncorp.vn/gpt-mcp/<redacted>/mcp \
  -X POST -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{...},"id":1}'

Test cả /mcp/mcp/.

Step 3: MCP client test

# test_mcp_client.py — version check first:
# python --version && pip show fastmcp
import asyncio
from fastmcp import Client
from fastmcp.client.transports import StreamableHTTPTransport

async def test():
    url = "https://vps.../gpt-mcp/<redacted>/mcp"
    transport = StreamableHTTPTransport(url=url)
    async with Client(transport=transport) as client:
        tools = await client.list_tools()
        print(f"Tools: {[t.name for t in tools]}")
        result = await client.call_tool("healthCheck", {})
        print(f"Health: {result}")

asyncio.run(test())

Fallback: curl với MCP initialize + tools/list nếu FastMCP Client không hỗ trợ remote.

Step 4: Test từng tool (read)

healthCheck → listDocuments → searchKnowledge → getDocument → batchRead

Step 5: Test write (chỉ sau khi read ổn VÀ được duyệt bật ENABLE_WRITE)

createDocument vào knowledge/test/gpt-mcp-write-test.md


14. Rollback

  • docker stop gpt-mcp && docker rm gpt-mcp
  • Comment nginx location block → nginx -s reload
  • Claude MCP: KHÔNG BỊ ẢNH HƯỞNG

15. Auth roadmap

  • Phase 1: No Auth + capability URL secret (temporary)
  • Phase 3/4 nếu ổn định: đánh giá OAuth 2.1 / Mixed Auth theo OpenAI Apps SDK