{"record":{"id":"5880b73624b8c3ab","repo":"toeverything/AFFiNE","slug":"mcp-write-tools-are-not-available","errorCode":null,"errorMessage":"MCP write tools are not available","messagePattern":"MCP write tools are not available","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"packages/backend/server/src/plugins/copilot/mcp/resolver.ts","lineNumber":125,"sourceCode":"    return await this.credentials.list(user.id, workspaceId);\n  }\n\n  @Query(() => Boolean)\n  mcpCredentialReadWriteAvailable() {\n    return env.dev || env.namespaces.canary;\n  }\n\n  @Mutation(() => RevealedMcpCredentialType)\n  async createMcpCredential(\n    @CurrentUser() user: CurrentUser,\n    @Args('input') input: CreateMcpCredentialInput\n  ) {\n    if (\n      input.accessMode === McpAccessMode.READ_WRITE &&\n      !env.dev &&\n      !env.namespaces.canary\n    ) {\n      throw new BadRequestException('MCP write tools are not available');\n    }\n    await this.ac\n      .user(user.id)\n      .workspace(input.workspaceId)\n      .assert('Workspace.Read');\n    return await this.credentials.create({ ...input, userId: user.id });\n  }\n\n  @Mutation(() => RevealedMcpCredentialType)\n  async rotateMcpCredential(\n    @CurrentUser() user: CurrentUser,\n    @Args('id', { type: () => ID }) id: string,\n    @Args('workspaceId') workspaceId: string,\n    @Args('expirationDays', { type: () => Int, defaultValue: 90 })\n    expirationDays: number\n  ) {\n    await this.ac.user(user.id).workspace(workspaceId).assert('Workspace.Read');\n    return await this.credentials.rotate(","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/plugins/copilot/mcp/resolver.ts#L107-L143","documentation":"BadRequestException('MCP write tools are not available') from the createMcpCredential GraphQL mutation: requesting accessMode READ_WRITE is only allowed when env.dev is true or the deployment's namespaces.canary flag is set. On production namespaces, write-capable MCP credentials are feature-flagged off, so only READ may be issued.","triggerScenarios":"Calling createMcpCredential with accessMode: READ_WRITE on a production deployment; canary flag not set in the release environment; dev flag accidentally false in local docker-compose.","commonSituations":"Feature ships to canary but the client is pointed at prod; environment misconfiguration where canary namespace label is missing; users requesting write credentials before GA of the feature.","solutions":["Use accessMode: READ on non-canary production deployments","To test write tools locally, set the dev environment flag (env.dev = true)","To enable writes for a deployment, run it in the canary namespace (env.namespaces.canary)","Client-side: hide/disable the READ_WRITE option based on a server capability flag instead of letting users hit the 400"],"exampleFix":"// before\nawait graphql(`mutation { createMcpCredential(input: { accessMode: READ_WRITE, ... }) }`);\n\n// after\nconst accessMode = canaryOrDev ? 'READ_WRITE' : 'READ';\nawait graphql(`mutation { createMcpCredential(input: { accessMode: ${accessMode}, ... }) }`);","handlingStrategy":"validation","validationCode":"const canWrite = env.dev || env.namespaces.canary; // mirror server flags\nconst accessMode = canWrite ? 'READ_WRITE' : 'READ';\nif (input.accessMode === 'READ_WRITE' && !canWrite) input.accessMode = 'READ';\nawait createMcpCredential(input);","typeGuard":"const isAllowedAccessMode = (mode: string, canWrite: boolean): mode is 'READ' | 'READ_WRITE' =>\n  mode === 'READ' || (mode === 'READ_WRITE' && canWrite);","tryCatchPattern":"try {\n  await createMcpCredential(input);\n} catch (e) {\n  if (e instanceof BadRequestException && /write tools/.test(e.message)) {\n    input.accessMode = 'READ';\n    await createMcpCredential(input);\n  } else throw e;\n}","preventionTips":["Expose a server capability flag for MCP write support and gate the UI option on it","Default forms to READ on production deployments","Read the deployment's namespace config before requesting write credentials"],"tags":["mcp","credential","feature-flag","access-mode"],"backgroundTag":"feature-flag-disabled","analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}