[feature] MCP 加 list_my_invitations / accept_invitation:受邀者不用離開對話就能接受組織邀請 - #66
Merged
Conversation
…組織邀請 - 新增 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>
✅ SonarQube Quality Gate passed — pathorsAI_internal0 open issues on this PR. |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
問題
帳號第一次連上 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]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}其他一起動的:
handler.ts:SERVER_VERSION1.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 --noEmit、eslint、next build皆通過。tools/list經 handler 走一遍:70 支工具、兩支新工具的 annotations / title / outputSchema 正確。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