feat(core): improve mcp management (#15221)

#### PR Dependency Tree


* **PR #15221** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added MCP credential management (create/reveal, list, rotate, revoke)
with expiration and status tracking.
* Introduced read-only vs read/write access modes, with read/write
tooling enabled only when permitted.
* Added workspace MCP credential configuration UI, including token
reveal and setup generation.
  * Added MCP credential GraphQL APIs to back the UI.
* **Changes**
* Replaced legacy access-token support with MCP credentials across
authentication and realtime updates.
* **Bug Fixes**
* MCP authentication now reliably rejects revoked, rotated, expired, or
disabled-user credentials.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-07-12 19:30:44 +08:00
committed by GitHub
parent abf37d3dfa
commit 9b81c6debd
57 changed files with 2180 additions and 1213 deletions
+41 -23
View File
@@ -2,13 +2,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
# ------------------------------------------------------
type AccessToken {
createdAt: DateTime!
expiresAt: DateTime
id: String!
name: String!
}
input AddContextBlobInput {
blobId: String!
contextId: String!
@@ -810,6 +803,13 @@ input CreateCheckoutSessionInput {
variant: SubscriptionVariant
}
input CreateMcpCredentialInput {
accessMode: McpAccessMode! = READ_ONLY
expirationDays: Int! = 90
name: String!
workspaceId: String!
}
input CreateUserInput {
email: String!
name: String
@@ -1196,11 +1196,6 @@ input ForkChatSessionInput {
workspaceId: String!
}
input GenerateAccessTokenInput {
expiresAt: DateTime
name: String!
}
input GrantDocUserRolesInput {
docId: String!
role: DocRole!
@@ -1533,6 +1528,33 @@ input ManageUserInput {
name: String
}
enum McpAccessMode {
READ_ONLY
READ_WRITE
}
enum McpCredentialStatus {
ACTIVE
EXPIRED
EXPIRING
REVOKED
ROTATING
}
type McpCredentialType {
accessMode: McpAccessMode!
createdAt: DateTime!
expiresAt: DateTime!
fingerprint: String!
graceEndsAt: DateTime
id: ID!
lastUsedAt: DateTime
name: String!
revokedAt: DateTime
status: McpCredentialStatus!
workspaceId: String!
}
type MeetingActionItemType {
deadline: String
description: String!
@@ -1657,6 +1679,7 @@ type Mutation {
"""Create a stripe customer portal to manage payment methods"""
createCustomerPortal: String!
createInviteLink(expireTime: WorkspaceInviteLinkExpireTime!, workspaceId: String!): InviteLink!
createMcpCredential(input: CreateMcpCredentialInput!): RevealedMcpCredentialType!
createReply(input: ReplyCreateInput!): ReplyObjectType!
createSelfhostWorkspaceCustomerPortal(workspaceId: String!): String!
@@ -1688,7 +1711,6 @@ type Mutation {
"""Create a chat session"""
forkCopilotSession(options: ForkChatSessionInput!): String!
generateLicenseKey(sessionId: String!): String!
generateUserAccessToken(input: GenerateAccessTokenInput!): RevealedAccessToken!
grantCommercialEntitlement(plan: String!, quantity: Int, targetId: String!, targetType: String!): Boolean!
grantDocUserRoles(input: GrantDocUserRolesInput!): Boolean!
grantMember(permission: Permission!, userId: String!, workspaceId: String!): Boolean!
@@ -1749,10 +1771,11 @@ type Mutation {
revokeCommercialEntitlement(targetId: String!, targetType: String!): Boolean!
revokeDocUserRoles(input: RevokeDocUserRoleInput!): Boolean!
revokeInviteLink(workspaceId: String!): Boolean!
revokeMcpCredential(id: ID!, workspaceId: String!): Boolean!
revokeMember(userId: String!, workspaceId: String!): Boolean!
revokePublicDoc(docId: String!, workspaceId: String!): DocType!
revokeUserAccessToken(id: String!): Boolean!
rotateAuthSigningKey(expectedActiveKeyId: String!): [AuthSigningKeyType!]!
rotateMcpCredential(expirationDays: Int! = 90, id: ID!, workspaceId: String!): RevealedMcpCredentialType!
sendChangeEmail(callbackUrl: String!): Boolean!
sendChangePasswordEmail(callbackUrl: String!, email: String @deprecated(reason: "fetched from signed in user")): Boolean!
sendSetPasswordEmail(callbackUrl: String!, email: String @deprecated(reason: "fetched from signed in user")): Boolean!
@@ -2031,6 +2054,8 @@ type Query {
"""get workspace invitation info"""
getInviteInfo(inviteId: String!): InvitationType!
mcpCredentialReadWriteAvailable: Boolean!
mcpCredentials(workspaceId: String!): [McpCredentialType!]!
prices: [SubscriptionPrice!]!
"""Get public user by id"""
@@ -2038,7 +2063,6 @@ type Query {
"""query workspace embedding status"""
queryWorkspaceEmbeddingStatus(workspaceId: String!): ContextWorkspaceEmbeddingStatus! @deprecated(reason: "Use realtime subscription \"workspace.embedding.progress.changed\" instead.")
revealedAccessTokens: [RevealedAccessToken!]! @deprecated(reason: "use currentUser.revealedAccessTokens")
"""server config"""
serverConfig: ServerConfigType!
@@ -2173,11 +2197,8 @@ type ResponseTooLargeErrorDataType {
receivedBytes: Int!
}
type RevealedAccessToken {
createdAt: DateTime!
expiresAt: DateTime
id: String!
name: String!
type RevealedMcpCredentialType {
credential: McpCredentialType!
token: String!
}
@@ -2700,8 +2721,6 @@ type UserSettingsType {
}
type UserType {
accessTokens: [AccessToken!]!
"""User avatar url"""
avatarUrl: String
calendarAccounts: [CalendarAccountObjectType!]!
@@ -2737,7 +2756,6 @@ type UserType {
notifications(pagination: PaginationInput!): PaginatedNotificationObjectType!
quota: UserQuotaType!
quotaUsage: UserQuotaUsageType!
revealedAccessTokens: [RevealedAccessToken!]!
"""Get user settings"""
settings: UserSettingsType!