MCP stdio server: GAC workflow tools (calls REST API with Bearer token)
Project description
GAC Workflow MCP (stdio)
MCP gọi REST với Authorization: Bearer <token>. Mặc định mới: dùng PAT (GAC_PAT) để gọi BE exchange sang JWT ngắn hạn (/auth/pat/exchange), sau đó MCP tự dùng JWT đó để call API.
Fallback vẫn hỗ trợ JWT trực tiếp (GAC_JWT / GAC_TOKEN) để tương thích ngược.
Auth trước khi bật MCP: trước mcp.run(), process gọi GET /me với JWT. Nếu 401/403 → thoát mã 2, Cursor báo MCP lỗi và không expose tools/prompts (vì chưa vào vòng lặp stdio).
Lưu ý: Cookie session của trình duyệt không được gửi sang MCP. Chỉ Bearer. Tool list_projects gọi GET /projects (project user được phép xem). Các tool workflow dùng JWT là đủ. Tool execute_workflow phụ thuộc endpoint execute (hiện ưu tiên session) — có thể bỏ qua hoặc bật thử bằng GAC_MCP_ENABLE_EXECUTE=true.
CLI — giống tool MCP list_workflows
Sau khi export GAC_BASE_URL và GAC_PAT (hoặc GAC_JWT):
cd examples/gac_mcp_workflow
uv run python scripts/list_workflows.py 1
(1 = project_id; hoặc chỉ uv run python scripts/list_workflows.py nếu đã set GAC_DEFAULT_PROJECT_ID.)
PAT/JWT auth cho MCP
Ưu tiên đặt GAC_PAT trong env của MCP. MCP sẽ gọi endpoint exchange để lấy access token JWT runtime.
Nếu chưa có PAT hoặc chưa bật exchange endpoint, dùng GAC_JWT (hoặc GAC_TOKEN) như trước.
Tuỳ chọn: GAC_JWT_FILE = đường dẫn file chỉ chứa JWT (khi không muốn lưu token trong JSON). Không bắt buộc; nếu không set thì chỉ cần GAC_JWT như trên.
Với PAT mode, MCP tự refresh JWT trước khi hết hạn. Với JWT direct mode, khi token hết hạn cần cập nhật lại GAC_JWT.
Workflow CRUD tools (focus)
MCP hiện tập trung mạnh vào CRUD cho workflow:
list_workflowsget_workflowcreate_workflowupdate_workflowdelete_workflowpublish_workflowlist_workflow_versionsget_workflow_versiondelete_workflow_versionrestore_workflow_version
Khuyến nghị thứ tự thao tác:
list_workflowsđể kiểm tra trùng tên.create_workflowvới graph tối thiểu hợp lệ.get_workflowđể review draft.update_workflowkhi cần chỉnh node/edge.delete_workflowchỉ sau khi xác nhận.
Cách prompt để agent tạo workflow đúng
Khi prompt user, nên ghi rõ:
- Mục tiêu workflow.
- Tổng số node.
- Mỗi node gồm:
id,type, chức năng. - Mỗi edge gồm:
source -> target. - Nếu có branch thì ghi rõ nhánh điều kiện.
Prompt mẫu (VN):
Tạo workflow gồm 4 node:
1) start-1 (start): điểm bắt đầu
2) agent-1 (agent): tóm tắt nội dung user
3) agent-2 (agent): chuyển summary thành checklist
4) end-1 (end): kết thúc
Edges:
- e1: start-1 -> agent-1
- e2: agent-1 -> agent-2
- e3: agent-2 -> end-1
Hãy tạo nodes_json và edges_json hợp lệ để gọi create_workflow.
Prompt mẫu (EN):
Create a workflow with 3 nodes:
- start-1 (start): entry
- agent-1 (agent): classify incoming request into categories
- end-1 (end): finish
Edges:
- e1: start-1 -> agent-1
- e2: agent-1 -> end-1
Return valid nodes_json and edges_json for create_workflow.
Checklist trước khi gọi create_workflow / update_workflow
- Có đúng 1 node
start. - Có ít nhất 1 node
end. - Mọi
edge.sourcevàedge.targetđều tồn tại trong danh sách node. - Không có node quan trọng bị disconnected.
nodes_jsonvàedges_jsonlà JSON hợp lệ (parse được).
MCP preflight/normalize (mới) — tham chiếu DSL GAC FE
Payload POST/PUT giống console: name, description?, nodes[], edges[]. Để gần với Next.js + React Flow (sanitize trước khi lưu), MCP tự bổ sung/ chuẩn hóa:
| Thành phần | Hành vi MCP |
|---|---|
| Edges | Nếu thiếu type, gán "status" (StatusEdge như UI). |
| Agent | Thiếu data.sourceType → {"type":"text"}. |
| if-else | Map else → output-else; condition-<id> → output-<id>; sinh dynamicSourceHandles từ conditions khi UI field chưa có; nếu chỉ có dynamicSourceHandles (bản export FE) thì mirror sang conditions cho BE. |
| Thực thi (CEL) | Trên BE, biến input.<field> (khớp validator FE) và input.params.<field> đều trỏ cùng payload node trước; ưu tiên viết điều kiện dạng input.<field> cho if-else. |
| data-extractor | Không tự sửa: khi nguồn project, FE thường lưu selectedFilePath: null (path động) — cần nắm khi copy graph từ UI. |
Graph cơ bản: đúng 1 start, ≥1 end, mọi source/target tồn tại. Preflight với update_workflow chỉ chạy khi gửi cả nodes_json và edges_json trong cùng lần gọi.
Chạy tay
cd examples/gac_mcp_workflow
uv sync
export GAC_BASE_URL="http://localhost:8000/api/v1"
export GAC_PAT="gac_pat_<id>_<secret>"
# hoặc fallback:
# export GAC_JWT="<access_token từ login>"
# export GAC_DEFAULT_PROJECT_ID="1" # tùy chọn
uv run python -m gac_mcp
Lỗi No module named gac_mcp trong Cursor
Cursor đôi khi không áp dụng cwd khi spawn MCP → uv run python -m gac_mcp chạy nhầm context và gọi Python hệ thống (vd. 3.10) không có package.
Cách xử lý: dùng uv run --directory <đường_dẫn_tuyệt_đối_tới_examples/gac_mcp_workflow> ... trong args (xem mcp.json.example). Không phụ thuộc cwd.
Trong thư mục package chạy một lần: uv sync.
Lệnh trong mcp.json có chắc chạy local không?
Có, nếu đủ điều kiện sau:
| Điều kiện | Ghi chú |
|---|---|
uv có trên PATH |
Cài: https://docs.astral.sh/uv/ (brew install uv hoặc script). |
Project context cho uv |
Dùng uv run --directory /path/to/examples/gac_mcp_workflow trong args (khuyến nghị). Chỉ dùng cwd là không đủ với một số bản Cursor. |
Đã uv sync ít nhất một lần trong thư mục đó |
Tạo .venv và cài mcp, httpx. Không sync vẫn có thể chạy nhưng uv run sẽ resolve deps chậm / lỗi. |
uv run --directory … python -m gac_mcp = chạy module trong đúng project — ổn định hơn cwd một mình.
Cursor — copy mcp.json.example
- Copy nội dung vào Cursor → MCP hoặc
.cursor/mcp.json(tùy bản Cursor). - Trong
args, sửa đường dẫn sau--directorythành thư mụcexamples/gac_mcp_workflowtrên máy bạn (path tuyệt đối). - Đặt
GAC_PAT(hoặcGAC_JWT) vàGAC_BASE_URL.
File mẫu mcp.json.example đã dùng --directory + path workspace dev; máy khác chỉ cần sửa segment path trong args.
uv là gì? (tại sao uv build, uvx, uv run?)
uv là công cụ dòng lệnh (một file binary) của Astral dùng để quản lý Python + package + virtualenv: cài nhanh, tương thích pyproject.toml / pip, thường dùng thay cho hoặc cùng với pip + venv trong project hiện đại.
| Lệnh (gợi ý) | Ý nghĩa |
|---|---|
uv sync |
Đồng bộ dependency theo pyproject.toml / lock, tạo .venv trong project. |
uv run … |
Chạy lệnh trong môi trường project (vd. uv run python -m gac_mcp). |
uv build |
Đóng gói wheel + sdist để publish (lên PyPI / index nội bộ). |
uv publish |
Đẩy bản build lên registry (cần cấu hình token PyPI / index). |
uvx |
Tải và chạy một bản công cụ từ PyPI tạm thời (kiểu npx): user không cần git clone hay --directory nếu package đã publish và khai báo console script (ở đây là gac-mcp trong pyproject.toml). |
Khi chưa publish: vẫn cần uv run --directory <path> … từ source. Khi đã publish: có thể cấu hình Cursor với command: uvx + args trỏ tới tên package + entrypoint (kiểm tra bản uv cụ thể, ví dụ uvx --from gac-mcp-workflow gac-mcp).
Cài uv: xem Installing uv (macOS: brew install uv, v.v.).
Nhiều người dùng / chuyển giao (không bắt mọi người clone cùng path)
| Phương án | Ý tưởng | mcp.json |
|---|---|---|
| A. Mỗi người clone repo | Mỗi máy sửa path trong uv run --directory ... trong args. |
command + args (+ env). |
| B. Publish package (PyPI / private index) | Đặt tên ví dụ gac-mcp-workflow, publish version; user cài một lệnh toàn cục. |
"command": "uvx", "args": ["--from", "gac-mcp-workflow", "gac-mcp"] (hoặc tương đương sau khi thử trên máy); không cần cwd nếu entrypoint resolve được. |
C. pip install / pipx |
pipx install . trong thư mục package hoặc từ wheel. |
"command": "gac-mcp" hoặc "python", "-m", "gac_mcp" tùy cách cài. |
| D. Docker | Image có sẵn uv + code; chạy container với env. |
command/args trỏ vào script trong image; phức tạp hơn với Cursor (cần mount / network). |
POC hiện tại là phương án A (rõ ràng, không cần registry). Khi ổn định, B giúp mọi người dùng chung một lệnh và chỉ khác env (URL + JWT).
Ví dụ tối thiểu (local — bắt buộc --directory trỏ tới examples/gac_mcp_workflow):
{
"mcpServers": {
"gac-workflow": {
"command": "uv",
"args": [
"run",
"--directory",
"/Users/you/path/to/gac-gen-ai-console-be/examples/gac_mcp_workflow",
"python",
"-m",
"gac_mcp"
],
"env": {
"GAC_BASE_URL": "http://localhost:8000/api/v1",
"GAC_PAT": "gac_pat_<id>_<secret>",
"GAC_PAT_EXCHANGE_PATH": "/auth/pat/exchange"
}
}
}
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_gac_ex-1.0.2.tar.gz.
File metadata
- Download URL: mcp_gac_ex-1.0.2.tar.gz
- Upload date:
- Size: 74.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
83c81307fd408be90c839568335564f521d795ea4eb41ea97433f5134342f3d8
|
|
| MD5 |
84ecbaaa07e262eb8a662607a2b2cf5a
|
|
| BLAKE2b-256 |
8a8cf1993c84011b507027d0e58a3cdb8ff18876abc34041c525f94a5dedc472
|
File details
Details for the file mcp_gac_ex-1.0.2-py3-none-any.whl.
File metadata
- Download URL: mcp_gac_ex-1.0.2-py3-none-any.whl
- Upload date:
- Size: 16.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6554541ce59326f8aad278b93247747854e91f0cda75a432a340cda82e77e36f
|
|
| MD5 |
9e4117a8ea919406ae7721545dee77f3
|
|
| BLAKE2b-256 |
1ba66b340df516ffb5212ab16b149f3cbd0bdb0a21bc9f668fbd0d3618eae70e
|