fix(backend): stamp org-scoped organizationId on MCP group template server imports | ENG-213#306
Conversation
…erver imports | ENG-213
importTemplate now requires a valid AuthContext with organizationId and passes it
through syncTemplate → createGroupFromTemplate / updateGroupFromTemplate → createServer,
so every mcp_servers row created via template import is scoped to the caller's org.
syncAllTemplates (admin-only startup bootstrap) continues to pass null so
platform-seeded servers remain globally visible via the existing OR org_id IS NULL
fallback in the repo — backward-compatible.
- Thread organizationId: string through McpGroupsService.importTemplate
- Controller un-discards @CurrentAuth and throws UnauthorizedException early if
auth or organizationId is missing
- McpGroupsSeedingService.syncTemplate gains optional organizationId param (default null)
- createServer and updateGroupFromTemplate inline insert both stamp organizationId
- Tests: mcp-groups-seeding.service.spec.ts (create/update/skip/unknown slug paths)
mcp-groups.controller.spec.ts (null auth, null orgId, happy path)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: betterclever <paliwal.pranjal83@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0407032012
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const result: TemplateSyncResult = await this.seedingService.syncTemplate( | ||
| slug, | ||
| false, | ||
| organizationId, | ||
| ); |
There was a problem hiding this comment.
Seed per-org servers even when template hash is unchanged
importTemplate now passes organizationId into syncTemplate, but syncTemplate still short-circuits on the global mcp_groups.templateHash and does not verify that the calling org already has server rows; once one org has imported a slug, another org importing the same version can get skipped and no org-scoped servers are created for it. Because /mcp-servers queries are organization-filtered (org_id = current OR org_id IS NULL), that org can end up with no usable servers despite a successful import response.
Useful? React with 👍 / 👎.
| organizationId, | ||
| enabled: true, |
There was a problem hiding this comment.
Preserve tenant isolation when updating existing template servers
Only the insert branch now writes organizationId; when updateGroupFromTemplate finds an existing server by name, it updates that row without setting/scoping organizationId, so shared (NULL) or other-org rows remain reused and mutable during org imports. This means a template update/import path can still operate on non-tenant-scoped server records, undermining the isolation this change is intended to enforce.
Useful? React with 👍 / 👎.
Summary
Fixes a multi-tenant isolation bug where
importTemplatecreatedmcp_serversrows withorganization_id = NULL, causing all orgs to share the same template server instances (Org A enabling/disabling a tool affected Org B).mcp-groups.controller.ts): un-discards@CurrentAuth()onimportTemplate, throwsUnauthorizedExceptionearly ifauthororganizationIdis missing, passesauth.organizationIdto the servicemcp-groups.service.ts):importTemplatenow acceptsorganizationId: string(non-nullable) and threads it tosyncTemplatemcp-groups-seeding.service.ts):syncTemplategains anorganizationId: string | null = nullparam (default null for backward compat);createGroupFromTemplate,updateGroupFromTemplate, andcreateServerall stamporganizationIdon inserted server rowssyncAllTemplates(admin startup bootstrap) explicitly passesnull— platform-seeded servers remain globally visible via the existingOR org_id IS NULLfallback in the repoTest plan
mcp-groups-seeding.service.spec.ts— create path stampsorganizationId; bootstrap path stampsnull; update path stampsorganizationIdon new server inserts; skip path inserts nothing; unknown slug throwsmcp-groups.controller.spec.ts—nullauth throwsUnauthorizedException;nullorganizationId throwsUnauthorizedException; valid auth passesorganizationIdto serviceCloses ENG-213
🤖 Generated with Claude Code