Skip to content

refactor(mcp): rename packages/mcp-v2 to packages/mcp and de-version all user-visible surfaces - #6079

Merged
saddlepaddle merged 3 commits into
mainfrom
mcp-rework/rename-mcp-v2
Aug 1, 2026
Merged

saddlepaddle merged 3 commits into
mainfrom
mcp-rework/rename-mcp-v2

Conversation

@saddlepaddle

@saddlepaddle saddlepaddle commented Jul 31, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #6077 (needs the v1 package deleted first to free the name); retargets automatically as the stack merges.

Two commits:

1. Mechanical rename (git mv, history preserved):

2. De-versioning sweep — after this PR, the MCP is just "the MCP" everywhere a user can see:

  • Canonical URL is https://api.superset.sh/mcp in every advertised surface: docs (all 20 client-setup snippets + callout), marketing llms.txt, .well-known/mcp, server card, openapi (path entry + description), API root/404 hints, and the v1 410 hint. /api/v2/agent/mcp keeps serving forever as a legacy alias (its OAuth audience remains valid; fix(auth): accept /mcp alias as OAuth audience #6078 made /mcp valid too).
  • MCP server info name superset-v2 → superset; internal cosmetic strings ([mcp-v2] log prefix, mcp-v2-internal client id, caller request id prefix) de-versioned.

Deliberately kept (continuity, not user-visible): telemetry mcp_server: "superset-v2" (PostHog insights key on it) and the userAgent: "mcp-v2" pair matched by packages/trpc automation helpers.

Verify post-deploy: .well-known/mcp + server card advertise /mcp; claude mcp add --transport http https://api.superset.sh/mcp connects and lists tools; existing clients on the versioned URL unaffected.

https://claude.ai/code/session_01Kub4p3Eim9pc1qaRRmGea2

3. Handler inversion (third commit): the MCP implementation now physically lives at apps/api/src/app/mcp/route.ts (the canonical URL); apps/api/src/app/api/v2/agent/[transport]/route.ts is reduced to a 4-line re-export kept for already-configured clients. Both URLs serve byte-identical behavior.

Summary by CodeRabbit

  • New Features
    • Added /mcp as the primary MCP server endpoint with authentication and organization-aware access.
    • Added tools for agents, automations, hosts, projects, tasks, terminals, and workspaces.
    • Added support for MCP-based terminal, workspace, task, and automation management.
  • Bug Fixes
    • Updated redirects, metadata, API documentation, and client guidance to use the new endpoint.
  • Documentation
    • Updated MCP setup examples and documented the previous endpoint as a backward-compatible alias.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The MCP implementation moves from @superset/mcp-v2 to @superset/mcp. /mcp becomes the canonical authenticated server route, while /api/v2/agent/mcp remains a legacy alias. Tools, discovery metadata, OpenAPI output, and documentation use the new endpoint.

Changes

MCP migration

Layer / File(s) Summary
MCP package foundation
packages/mcp/src/auth.ts, packages/mcp/src/context-utils.ts, packages/mcp/src/host-service-client.ts, packages/mcp/src/index.ts, packages/mcp/src/server.ts, packages/mcp/tsconfig.json
Adds authentication context resolution, scoped JWT creation, host-service requests, public exports, and package configuration.
MCP tool registration and handlers
packages/mcp/src/tools/*
Registers tools for agents, automations, hosts, organization members, projects, tasks, terminals, and workspaces with validation and caller or host-service delegation.
Canonical MCP route and legacy alias
apps/api/src/app/mcp/route.ts, apps/api/src/app/api/v2/agent/[transport]/route.ts, apps/api/package.json
Moves authentication, server creation, telemetry, and streamable HTTP handling to /mcp. The former route re-exports the canonical handlers.
Endpoint metadata and migration guidance
apps/api/src/app/.well-known/mcp/*, apps/api/src/app/openapi.json/route.ts, apps/docs/content/docs/mcp-server.mdx, apps/marketing/src/lib/llms.ts
Advertises /mcp as the primary endpoint and documents /api/v2/agent/mcp as a legacy alias.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant MCPRoute
  participant AuthContext
  participant MCPServer
  participant HostService
  MCPClient->>MCPRoute: Request /mcp
  MCPRoute->>AuthContext: Resolve credentials and organization
  AuthContext-->>MCPRoute: MCP context and relay URL
  MCPRoute->>MCPServer: Create and connect server
  MCPServer->>HostService: Execute tool request
  HostService-->>MCPClient: MCP response
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the package rename, de-versioning, and user-visible MCP updates.
Description check ✅ Passed The description explains the changes, rationale, compatibility behavior, and verification steps, but does not include the template checklist.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mcp-rework/rename-mcp-v2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ghost

ghost commented Jul 31, 2026 •

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 6 individual chapters for you:

Title
1 Rename MCP package and update internal identifiers
2 Update API workspace dependencies and imports
3 Invert MCP route handlers for canonical URL
4 Update advertised MCP URLs and hints
5 De-version MCP setup documentation
6 Other changes
Open in Stage

Chapters generated by Stage for commit 7249a46 on Jul 31, 2026 11:53pm UTC.

@github-actions

github-actions Bot commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@saddlepaddle saddlepaddle changed the title refactor(mcp): rename packages/mcp-v2 to packages/mcp refactor(mcp): rename packages/mcp-v2 to packages/mcp and de-version all user-visible surfaces Jul 31, 2026
@saddlepaddle
saddlepaddle force-pushed the mcp-rework/rename-mcp-v2 branch from 8e38c7c to 08daae5 Compare July 31, 2026 23:44
@saddlepaddle
saddlepaddle changed the base branch from mcp-rework/e1-remove-v1-mcp to mcp-rework/e1-remove-v1-mcp-2 July 31, 2026 23:44
With the v1 server deleted, the -v2 suffix is an artifact. Directory,
package name, and import specifiers only — runtime identity strings
(server name, telemetry mcp_server, session userAgent) are unchanged
to preserve PostHog continuity and the automation-source check.

Claude-Session: https://claude.ai/code/session_01Kub4p3Eim9pc1qaRRmGea2
Canonical URL is now /mcp everywhere it is advertised (docs, llms.txt,
.well-known, server card, openapi, API hints, 410 hint); the versioned
path stays served as a legacy alias. Server info name drops the -v2
suffix. Telemetry mcp_server value and the session userAgent pair stay
superset-v2/mcp-v2 for PostHog and automation-source continuity.

Claude-Session: https://claude.ai/code/session_01Kub4p3Eim9pc1qaRRmGea2
…s the alias

The implementation now lives at the canonical /mcp route;
/api/v2/agent/[transport] is a thin re-export kept for
already-configured clients.

Claude-Session: https://claude.ai/code/session_01Kub4p3Eim9pc1qaRRmGea2

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (5)
apps/api/src/app/mcp/route.ts (1)

14-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate WWW-Authenticate/401 envelope logic.

unauthorizedResponse rebuilds the same Bearer realm="superset", resource_metadata="..." header construction and JSON error envelope shape found in unauthorized in apps/api/src/app/api/route.ts. Extract a shared helper for the header value and envelope so both authentication failure paths stay in sync. Divergence here would produce inconsistent OAuth discovery behavior between /mcp and other endpoints.

♻️ Proposed shared helper
// e.g. apps/api/src/lib/oauth-metadata.ts
export function buildBearerChallenge(req: Request): string {
	return `Bearer realm="superset", resource_metadata="${getOAuthProtectedResourceMetadataUrl(req)}"`;
}
 function unauthorizedResponse(req: Request, message: string): Response {
 	return new Response(
 		JSON.stringify({ error: { code: "UNAUTHORIZED", message } }),
 		{
 			status: 401,
 			headers: {
-				"WWW-Authenticate": `Bearer realm="superset", resource_metadata="${getOAuthProtectedResourceMetadataUrl(req)}"`,
+				"WWW-Authenticate": buildBearerChallenge(req),
 				"Content-Type": "application/json",
 			},
 		},
 	);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/app/mcp/route.ts` around lines 14 - 25, Extract the duplicated
OAuth authentication failure construction from unauthorizedResponse and the
unauthorized handler in the API route into shared helpers, including the Bearer
challenge built from getOAuthProtectedResourceMetadataUrl and the UNAUTHORIZED
JSON envelope. Update both callers to reuse these helpers while preserving the
401 status and consistent WWW-Authenticate and Content-Type headers.
packages/mcp/src/tools/workspaces/update.ts (1)

17-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider migrating from deprecated .uuid() chain to z.uuid().

z.string().uuid() still works in Zod 4 but is deprecated in favor of the top-level z.uuid(). Also confirm that workspace IDs conform to the stricter RFC 9562/4122 variant-bit validation Zod 4 now enforces, since some non-standard UUID-like values that passed before can now fail.

♻️ Proposed refactor
-			id: z.string().uuid().describe("Workspace UUID."),
+			id: z.uuid().describe("Workspace UUID."),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/workspaces/update.ts` at line 17, Update the workspace
ID schema in the relevant update tool definition from the deprecated
string-based UUID chain to Zod 4’s top-level UUID validator, and verify that
accepted workspace IDs meet its stricter RFC 9562/4122 variant-bit requirements
without adding a compatibility fallback.
packages/mcp/src/tools/automations/get_prompt.ts (1)

13-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Multiple tool files use deprecated Zod 4 chained string-format validators. All these sites use z.string().uuid() or z.string().datetime(). Zod 4.3.6 deprecates these chained forms in favor of top-level functions (z.uuid(), z.iso.datetime()) and plans to remove the chained forms in a future major version.

  • packages/mcp/src/tools/automations/get_prompt.ts#L13-L13: replace z.string().uuid() with z.uuid() for the id field.
  • packages/mcp/src/tools/automations/logs.ts#L13-L13: replace z.string().uuid() with z.uuid() for the automationId field.
  • packages/mcp/src/tools/automations/resume.ts#L13-L13: replace z.string().uuid() with z.uuid() for the id field.
  • packages/mcp/src/tools/automations/set_prompt.ts#L13-L13: replace z.string().uuid() with z.uuid() for the id field.
  • packages/mcp/src/tools/tasks/create.ts#L15-L36: replace z.string().uuid() with z.uuid() for statusId and assigneeId, and replace z.string().datetime() with z.iso.datetime() for dueDate.
  • packages/mcp/src/tools/workspaces/delete.ts#L17-L17: replace z.string().uuid() with z.uuid() for the id field.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/automations/get_prompt.ts` at line 13, Replace
deprecated chained Zod validators: in
packages/mcp/src/tools/automations/get_prompt.ts:13-13, logs.ts:13-13,
resume.ts:13-13, set_prompt.ts:13-13, and
packages/mcp/src/tools/workspaces/delete.ts:17-17, use z.uuid() for the
identified UUID fields; in packages/mcp/src/tools/tasks/create.ts:15-36, use
z.uuid() for statusId and assigneeId and z.iso.datetime() for dueDate.
packages/mcp/src/tools/tasks/update.ts (1)

13-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Migrate deprecated chained Zod string-format methods.

id, prUrl, and dueDate use .string().uuid(), .string().url(), and .string().datetime(). Zod v4 deprecates these chained forms in favor of top-level z.uuid(), z.url(), and z.iso.datetime(). The chained forms still work today but are scheduled for removal in a future major version.

This pattern repeats in automations/run.ts, tasks/delete.ts, tasks/list.ts, terminals/close.ts, terminals/create.ts, terminals/read.ts, terminals/send.ts, and workspaces/create.ts. Consider a single follow-up pass across the package.

Note: z.uuid() also validates the UUID variant bits more strictly (RFC 9562/4122) than the old chained check. Verify that existing UUID values in the system satisfy this stricter check before switching.

♻️ Proposed migration for this file
 		inputSchema: {
 			id: z
-				.string()
-				.uuid()
+				.uuid()
 				.describe("Task UUID. Use tasks_get to resolve a slug to UUID first."),
 			title: z.string().min(1).optional(),
 			description: z.string().nullish(),
-			statusId: z.string().uuid().optional(),
+			statusId: z.uuid().optional(),
 			priority: z.enum(["urgent", "high", "medium", "low", "none"]).optional(),
-			assigneeId: z.string().uuid().nullish(),
-			prUrl: z.string().url().nullish(),
+			assigneeId: z.uuid().nullish(),
+			prUrl: z.url().nullish(),
 			estimate: z.number().int().positive().nullish(),
-			dueDate: z.string().datetime().nullish().describe("ISO 8601 due date."),
+			dueDate: z.iso.datetime().nullish().describe("ISO 8601 due date."),
 			labels: z.array(z.string()).nullish(),
 		},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/tasks/update.ts` around lines 13 - 25, Replace the
deprecated chained Zod string-format validators in the update task schema: use
top-level z.uuid() for id and statusId, z.url() for prUrl, and z.iso.datetime()
for dueDate while preserving optional/nullish behavior and descriptions. Apply
the same migration pattern to the corresponding schemas in the other listed
task, terminal, automation, and workspace tools, after confirming existing UUID
values satisfy the stricter validation.
packages/mcp/src/tools/automations/create.ts (1)

37-46: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Verify the "one of" requirement is enforced somewhere.

The description says either v2ProjectId or v2WorkspaceId is required. The schema marks both fields optional. A call that omits both passes MCP input validation and only fails later, inside caller.automation.create.

Confirm that caller.automation.create rejects the case where both fields are missing with a clear error message. If it does not, add an explicit check in the handler.

🛡️ Proposed handler-level guard, if not already enforced downstream
 		handler: async (input, ctx) => {
+			if (!input.v2ProjectId && !input.v2WorkspaceId) {
+				throw new Error(
+					"Provide either v2ProjectId or v2WorkspaceId.",
+				);
+			}
 			const caller = createMcpCaller(ctx);
 			return caller.automation.create(input);
 		},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/automations/create.ts` around lines 37 - 46, Verify
that the handler or caller used by the automation creation flow rejects requests
where both v2ProjectId and v2WorkspaceId are absent, with a clear error message.
If caller.automation.create does not enforce this, add an explicit guard in the
create handler before invoking it; preserve acceptance when either identifier is
provided.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/mcp/src/host-service-client.ts`:
- Around line 40-44: Update hostServiceCall to bound its fetch request with an
abort signal and a finite timeout, ensuring unresponsive hosts fail promptly
with a clear timeout error. Pass the signal into the existing fetch call and
preserve the current method, headers, and body behavior.

In `@packages/mcp/src/tools/workspaces/create.ts`:
- Around line 31-45: Update the handler that dispatches through hostServiceCall
to validate that exactly one of the optional inputs, branch or pr, is provided
before dispatching. Reject requests where both are present or both are absent
with a clear validation error, while preserving dispatch for valid inputs;
implement this in the handler rather than applying refine to the raw inputSchema
shape.

---

Nitpick comments:
In `@apps/api/src/app/mcp/route.ts`:
- Around line 14-25: Extract the duplicated OAuth authentication failure
construction from unauthorizedResponse and the unauthorized handler in the API
route into shared helpers, including the Bearer challenge built from
getOAuthProtectedResourceMetadataUrl and the UNAUTHORIZED JSON envelope. Update
both callers to reuse these helpers while preserving the 401 status and
consistent WWW-Authenticate and Content-Type headers.

In `@packages/mcp/src/tools/automations/create.ts`:
- Around line 37-46: Verify that the handler or caller used by the automation
creation flow rejects requests where both v2ProjectId and v2WorkspaceId are
absent, with a clear error message. If caller.automation.create does not enforce
this, add an explicit guard in the create handler before invoking it; preserve
acceptance when either identifier is provided.

In `@packages/mcp/src/tools/automations/get_prompt.ts`:
- Line 13: Replace deprecated chained Zod validators: in
packages/mcp/src/tools/automations/get_prompt.ts:13-13, logs.ts:13-13,
resume.ts:13-13, set_prompt.ts:13-13, and
packages/mcp/src/tools/workspaces/delete.ts:17-17, use z.uuid() for the
identified UUID fields; in packages/mcp/src/tools/tasks/create.ts:15-36, use
z.uuid() for statusId and assigneeId and z.iso.datetime() for dueDate.

In `@packages/mcp/src/tools/tasks/update.ts`:
- Around line 13-25: Replace the deprecated chained Zod string-format validators
in the update task schema: use top-level z.uuid() for id and statusId, z.url()
for prUrl, and z.iso.datetime() for dueDate while preserving optional/nullish
behavior and descriptions. Apply the same migration pattern to the corresponding
schemas in the other listed task, terminal, automation, and workspace tools,
after confirming existing UUID values satisfy the stricter validation.

In `@packages/mcp/src/tools/workspaces/update.ts`:
- Line 17: Update the workspace ID schema in the relevant update tool definition
from the deprecated string-based UUID chain to Zod 4’s top-level UUID validator,
and verify that accepted workspace IDs meet its stricter RFC 9562/4122
variant-bit requirements without adding a compatibility fallback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b2b0b95-9293-4c56-9e8c-205ca0f039aa

📥 Commits

Reviewing files that changed from the base of the PR and between 0290c46 and 7249a46.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (55)
  • apps/api/package.json
  • apps/api/src/app/.well-known/mcp/route.ts
  • apps/api/src/app/.well-known/mcp/server-card.json/route.ts
  • apps/api/src/app/api/[...unmatched]/route.ts
  • apps/api/src/app/api/agent/[transport]/route.ts
  • apps/api/src/app/api/integrations/slack/events/utils/run-agent/mcp-clients.ts
  • apps/api/src/app/api/route.ts
  • apps/api/src/app/api/v2/agent/[transport]/route.ts
  • apps/api/src/app/mcp/route.ts
  • apps/api/src/app/openapi.json/route.ts
  • apps/docs/content/docs/mcp-server.mdx
  • apps/marketing/src/lib/llms.ts
  • packages/mcp/package.json
  • packages/mcp/src/auth.ts
  • packages/mcp/src/caller.ts
  • packages/mcp/src/context-utils.ts
  • packages/mcp/src/define-tool.ts
  • packages/mcp/src/host-service-client.ts
  • packages/mcp/src/in-memory.ts
  • packages/mcp/src/index.ts
  • packages/mcp/src/server.ts
  • packages/mcp/src/tools/agents/create.ts
  • packages/mcp/src/tools/agents/list.ts
  • packages/mcp/src/tools/automations/create.ts
  • packages/mcp/src/tools/automations/delete.ts
  • packages/mcp/src/tools/automations/get.ts
  • packages/mcp/src/tools/automations/get_prompt.ts
  • packages/mcp/src/tools/automations/list.ts
  • packages/mcp/src/tools/automations/logs.ts
  • packages/mcp/src/tools/automations/pause.ts
  • packages/mcp/src/tools/automations/resume.ts
  • packages/mcp/src/tools/automations/run.ts
  • packages/mcp/src/tools/automations/set_prompt.ts
  • packages/mcp/src/tools/automations/update.ts
  • packages/mcp/src/tools/hosts/list.ts
  • packages/mcp/src/tools/organization/members/list.ts
  • packages/mcp/src/tools/projects/list.ts
  • packages/mcp/src/tools/register.ts
  • packages/mcp/src/tools/tasks/create.ts
  • packages/mcp/src/tools/tasks/delete.ts
  • packages/mcp/src/tools/tasks/get.ts
  • packages/mcp/src/tools/tasks/list.ts
  • packages/mcp/src/tools/tasks/statuses/list.ts
  • packages/mcp/src/tools/tasks/update.ts
  • packages/mcp/src/tools/terminals/close.ts
  • packages/mcp/src/tools/terminals/create.ts
  • packages/mcp/src/tools/terminals/list.ts
  • packages/mcp/src/tools/terminals/read.ts
  • packages/mcp/src/tools/terminals/send.ts
  • packages/mcp/src/tools/workspaces/create.ts
  • packages/mcp/src/tools/workspaces/delete.ts
  • packages/mcp/src/tools/workspaces/list.ts
  • packages/mcp/src/tools/workspaces/update.ts
  • packages/mcp/tsconfig.json
  • packages/shared/src/constants.ts
💤 Files with no reviewable changes (1)
  • packages/shared/src/constants.ts

@coderabbitai coderabbitai Bot 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🧹 Nitpick comments (5)
apps/api/src/app/mcp/route.ts (1)

14-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate WWW-Authenticate/401 envelope logic.

unauthorizedResponse rebuilds the same Bearer realm="superset", resource_metadata="..." header construction and JSON error envelope shape found in unauthorized in apps/api/src/app/api/route.ts. Extract a shared helper for the header value and envelope so both authentication failure paths stay in sync. Divergence here would produce inconsistent OAuth discovery behavior between /mcp and other endpoints.

♻️ Proposed shared helper
// e.g. apps/api/src/lib/oauth-metadata.ts
export function buildBearerChallenge(req: Request): string {
	return `Bearer realm="superset", resource_metadata="${getOAuthProtectedResourceMetadataUrl(req)}"`;
}
 function unauthorizedResponse(req: Request, message: string): Response {
 	return new Response(
 		JSON.stringify({ error: { code: "UNAUTHORIZED", message } }),
 		{
 			status: 401,
 			headers: {
-				"WWW-Authenticate": `Bearer realm="superset", resource_metadata="${getOAuthProtectedResourceMetadataUrl(req)}"`,
+				"WWW-Authenticate": buildBearerChallenge(req),
 				"Content-Type": "application/json",
 			},
 		},
 	);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/app/mcp/route.ts` around lines 14 - 25, Extract the duplicated
OAuth authentication failure construction from unauthorizedResponse and the
unauthorized handler in the API route into shared helpers, including the Bearer
challenge built from getOAuthProtectedResourceMetadataUrl and the UNAUTHORIZED
JSON envelope. Update both callers to reuse these helpers while preserving the
401 status and consistent WWW-Authenticate and Content-Type headers.
packages/mcp/src/tools/workspaces/update.ts (1)

17-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider migrating from deprecated .uuid() chain to z.uuid().

z.string().uuid() still works in Zod 4 but is deprecated in favor of the top-level z.uuid(). Also confirm that workspace IDs conform to the stricter RFC 9562/4122 variant-bit validation Zod 4 now enforces, since some non-standard UUID-like values that passed before can now fail.

♻️ Proposed refactor
-			id: z.string().uuid().describe("Workspace UUID."),
+			id: z.uuid().describe("Workspace UUID."),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/workspaces/update.ts` at line 17, Update the workspace
ID schema in the relevant update tool definition from the deprecated
string-based UUID chain to Zod 4’s top-level UUID validator, and verify that
accepted workspace IDs meet its stricter RFC 9562/4122 variant-bit requirements
without adding a compatibility fallback.
packages/mcp/src/tools/automations/get_prompt.ts (1)

13-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Multiple tool files use deprecated Zod 4 chained string-format validators. All these sites use z.string().uuid() or z.string().datetime(). Zod 4.3.6 deprecates these chained forms in favor of top-level functions (z.uuid(), z.iso.datetime()) and plans to remove the chained forms in a future major version.

  • packages/mcp/src/tools/automations/get_prompt.ts#L13-L13: replace z.string().uuid() with z.uuid() for the id field.
  • packages/mcp/src/tools/automations/logs.ts#L13-L13: replace z.string().uuid() with z.uuid() for the automationId field.
  • packages/mcp/src/tools/automations/resume.ts#L13-L13: replace z.string().uuid() with z.uuid() for the id field.
  • packages/mcp/src/tools/automations/set_prompt.ts#L13-L13: replace z.string().uuid() with z.uuid() for the id field.
  • packages/mcp/src/tools/tasks/create.ts#L15-L36: replace z.string().uuid() with z.uuid() for statusId and assigneeId, and replace z.string().datetime() with z.iso.datetime() for dueDate.
  • packages/mcp/src/tools/workspaces/delete.ts#L17-L17: replace z.string().uuid() with z.uuid() for the id field.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/automations/get_prompt.ts` at line 13, Replace
deprecated chained Zod validators: in
packages/mcp/src/tools/automations/get_prompt.ts:13-13, logs.ts:13-13,
resume.ts:13-13, set_prompt.ts:13-13, and
packages/mcp/src/tools/workspaces/delete.ts:17-17, use z.uuid() for the
identified UUID fields; in packages/mcp/src/tools/tasks/create.ts:15-36, use
z.uuid() for statusId and assigneeId and z.iso.datetime() for dueDate.
packages/mcp/src/tools/tasks/update.ts (1)

13-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Migrate deprecated chained Zod string-format methods.

id, prUrl, and dueDate use .string().uuid(), .string().url(), and .string().datetime(). Zod v4 deprecates these chained forms in favor of top-level z.uuid(), z.url(), and z.iso.datetime(). The chained forms still work today but are scheduled for removal in a future major version.

This pattern repeats in automations/run.ts, tasks/delete.ts, tasks/list.ts, terminals/close.ts, terminals/create.ts, terminals/read.ts, terminals/send.ts, and workspaces/create.ts. Consider a single follow-up pass across the package.

Note: z.uuid() also validates the UUID variant bits more strictly (RFC 9562/4122) than the old chained check. Verify that existing UUID values in the system satisfy this stricter check before switching.

♻️ Proposed migration for this file
 		inputSchema: {
 			id: z
-				.string()
-				.uuid()
+				.uuid()
 				.describe("Task UUID. Use tasks_get to resolve a slug to UUID first."),
 			title: z.string().min(1).optional(),
 			description: z.string().nullish(),
-			statusId: z.string().uuid().optional(),
+			statusId: z.uuid().optional(),
 			priority: z.enum(["urgent", "high", "medium", "low", "none"]).optional(),
-			assigneeId: z.string().uuid().nullish(),
-			prUrl: z.string().url().nullish(),
+			assigneeId: z.uuid().nullish(),
+			prUrl: z.url().nullish(),
 			estimate: z.number().int().positive().nullish(),
-			dueDate: z.string().datetime().nullish().describe("ISO 8601 due date."),
+			dueDate: z.iso.datetime().nullish().describe("ISO 8601 due date."),
 			labels: z.array(z.string()).nullish(),
 		},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/tasks/update.ts` around lines 13 - 25, Replace the
deprecated chained Zod string-format validators in the update task schema: use
top-level z.uuid() for id and statusId, z.url() for prUrl, and z.iso.datetime()
for dueDate while preserving optional/nullish behavior and descriptions. Apply
the same migration pattern to the corresponding schemas in the other listed
task, terminal, automation, and workspace tools, after confirming existing UUID
values satisfy the stricter validation.
packages/mcp/src/tools/automations/create.ts (1)

37-46: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Verify the "one of" requirement is enforced somewhere.

The description says either v2ProjectId or v2WorkspaceId is required. The schema marks both fields optional. A call that omits both passes MCP input validation and only fails later, inside caller.automation.create.

Confirm that caller.automation.create rejects the case where both fields are missing with a clear error message. If it does not, add an explicit check in the handler.

🛡️ Proposed handler-level guard, if not already enforced downstream
 		handler: async (input, ctx) => {
+			if (!input.v2ProjectId && !input.v2WorkspaceId) {
+				throw new Error(
+					"Provide either v2ProjectId or v2WorkspaceId.",
+				);
+			}
 			const caller = createMcpCaller(ctx);
 			return caller.automation.create(input);
 		},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/automations/create.ts` around lines 37 - 46, Verify
that the handler or caller used by the automation creation flow rejects requests
where both v2ProjectId and v2WorkspaceId are absent, with a clear error message.
If caller.automation.create does not enforce this, add an explicit guard in the
create handler before invoking it; preserve acceptance when either identifier is
provided.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/mcp/src/host-service-client.ts`:
- Around line 40-44: Update hostServiceCall to bound its fetch request with an
abort signal and a finite timeout, ensuring unresponsive hosts fail promptly
with a clear timeout error. Pass the signal into the existing fetch call and
preserve the current method, headers, and body behavior.

In `@packages/mcp/src/tools/workspaces/create.ts`:
- Around line 31-45: Update the handler that dispatches through hostServiceCall
to validate that exactly one of the optional inputs, branch or pr, is provided
before dispatching. Reject requests where both are present or both are absent
with a clear validation error, while preserving dispatch for valid inputs;
implement this in the handler rather than applying refine to the raw inputSchema
shape.

---

Nitpick comments:
In `@apps/api/src/app/mcp/route.ts`:
- Around line 14-25: Extract the duplicated OAuth authentication failure
construction from unauthorizedResponse and the unauthorized handler in the API
route into shared helpers, including the Bearer challenge built from
getOAuthProtectedResourceMetadataUrl and the UNAUTHORIZED JSON envelope. Update
both callers to reuse these helpers while preserving the 401 status and
consistent WWW-Authenticate and Content-Type headers.

In `@packages/mcp/src/tools/automations/create.ts`:
- Around line 37-46: Verify that the handler or caller used by the automation
creation flow rejects requests where both v2ProjectId and v2WorkspaceId are
absent, with a clear error message. If caller.automation.create does not enforce
this, add an explicit guard in the create handler before invoking it; preserve
acceptance when either identifier is provided.

In `@packages/mcp/src/tools/automations/get_prompt.ts`:
- Line 13: Replace deprecated chained Zod validators: in
packages/mcp/src/tools/automations/get_prompt.ts:13-13, logs.ts:13-13,
resume.ts:13-13, set_prompt.ts:13-13, and
packages/mcp/src/tools/workspaces/delete.ts:17-17, use z.uuid() for the
identified UUID fields; in packages/mcp/src/tools/tasks/create.ts:15-36, use
z.uuid() for statusId and assigneeId and z.iso.datetime() for dueDate.

In `@packages/mcp/src/tools/tasks/update.ts`:
- Around line 13-25: Replace the deprecated chained Zod string-format validators
in the update task schema: use top-level z.uuid() for id and statusId, z.url()
for prUrl, and z.iso.datetime() for dueDate while preserving optional/nullish
behavior and descriptions. Apply the same migration pattern to the corresponding
schemas in the other listed task, terminal, automation, and workspace tools,
after confirming existing UUID values satisfy the stricter validation.

In `@packages/mcp/src/tools/workspaces/update.ts`:
- Line 17: Update the workspace ID schema in the relevant update tool definition
from the deprecated string-based UUID chain to Zod 4’s top-level UUID validator,
and verify that accepted workspace IDs meet its stricter RFC 9562/4122
variant-bit requirements without adding a compatibility fallback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b2b0b95-9293-4c56-9e8c-205ca0f039aa

📥 Commits

Reviewing files that changed from the base of the PR and between 0290c46 and 7249a46.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (55)
  • apps/api/package.json
  • apps/api/src/app/.well-known/mcp/route.ts
  • apps/api/src/app/.well-known/mcp/server-card.json/route.ts
  • apps/api/src/app/api/[...unmatched]/route.ts
  • apps/api/src/app/api/agent/[transport]/route.ts
  • apps/api/src/app/api/integrations/slack/events/utils/run-agent/mcp-clients.ts
  • apps/api/src/app/api/route.ts
  • apps/api/src/app/api/v2/agent/[transport]/route.ts
  • apps/api/src/app/mcp/route.ts
  • apps/api/src/app/openapi.json/route.ts
  • apps/docs/content/docs/mcp-server.mdx
  • apps/marketing/src/lib/llms.ts
  • packages/mcp/package.json
  • packages/mcp/src/auth.ts
  • packages/mcp/src/caller.ts
  • packages/mcp/src/context-utils.ts
  • packages/mcp/src/define-tool.ts
  • packages/mcp/src/host-service-client.ts
  • packages/mcp/src/in-memory.ts
  • packages/mcp/src/index.ts
  • packages/mcp/src/server.ts
  • packages/mcp/src/tools/agents/create.ts
  • packages/mcp/src/tools/agents/list.ts
  • packages/mcp/src/tools/automations/create.ts
  • packages/mcp/src/tools/automations/delete.ts
  • packages/mcp/src/tools/automations/get.ts
  • packages/mcp/src/tools/automations/get_prompt.ts
  • packages/mcp/src/tools/automations/list.ts
  • packages/mcp/src/tools/automations/logs.ts
  • packages/mcp/src/tools/automations/pause.ts
  • packages/mcp/src/tools/automations/resume.ts
  • packages/mcp/src/tools/automations/run.ts
  • packages/mcp/src/tools/automations/set_prompt.ts
  • packages/mcp/src/tools/automations/update.ts
  • packages/mcp/src/tools/hosts/list.ts
  • packages/mcp/src/tools/organization/members/list.ts
  • packages/mcp/src/tools/projects/list.ts
  • packages/mcp/src/tools/register.ts
  • packages/mcp/src/tools/tasks/create.ts
  • packages/mcp/src/tools/tasks/delete.ts
  • packages/mcp/src/tools/tasks/get.ts
  • packages/mcp/src/tools/tasks/list.ts
  • packages/mcp/src/tools/tasks/statuses/list.ts
  • packages/mcp/src/tools/tasks/update.ts
  • packages/mcp/src/tools/terminals/close.ts
  • packages/mcp/src/tools/terminals/create.ts
  • packages/mcp/src/tools/terminals/list.ts
  • packages/mcp/src/tools/terminals/read.ts
  • packages/mcp/src/tools/terminals/send.ts
  • packages/mcp/src/tools/workspaces/create.ts
  • packages/mcp/src/tools/workspaces/delete.ts
  • packages/mcp/src/tools/workspaces/list.ts
  • packages/mcp/src/tools/workspaces/update.ts
  • packages/mcp/tsconfig.json
  • packages/shared/src/constants.ts
💤 Files with no reviewable changes (1)
  • packages/shared/src/constants.ts
🛑 Comments failed to post (2)
packages/mcp/src/host-service-client.ts (1)

40-44: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add a request timeout to hostServiceCall.

The fetch call has no timeout or abort signal. If a host is slow or unresponsive, the call can hang for the full route maxDuration (800 seconds per apps/api/src/app/mcp/route.ts). Every MCP tool that calls a host (agents, workspaces, terminals, projects) shares this risk through hostServiceCall.

Add a bounded timeout so a dead host fails fast with a clear error instead of hanging the request.

🔧 Proposed fix: bound the request with a timeout
 	const response = await fetch(url, {
 		method: method === "query" ? "GET" : "POST",
 		headers,
 		body,
+		signal: AbortSignal.timeout(30_000),
 	});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

	const response = await fetch(url, {
		method: method === "query" ? "GET" : "POST",
		headers,
		body,
		signal: AbortSignal.timeout(30_000),
	});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/host-service-client.ts` around lines 40 - 44, Update
hostServiceCall to bound its fetch request with an abort signal and a finite
timeout, ensuring unresponsive hosts fail promptly with a clear timeout error.
Pass the signal into the existing fetch call and preserve the current method,
headers, and body behavior.
packages/mcp/src/tools/workspaces/create.ts (1)

31-45: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Enforce "exactly one of branch or pr" before dispatching.

The description states that the caller must provide exactly one of branch or pr. The schema does not enforce this, and the handler does not check it either. If a caller passes both or neither, the request goes to hostServiceCall unvalidated, producing a less clear error for the calling agent.

Add an explicit check in the handler. Since defineTool's inputSchema is a raw shape (not a ZodObject), a schema-level .refine() is not directly available here.

🐛 Proposed handler-level check
 		handler: async (input, ctx) => {
+			if ((input.branch === undefined) === (input.pr === undefined)) {
+				throw new Error("Provide exactly one of `branch` or `pr`.");
+			}
 			return hostServiceCall<{

Also applies to: 73-77

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/mcp/src/tools/workspaces/create.ts` around lines 31 - 45, Update the
handler that dispatches through hostServiceCall to validate that exactly one of
the optional inputs, branch or pr, is provided before dispatching. Reject
requests where both are present or both are absent with a clear validation
error, while preserving dispatch for valid inputs; implement this in the handler
rather than applying refine to the raw inputSchema shape.

This branch was previously deployed

1 inactive deployment
preview — 7249a462 Deployed Jul 31, 2026 by saddlepaddle via Deploy Web #6962
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.

1 participant