Skip to content
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

Support MCP( WIP) #5974

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Support MCP( WIP) #5974

wants to merge 5 commits into from

Conversation

Leizhenpeng
Copy link
Member

@Leizhenpeng Leizhenpeng commented Dec 23, 2024

💻 变更类型 | Change Type

  • feat
  • fix
  • refactor
  • perf
  • style
  • test
  • docs
  • ci
  • chore
  • build

🔀 变更说明 | Description of Change

📝 补充信息 | Additional Information

Summary by CodeRabbit

  • Documentation

    • Updated Chinese README to reflect supported AI models, replacing GPT-3 with Claude.
  • New Features

    • Added Multi-Channel Processing (MCP) client management system.
    • Integrated MCP actions and server communication capabilities.
    • Introduced new logging capabilities for better tracking of MCP operations.
  • Chores

    • Updated Next.js configuration to enable experimental server actions.
    • Updated TypeScript configuration to use ES2022.
    • Added new dependencies for MCP SDK and Zod validation.
  • Configuration

    • Added MCP server configuration file.
    • Updated ESLint ignore list.

Copy link

vercel bot commented Dec 23, 2024

Deployment failed with the following error:

You don't have permission to create a Preview Deployment for this project.

View Documentation: https://vercel.com/docs/accounts/team-members-and-roles

Copy link
Contributor

coderabbitai bot commented Dec 23, 2024

Walkthrough

This pull request introduces significant enhancements to the NextChat application by implementing the Message Control Protocol (MCP). Key changes include the addition of modules for MCP client management, logging, and configuration. The application now supports dynamic client initialization, server interactions, and improved logging capabilities. Modifications span multiple files, adding functionality for handling MCP actions, configuring servers, and integrating MCP processing into the chat system. Additionally, the supported AI models have been updated in the documentation.

Changes

File Change Summary
README_CN.md Updated supported models from GPT3 to Claude
app/mcp/actions.ts Added MCP client initialization and management functions
app/mcp/client.ts Implemented client creation, primitive listing, and request execution
app/mcp/example.ts Added example MCP server connection and capability retrieval
app/mcp/logger.ts Created a custom logger with color-coded output
app/store/chat.ts Integrated MCP action processing in message handling
next.config.mjs Enabled experimental serverActions
package.json Added MCP-related dependencies and updated scripts
tsconfig.json Updated ECMAScript target to ES2022
.eslintignore Added app/mcp/mcp_config.json to ignore list
app/mcp/mcp_config.json Added MCP server configurations
app/mcp/utils.ts Added utility functions for MCP JSON handling
app/page.tsx Added MCP clients initialization

Possibly related PRs

  • Feature/byte dance #4939: Introduces changes related to the ByteDance service provider, which may involve model handling similar to the changes in the main PR regarding supported models.
  • [Feature] Stable Diffusion #4983: Updates the README.md and README_CN.md files to include new optional configurations for the Stability API, relevant to changes in supported models in the documentation.
  • Change gpt summary model to gpt-4o-mini #5063: Changes the summary model from gpt-3.5-turbo to gpt-4o-mini, related to the model support aspect of the main PR.
  • fix model leak issue #5883: Addresses model availability checks, relevant to the changes in supported models in the main PR.

Suggested labels

planned

Suggested reviewers

  • Dogtiti

Poem

🐰 Hop, hop, through the MCP lane,
Clients dancing, no protocol pain!
Servers whisper, actions flow free,
NextChat's magic, just wait and see!
Code rabbits rejoice, new features bloom! 🌟

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

Your build has completed!

Preview deployment

Copy link

vercel bot commented Dec 28, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
nextchat ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 29, 2024 3:59am

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (9)
app/store/chat.ts (1)

429-447: Validate JSON parsing & protect against malformed message content

  • The regular expression approach to identify ```json:mcp blocks is functional, but consider graceful fallbacks if the block is missing or incomplete.
  • You already catch JSON parsing errors, which is good. In case of invalid JSON from user-provided data, ensuring a user-facing error response could be beneficial.
  • If multiple MCP calls can happen concurrently, verify the system’s concurrency handling to avoid race conditions.
app/mcp/actions.ts (1)

1-33: Leverage stronger typing and ensure concurrency safety

  • Currently, fsClient is typed as any—consider adding an explicit interface or type to make maintenance easier and reduce accidental misuse.
  • When multiple calls happen in quick succession, ensure initFileSystemClient can safely handle simultaneous initialization requests.
app/mcp/logger.ts (1)

1-60: Ensure cross-platform log compatibility

  • ANSI color codes might not display as intended across all terminals (e.g., some CI/CD environments or Windows shells).
  • Consider adding timestamps or structured logging for easier troubleshooting and correlation with other logs.
app/mcp/client.ts (4)

1-5: Use absolute imports selectively.

Imports from the "@modelcontextprotocol" package and Zod library are fine. However, ensure that these external imports remain minimal for faster builds and better maintainability. If future code only requires submodules, consider selective imports from large packages (e.g., import { ... } from "@modelcontextprotocol/sdk/client").


6-10: Clarify optional fields in ServerConfig interface.

Currently, args and env are optional. Provide doc comments describing the scenarios in which these fields would be omitted to improve code clarity.


44-47: Validate Primitive structure and values.

As Primitive.value is typed to any, adding a Zod schema or another validation layer for resource, tool, or prompt objects can improve type safety and help catch unexpected data structures from the server.


83-87: Use structured logging for request execution.

Currently, you only do console.log(r) after executing the request. Consider using logger.info or a more structured approach to log request/response pairs for debugging and auditing.

  ...
  const r = client.request(request, z.any());
- console.log(r);
+ logger.info("Request response:", r);
  return r;
}
tsconfig.json (1)

26-26: Cleanup references to removed files in include.

Removing "app/calcTextareaHeight.ts" from the include array is fine. Ensure that all references (e.g., imports) to that file are also removed throughout the codebase to avoid confusion.

package.json (1)

25-25: Leverage the @modelcontextprotocol/sdk dependency effectively.

Ensure that all relevant modules from the new SDK are utilized. If only a small subset is needed, consider partial imports or code splitting to reduce bundle size.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1c7c54 and c3108ad.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (9)
  • app/mcp/actions.ts (1 hunks)
  • app/mcp/client.ts (1 hunks)
  • app/mcp/example.ts (1 hunks)
  • app/mcp/logger.ts (1 hunks)
  • app/mcp/mcp_config.ts (1 hunks)
  • app/store/chat.ts (2 hunks)
  • next.config.mjs (3 hunks)
  • package.json (2 hunks)
  • tsconfig.json (2 hunks)
🔇 Additional comments (8)
app/store/chat.ts (1)

32-32: Add test coverage for 'executeMcpAction' usage

The new import integrates MCP action processing into the chat flow. To reduce the risk of unhandled edge cases (e.g., unavailable server, invalid JSON structures, etc.), please ensure the code path invoking executeMcpAction is tested thoroughly.

app/mcp/mcp_config.ts (1)

1-40: Secure storage of credentials and externalize paths

  • The placeholders for API keys and tokens should never be replaced by real secrets in the repository; instead, reading from environment variables or a vault is recommended.
  • The path "/Users/kadxy/Desktop" is hard-coded. Consider making this path configurable for different environments.
app/mcp/example.ts (1)

1-92: Harden the file reading mechanism

  • The code showcases reading arbitrary files from a specified path. Confirm that server-side controls or directory whitelisting is in place to guard against unauthorized access.
  • Good job using Zod schemas for validation—this helps ensure the integrity of server responses.
app/mcp/client.ts (1)

49-81: Parallel asynchronous operations are well handled; keep an eye on performance.

The approach of collecting promises in an array and awaiting them simultaneously is a good practice. For large-scale data, ensure the server handles concurrent calls effectively to avoid resource contention or throttling.

next.config.mjs (2)

35-35: Ensure experimental features are stable enough for production.

serverActions: true is an experimental feature. Confirm that your production environment accepts potential breaking changes or instabilities. Consider adding a feature gate or fallback logic.


75-78: Maintain consistent pattern for rewrite placeholders.

Rewrite placeholders, such as :resource_name and :deploy_name, are used in the destination URL. Confirm that you handle all edge cases (like missing or invalid resource_name / deploy_name). Potentially add server-side validation to avoid runtime errors.

tsconfig.json (1)

3-3: Check compatibility of ES2022 target.

Confirm that your deployment environment supports ES2022 features, or use a transpilation step if targeting older browsers. Some hosting platforms may not yet fully support ES2022 natively.

package.json (1)

57-58: Check versions & synergy for zod and zustand.

zod is now widely used for schema validation. Keep an eye on potential conflicts when using zustand for state management if any store-based validations are needed.

Comment on lines 14 to 42
export async function createClient(
serverConfig: ServerConfig,
name: string,
): Promise<Client> {
logger.info(`Creating client for server ${name}`);

const transport = new StdioClientTransport({
command: serverConfig.command,
args: serverConfig.args,
env: serverConfig.env,
});
const client = new Client(
{
name: `nextchat-mcp-client-${name}`,
version: "1.0.0",
},
{
capabilities: {
roots: {
// listChanged indicates whether the client will emit notifications when the list of roots changes.
// listChanged 指示客户端在根列表更改时是否发出通知。
listChanged: true,
},
},
},
);
await client.connect(transport);
return client;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider robust error handling for client creation.

When creating the client and connecting to the transport (line 40), include error handling for potential failures (e.g., invalid command, environment issues). This ensures unexpected errors are caught gracefully.

  ...
  await client.connect(transport);
+ // TODO: Consider wrapping this in try/catch:
+ // try {
+ //   await client.connect(transport);
+ // } catch (err) {
+ //   logger.error('Failed to connect to transport', err);
+ //   throw err;
+ // }
  return client;
}

Committable suggestion skipped: line range outside the PR's diff.

@@ -49,11 +50,12 @@
"remark-breaks": "^3.0.2",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1",
"rt-client": "https://github.com/Azure-Samples/aoai-realtime-audio-sdk/releases/download/js/v0.5.0/rt-client-0.5.0.tgz",
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Warning: The rt-client dependency is actively used and cannot be removed

The rt-client package is an essential dependency that is actively used in the realtime chat functionality:

  • It's imported and used extensively in app/components/realtime-chat/realtime-chat.tsx
  • Core functionalities depend on it:
    • Real-time audio streaming and processing
    • Voice chat features
    • Server communication for real-time responses
    • Audio transcription and playback

Removing this dependency would break the real-time chat feature. The package should be kept unless there's a planned replacement or the real-time chat functionality is being removed.

🔗 Analysis chain

Confirm removal of the deprecated rt-client dependency.

Verify that no modules still rely on rt-client. Skipping this verification might lead to runtime errors if references remain.


Let me gather more information about the actual usage of rt-client in the code.


Let me check the actual usage in the realtime-chat.tsx file to understand if this is an active dependency.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching for references to rt-client in the codebase:
rg 'rt-client' -A 3 -B 3

Length of output: 2671


Script:

#!/bin/bash
# Check for imports and actual usage of rt-client in the realtime components
ast-grep --pattern 'import { $$$ } from "rt-client"'

# Check for any direct usage of rt-client package
rg -l 'new RTClient|RTClient\.' 

Length of output: 675


Script:

#!/bin/bash
# Check the implementation in realtime-chat.tsx
cat app/components/realtime-chat/realtime-chat.tsx

Length of output: 10998

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (12)
app/mcp/actions.ts (3)

7-17: Global variables and maps
Storing clients in a global Map and a global initialized flag may be problematic in multi-instance or serverless environments. Consider a more robust design (e.g., an initialization manager) if concurrency or horizontal scaling are required.


18-51: initializeMcpClients function

  1. Code loops over conf.mcpServers and initializes each client with proper logging.
  2. Catches errors and tracks failed clients in errorClients.
  3. Marks initialized = true to prevent reinitialization.
  4. Logs final status and available clients.
    This flow is user-friendly and understandable. Consider adding retries or fallback logic for partial initialization failures.

53-70: executeMcpAction function

  1. Fetches the client from clientsMap by ID and executes the request.
  2. Logs any execution errors and rethrows them.
    Consider returning a standardized error object for better client-side handling, especially if this function may be extended for user-facing error messages in the future.
app/store/chat.ts (2)

363-367: MCP check on new messages
Line 366 calls checkMcpJson whenever a new message arrives. This integration ensures automatic detection of MCP requests without additional code in the message pipeline. Be sure to handle potential performance impacts if message volume is very high.


773-798: checkMcpJson function

  1. Validates if message content matches MCP JSON format.
  2. On success, extracts the MCP payload and invokes executeMcpAction.
  3. Uses onUserInput to feed back results as a new message.
    This is a clean, modular approach. However, watch for large JSON payloads or malicious content. Consider adding rate-limits or size checks for production.
app/mcp/utils.ts (2)

1-3: isMcpJson function
Returns the match result of a regex. This function is concise but slightly at risk of returning null or array. Consider returning a boolean explicitly (!!content.match(...)) if you only need a truthy check.


5-11: extractMcpJson function
Captures clientId and parses JSON from the second capture group. The approach is straightforward. A try-catch block for JSON parsing (or an upfront validity check) might guard against syntax errors or maliciously malformed JSON.

app/page.tsx (1)

9-10: Await MCP initialization
Blocking initialization ensures MCP dependencies are ready before UI rendering. Ensure that this call won’t degrade page responsiveness for users if the initialization is slow. Consider deferring or parallelizing if needed.

app/mcp/logger.ts (1)

24-65: Logging methods

  1. Provides functions for info, success, error, warn, and debug with consistent output formatting.
  2. debug is controlled by a flag to prevent noisy logs.
  3. A structured formatMessage method safely handles objects.
    Well-structured, though consider a fallback or custom transport in production to integrate with external logging systems (e.g., Winston, Bunyan).
app/mcp/client.ts (3)

32-35: Document or remove commented capabilities configuration.

The commented capabilities configuration lacks explanation. Either document why it's preserved for future use or remove it if unnecessary.


28-28: Consider extracting version to a configuration constant.

The hardcoded version "1.0.0" should be moved to a configuration constant for better maintainability.

+const CLIENT_VERSION = "1.0.0";
 
 export async function createClient(
   serverConfig: ServerConfig,
   name: string,
 ): Promise<Client> {
   // ...
   const client = new Client(
     {
       name: `nextchat-mcp-client-${name}`,
-      version: "1.0.0",
+      version: CLIENT_VERSION,
     },
     // ...
   );

52-76: Refactor duplicate promise handling pattern.

The promise handling pattern is repeated for resources, tools, and prompts. Consider extracting this to a helper function.

+const createPrimitivePromise = (
+  client: Client,
+  type: Primitive["type"],
+  listFn: () => Promise<{ [key: string]: any[] }>
+) => {
+  return listFn().then((result) => {
+    const items = result[`${type}s`];
+    items.forEach((item) => primitives.push({ type, value: item }));
+  });
+};

 if (capabilities?.resources) {
-  promises.push(
-    client.listResources().then(({ resources }) => {
-      resources.forEach((item) =>
-        primitives.push({ type: "resource", value: item }),
-      );
-    }),
-  );
+  promises.push(createPrimitivePromise(client, "resource", () => client.listResources()));
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3108ad and e1ba8f1.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (10)
  • .eslintignore (1 hunks)
  • app/mcp/actions.ts (1 hunks)
  • app/mcp/client.ts (1 hunks)
  • app/mcp/example.ts (1 hunks)
  • app/mcp/logger.ts (1 hunks)
  • app/mcp/mcp_config.json (1 hunks)
  • app/mcp/utils.ts (1 hunks)
  • app/page.tsx (1 hunks)
  • app/store/chat.ts (4 hunks)
  • package.json (3 hunks)
✅ Files skipped from review due to trivial changes (2)
  • .eslintignore
  • app/mcp/mcp_config.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/mcp/example.ts
  • package.json
🔇 Additional comments (10)
app/mcp/actions.ts (3)

1-2: Use of "use server" directive
These lines establish a server-only execution context. Be mindful of referencing browser-specific APIs in server files to avoid runtime errors.


3-6: Import dependencies
Imports for createClient, executeRequest, MCPClientLogger, and the JSON config look consistent with the intended usage. Ensure that underlying modules handle errors gracefully.


72-77: getAvailableClients function
Filters out clients that failed to initialize. This is straightforward and aligns with the error management strategy. Ensure future expansions remain in sync (e.g., re-checking previously error-prone clients).

app/store/chat.ts (2)

32-33: New MCP imports
Imports from mcp/actions and mcp/utils introduce the MCP functionality into the chat store. This is a logical location given the store’s role in handling messages.


434-434: Asynchronous onFinish callback
This line suggests the onFinish callback is asynchronous. Confirm that all references to onFinish handle promises and potential errors correctly to avoid unhandled promise rejections.

app/page.tsx (1)

4-4: Import initializeMcpClients
This sets up a new dependency on actions.ts. Verify that all required environment variables and config references are available at runtime.

app/mcp/logger.ts (2)

1-10: Color codes definition
Defines ANSI codes for styling the log output. Straightforward and correct for Node.js environments.


12-22: Logger constructor and fields
The prefix and debugMode options provide flexible logging. This is a neat approach for customizing logs.

app/mcp/client.ts (2)

1-10: LGTM! Well-structured imports and interface definition.

The ServerConfig interface is well-designed with appropriate optional parameters for args and env configuration.


14-40: Add error handling for client creation and connection.

The client creation process should include proper error handling for transport creation and connection failures.


interface Primitive {
type: "resource" | "tool" | "prompt";
value: any;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace 'any' type with a more specific type.

Using 'any' type reduces type safety. Consider defining specific types for resource, tool, and prompt values.

Comment on lines 81 to 84
/** Execute a request */
export async function executeRequest(client: Client, request: any) {
return client.request(request, z.any());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve request validation and error handling.

The current implementation has several concerns:

  1. Using z.any() bypasses the benefits of Zod's type validation
  2. No request validation before execution
  3. No error handling for failed requests

Consider implementing proper validation and error handling:

-export async function executeRequest(client: Client, request: any) {
-  return client.request(request, z.any());
+export async function executeRequest(client: Client, request: unknown) {
+  const requestSchema = z.object({
+    // Define your request schema here
+    // Example:
+    // method: z.string(),
+    // params: z.record(z.unknown())
+  });
+
+  try {
+    const validatedRequest = requestSchema.parse(request);
+    return await client.request(validatedRequest, z.unknown());
+  } catch (error) {
+    if (error instanceof z.ZodError) {
+      throw new Error(`Invalid request format: ${error.message}`);
+    }
+    throw error;
+  }
+}

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (6)
app/store/chat.ts (2)

Line range hint 376-402: Enhance type safety in onUserInput function.

The function could benefit from improved type safety:

  1. The isMcpResponse parameter should have a default value since it's optional
  2. The content type assertion should be more explicit

Consider applying these changes:

  async onUserInput(
    content: string,
    attachImages?: string[],
-   isMcpResponse?: boolean,
+   isMcpResponse: boolean = false,
  ) {
    const session = get().currentSession();
    const modelConfig = session.mask.modelConfig;

-   let mContent: string | MultimodalContent[] = isMcpResponse
+   let mContent: string | MultimodalContent[] = isMcpResponse === true
      ? content
      : fillTemplateWith(content, modelConfig);

782-810: Enhance error handling and maintainability in checkMcpJson.

Consider the following improvements:

  1. Add specific error type handling
  2. Add debug logging for the response formatting
  3. Extract JSON response formatting to a separate function

Consider applying these changes:

  checkMcpJson(message: ChatMessage) {
    const content = getMessageTextContent(message);
    if (isMcpJson(content)) {
      try {
        const mcpRequest = extractMcpJson(content);
        if (mcpRequest) {
          console.debug("[MCP Request]", mcpRequest);

          executeMcpAction(mcpRequest.clientId, mcpRequest.mcp)
            .then((result) => {
              console.log("[MCP Response]", result);
-             const mcpResponse =
-               typeof result === "object"
-                 ? JSON.stringify(result)
-                 : String(result);
+             const mcpResponse = formatMcpResponse(result);
+             console.debug("[MCP Formatted Response]", mcpResponse);
              get().onUserInput(
                `\`\`\`json:mcp:${mcpRequest.clientId}\n${mcpResponse}\n\`\`\``,
                [],
                true,
              );
            })
-           .catch((error) => showToast(String(error)));
+           .catch((error) => {
+             console.error("[MCP Execution Error]", error);
+             showToast(error instanceof Error ? error.message : String(error));
+           });
        }
-     } catch (error) {
+     } catch (error: unknown) {
        console.error("[MCP Error]", error);
+       showToast("Failed to process MCP request");
      }
    }
  },

+ function formatMcpResponse(result: unknown): string {
+   return typeof result === "object" ? JSON.stringify(result) : String(result);
+ }
app/mcp/types.ts (2)

1-2: Optional: Confirm the specification link remains stable.

The comment references an external spec URL. If it’s crucial, ensure the link remains valid. If the spec is versioned, consider pinning a specific version for documentation stability.


21-32: Response interface structure is flexible and aligns well with standard JSON-RPC patterns.

The error structure is appropriately typed, ensuring systematic error reporting. Consider adding clearer distinction for success vs. error states if your logic requires it.

app/mcp/client.ts (2)

43-46: Primitive interface uses 'any'.

Using any type for value reduces type safety. Define a union or more explicit shape if the data is known.

-interface Primitive {
-  type: "resource" | "tool" | "prompt";
-  value: any;
-}
+interface Resource { /* shape */}
+interface Tool { /* shape */}
+interface Prompt { /* shape */}
+type PrimitiveValue = Resource | Tool | Prompt;
+
+interface Primitive {
+  type: "resource" | "tool" | "prompt";
+  value: PrimitiveValue;
+}

48-80: listPrimitives merges capability checks with asynchronous calls.

  1. The approach is valid and merges results from multiple promises.
  2. Consider an early break if no capabilities exist to optimize performance in some edge cases.
  3. See if any concurrency issues might arise if the server is large or if many resources are loaded at once.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1ba8f1 and fe67f79.

📒 Files selected for processing (4)
  • app/mcp/actions.ts (1 hunks)
  • app/mcp/client.ts (1 hunks)
  • app/mcp/types.ts (1 hunks)
  • app/store/chat.ts (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/mcp/actions.ts
🔇 Additional comments (14)
app/store/chat.ts (4)

Line range hint 1-37: LGTM! Import changes are well-organized.

The new imports for MCP functionality are properly structured and necessary for the implementation.


62-62: LGTM! Type extension is clean and minimal.

The addition of isMcpResponse to ChatMessage type is well-typed and follows TypeScript best practices.


368-372: LGTM! Clean integration of MCP checking.

The addition of checkMcpJson call is well-placed and maintains the existing message processing flow.


Line range hint 1-810: Verify integration with existing chat functionality.

Since this is a WIP PR adding MCP support, please ensure:

  1. The changes don't affect existing chat functionality
  2. Error states are properly propagated to the UI
  3. MCP responses don't break the chat history display
✅ Verification successful

Based on the verification results, I can now provide a final response:

MCP integration maintains existing chat functionality with proper error handling

The code review shows that the MCP (Message Control Protocol) integration:

  1. Properly maintains existing chat functionality:

    • Core message handling (onNewMessage, onUserInput) remains intact
    • Message rendering and display components are unaffected
    • Existing error states and UI feedback are preserved
  2. Has appropriate error handling:

    • MCP errors are caught and displayed via showToast
    • Failed MCP actions are properly logged: console.error("[MCP Error]", error)
    • Error states are propagated to the UI through existing message error flags
  3. Safely integrates with chat history:

    • MCP responses are clearly marked with isMcpResponse flag
    • Messages are properly added to chat history with correct formatting
    • Template handling is properly skipped for MCP responses
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for potential regressions in chat functionality
echo "Checking for chat message handling..."
rg -A 5 "onUserInput|onNewMessage" --type ts

echo "Checking for error handling patterns..."
rg "showToast|console\.error" --type ts

echo "Checking for message display components..."
rg -A 5 "ChatMessage|renderMessage" --type tsx

Length of output: 10897


Script:

#!/bin/bash
# Let's check for message display components with proper extension
echo "Checking for message display components..."
rg -A 5 "ChatMessage|renderMessage" --type ts --type tsx

# Check for MCP-related changes
echo "Checking for MCP-related code..."
rg -A 5 "mcp|MCP" --type ts --type tsx

# Check for error handling in chat store
echo "Checking error handling in chat store..."
ast-grep --pattern 'onError(error) {
  $$$
}'

Length of output: 464


Script:

#!/bin/bash
# Let's try with just ts extension first
echo "Checking for message display components..."
rg -A 5 "ChatMessage|renderMessage" ./*.ts ./app/**/*.ts

echo "Checking for MCP-related code..."
rg -A 5 "mcp|MCP" ./*.ts ./app/**/*.ts

echo "Checking error handling in chat store..."
rg -A 5 "onError.*{" ./app/store/chat.ts

# Check for message rendering components
echo "Checking message components..."
fd -e tsx . -x cat {} | rg -A 5 "ChatMessage|renderMessage"

Length of output: 23199

app/mcp/types.ts (5)

5-12: Interfaces with typed methods and flexible params are well structured.

The McpRequestMessage interface design uses a union for the id and retains flexibility in params. This is good for requests where the schema can evolve over time.


14-20: Schema validation ensures robust request handling.

Good use of Zod for optional jsonrpc and union types for id. This schema can mitigate malformed requests by typechecking at runtime.


34-47: Robust schema for JSON-RPC responses.

The optional error object’s shape is well-defined. Ensure the client code handles partial responses (e.g., result or error fields) gracefully.


49-55: Encapsulated notifications match JSON-RPC patterns.

Separating notifications into a distinct interface clarifies the difference between requests and notifications.


57-61: Notifications schema aligns with the interface.

The use of z.record(z.unknown()) for params preserves flexibility while still enforcing structural constraints.

app/mcp/client.ts (5)

1-6: Imports are consistent and descriptive.

All necessary dependencies (Client, StdioClientTransport, custom logger, and McpRequestMessage) are imported cleanly. The use of zod is appropriate for runtime type checks.


7-11: ServerConfig is concise and extendable.

Storing command, arguments, and environment variables in an interface fosters clarity. If future expansions are likely (e.g., working directories, timeouts), consider grouping them under optional sub-objects or adding additional properties.


13-14: Logger usage is straightforward.

A dedicated logger is beneficial for debugging and operational visibility. Ensure logging levels are adjustable in production environments if needed.


15-41: createClient handles basic client setup.

  1. Logging the server name is helpful for troubleshooting.
  2. Consider error handling around client.connect in case the process fails to start or times out.

Would you like a script to search for unhandled promise rejections around connect calls and propose structured error-handling code if discovered?


82-88: 🛠️ Refactor suggestion

executeRequest returns data without intermediate validation or error handling.

Even though z.any() is used, you might want stronger type checks if the response format is critical. Also, consider how errors from client.request are caught and propagated.

 export async function executeRequest(
   client: Client,
   request: McpRequestMessage,
 ) {
-  return client.request(request, z.any());
+  try {
+    const response = await client.request(request, z.unknown());
+    // Potentially parse the response with the McpResponseMessageSchema
+    return McpResponseMessageSchema.parse(response);
+  } catch (err) {
+    logger.error('Failed to execute MCP request', err);
+    throw err;
+  }
 }

Likely invalid or redundant comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request wip
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants