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.
@@ -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
@@ -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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env python3
2
+ """Repo shim: use the CLI straight from a source checkout."""
3
+ import os, sys
4
+
5
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "src"))
6
+ from dot_mcp.cli import main
7
+
8
+ raise SystemExit(main())