Skip to content

[feature] MCP 加 list_my_invitations / accept_invitation:受邀者不用離開對話就能接受組織邀請 - #66

Merged
grace0950 merged 2 commits into
mainfrom
claude/ncp-invite-accept-9eea62
Sep 7, 2026
Merged

[feature] MCP 加 list_my_invitations / accept_invitation:受邀者不用離開對話就能接受組織邀請#66
grace0950 merged 2 commits into
mainfrom
claude/ncp-invite-accept-9eea62

Conversation

@grace0950

Copy link
Copy Markdown
Contributor

問題

帳號第一次連上 MCP(ChatGPT / Claude / Codex)時,如果它還不屬於任何組織,list_organizations 回空、所有 org-scoped 工具都報 No organization is associated with your account。就算管理者已經從 web 端 members 頁發了邀請,受邀者也得離開對話、開瀏覽器登入 /onboarding 按接受,才能回來繼續。這一段對「用 MCP 當主要入口」的人來說是斷點。

修法

MCP server 補上受邀者這一側的兩支工具(src/lib/mcp/tools-org.ts):

工具 類型 做什麼
list_my_invitations [read] 列出自己 email 名下、status 仍是 pending 的邀請。帶 expired 旗標 —— better-auth 從不把過期邀請改成 expired,「pending 但已過期」是常態,得自己判。
accept_invitation [write] invitationId(或 organizationId,當該組織只有一筆有效邀請時)接受邀請:寫 member 列、邀請標 accepted,回傳之後要用的 organizationId

為什麼不直接呼叫 auth.api.acceptInvitation:它掛在 orgSessionMiddleware 後面,需要 session cookie;MCP 的 OAuth bearer token 只給我們 userId。所以照 better-auth 自己的 accept route(plugins/organization/routes/crud-invites)把檢查一條條重做:pending、未過期、email 相符(不分大小寫)、成員數上限(100,plugin 預設)。唯一差別是不更新 session 的 activeOrganizationId —— MCP 沒有 session,而 src/lib/session.ts 本來就會在 active org 為空時回退到第一個 membership。

neon-http 沒有 transaction,寫入順序刻意是「先 member、後 invitation」:中間斷掉留下的是「已是成員 + 邀請仍 pending」,重跑會走 alreadyMember 修復路徑把邀請收掉;反過來會變成「邀請 accepted 但人不在組織裡」,無法從 MCP 自救。邀請的 update 帶 status = 'pending' 條件,兩個 client 同時接受時第二個會拿到明確錯誤。

sequenceDiagram
  participant M as MCP client
  participant S as /mcp
  participant DB
  M->>S: list_organizations
  S-->>M: [] (instructions: 去看 list_my_invitations)
  M->>S: list_my_invitations
  S->>DB: invitation ⋈ organization ⋈ user(inviter) where lower(email)=me and status=pending
  S-->>M: items[{id, organizationId, expired, …}]
  M->>S: accept_invitation {invitationId}
  S->>DB: 檢查 pending/未過期/email/成員數 → insert member → update invitation status=accepted
  S-->>M: {organizationId, role, memberId, hint}
Loading

其他一起動的:

  • handler.tsSERVER_VERSION 1.2.0 → 1.3.0(client 以此 key 快取 tool list);instructions 加一句「list_organizations 空的時候走邀請流程,接受前先跟使用者確認」;title 覆寫;accept_invitation 的 audit log 改用回傳的 organizationId 定位組織(呼叫前那個組織還不是使用者的,resolveOrg(args) 會失敗)。
  • org.ts:帳號沒有任何組織時的錯誤訊息直接指向 list_my_invitations
  • docs/mcp.md:補 Invitations 段、工具數 68 → 70。

Schema 影響

無。只讀寫既有的 invitation / member 表,不需要 migration

驗證

  • tsc --noEmiteslintnext build 皆通過。
  • tools/list 經 handler 走一遍:70 支工具、兩支新工具的 annotations / title / outputSchema 正確。
  • 起了一個本機 Postgres 套 repo 的 auth migrations,用 mock.module("@/db")getDb 換成 bun-sql,跑 9 個 end-to-end 情境全過:email 大小寫不同仍能對上、expired 旗標、無參數報錯、走 handler 用 slug 接受並確認 member 列與邀請狀態、重複接受被擋、過期被擋、別人的邀請看不到、role 為 null 時預設 member、已是成員時只收邀請不重複建 member。測試檔與 DB 已清掉,沒有進 repo。

🤖 Generated with Claude Code

…組織邀請

- 新增 src/lib/mcp/tools-org.ts:列出自己 email 名下 pending 的邀請(含 expired 旗標),
  以及依 invitationId 或 organizationId 接受邀請(照 better-auth 的 accept route
  重做檢查:pending / 未過期 / email 相符 / 成員數上限,寫 member、邀請標 accepted)
- handler:SERVER_VERSION 1.2.0 → 1.3.0、instructions 指引空組織時走邀請流程、
  title 覆寫、accept 的 audit log 用回傳的 organizationId 定位組織
- org.ts:帳號沒有任何組織時的錯誤訊息改指向 list_my_invitations
- docs/mcp.md:補 Invitations 段、工具數 68 → 70

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

✅ SonarQube Quality Gate passed — pathorsAI_internal

0 open issues on this PR.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@yui0303 yui0303 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved.

@grace0950
grace0950 merged commit 68850d1 into main Sep 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants