feat(mcp): add native /mcp for cost control#4168
Conversation
| return NextResponse.json({ error: 'invalid_request' }, { status: 400 }); | ||
| } | ||
| const services = createGatewayServices(); | ||
| if (isNativeMcpResource(parsed.data.resource)) { |
There was a problem hiding this comment.
WARNING: Native refresh-token exchanges are dispatched incorrectly when resource is omitted
OAuthTokenRequestSchema makes resource optional, and the existing gateway token service already handles refresh requests without it. This branch only selects nativeMcpTokenService when the incoming request repeats resource=https://app.kilocode.ai/mcp, so a standards-compliant native refresh request that omits resource will fall through to tokenService.exchangeToken() and fail because the token is looked up in the wrong table.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| const services = createGatewayServices(); | ||
| try { | ||
| return await services.nativeMcpTokenVerifier.verify(token); | ||
| } catch { |
There was a problem hiding this comment.
WARNING: This collapses authorization failures into 401 invalid_token
verifyNativeMcpBearerToken() distinguishes bad tokens from missing mcp:access and from users who are no longer eligible, but this blanket catch converts every verifier error into the same OAuth challenge. That means a valid token without mcp:access now reports as invalid_token instead of insufficient_scope, and the forbidden path for revoked admin eligibility is hidden from clients too.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| if (type === 'timestamp') return new Date(String(value)).toISOString(); | ||
| if (type === 'integer') return Number(value); | ||
| if (type === 'decimal') return String(value); | ||
| if (type === 'boolean') return Boolean(value); |
There was a problem hiding this comment.
WARNING: Boolean serialization will invert string-backed Postgres values
tx.execute() can surface booleans as strings such as 't'/'f' or 'true'/'false' depending on the driver/query path. Boolean(value) treats any non-empty string as true, so fields like hasError, repositoryReviewInstructionsUsed, and isRoot can be silently flipped in the MCP response.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
| import { GatewayMcpAccessScope } from './types'; | ||
|
|
||
| export const NativeMcpResourcePath = '/mcp'; | ||
| export const NativeMcpResourceUrl = 'https://app.kilocode.ai/mcp'; |
There was a problem hiding this comment.
WARNING: The native MCP resource is hard-coded to production
Every challenge, protected-resource document, JWT aud check, and token claim now binds to https://app.kilocode.ai/mcp even when the app is running under another MCP_GATEWAY_APP_BASE_URL such as preview, staging, or local development. That breaks non-production discovery/token exchange and violates the exact-resource audience contract outside production.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
Code Review SummaryStatus: 4 Issues Found | Recommendation: Address before merge Fix these issues in Kilo Cloud Overview
Issue Details (click to expand)WARNING
Files Reviewed (31 files)
Reviewed by gpt-5.4-20260305 · Input: 181K · Output: 19.9K · Cached: 2.4M Review guidance: REVIEW.md from base branch |
Summary
Kilo now has a standard MCP endpoint for admins to read their own Kilo stats without setting custom headers. It uses the normal browser sign-in and OAuth flow, then gives MCP clients one read-only stats tool. Access is limited to Kilo org admins for the first rollout, and each query can only look at the signed-in user's last 60 days.
Verification
/mcpwithout a token and confirm it returns a401OAuth challenge.tools/list.query_kilo_datasetformicrodollar_usagewith a count metric and confirm it returns a structured result.Visual Changes
N/A
Reviewer Notes
This adds new OAuth tables and keeps the first rollout behind the Kilo org admin gate. The MCP tool returns aggregate and time series stats only, not raw rows.