Skip to main content
Glama
README.md
# OMOS-MCP

MCP server ให้ AI agent (Claude, ChatGPT, Cursor ฯลฯ) อ่านเอกสารโปรเจคใน **OMOS Shared Drive** เพื่อตอบคำถาม — ทุกคำตอบอ้างอิงไฟล์ต้นทางพร้อม link Google Drive

โครงสร้าง Drive: **โฟลเดอร์ชั้นบนสุด = 1 โปรเจค (ชื่อโฟลเดอร์คือชื่อโปรเจค)** ข้างในจะจัดยังไงก็ได้ ไม่บังคับ structure

```
OMOS/
├── Project A/   ← ชื่อโปรเจค
│   └── ... (อะไรก็ได้)
└── Project B/
    └── ...
```

## Tools

| Tool | คำอธิบาย |
|------|----------|
| `omos_index` | หาโปรเจคจากชื่อ — ใส่ `filter` = คำที่ผู้ใช้พูด (ไทย/อังกฤษ) ไม่ใส่จะได้แค่ตัวอย่าง 10 ชื่อ (ปรับ `limit` ได้) agent เรียกอันนี้ก่อนเสมอ |
| `omos_list` | ไฟล์ทั้งหมดในโปรเจคที่ระบุ พร้อม id + link (ใส่ `subfolder` เพื่อดูเฉพาะบางส่วน) |
| `omos_search` | ค้นหา full-text ทั้ง Drive หรือเจาะเฉพาะโปรเจค |
| `omos_read` | อ่านไฟล์เป็น text — Google Docs/Sheets/Slides, PDF, .docx, .xlsx, md/text — ส่วนรูปภาพส่งเป็นรูปให้ agent ดูตรงๆ |
| `omos_refresh` | โหลดรายชื่อโปรเจคใหม่ทันที (ปกติ cache 5 นาที) |

Drive จริงมีหลักร้อยโปรเจคและไฟล์หลักหมื่น server จึงไม่เดินทั้ง Drive: อ่านเฉพาะที่ถูกถามถึง — `omos_index` = 1 API call, `omos_list` เดินเฉพาะ subtree ของโปรเจคนั้น, path ของผลลัพธ์ search/read resolve ทีละไฟล์ตอนใช้จริง

Flow ที่ฝังไว้ใน server instructions: `omos_index(filter=คำที่ผู้ใช้พูด)` → เทียบชื่อโปรเจค (ไม่ชัดให้ถามยืนยัน ห้ามเดาเงียบๆ) → `omos_list` หรือ `omos_search` เจาะโปรเจคนั้น → `omos_read` → ทุกคำตอบต้องอ้างอิงชื่อไฟล์พร้อม link

Drive จริงมีเกือบ 500 โปรเจค การเทชื่อทั้งหมดใส่ context ไม่ช่วยให้หาเจอ `omos_index` จึงเน้นให้ค้นด้วย `filter` แทน

## ตั้งค่าครั้งเดียว: Service Account

server เข้าถึง Drive ด้วย service account (ไม่ต้องให้ทุกคน login):

1. เข้า [console.cloud.google.com](https://console.cloud.google.com) → สร้าง project ใหม่ (หรือใช้ที่มีอยู่)
2. **APIs & Services → Library** → ค้นหา **Google Drive API** → กด **Enable**
3. **IAM & Admin → Service Accounts → Create Service Account** → ตั้งชื่อ เช่น `omos-mcp` → กด Create (ข้ามขั้นตอน role ได้เลย ไม่ต้องให้สิทธิ์อะไร)
4. เข้า service account ที่สร้าง → แท็บ **Keys → Add Key → Create new key → JSON** → ไฟล์ key จะดาวน์โหลดมา
5. copy อีเมลของ service account (หน้าตา `omos-mcp@<project>.iam.gserviceaccount.com`) ไป**แชร์ Shared Drive / โฟลเดอร์ OMOS** ให้อีเมลนี้เป็น **Viewer** (ถ้าจะใช้ [รับ transcript อัตโนมัติ](#รับ-transcript-อัตโนมัติ-post-transcripts) ต้องให้เป็น **Content manager** เพราะต้องเขียนไฟล์ได้)
6. หา **folder id** ของ root OMOS: เปิดโฟลเดอร์ใน browser แล้วดู URL `https://drive.google.com/drive/folders/<อันนี้คือ id>`

## Environment Variables

| ตัวแปร | คำอธิบาย |
|--------|----------|
| `OMOS_ROOT_FOLDER_ID` | folder id ของ root OMOS (จากขั้นตอนที่ 6) — **บังคับ** |
| `GOOGLE_SERVICE_ACCOUNT_JSON` | เนื้อไฟล์ key JSON ทั้งก้อน หรือ path ไปยังไฟล์ — **บังคับ** |
| `OMOS_AUTH_TOKEN` | (HTTP mode) bearer token ที่ client ต้องส่งมา |
| `OMOS_INDEX_TTL` | อายุ cache ของรายชื่อโปรเจค เป็นวินาที (default 300) |
| `OMOS_INGEST_TOKEN` | token สำหรับ `POST /transcripts` (แยกจาก MCP token) — ไม่ตั้ง = endpoint ปิดใช้งาน |
| `OMOS_TRANSCRIPT_FOLDER` | ชื่อ subfolder ที่เก็บ transcript (default `Meeting Transcripts`) |
| `OMOS_DEADLINE` | เวลาสูงสุดต่อ 1 tool call เป็นวินาที (default 20) — เกินแล้วคืนผลเท่าที่ได้พร้อมคำเตือน |
| `OMOS_HTTP_TIMEOUT` | timeout ต่อ 1 request ที่ยิงไป Drive เป็นวินาที (default 20) |
| `OAUTH_ISSUER` / `OAUTH_AUDIENCE` / `PUBLIC_URL` | (HTTP mode) เปิดโหมด OAuth สำหรับ Claude.ai / ChatGPT เว็บ |
| `PORT` | (HTTP mode) port ที่ฟัง (default 8000) |

## รัน local

ติดตั้ง [uv](https://docs.astral.sh/uv/) ก่อน (`curl -LsSf https://astral.sh/uv/install.sh | sh`)

**1) ตั้งค่า `.env`** (server โหลดให้อัตโนมัติจาก root ของ repo):

```bash
cp .env.example .env
```

แก้ `.env` ใส่ `OMOS_ROOT_FOLDER_ID` และ path ไฟล์ key (เช่นวางไฟล์ key ไว้ที่ `./service-account.json` — gitignore ไว้ให้แล้ว)

**2) เชื่อมกับ Claude Code (stdio):**

```bash
claude mcp add omos -- uv run --directory "/path/to/OMOS-MCP" omos-mcp
```

Claude Desktop / Cursor / Windsurf — ใส่ใน MCP config:

```json
{
  "mcpServers": {
    "omos": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/OMOS-MCP", "omos-mcp"]
    }
  }
}
```

**3) ทดสอบ:** ถาม agent ว่า *"มีโปรเจคอะไรบ้างใน OMOS"* — ต้องได้รายชื่อโปรเจค แล้วถามต่อเจาะโปรเจคใดโปรเจคหนึ่งต้องได้ไฟล์พร้อม link

**(ทางเลือก) รันเป็น HTTP server ในเครื่อง:** เปิด `OMOS_AUTH_TOKEN` ใน `.env` แล้ว

```bash
uv run omos-mcp-http
```

endpoint อยู่ที่ `http://localhost:8000/mcp` เชื่อมด้วย:

```bash
claude mcp add --transport http omos http://localhost:8000/mcp -H "Authorization: Bearer <OMOS_AUTH_TOKEN>"
```

## รับ Transcript อัตโนมัติ (`POST /transcripts`)

สำหรับให้ระบบอื่น (เช่น **น้องจิก**) ส่ง transcript หลังประชุมจบ แล้ว OMOS หาโฟลเดอร์โปรเจคให้เอง บันทึกเป็น **Google Doc** ใน `<Project>/Meeting Transcripts/`

```bash
curl -X POST https://<app>.onrender.com/transcripts \
  -H "Authorization: Bearer $OMOS_INGEST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "project": "To Do List",
    "title": "Weekly sync",
    "date": "2026-09-03",
    "transcript": "...",
    "meeting_id": "zoom-8891",
    "translation": "..."
  }'
```

| field | บังคับ | หมายเหตุ |
|---|---|---|
| `project` | ✅ | ต้องตรงกับชื่อโฟลเดอร์ชั้นบนสุด **เป๊ะๆ** — ไม่มี fuzzy match |
| `title` / `date` | ✅ | ใช้ตั้งชื่อไฟล์: `2026-09-03 — Weekly sync` |
| `transcript` | ✅ | สูงสุด 1 MB (~350,000 ตัวอักษรไทย) |
| `meeting_id` | ➖ | **ควรส่ง** — ใช้กันไฟล์ซ้ำตอน retry |
| `translation` | ➖ | ต่อท้ายเป็นอีก section ในไฟล์เดียวกัน |

ตอบกลับ `{"status": "created"|"exists", "file_id", "link", "folder"}`

| HTTP | ความหมาย | `retryable` |
|---|---|---|
| `200` | บันทึกแล้ว (`created`) หรือเคยบันทึกไว้แล้ว (`exists`) | — |
| `400` | ข้อมูลไม่ครบ / ใหญ่เกิน | `false` |
| `401` | token ผิด | `false` |
| `403` | service account ไม่มีสิทธิ์เขียน | `false` |
| `404` | ไม่รู้จักชื่อโปรเจค | `false` |
| `409` | ชื่อโปรเจคซ้ำ ตัดสินไม่ได้ | `false` |
| `429` | ชน rate limit ของ Google | `true` |
| `502` | Drive ล่มชั่วคราว | `true` |
| `507` | Drive เต็ม / ปลายทางไม่ใช่ Shared Drive | `false` |

ทุก error body มี field `retryable` บอกตรงๆ ว่า retry แล้วมีโอกาสสำเร็จไหม — ผู้เรียกไม่ต้องจำ status code

📘 **สเปกเต็มสำหรับทีมที่จะเรียก API นี้: [docs/API.md](docs/API.md)**

> **ความปลอดภัย:** endpoint นี้เขียนไฟล์ได้ ต้องตั้ง `OMOS_INGEST_TOKEN` ถึงจะทำงาน (ไม่ตั้ง = ไม่มี route นี้อยู่เลย ตอบ 404 และ scope ของ service account เป็น `drive.readonly` เขียนอะไรไม่ได้) และโค้ด**สร้างไฟล์ใหม่อย่างเดียว ไม่มี update/delete** เขียนได้เฉพาะในโฟลเดอร์โปรเจคที่ resolve ได้แล้วเท่านั้น
>
> ⚠️ ฟีเจอร์นี้ต้องให้ service account มีสิทธิ์ **Content manager** (เขียนได้) บน Shared Drive และ scope จะเปลี่ยนเป็น `drive` อัตโนมัติเมื่อตั้ง token — ถ้าใช้แค่ฝั่งอ่าน ไม่ต้องตั้ง `OMOS_INGEST_TOKEN` ก็ได้
>
> **ลำดับสำคัญ:** ให้สิทธิ์ Content manager **ก่อน** แล้วค่อยตั้ง token — ถ้าสลับกัน transcript ที่ส่งเข้ามาช่วงนั้นจะได้ `403` พร้อม `retryable: false` ผู้เรียกจะไม่ส่งซ้ำ ข้อมูลหายถาวร

## เรื่อง timeout

Drive ใหญ่ + Render free tier ทำให้ tool call ถูก client ตัดได้ ฝั่ง server จัดการให้แล้ว: ทุก tool มี **deadline 20 วินาที** ถ้าไม่ทันจะ**คืนผลเท่าที่ได้พร้อมคำเตือนว่ายังไม่ครบ** (ไม่ใช่ error เปล่าๆ) ปรับได้ที่ `OMOS_DEADLINE`

สองอย่างที่ต้องทำเองถ้ายังเจอ timeout:

**1) ขยาย timeout ฝั่ง client** — Claude Code ตั้งได้ (หน่วยมิลลิวินาที):

```bash
claude mcp add --transport http omos https://<app>.onrender.com/mcp -e MCP_TOOL_TIMEOUT=120000
```

> Claude.ai เว็บ / Cowork ตั้งค่านี้ไม่ได้ — ต้องพึ่ง deadline ฝั่ง server อย่างเดียว

**2) กัน Render หลับ** — free tier จะ spin down เมื่อไม่มีคนใช้ request แรกหลังหลับจะช้า 50 วินาทีขึ้นไป (มักโดน timeout พอดี) แก้ได้ 2 ทาง:
- ตั้ง cron ฟรี (เช่น [cron-job.org](https://cron-job.org)) ยิง `https://<app>.onrender.com/healthz` ทุก 10 นาที
- หรืออัพเป็น Render Starter (~$7/เดือน) แล้วไม่หลับเลย

## Deploy เป็น MCP link (Render)

1. Push repo นี้ขึ้น GitHub (มี `Dockerfile` + `render.yaml` ให้แล้ว)
2. Render → **New → Blueprint** → เลือก repo นี้
3. ตั้ง env ใน dashboard:
   - `OMOS_ROOT_FOLDER_ID` = folder id ของ root OMOS
   - `GOOGLE_SERVICE_ACCOUNT_JSON` = เนื้อไฟล์ key JSON ทั้งก้อน (paste ตรงๆ)
   - `OMOS_AUTH_TOKEN` Render สุ่มให้เอง → ก็อปไปแจกทีม
4. Deploy เสร็จ → endpoint คือ `https://<app>.onrender.com/mcp`

ผู้ใช้เชื่อมต่อ:

```bash
claude mcp add --transport http omos https://<app>.onrender.com/mcp \
  -H "Authorization: Bearer <OMOS_AUTH_TOKEN>"
```

Cursor / VS Code: ใส่ URL + header `Authorization: Bearer <token>` ใน MCP config

### ให้ Claude.ai / ChatGPT (เว็บ) ใช้ — OAuth

เว็บ client ไม่มีช่องใส่ header ต้องใช้ OAuth ผ่าน provider เช่น **WorkOS AuthKit** (ฟรีถึง 1M users):

1. สมัคร [workos.com](https://workos.com) → เปิดใช้ AuthKit → ตั้งวิธี login + จำกัดเฉพาะคนในทีม
2. Dashboard → Connect → Configuration → เปิด **Client ID Metadata Document** และ **Dynamic Client Registration**
3. เพิ่ม **Resource Indicator** = `https://<app>.onrender.com` (ไม่มี `/mcp`)
4. ตั้ง env บน Render เพิ่ม 3 ตัว: `OAUTH_ISSUER` = AuthKit domain, `OAUTH_AUDIENCE` = `https://<app>.onrender.com`, `PUBLIC_URL` = `https://<app>.onrender.com`
5. ผู้ใช้: Claude.ai → Settings → Connectors → Add custom connector → ใส่ `https://<app>.onrender.com/mcp` → login ผ่าน WorkOS

> โหมด OAuth กับ bearer token อยู่ด้วยกันได้ — เว็บใช้ OAuth, CLI ยังใช้ token ได้

## ทดสอบ (converters + thread safety + การอ่านแบบ lazy)

```bash
uv run python test_convert.py
uv run python test_ingest.py
```

TDQS

A4.4/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: omos_index provides the full index, omos_search performs full-text search with optional filters, omos_refresh rebuilds the index, and omos_read reads file content. There is no overlap or ambiguity between them.

Naming Consistency5/5

All tools follow a consistent 'omos_<verb>' pattern (index, search, refresh, read). The naming is predictable and uniform, making it easy for an agent to understand the action each tool performs.

Tool Count5/5

With 4 tools, the set is well-scoped for a drive retrieval server. Each tool addresses a necessary function (listing, searching, refreshing, reading) without being too few or excessive. The count matches the domain's core operations.

Completeness5/5

The tool surface covers the full read lifecycle for the OMOS drive: obtaining the index, searching, refreshing for updates, and reading file content. No obvious gaps exist for a retrieval-focused server; all necessary operations are present.

Maintenance

ActivityMaintained
ResponsivenessNo issues