dot-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dot_mcp-0.1.0/.gitignore +30 -0
- dot_mcp-0.1.0/LICENSE +21 -0
- dot_mcp-0.1.0/PKG-INFO +196 -0
- dot_mcp-0.1.0/README.md +165 -0
- dot_mcp-0.1.0/dots +8 -0
- dot_mcp-0.1.0/expose.sh +264 -0
- dot_mcp-0.1.0/pyproject.toml +60 -0
- dot_mcp-0.1.0/requirements.txt +3 -0
- dot_mcp-0.1.0/run.sh +10 -0
- dot_mcp-0.1.0/setup.sh +12 -0
- dot_mcp-0.1.0/src/dot_mcp/__init__.py +3 -0
- dot_mcp-0.1.0/src/dot_mcp/agent_test.py +43 -0
- dot_mcp-0.1.0/src/dot_mcp/cli.py +244 -0
- dot_mcp-0.1.0/src/dot_mcp/local_agent.py +107 -0
- dot_mcp-0.1.0/src/dot_mcp/orchestrator.py +883 -0
- dot_mcp-0.1.0/src/dot_mcp/server.py +1054 -0
- dot_mcp-0.1.0/src/dot_mcp/ui/workspace.html +84 -0
- dot_mcp-0.1.0/test.sh +17 -0
dot_mcp-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.venv/
|
|
6
|
+
venv/
|
|
7
|
+
.env
|
|
8
|
+
|
|
9
|
+
# Logs
|
|
10
|
+
*.log
|
|
11
|
+
mcp.log
|
|
12
|
+
tunnel.log
|
|
13
|
+
nohup.out
|
|
14
|
+
logs/
|
|
15
|
+
|
|
16
|
+
# Downloaded binaries (auto-fetched by expose.sh)
|
|
17
|
+
bin/cloudflared
|
|
18
|
+
|
|
19
|
+
# Local data (server state, not source)
|
|
20
|
+
.dot-mcp/
|
|
21
|
+
*.tmp
|
|
22
|
+
|
|
23
|
+
# Packaging
|
|
24
|
+
dist/
|
|
25
|
+
build/
|
|
26
|
+
src/*.egg-info/
|
|
27
|
+
*.egg-info
|
|
28
|
+
|
|
29
|
+
# third-party agent state (not source)
|
|
30
|
+
.freebuff/
|
dot_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dot-mcp contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
dot_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: dot-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Personal MCP agent: shell, files, memory, goals, inbox, scheduler, capability URL + self-hosted OAuth
|
|
5
|
+
Project-URL: Homepage, https://github.com/Ashveil1/dot-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/Ashveil1/dot-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/Ashveil1/dot-mcp/issues
|
|
8
|
+
Author: Ashveil1
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent,cli,mcp,personal-assistant,termux
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: mcp<3,>=1
|
|
25
|
+
Requires-Dist: rich>=13
|
|
26
|
+
Requires-Dist: uvicorn>=0.30
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: httpx; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# dot-mcp
|
|
33
|
+
|
|
34
|
+
Single-file MCP agent แบบ dots สำหรับ Termux / Linux — shell + files + memory + goals + inbox + scheduler ในไฟล์เดียว (`dot_mcp.py`)
|
|
35
|
+
|
|
36
|
+
> ⚠️ URL สะอาด (`/mcp/`) — auth เป็น Bearer 2 แบบ: JWT จาก OAuth (ให้ ChatGPT/Claude/Gemini) หรือ secret เดิมใน header (ให้สคริปต์ local) ไม่มี header = 401 แม้ localhost
|
|
37
|
+
|
|
38
|
+
Endpoint: `http://127.0.0.1:33041/mcp/` · Health: `/health`
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- **Shell:** `run_command` (background session + timeout) + `read_output`
|
|
43
|
+
- **Files:** `list_dir`, `read_file` (paginated + sha256), `write_file` (atomic + sha guard), `append_file`, `edit_file` (unique-match)
|
|
44
|
+
- **Memory:** `remember`, `recall`, `forget` — จำข้ามแชท (`~/.dot-mcp/memory.json`)
|
|
45
|
+
- **Goals/Tasks:** `set_goal`, `add_update`, `get_state`, `add_task`, `complete_task`
|
|
46
|
+
- **Inbox (ข้ามแชท):** `notify_user`, `poll_inbox`, `ack_inbox`
|
|
47
|
+
- **Scheduler:** `add_schedule`, `list_schedules`, `remove_schedule` — งานประจำรันเองตอนไม่มีแชท ผลเข้า inbox
|
|
48
|
+
- **Embedded UI:** `open_workspace` — MCP Apps dashboard สไตล์ Codex แสดง tasks, memory, command sessions และ schedules
|
|
49
|
+
- รวม 22 tools
|
|
50
|
+
|
|
51
|
+
## Quickstart
|
|
52
|
+
|
|
53
|
+
**ติดตั้งจาก PyPI:**
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install dot-mcp
|
|
57
|
+
dot-mcp start # server + tunnel + public URL (port 33041, secret ประจำเครื่อง)
|
|
58
|
+
dot-mcp status # เช็คว่ารันอยู่ไหม
|
|
59
|
+
dot-mcp stop # หยุด server + tunnel
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`dot-mcp start` รัน server ในพื้นหลังแล้วคืน shell ทันที — จะได้ URL,
|
|
63
|
+
owner secret, OAuth client ID/secret ให้เอาไปตั้ง connector เลย
|
|
64
|
+
|
|
65
|
+
**รันจาก source checkout:**
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
./setup.sh # สร้าง .venv + ติดตั้ง deps + editable install
|
|
69
|
+
./dots start # เหมือนด้านบน
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
สำรอง: `./run.sh` (server เฉยๆ ไม่มี tunnel) · `./test.sh` (health + initialize) ·
|
|
73
|
+
`./expose.sh` (tunnel เฉยๆสำหรับ ChatGPT connector)
|
|
74
|
+
|
|
75
|
+
คุยแบบ local-only (ไม่ต้อง tunnel, ไม่ต้องจ่าย sub):
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
export OPENAI_API_KEY=sk-...
|
|
79
|
+
python -m dot_mcp.local_agent # chat loop
|
|
80
|
+
python -m dot_mcp.local_agent --list # ดู tools เฉยๆ
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
เทสผ่าน MCP client จริง:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
.venv/bin/python agent_test.py
|
|
87
|
+
.venv/bin/python agent_test.py http://127.0.0.1:33041/mcp/ # อ่าน secret จาก env/ไฟล์ให้เอง
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
เปิดให้ ChatGPT web เรียกผ่าน tunnel:
|
|
91
|
+
|
|
92
|
+
**วิธีแนะนำ: tunnl.gg (URL สุ่มแต่คงเดิมเมื่อใช้ key เดิม)**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/Ashveil1/dot-mcp.git
|
|
96
|
+
cd dot-mcp
|
|
97
|
+
./setup.sh
|
|
98
|
+
./expose.sh
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
ครั้งแรกสคริปต์จะสร้าง SSH key และ owner secret ให้อัตโนมัติ เก็บไว้ใน `~/.config/dot-mcp/` (`owner_secret` 0600) แล้วแสดง URL `/mcp/` เส้นสะอาดสำหรับตั้งค่า connector (auth = OAuth) การรันครั้งต่อไปใช้ key และ secret เดิม URL และ consent ไม่เปลี่ยน ตราบใดที่ยังเก็บโฟลเดอร์นี้ไว้
|
|
102
|
+
|
|
103
|
+
ข้อจำกัดแผนฟรีของ tunnl.gg: URL เป็นชื่อสุ่มที่ผู้ให้บริการกำหนด (ไม่สามารถเลือก prefix `dot-mcp-` เองได้); tunnel หมดอายุหลัง 24 ชั่วโมง หรือหลังไม่มี traffic 2 ชั่วโมง ต้องรัน `./expose.sh` ใหม่เพื่อเชื่อมต่ออีกครั้ง แต่ URL จะคงเดิมเมื่อใช้ SSH key เดิม ต้องมี OpenSSH (`ssh` และ `ssh-keygen`) และเครื่องต้องออนไลน์ขณะใช้ MCP อย่าเผยแพร่ private key ใน `~/.config/dot-mcp/`
|
|
104
|
+
|
|
105
|
+
สคริปต์จะตรวจ MCP `initialize` ผ่าน public HTTPS ก่อนแสดง URL หากการทดสอบไม่ผ่านจะรายงานข้อผิดพลาดแทนการบอกว่าเชื่อมต่อสำเร็จ MCP สคริปต์จะรายงานว่าไม่ผ่านแทนการแสดงว่าใช้งานได้ URL แบบสุ่มนี้ **ไม่คงเดิมเมื่อรันใหม่** และชื่อที่ขึ้นต้น `dot-mcp-` ไม่ได้แปลว่าถูกจองถาวร
|
|
106
|
+
|
|
107
|
+
**Cloudflare Quick Tunnel (URL สุ่ม):**
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
TUNNEL_PROVIDER=cloudflare ./expose.sh
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**URL คงที่ด้วย ngrok (ต้องตั้งค่าบัญชีครั้งเดียว):**
|
|
114
|
+
|
|
115
|
+
1. สร้างบัญชี ngrok และคัดลอก authtoken จาก dashboard
|
|
116
|
+
2. คัดลอกโดเมนฟรีที่ ngrok assign ให้บัญชี (เช่น `example.ngrok-free.app`) จาก dashboard
|
|
117
|
+
3. ติดตั้ง ngrok binary ให้ตรงกับ OS/architecture ของเครื่อง แล้วตั้งค่าตัวแปรและเริ่ม:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
export TUNNEL_PROVIDER=ngrok
|
|
121
|
+
export NGROK_AUTHTOKEN='ใส่-authtoken-ของคุณ'
|
|
122
|
+
export NGROK_DOMAIN='โดเมนที่-ngrok-assign-ให้คุณ'
|
|
123
|
+
./expose.sh
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
สคริปต์จะตรวจสอบ `/health` และส่ง MCP `initialize` ผ่าน public URL ก่อนแสดง URL สำหรับ ChatGPT หากใช้ ngrok ต้องใช้ `NGROK_DOMAIN` เดิมทุกครั้ง และเก็บ authtoken เป็นความลับ การมี URL คงที่ไม่ได้หมายความว่าเซิร์ฟเวอร์จะออนไลน์เมื่อเครื่องปิดอยู่
|
|
127
|
+
|
|
128
|
+
หมายเหตุ: `expose.sh` ไม่ดาวน์โหลด ngrok ให้อัตโนมัติ เพราะต้องใช้ binary ที่เหมาะกับระบบปฏิบัติการ/สถาปัตยกรรมของเครื่อง โดยเฉพาะ Android/Termux อาจต้องใช้วิธีติดตั้งที่รองรับ Termux โดยตรง
|
|
129
|
+
|
|
130
|
+
เมื่อเริ่มสำเร็จ ให้เอา `MCP URL` ที่สคริปต์แสดงไปใส่ Settings > Apps > Advanced > Developer Mode > Add connector (ไม่ต้องตั้ง token)
|
|
131
|
+
|
|
132
|
+
## Embedded UI in ChatGPT
|
|
133
|
+
|
|
134
|
+
When connected through a ChatGPT MCP connector that supports MCP Apps, call `open_workspace` to render the responsive Dots Workspace panel. It provides Overview, Tasks, Memory, Activity/Schedules and Rules views. This is an embedded app surface; it cannot change ChatGPT's global sidebar, composer, or native Codex interface. Use MCP SDK v2 for the interactive UI path; the older SDK fallback returns text only.
|
|
135
|
+
|
|
136
|
+
## Env
|
|
137
|
+
|
|
138
|
+
| ตัวแปร | ค่าเริ่มต้น | หมายถึง |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| `MCP_HOST` / `MCP_PORT` | `127.0.0.1` / `33041` | bind server |
|
|
141
|
+
| `MCP_PUBLIC_HOST` | `""` | tunnel host ที่ allow (`expose.sh` ตั้งให้เอง) |
|
|
142
|
+
| `DOT_MCP_DATA` | `~/.dot-mcp` | ที่เก็บ memory/state/inbox/schedules/oauth/audit |
|
|
143
|
+
| `MCP_TRUNC_LIMIT` | `8192` | ตัด stdout ยาวๆ แล้วให้ต่อด้วย `read_output` |
|
|
144
|
+
| `MCP_RATE_MCP_PER_MIN` | `300` | rate limit ต่อ IP บน `/mcp*` (เกิน → 429) |
|
|
145
|
+
| `MCP_RATE_AUTH_PER_MIN` | `30` | rate limit ต่อ IP บน `/register` `/authorize` `/token` |
|
|
146
|
+
| `MCP_SESSION_CAP` | `50` | จำนวน background session สูงสุด |
|
|
147
|
+
| `HOME` / `TMPDIR` | — | `resolve()` จำกัด path อยู่ใน HOME/TMPDIR//sdcard, `/tmp` ถูก map ไป `$TMPDIR` (Android ไม่มี /tmp) |
|
|
148
|
+
|
|
149
|
+
ไฟล์ข้อมูล: `memory.json`, `state.json`, `inbox.json`, `schedules.json`, `oauth.json` (0600), `audit.jsonl`
|
|
150
|
+
|
|
151
|
+
## Files
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
src/dot_mcp/server.py # MCP server (22 tools + OAuth 2.1)
|
|
155
|
+
src/dot_mcp/cli.py # CLI: dot-mcp start/status/stop
|
|
156
|
+
src/dot_mcp/orchestrator.py # boot → tunnel → verify flow
|
|
157
|
+
src/dot_mcp/ui/workspace.html # embedded workspace UI (MCP Apps)
|
|
158
|
+
src/dot_mcp/local_agent.py # ChatGPT model + MCP local (ไม่ต้อง tunnel)
|
|
159
|
+
src/dot_mcp/agent_test.py # client smoke test
|
|
160
|
+
tests/test_server.py # pytest suite (รัน: .venv/bin/python -m pytest tests/ -q)
|
|
161
|
+
dots # repo shim (./dots start)
|
|
162
|
+
setup.sh / run.sh / test.sh / expose.sh
|
|
163
|
+
pyproject.toml # pip packaging (console scripts dot-mcp + dots)
|
|
164
|
+
requirements.txt # mcp>=1,<3, uvicorn>=0.30, rich>=13
|
|
165
|
+
bin/cloudflared # auto-download (arm64) — ไม่ commit
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Security
|
|
169
|
+
|
|
170
|
+
> ⚠️ **เซิร์ฟเวอร์นี้ให้ shell เต็มเครื่องแก่ผู้ถือ credential** — ถือว่าเป็น production
|
|
171
|
+
> เฉพาะเมื่อใช้คนเดียว + ปฏิบัติตามนี้
|
|
172
|
+
|
|
173
|
+
- `/mcp/` ต้องมี `Authorization: Bearer` เสมอ (JWT จาก OAuth หรือ owner secret) — ไม่มี = 401 แม้ localhost (ตั้งใจ: traffic จาก tunnel ดูเหมือน loopback แยกไม่ออก)
|
|
174
|
+
- Owner secret อยู่ใน header/consent form ไม่โผล่ใน URL; log (`mcp.log`, `tunnel.log`) ตั้ง `600` + ปิด access log; เปิด tunnel เฉพาะตอนใช้ + ปิดทันที
|
|
175
|
+
- Rate limit: `/mcp*` 300 req/min/IP, `/register` `/authorize` `/token` 30 req/min/IP (เกิน → 429) — ปรับผ่าน `MCP_RATE_MCP_PER_MIN` / `MCP_RATE_AUTH_PER_MIN`
|
|
176
|
+
- ทุก request ถูกบันทึก `audit.jsonl` (เวลา/IP/method/path/status/tool) — ตรวจย้อนหลังได้
|
|
177
|
+
- Consent POST ตรวจ `Origin`/`Referer` ว่าตรง issuer (กัน CSRF ข้ามเว็บ)
|
|
178
|
+
- Refresh token เก็บแบบ hash + หมุนทุกครั้งที่ใช้; JWT ตรวจลายเซ็น/issuer/audience/expiry/scope
|
|
179
|
+
- ไฟล์ state ล็อกข้าม process (`fcntl`) + เขียน atomic (tmp + rename) — รัน server ซ้อนกันไม่ทำข้อมูลพัง
|
|
180
|
+
- **ข้อจำกัดที่ต้องรู้:** provider ของ tunnel (tunnl/cloudflare) เห็น traffic เพราะ TLS จบที่ edge เขา; rate limit/audit เป็น per-process (รันหลาย process ให้นับแยกกัน); backup `~/.dot-mcp` เอง (ไม่มีระบบ backup ในตัว)
|
|
181
|
+
|
|
182
|
+
## OAuth (ChatGPT / Claude / Gemini)
|
|
183
|
+
|
|
184
|
+
ฟรี ทำเองในไฟล์เดียว ไม่ต้องมี IdP เจ้าอื่น — server นี้เป็นทั้งคนออกและคนตรวจ token:
|
|
185
|
+
|
|
186
|
+
- Metadata: `/.well-known/oauth-authorization-server` + `/.well-known/oauth-protected-resource`
|
|
187
|
+
- `POST /register` — Dynamic Client Registration (รับ `redirect_uris` https, หรือ `http://localhost`/`127.0.0.1`)
|
|
188
|
+
- `GET/POST /authorize` — หน้า consent ครั้งเดียว ปลดล็อกด้วย owner secret (code + PKCE S256, อายุ 10 นาที, ใช้ครั้งเดียว)
|
|
189
|
+
- `POST /token` — แลก code เป็น JWT (1 ชม.) + refresh token (30 วัน, หมุนทุกครั้งที่ใช้)
|
|
190
|
+
- เรียก MCP ใส่ `Authorization: Bearer <jwt>` ได้เลย (OAuth) หรือ `Bearer <owner secret>` (สคริปต์ local)
|
|
191
|
+
- ตั้งค่า connector: URL = `https://<host>/mcp/`, auth = OAuth, issuer = `https://<host>` (ดูจาก `/.well-known/...` ได้)
|
|
192
|
+
- connector แบบ DCR (ChatGPT) สมัคร client เอง + PKCE; แบบกรอกมือ (Claude) ใช้ **OAuth client ID/secret** ประจำเครื่องที่ `dots start` โชว์ (เก็บใน `oauth.json` 0600, ไม่ต้อง register)
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
dot_mcp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# dot-mcp
|
|
2
|
+
|
|
3
|
+
Single-file MCP agent แบบ dots สำหรับ Termux / Linux — shell + files + memory + goals + inbox + scheduler ในไฟล์เดียว (`dot_mcp.py`)
|
|
4
|
+
|
|
5
|
+
> ⚠️ URL สะอาด (`/mcp/`) — auth เป็น Bearer 2 แบบ: JWT จาก OAuth (ให้ ChatGPT/Claude/Gemini) หรือ secret เดิมใน header (ให้สคริปต์ local) ไม่มี header = 401 แม้ localhost
|
|
6
|
+
|
|
7
|
+
Endpoint: `http://127.0.0.1:33041/mcp/` · Health: `/health`
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Shell:** `run_command` (background session + timeout) + `read_output`
|
|
12
|
+
- **Files:** `list_dir`, `read_file` (paginated + sha256), `write_file` (atomic + sha guard), `append_file`, `edit_file` (unique-match)
|
|
13
|
+
- **Memory:** `remember`, `recall`, `forget` — จำข้ามแชท (`~/.dot-mcp/memory.json`)
|
|
14
|
+
- **Goals/Tasks:** `set_goal`, `add_update`, `get_state`, `add_task`, `complete_task`
|
|
15
|
+
- **Inbox (ข้ามแชท):** `notify_user`, `poll_inbox`, `ack_inbox`
|
|
16
|
+
- **Scheduler:** `add_schedule`, `list_schedules`, `remove_schedule` — งานประจำรันเองตอนไม่มีแชท ผลเข้า inbox
|
|
17
|
+
- **Embedded UI:** `open_workspace` — MCP Apps dashboard สไตล์ Codex แสดง tasks, memory, command sessions และ schedules
|
|
18
|
+
- รวม 22 tools
|
|
19
|
+
|
|
20
|
+
## Quickstart
|
|
21
|
+
|
|
22
|
+
**ติดตั้งจาก PyPI:**
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install dot-mcp
|
|
26
|
+
dot-mcp start # server + tunnel + public URL (port 33041, secret ประจำเครื่อง)
|
|
27
|
+
dot-mcp status # เช็คว่ารันอยู่ไหม
|
|
28
|
+
dot-mcp stop # หยุด server + tunnel
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`dot-mcp start` รัน server ในพื้นหลังแล้วคืน shell ทันที — จะได้ URL,
|
|
32
|
+
owner secret, OAuth client ID/secret ให้เอาไปตั้ง connector เลย
|
|
33
|
+
|
|
34
|
+
**รันจาก source checkout:**
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
./setup.sh # สร้าง .venv + ติดตั้ง deps + editable install
|
|
38
|
+
./dots start # เหมือนด้านบน
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
สำรอง: `./run.sh` (server เฉยๆ ไม่มี tunnel) · `./test.sh` (health + initialize) ·
|
|
42
|
+
`./expose.sh` (tunnel เฉยๆสำหรับ ChatGPT connector)
|
|
43
|
+
|
|
44
|
+
คุยแบบ local-only (ไม่ต้อง tunnel, ไม่ต้องจ่าย sub):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export OPENAI_API_KEY=sk-...
|
|
48
|
+
python -m dot_mcp.local_agent # chat loop
|
|
49
|
+
python -m dot_mcp.local_agent --list # ดู tools เฉยๆ
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
เทสผ่าน MCP client จริง:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
.venv/bin/python agent_test.py
|
|
56
|
+
.venv/bin/python agent_test.py http://127.0.0.1:33041/mcp/ # อ่าน secret จาก env/ไฟล์ให้เอง
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
เปิดให้ ChatGPT web เรียกผ่าน tunnel:
|
|
60
|
+
|
|
61
|
+
**วิธีแนะนำ: tunnl.gg (URL สุ่มแต่คงเดิมเมื่อใช้ key เดิม)**
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
git clone https://github.com/Ashveil1/dot-mcp.git
|
|
65
|
+
cd dot-mcp
|
|
66
|
+
./setup.sh
|
|
67
|
+
./expose.sh
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
ครั้งแรกสคริปต์จะสร้าง SSH key และ owner secret ให้อัตโนมัติ เก็บไว้ใน `~/.config/dot-mcp/` (`owner_secret` 0600) แล้วแสดง URL `/mcp/` เส้นสะอาดสำหรับตั้งค่า connector (auth = OAuth) การรันครั้งต่อไปใช้ key และ secret เดิม URL และ consent ไม่เปลี่ยน ตราบใดที่ยังเก็บโฟลเดอร์นี้ไว้
|
|
71
|
+
|
|
72
|
+
ข้อจำกัดแผนฟรีของ tunnl.gg: URL เป็นชื่อสุ่มที่ผู้ให้บริการกำหนด (ไม่สามารถเลือก prefix `dot-mcp-` เองได้); tunnel หมดอายุหลัง 24 ชั่วโมง หรือหลังไม่มี traffic 2 ชั่วโมง ต้องรัน `./expose.sh` ใหม่เพื่อเชื่อมต่ออีกครั้ง แต่ URL จะคงเดิมเมื่อใช้ SSH key เดิม ต้องมี OpenSSH (`ssh` และ `ssh-keygen`) และเครื่องต้องออนไลน์ขณะใช้ MCP อย่าเผยแพร่ private key ใน `~/.config/dot-mcp/`
|
|
73
|
+
|
|
74
|
+
สคริปต์จะตรวจ MCP `initialize` ผ่าน public HTTPS ก่อนแสดง URL หากการทดสอบไม่ผ่านจะรายงานข้อผิดพลาดแทนการบอกว่าเชื่อมต่อสำเร็จ MCP สคริปต์จะรายงานว่าไม่ผ่านแทนการแสดงว่าใช้งานได้ URL แบบสุ่มนี้ **ไม่คงเดิมเมื่อรันใหม่** และชื่อที่ขึ้นต้น `dot-mcp-` ไม่ได้แปลว่าถูกจองถาวร
|
|
75
|
+
|
|
76
|
+
**Cloudflare Quick Tunnel (URL สุ่ม):**
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
TUNNEL_PROVIDER=cloudflare ./expose.sh
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**URL คงที่ด้วย ngrok (ต้องตั้งค่าบัญชีครั้งเดียว):**
|
|
83
|
+
|
|
84
|
+
1. สร้างบัญชี ngrok และคัดลอก authtoken จาก dashboard
|
|
85
|
+
2. คัดลอกโดเมนฟรีที่ ngrok assign ให้บัญชี (เช่น `example.ngrok-free.app`) จาก dashboard
|
|
86
|
+
3. ติดตั้ง ngrok binary ให้ตรงกับ OS/architecture ของเครื่อง แล้วตั้งค่าตัวแปรและเริ่ม:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
export TUNNEL_PROVIDER=ngrok
|
|
90
|
+
export NGROK_AUTHTOKEN='ใส่-authtoken-ของคุณ'
|
|
91
|
+
export NGROK_DOMAIN='โดเมนที่-ngrok-assign-ให้คุณ'
|
|
92
|
+
./expose.sh
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
สคริปต์จะตรวจสอบ `/health` และส่ง MCP `initialize` ผ่าน public URL ก่อนแสดง URL สำหรับ ChatGPT หากใช้ ngrok ต้องใช้ `NGROK_DOMAIN` เดิมทุกครั้ง และเก็บ authtoken เป็นความลับ การมี URL คงที่ไม่ได้หมายความว่าเซิร์ฟเวอร์จะออนไลน์เมื่อเครื่องปิดอยู่
|
|
96
|
+
|
|
97
|
+
หมายเหตุ: `expose.sh` ไม่ดาวน์โหลด ngrok ให้อัตโนมัติ เพราะต้องใช้ binary ที่เหมาะกับระบบปฏิบัติการ/สถาปัตยกรรมของเครื่อง โดยเฉพาะ Android/Termux อาจต้องใช้วิธีติดตั้งที่รองรับ Termux โดยตรง
|
|
98
|
+
|
|
99
|
+
เมื่อเริ่มสำเร็จ ให้เอา `MCP URL` ที่สคริปต์แสดงไปใส่ Settings > Apps > Advanced > Developer Mode > Add connector (ไม่ต้องตั้ง token)
|
|
100
|
+
|
|
101
|
+
## Embedded UI in ChatGPT
|
|
102
|
+
|
|
103
|
+
When connected through a ChatGPT MCP connector that supports MCP Apps, call `open_workspace` to render the responsive Dots Workspace panel. It provides Overview, Tasks, Memory, Activity/Schedules and Rules views. This is an embedded app surface; it cannot change ChatGPT's global sidebar, composer, or native Codex interface. Use MCP SDK v2 for the interactive UI path; the older SDK fallback returns text only.
|
|
104
|
+
|
|
105
|
+
## Env
|
|
106
|
+
|
|
107
|
+
| ตัวแปร | ค่าเริ่มต้น | หมายถึง |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `MCP_HOST` / `MCP_PORT` | `127.0.0.1` / `33041` | bind server |
|
|
110
|
+
| `MCP_PUBLIC_HOST` | `""` | tunnel host ที่ allow (`expose.sh` ตั้งให้เอง) |
|
|
111
|
+
| `DOT_MCP_DATA` | `~/.dot-mcp` | ที่เก็บ memory/state/inbox/schedules/oauth/audit |
|
|
112
|
+
| `MCP_TRUNC_LIMIT` | `8192` | ตัด stdout ยาวๆ แล้วให้ต่อด้วย `read_output` |
|
|
113
|
+
| `MCP_RATE_MCP_PER_MIN` | `300` | rate limit ต่อ IP บน `/mcp*` (เกิน → 429) |
|
|
114
|
+
| `MCP_RATE_AUTH_PER_MIN` | `30` | rate limit ต่อ IP บน `/register` `/authorize` `/token` |
|
|
115
|
+
| `MCP_SESSION_CAP` | `50` | จำนวน background session สูงสุด |
|
|
116
|
+
| `HOME` / `TMPDIR` | — | `resolve()` จำกัด path อยู่ใน HOME/TMPDIR//sdcard, `/tmp` ถูก map ไป `$TMPDIR` (Android ไม่มี /tmp) |
|
|
117
|
+
|
|
118
|
+
ไฟล์ข้อมูล: `memory.json`, `state.json`, `inbox.json`, `schedules.json`, `oauth.json` (0600), `audit.jsonl`
|
|
119
|
+
|
|
120
|
+
## Files
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
src/dot_mcp/server.py # MCP server (22 tools + OAuth 2.1)
|
|
124
|
+
src/dot_mcp/cli.py # CLI: dot-mcp start/status/stop
|
|
125
|
+
src/dot_mcp/orchestrator.py # boot → tunnel → verify flow
|
|
126
|
+
src/dot_mcp/ui/workspace.html # embedded workspace UI (MCP Apps)
|
|
127
|
+
src/dot_mcp/local_agent.py # ChatGPT model + MCP local (ไม่ต้อง tunnel)
|
|
128
|
+
src/dot_mcp/agent_test.py # client smoke test
|
|
129
|
+
tests/test_server.py # pytest suite (รัน: .venv/bin/python -m pytest tests/ -q)
|
|
130
|
+
dots # repo shim (./dots start)
|
|
131
|
+
setup.sh / run.sh / test.sh / expose.sh
|
|
132
|
+
pyproject.toml # pip packaging (console scripts dot-mcp + dots)
|
|
133
|
+
requirements.txt # mcp>=1,<3, uvicorn>=0.30, rich>=13
|
|
134
|
+
bin/cloudflared # auto-download (arm64) — ไม่ commit
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Security
|
|
138
|
+
|
|
139
|
+
> ⚠️ **เซิร์ฟเวอร์นี้ให้ shell เต็มเครื่องแก่ผู้ถือ credential** — ถือว่าเป็น production
|
|
140
|
+
> เฉพาะเมื่อใช้คนเดียว + ปฏิบัติตามนี้
|
|
141
|
+
|
|
142
|
+
- `/mcp/` ต้องมี `Authorization: Bearer` เสมอ (JWT จาก OAuth หรือ owner secret) — ไม่มี = 401 แม้ localhost (ตั้งใจ: traffic จาก tunnel ดูเหมือน loopback แยกไม่ออก)
|
|
143
|
+
- Owner secret อยู่ใน header/consent form ไม่โผล่ใน URL; log (`mcp.log`, `tunnel.log`) ตั้ง `600` + ปิด access log; เปิด tunnel เฉพาะตอนใช้ + ปิดทันที
|
|
144
|
+
- Rate limit: `/mcp*` 300 req/min/IP, `/register` `/authorize` `/token` 30 req/min/IP (เกิน → 429) — ปรับผ่าน `MCP_RATE_MCP_PER_MIN` / `MCP_RATE_AUTH_PER_MIN`
|
|
145
|
+
- ทุก request ถูกบันทึก `audit.jsonl` (เวลา/IP/method/path/status/tool) — ตรวจย้อนหลังได้
|
|
146
|
+
- Consent POST ตรวจ `Origin`/`Referer` ว่าตรง issuer (กัน CSRF ข้ามเว็บ)
|
|
147
|
+
- Refresh token เก็บแบบ hash + หมุนทุกครั้งที่ใช้; JWT ตรวจลายเซ็น/issuer/audience/expiry/scope
|
|
148
|
+
- ไฟล์ state ล็อกข้าม process (`fcntl`) + เขียน atomic (tmp + rename) — รัน server ซ้อนกันไม่ทำข้อมูลพัง
|
|
149
|
+
- **ข้อจำกัดที่ต้องรู้:** provider ของ tunnel (tunnl/cloudflare) เห็น traffic เพราะ TLS จบที่ edge เขา; rate limit/audit เป็น per-process (รันหลาย process ให้นับแยกกัน); backup `~/.dot-mcp` เอง (ไม่มีระบบ backup ในตัว)
|
|
150
|
+
|
|
151
|
+
## OAuth (ChatGPT / Claude / Gemini)
|
|
152
|
+
|
|
153
|
+
ฟรี ทำเองในไฟล์เดียว ไม่ต้องมี IdP เจ้าอื่น — server นี้เป็นทั้งคนออกและคนตรวจ token:
|
|
154
|
+
|
|
155
|
+
- Metadata: `/.well-known/oauth-authorization-server` + `/.well-known/oauth-protected-resource`
|
|
156
|
+
- `POST /register` — Dynamic Client Registration (รับ `redirect_uris` https, หรือ `http://localhost`/`127.0.0.1`)
|
|
157
|
+
- `GET/POST /authorize` — หน้า consent ครั้งเดียว ปลดล็อกด้วย owner secret (code + PKCE S256, อายุ 10 นาที, ใช้ครั้งเดียว)
|
|
158
|
+
- `POST /token` — แลก code เป็น JWT (1 ชม.) + refresh token (30 วัน, หมุนทุกครั้งที่ใช้)
|
|
159
|
+
- เรียก MCP ใส่ `Authorization: Bearer <jwt>` ได้เลย (OAuth) หรือ `Bearer <owner secret>` (สคริปต์ local)
|
|
160
|
+
- ตั้งค่า connector: URL = `https://<host>/mcp/`, auth = OAuth, issuer = `https://<host>` (ดูจาก `/.well-known/...` ได้)
|
|
161
|
+
- connector แบบ DCR (ChatGPT) สมัคร client เอง + PKCE; แบบกรอกมือ (Claude) ใช้ **OAuth client ID/secret** ประจำเครื่องที่ `dots start` โชว์ (เก็บใน `oauth.json` 0600, ไม่ต้อง register)
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
MIT
|
dot_mcp-0.1.0/dots
ADDED