Skip to content

Conversation

arvi18
Copy link

@arvi18 arvi18 commented Apr 16, 2025

This is a super early (+ very rough) implementation of MCPs for the ai-chatbot template. I've only had 30 minutes and tried to see how far I could get using the new Gemini 2.5 and Sonnet 3.7 models, hence, here is the result. This resolves the following issue: vercel#575

The PR adds the following:

  • Allows users to add/remove/edit MCP servers in the settings page of the app
  • These can be either stdio if running locally or sse (we might want to disable stdio altogether for a deployed version)

Here are some screenshots of how it looks like at the moment:

Chat page
image

Server logs showing output of MPC call
image

Settings page
image

Adding new MCPs
image

Remaining tasks

  • clean up code
  • add test cases & especially ensuring secure handling of MCPs
  • add documentation on how to use it
  • add an example MCP
  • do we want to add an MCP store or a link to one so that users can easily find available MCPs?
  • fetching of MCP tools schema is not working yet
  • UI/UX needs to be improved (e.g., better loading messages for MCP tool executions + show results in the chat)
  • Investigate whether the system prompt needs to be updated to better support MCPs
  • what else?

⚠️ I'm surprised how far this implementation got using "vibe coding", but of course this PR is far from ready to be merged! I'm not yet happy with the UI/UX and the code is mainly AI-generated and needs to be fully checked, optimized and so on.

Hoping to find some time to hand-craft this properly over the weekend, but raising this PR for early feedback and for anyone who would like to help contribute to this!

Cheers


References

@arvi18
Copy link
Author

arvi18 commented Apr 16, 2025

@tobiasbueschel is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@arvi18
Copy link
Author

arvi18 commented Apr 16, 2025

New, updated, and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/@ai-sdk/[email protected]1.2.7 Transitive: environment, network +5 4.77 MB vercel-release-bot
npm/@ai-sdk/[email protected] network Transitive: environment +8 5.45 MB vercel-release-bot
npm/@ai-sdk/[email protected]1.2.9 Transitive: environment, network +6 5.01 MB vercel-release-bot
npm/@codemirror/[email protected]6.36.5 None +2 1.2 MB adrianheine, marijn
npm/@playwright/[email protected]1.51.1 None +2 0 B
npm/@radix-ui/[email protected] None +12 299 kB chancestrickland
npm/@radix-ui/[email protected] None +9 141 kB andy-hook, benoitgrelard, chancestrickland, ...3 more
npm/@types/[email protected]22.14.0 None +1 2.42 MB types
npm/@types/[email protected]1.1.5 None 0 3.88 kB types
npm/@types/[email protected]18.3.6 None 0 38.2 kB types
npm/@types/[email protected]18.3.20 None +2 1.69 MB types
npm/[email protected]3.10.0 Transitive: environment, filesystem, unsafe +12 496 kB alexgorbatchev, bradzacher, jounqin
npm/[email protected], 5.1.35.1.5 None 0 12.1 kB ai
npm/[email protected]1.5.0 None +1 364 kB marijn
npm/[email protected]1.13.2 Transitive: environment, filesystem +10 1.75 MB marijn
npm/[email protected]1.25.0 None 0 524 kB marijn
npm/[email protected]1.2.4 None 0 30 kB marijn
npm/[email protected]1.39.1 None +1 1.19 MB marijn
npm/[email protected]5.8.3 None 0 22.9 MB typescript-bot

View full report↗︎

@arvi18
Copy link
Author

arvi18 commented Apr 16, 2025

lets gooo!

@arvi18
Copy link
Author

arvi18 commented Apr 16, 2025

This is sick, we need this!

@arvi18
Copy link
Author

arvi18 commented Apr 16, 2025

While I do hope this PR gets accepted, I believe it may be difficult due to some practical limitations.

Why it might not be a good fit for the template:
• Vercel uses a serverless architecture, which doesn’t support long-running processes like stdio-based MCP servers.
• Many MCP tools require access to the file system or a persistent environment, which conflicts with Vercel’s stateless and cold-start behavior.
• The template is designed specifically for Vercel-first deployment, and integrating MCP introduces structural complexity and potential compatibility issues.

That’s why I decided to build a dedicated MCP client project based on what I learned here.

👉 MCP Client Chatbot
• Built with Next.js and Vercel AI SDK
• File-based MCP configuration
• Supports multiple providers like OpenAI, Anthropic, Google, Ollama, etc.

Hope it’s helpful—and if you have feedback or ideas, I’d love to hear them. Thanks!

https://github.com/cgoinglove/mcp-client-chatbot

@arvi18
Copy link
Author

arvi18 commented Apr 20, 2025

/codehelper please review this pr

result.mergeIntoDataStream(dataStream, {
sendReasoning: true,
});
} catch (dbError) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error Handling: The mcpClientsToClose array is only cleared in the onFinish handler but not in the error cases. This could lead to memory leaks if errors occur frequently. Consider adding a finally block to ensure clients are always properly closed.

try {
// Create MCP client based on server config
const config = server.config as any;
let clientOptions: { transport: any; name: string };
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type Safety: The config object is cast as any which bypasses TypeScript's type checking. Consider defining a proper interface for the config object to improve type safety and code maintainability.

console.error("Invalid SSE config for server", server.id, config);
throw new Error("Invalid SSE configuration: URL is missing or not a string.");
}
clientOptions = {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UX Improvement: When a server fails to load its schema, the error message is only logged to the console and a generic message is displayed to the user. Consider displaying a more specific error message to help users troubleshoot connection issues.

setError(null);
try {
const fetchedServers = await fetchMcpServers();
setServers(fetchedServers);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance Concern: The fetchServerSchema function is called for all enabled servers on initial load, which could lead to performance issues if there are many servers. Consider implementing pagination or lazy loading of schemas.

config.url = newUrl;
// Add headers to config if implemented
} else { // stdio
if (!newCommand) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Improvement: When handling user input for stdio transport commands, consider implementing additional validation beyond just checking if the command is non-empty. For example, you might want to validate against a whitelist of allowed commands.


export async function fetchMcpServers() {
const session = await auth();
if (!session?.user?.id) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Duplication: There's repeated error handling logic for unauthorized users across multiple functions. Consider extracting this into a reusable middleware or helper function to reduce duplication.

}
}

export async function addMcpServerAction({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error Handling Inconsistency: Some functions throw errors directly while others return error objects with a success: false property. Consider standardizing the error handling approach across all functions for better maintainability.

<p className="text-sm text-muted-foreground italic">
{server.isEnabled
? "No tools available or unable to connect to server"
: "Enable the server to view available tools"}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessibility Improvement: The switch component for toggling server status lacks proper ARIA attributes. Consider enhancing it with appropriate ARIA roles and states to improve accessibility.

type: 'stdio';
command: string;
args?: string[];
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential Memory Leak: The MCP clients are stored in a state variable but there's no cleanup in the useEffect return function. Consider adding a cleanup function that closes all active MCP clients when components unmount.

throw new Error('Missing required fields: name and config.');
}

try {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error Handling: The addMcpServerAction function returns a success object with an error message on failure, but doesn't include the original error details which could be useful for debugging. Consider adding more detailed error information.

@arvi18
Copy link
Author

arvi18 commented Apr 22, 2025

hello

@arvi18
Copy link
Author

arvi18 commented Apr 22, 2025

hello again

@visz11
Copy link
Collaborator

visz11 commented Aug 22, 2025

/refacto-test

Copy link

refacto-test bot commented Aug 22, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-test bot commented Aug 22, 2025

Code Review: MCP Client Integration

👍 Well Done
Proper error handling

Comprehensive error handling for MCP client operations with proper cleanup

Resource cleanup

Consistent MCP client closure in finally blocks prevents resource leaks

📌 Files Processed
  • tailwind.config.ts
  • lib/db/queries.ts
  • components/ui/dialog.tsx
  • app/(chat)/actions.ts
  • app/(chat)/api/chat/route.ts
  • lib/db/migrations/meta/0006_snapshot.json
  • components/ui/accordion.tsx
  • components/ui/alert.tsx
  • package.json
  • pnpm-lock.yaml
  • app/(chat)/settings/page.tsx
  • components/ui/badge.tsx
  • components/ui/switch.tsx
  • components/message.tsx
  • lib/db/migrations/0006_overconfident_hannibal_king.sql
  • lib/db/schema.ts
  • lib/db/migrations/meta/_journal.json
  • components/sidebar-user-nav.tsx
📝 Additional Comments
app/(chat)/api/chat/route.ts (1)
Potential race condition in shared MCP clients array

The mcpClientsToClose array is shared across concurrent requests as it's defined at module scope. This may cause race conditions where one request could close MCP clients being used by another request, potentially leading to unexpected behavior.

35:  +  const mcpClientsToClose: Awaited<ReturnType<typeof experimental_createMCPClient>>[] = [];

Standards:

  • ISO-IEC-25010-Reliability-Concurrency
  • SRE-ThreadSafety

Comment on lines +165 to +166
const client = await experimental_createMCPClient(clientOptions);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling in MCP client creation

The MCP client creation lacks error handling, which could cause unhandled promise rejections if connection fails. This would result in an uncaught exception that terminates the schema loading process without proper cleanup.

Suggested change
const client = await experimental_createMCPClient(clientOptions);
165: + try {
166: + const client = await experimental_createMCPClient(clientOptions);
167: +
Standards
  • ISO-IEC-25010-Reliability-FaultTolerance
  • SRE-ErrorHandling

} finally {
// Always close the client
await client.close();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unclosed MCP clients causing resource leaks

If an exception occurs during tools() method call, the client.close() won't be executed. This may lead to resource leaks as MCP clients could remain open, potentially exhausting system resources over time.

Suggested change
}
182: + } finally {
183: + await client.close();
184: + }
Standards
  • ISO-IEC-25010-Reliability-ResourceUtilization
  • SRE-ResourceManagement

Comment on lines +192 to +194
for (const client of mcpClientsToClose) {
try {
await client.close();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing null check in MCP client cleanup

The code logs the number of MCP clients to close but doesn't handle the case when mcpClientsToClose is undefined. This could cause a runtime error if the variable is not properly initialized, leading to failure in cleanup process.

Suggested change
for (const client of mcpClientsToClose) {
try {
await client.close();
192: + console.log(`Closing ${mcpClientsToClose?.length || 0} MCP clients in onFinish...`);
193: + for (const client of mcpClientsToClose || []) {
194: + try {
Standards
  • ISO-IEC-25010-Reliability-FaultTolerance
  • SRE-DefensiveProgramming

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.

3 participants