-
Notifications
You must be signed in to change notification settings - Fork 54
feat(playground): Add Connectors aka MCPs #958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…nents - Added functionality to handle GitHub personal access tokens for MCP tools. - Introduced a new button and dialog in the prompt input for token management. - Updated chat API to pass the GitHub token when available. - Removed the user provider component as it was no longer needed. - Enhanced state management for GitHub token in the API key hook.
❌ Preview Environment deleted from BunnyshellAvailable commands (reply to this comment):
|
WalkthroughEnables MCP initialization in the chat API when a GitHub token is provided, adds githubToken to request payloads from the UI, introduces a connectors button to manage the token via localStorage, passes tools to the LLM gateway stream, removes UserProvider, and extends the API key hook to manage GitHub token state. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as Playground UI
participant API as POST /api/chat
participant MCP as MCP Client
participant LLM as LLM Gateway
UI->>API: Send chat request {messages, model, githubToken?, apiKey?}
alt Authorized user missing
API-->>UI: 401 Unauthorized
else Valid request
opt githubToken provided
API->>MCP: Initialize transport (auth: githubToken)
MCP-->>API: Connected + tools
end
API->>LLM: stream({messages, model, tools?, apiKey/header})
alt Gateway success
LLM-->>API: Stream tokens/events
API-->>UI: Stream response
else Gateway failure
API-->>UI: 500 Error
end
end
sequenceDiagram
autonumber
participant User as User
participant UI as PromptInputConnectorsButton
participant LS as localStorage
participant Chat as chat-ui.tsx
User->>UI: Open Connectors dialog
User->>UI: Enter/clear GitHub token
UI->>LS: Save/remove llmgateway_github_token
Note over UI,Chat: Token change event dispatched
Chat->>LS: Read token when sending message
Chat->>API: Include githubToken in request payload
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/playground/src/app/api/chat/route.ts (1)
25-56
: Avoid caching the GitHub MCP client between requests
githubMCP
/tools
live at module scope, so the first request that supplies a token seeds a shared client for all subsequent requests (even for other users or when the token changes). That leaks credentials, reuses stale authorization, and lets tokenless calls keep using the prior user’s tools. Instantiate the MCP client inside the handler per request (or at least per token) instead of reusing a singleton.-let githubMCP: experimental_MCPClient | null = null; -let tools: any | null = null; +type MCPClientTools = Awaited< + ReturnType<experimental_MCPClient["tools"]> +> | undefined; export async function POST(req: Request) { const user = await getUser(); @@ - if (!githubMCP && githubToken) { - const transport = new StreamableHTTPClientTransport( + let tools: MCPClientTools; + if (githubToken) { + const transport = new StreamableHTTPClientTransport( new URL("https://api.githubcopilot.com/mcp"), { requestInit: { method: "POST", headers: { Authorization: `Bearer ${githubToken}`, }, }, }, ); - githubMCP = await experimental_createMCPClient({ transport }); - - if (!tools) { - tools = await githubMCP.tools(); - } + const githubMCP = await experimental_createMCPClient({ transport }); + tools = await githubMCP.tools(); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/playground/src/app/api/chat/route.ts
(3 hunks)apps/playground/src/components/ai-elements/prompt-input.tsx
(3 hunks)apps/playground/src/components/auth/user-provider.tsx
(0 hunks)apps/playground/src/components/playground/chat-ui.tsx
(5 hunks)apps/playground/src/hooks/useApiKey.ts
(3 hunks)
💤 Files with no reviewable changes (1)
- apps/playground/src/components/auth/user-provider.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Never useany
oras any
in this TypeScript project unless absolutely necessary
Always use top-levelimport
; never userequire
or dynamicimport()
Files:
apps/playground/src/components/playground/chat-ui.tsx
apps/playground/src/hooks/useApiKey.ts
apps/playground/src/components/ai-elements/prompt-input.tsx
apps/playground/src/app/api/chat/route.ts
{apps,packages}/**/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Always use top-level import; never use require() or dynamic import()
Files:
apps/playground/src/components/playground/chat-ui.tsx
apps/playground/src/hooks/useApiKey.ts
apps/playground/src/components/ai-elements/prompt-input.tsx
apps/playground/src/app/api/chat/route.ts
🧬 Code graph analysis (1)
apps/playground/src/components/playground/chat-ui.tsx (2)
apps/playground/src/components/ai-elements/tool.tsx (1)
ToolHeader
(64-87)apps/playground/src/components/ai-elements/prompt-input.tsx (1)
PromptInputConnectorsButton
(545-613)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: test / run
- GitHub Check: build / run
- GitHub Check: generate / run
- GitHub Check: lint / run
- GitHub Check: autofix
🔇 Additional comments (3)
apps/playground/src/components/playground/chat-ui.tsx (3)
204-210
: Nice UI improvement for tool headers.Passing the tool name into both the
type
andtitle
fields keeps the collapsible labels meaningful for MCP responses. Looks good.
308-314
: Good call on piping the GitHub token through the chat request.Fetching from
localStorage
with a browser guard and normalizing toundefined
fits the transport expectations cleanly.
342-348
: Appreciate the dedicated connectors entry point.Surfacing the GitHub token dialog alongside the existing tools menu keeps the UX focused without extra chrome.
const save = () => { | ||
if (typeof window !== "undefined") { | ||
if (token) { | ||
localStorage.setItem("llmgateway_github_token", token); | ||
} else { | ||
localStorage.removeItem("llmgateway_github_token"); | ||
} | ||
} | ||
setOpen(false); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dispatch the GitHub token change event after persisting
useApiKey
relies on the llmgateway_github_token_changed
custom event to refresh githubToken
. Saving here only mutates localStorage
, so components using useApiKey
keep the stale value, meaning chat requests continue without the new token until the page is reloaded. Please emit the event (and on clear as well) so in-tab consumers update immediately.
const save = () => {
if (typeof window !== "undefined") {
if (token) {
localStorage.setItem("llmgateway_github_token", token);
} else {
localStorage.removeItem("llmgateway_github_token");
}
+ window.dispatchEvent(new Event("llmgateway_github_token_changed"));
}
setOpen(false);
};
📝 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 save = () => { | |
if (typeof window !== "undefined") { | |
if (token) { | |
localStorage.setItem("llmgateway_github_token", token); | |
} else { | |
localStorage.removeItem("llmgateway_github_token"); | |
} | |
} | |
setOpen(false); | |
}; | |
const save = () => { | |
if (typeof window !== "undefined") { | |
if (token) { | |
localStorage.setItem("llmgateway_github_token", token); | |
} else { | |
localStorage.removeItem("llmgateway_github_token"); | |
} | |
window.dispatchEvent(new Event("llmgateway_github_token_changed")); | |
} | |
setOpen(false); | |
}; |
🤖 Prompt for AI Agents
In apps/playground/src/components/ai-elements/prompt-input.tsx around lines 557
to 566, saving/removing the GitHub token only updates localStorage which leaves
in-tab consumers using useApiKey stale; after calling localStorage.setItem or
localStorage.removeItem dispatch a browser event so listeners refresh: create
and dispatch a CustomEvent named "llmgateway_github_token_changed" (only when
window is defined) immediately after persisting or clearing the token so other
components update their githubToken without a reload, then close the modal as
before.
Summary by CodeRabbit
New Features
Bug Fixes
Chores