Skip to content

Add MCP integration for stock price retrieval #429

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

Merged
merged 4 commits into from
Mar 29, 2025
Merged

Add MCP integration for stock price retrieval #429

merged 4 commits into from
Mar 29, 2025

Conversation

MervinPraison
Copy link
Owner

@MervinPraison MervinPraison commented Mar 26, 2025

  • Introduced multiple new files for MCP agent functionality, including mcp-agents-detailed.py, mcp-agents.py, mcp-basic.py, mcp-multiagents.py, and mcp-test.py.
  • Implemented a dedicated MCP class for managing connections and tool execution.
  • Created an asynchronous function to retrieve stock prices using MCP tools.
  • Added example agents for stock price checking and web searching.
  • Updated pyproject.toml and uv.lock to reflect version increment to 0.0.66.
  • Ensured backward compatibility and improved tool function generation for better usability.

Summary by CodeRabbit

  • New Features
    • Introduced multiple new agents that interact with users for stock price inquiries, apartment booking, and web searches.
    • Enhanced asynchronous workflows and direct integrations with external services, enabling dynamic tool execution and improved responsiveness.
  • Chores
    • Upgraded the project version to 0.0.67.

- Introduced multiple new files for MCP agent functionality, including `mcp-agents-detailed.py`, `mcp-agents.py`, `mcp-basic.py`, `mcp-multiagents.py`, and `mcp-test.py`.
- Implemented a dedicated `MCP` class for managing connections and tool execution.
- Created an asynchronous function to retrieve stock prices using MCP tools.
- Added example agents for stock price checking and web searching.
- Updated `pyproject.toml` and `uv.lock` to reflect version increment to 0.0.66.
- Ensured backward compatibility and improved tool function generation for better usability.
Copy link

coderabbitai bot commented Mar 26, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces multiple new agent files for handling stock price inquiries, Airbnb bookings, and web search functionalities. Several asynchronous mechanisms and wrappers have been added to support integration with MCP servers, NPX commands, and the Google GenAI API. New classes and functions enhance tool initialization, execution, and error handling. Additionally, the project version has been updated, and package exports have been expanded to include the MCP class.

Changes

File(s) Change Summary
src/praisonai-agents/mcp-agents-detailed.py, src/praisonai-agents/mcp-agents.py New agent instances added that use MCP and the "gpt-4o-mini" language model for stock price inquiries.
src/praisonai-agents/mcp-basic.py Implements an asynchronous function to retrieve stock prices with a synchronous wrapper and initializes an Agent using the stock_price_tool.
src/praisonai-agents/mcp-multiagents.py Introduces multiple agents (stock_agent and search_agent) configured for stock prices and web search operations.
src/praisonai-agents/praisonaiagents/__init__.py Updates the module to import the MCP class and expands the __all__ export list to include it.
src/praisonai-agents/praisonaiagents/mcp/mcp.py Adds MCPToolRunner and MCP classes with methods for tool invocation, dynamic tool function generation, iteration, and error handling.
src/praisonai-agents/pyproject.toml Updates the project version from "0.0.65" to "0.0.67".
src/praisonai-agents/mcp-npx-airbnb-agent-direct.py, src/praisonai-agents/mcp-npx-airbnb-stockprice.py, src/praisonai-agents/mcp-npx-airbnb.py Introduce new agents using NPX commands for Airbnb booking and stock price inquiries with preset queries.
src/praisonai-agents/mcp-npx-brave.py Adds a new search agent utilizing NPX to install and run Brave search tools.
src/praisonai-agents/mcp_airbnb_client_direct.py, src/praisonai-agents/mcp_airbnb_full_direct.py Implements direct integration with Google GenAI via asynchronous flows for booking apartments, including agent loops and tool execution.
src/praisonai-agents/mcp_client_direct.py Provides a command-line interactive MCP client that uses MCPWrapper for server interaction and query execution.
src/praisonai-agents/mcp_wrapper.py Introduces the MCPWrapper class to interface with Google's Gemini models and manage asynchronous query execution and tool calls.
src/praisonai-agents/npx_mcp_wrapper_main.py Creates an NPX-based MCP wrapper with dynamic tool extraction, wrapper creation, and compatibility formatting for OpenAI tools.
src/praisonai-agents/praisonaiagents/mcp/__init__.py Establishes module initialization for MCP integration, exporting the MCP class for public usage.

Sequence Diagram(s)

Stock Price Inquiry Flow

sequenceDiagram
    participant User
    participant Agent
    participant MCP
    participant StockTool

    User->>Agent: "What is the stock price of Tesla?"
    Agent->>MCP: Invoke tool for stock price retrieval
    MCP->>StockTool: Execute stock price command
    StockTool-->>MCP: Return stock price result
    MCP-->>Agent: Send back result
    Agent->>User: Display Tesla stock price
Loading

Airbnb Booking Flow

sequenceDiagram
    participant User
    participant Agent
    participant MCP
    participant AirbnbService

    User->>Agent: "Book an apartment in Paris for two nights"
    Agent->>MCP: Invoke NPX command for Airbnb booking
    MCP->>AirbnbService: Execute booking command with parameters
    AirbnbService-->>MCP: Return booking confirmation
    MCP-->>Agent: Relay confirmation details
    Agent->>User: Present booking details
Loading

Possibly related PRs

  • Add MCP integration for stock price retrieval #429: The changes in the main PR are directly related to those in the retrieved PR, as both introduce new instances of the Agent class and utilize the MCP class for stock price inquiries, specifically referencing the same functionalities and initialization patterns.

Poem

I'm a little rabbit, hopping through the code,
Agents spring to life with a skip and a node.
Stock prices and bookings dance in the night,
NPX commands and GenAI set things right.
With each new tool and a clever debug spark,
I celebrate these changes, a joyous hop in the dark!
🐇✨


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 531dd4b and 5fc8c0b.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • pyproject.toml (3 hunks)

🪧 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.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @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

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Hello @MervinPraison, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Summary of Changes

This pull request introduces Model Context Protocol (MCP) integration to the praisonai-agents library, enabling agents to utilize external tools for tasks like retrieving stock prices. I've added new files (mcp-agents-detailed.py, mcp-agents.py, mcp-basic.py, mcp-multiagents.py, and mcp-test.py) to demonstrate MCP agent functionality. The core of the integration is the MCP class, which manages connections and tool execution. I've also included examples of agents that use MCP to check stock prices and search the web. Additionally, I've updated pyproject.toml and uv.lock to version 0.0.66 and ensured backward compatibility while improving tool function generation.

Highlights

  • MCP Integration: Introduced the MCP class for managing connections to MCP servers and executing tools within PraisonAI agents.
  • Example Agents: Added example agents for stock price checking and web searching using MCP tools.
  • Tool Function Generation: Improved tool function generation to enhance usability and ensure backward compatibility.
  • Version Update: Incremented the package version to 0.0.66 in pyproject.toml and uv.lock.

Changelog

Click here to see the changelog
  • src/praisonai-agents/mcp-agents-detailed.py
    • Created a new file to demonstrate detailed MCP agent usage for checking stock prices, utilizing the Agent and MCP classes from praisonaiagents.
    • The agent is configured with instructions to act as a helpful assistant that can check stock prices and perform other tasks using available tools.
    • The agent is initialized with the 'gpt-4o-mini' LLM and uses an MCP tool pointing to a stock price application.
    • The agent is started with the question 'What is the stock price of Tesla?'.
  • src/praisonai-agents/mcp-agents.py
    • Created a new file to demonstrate basic MCP agent usage for checking stock prices, utilizing the Agent and MCP classes from praisonaiagents.
    • The agent is configured with instructions to act as a helpful assistant that can check stock prices and perform other tasks using available tools.
    • The agent is initialized with the 'gpt-4o-mini' LLM and uses an MCP tool pointing to a stock price application.
    • The agent is started with the question 'What is the stock price of Tesla?'.
  • src/praisonai-agents/mcp-basic.py
    • Created a new file to demonstrate basic MCP integration for retrieving stock prices using asynchronous functions and custom tools.
    • Defines a server configuration pointing to a stock price application using StdioServerParameters.
    • Implements an asynchronous function get_stock_price to retrieve stock prices using MCP tools, including initializing a client session, listing available tools, and calling a tool to get the stock price for a given symbol.
    • Creates a custom tool stock_price_tool that wraps the asynchronous function to be used by the agent.
    • Creates an agent with instructions to check stock prices using the stock_price_tool and starts the agent with the question 'What is the stock price of Tesla?'.
  • src/praisonai-agents/mcp-multiagents.py
    • Created a new file to demonstrate the usage of multiple agents with MCP integration for different tasks, including stock price checking and web searching.
    • Defines a stock_agent that checks stock prices using an MCP tool pointing to a stock price application.
    • Defines a search_agent that searches the web using an MCP tool configured with Brave Search.
    • Starts both agents with questions related to their respective tasks: 'What is the stock price of Tesla?' for the stock agent and 'What is the weather in San Francisco?' for the search agent.
  • src/praisonai-agents/mcp-test.py
    • Created a new file to test MCP tool execution with proper error handling.
    • Defines a server configuration pointing to a stock price application using StdioServerParameters.
    • Implements an asynchronous function execute_tool to call a tool with error handling.
    • The main function initializes a client session, lists available tools, and calls the first available tool with empty parameters for demonstration purposes.
    • Prints the tool response for verification.
  • src/praisonai-agents/praisonaiagents/init.py
    • Added MCP to the list of exported classes and functions in the __init__.py file to make it accessible from the praisonaiagents package. The first change adds the import statement, and the second change adds MCP to the __all__ list.
  • src/praisonai-agents/praisonaiagents/mcp/mcp.py
    • Created a new file implementing the MCP class for Model Context Protocol integration.
    • The MCP class manages connections to MCP servers, executes tools, and generates tool functions.
    • It uses a dedicated thread (MCPToolRunner) to handle MCP operations asynchronously.
    • The class supports initializing the MCP connection using either a command and arguments separately or a single command string.
    • It dynamically generates wrapper functions for each MCP tool, creating a user-friendly interface for agents to call these tools.
    • The class also handles the cleanup of resources when the object is garbage collected.
  • src/praisonai-agents/pyproject.toml
    • Incremented the package version from 0.0.65 to 0.0.66.
  • src/praisonai-agents/uv.lock
    • Updated the package version from 0.0.65 to 0.0.66.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


From agents keen, with tasks in sight,
MCP emerges, shining bright.
Connecting tools, a seamless flow,
To fetch the data, help them grow.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces MCP integration for stock price retrieval, which is a valuable addition to the praisonai-agents library. The changes include new files for MCP agent functionality, an MCP class for managing connections, and example agents for stock price checking and web searching. Overall, the code is well-structured, but there are some areas that could be improved for clarity, efficiency, and maintainability.

Summary of Findings

  • Hardcoded Paths: The code contains several hardcoded paths, such as the path to the Python interpreter and the stock price app. This makes the code less portable and harder to configure. It would be better to use environment variables or configuration files to specify these paths.
  • Error Handling in MCPToolRunner: The error handling in the MCPToolRunner class could be improved. Currently, errors during tool execution are caught and returned as strings. It would be better to raise exceptions or use a more structured error reporting mechanism.
  • Tool Discovery: The tool discovery mechanism in mcp-basic.py relies on string matching (if "stock" in tool.name.lower() or "price" in tool.name.lower():). This is not very robust and could lead to incorrect tool selection. A more reliable method would be to use tool schemas or annotations to identify the correct tool.
  • Asynchronous Execution: The stock_price_tool function in mcp-basic.py uses asyncio.run to execute the asynchronous get_stock_price function. This blocks the event loop and can lead to performance issues. It would be better to use asyncio.create_task or a similar mechanism to run the asynchronous function in a non-blocking manner.

Merge Readiness

The pull request introduces important functionality. However, due to the presence of hardcoded paths and potential improvements in error handling and tool discovery, I recommend addressing the identified issues before merging. I am unable to approve this pull request, and other reviewers should review and approve this code before merging.

Comment on lines +47 to +51
def stock_price_tool(symbol: str) -> str:
"""Get the current stock price for a given symbol"""
# Run the async function to get the stock price
result = asyncio.run(get_stock_price(symbol))
return f"Stock price for {symbol}: {result}"

Choose a reason for hiding this comment

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

high

Using asyncio.run here blocks the event loop. It would be better to use asyncio.create_task or a similar mechanism to run the asynchronous function in a non-blocking manner. Consider refactoring to use await directly within an async context if possible.

    # Run the async function to get the stock price
    loop = asyncio.get_event_loop()
    result = loop.run_until_complete(get_stock_price(symbol))
    return f"Stock price for {symbol}: {result}"

Comment on lines +8 to +9
command="/Users/praison/miniconda3/envs/mcp/bin/python",
args=["/Users/praison/stockprice/app.py"]

Choose a reason for hiding this comment

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

medium

The command and args are hardcoded. Consider using environment variables or a configuration file to make this more configurable and portable.

Suggested change
command="/Users/praison/miniconda3/envs/mcp/bin/python",
args=["/Users/praison/stockprice/app.py"]
command=os.getenv("MCP_PYTHON_PATH", "/Users/praison/miniconda3/envs/mcp/bin/python"),
args=[os.getenv("STOCKPRICE_APP_PATH", "/Users/praison/stockprice/app.py")]

instructions="""You are a helpful assistant that can check stock prices and perform other tasks.
Use the available tools when relevant to answer user questions.""",
llm="gpt-4o-mini",
tools = MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")

Choose a reason for hiding this comment

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

medium

This path is hardcoded. Consider using environment variables or a configuration file to make this more configurable and portable.

Suggested change
tools = MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")
tools = MCP(os.getenv("MCP_COMMAND", "/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py"))

Comment on lines +8 to +11
command="/Users/praison/miniconda3/envs/mcp/bin/python",
args=[
"/Users/praison/stockprice/app.py",
],

Choose a reason for hiding this comment

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

medium

These paths are hardcoded. Consider using environment variables or a configuration file to make this more configurable and portable.

Suggested change
command="/Users/praison/miniconda3/envs/mcp/bin/python",
args=[
"/Users/praison/stockprice/app.py",
],
command=os.getenv("MCP_PYTHON_PATH", "/Users/praison/miniconda3/envs/mcp/bin/python"),
args=[
os.getenv("STOCKPRICE_APP_PATH", "/Users/praison/stockprice/app.py"),
],

Comment on lines +30 to +33
for tool in tools:
if "stock" in tool.name.lower() or "price" in tool.name.lower():
stock_tool = tool
break

Choose a reason for hiding this comment

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

medium

This tool discovery mechanism is not very robust. It relies on string matching, which could lead to incorrect tool selection. A more reliable method would be to use tool schemas or annotations to identify the correct tool.

            # Find a tool that can get stock prices based on schema or annotations
            stock_tool = next((tool for tool in tools if tool.inputSchema and "ticker" in tool.inputSchema.get("properties", {})), None)

Comment on lines 9 to 12
command="/Users/praison/miniconda3/envs/mcp/bin/python",
args=[
"/Users/praison/stockprice/app.py",
],

Choose a reason for hiding this comment

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

medium

These paths are hardcoded. Consider using environment variables or a configuration file to make this more configurable and portable.

Suggested change
command="/Users/praison/miniconda3/envs/mcp/bin/python",
args=[
"/Users/praison/stockprice/app.py",
],
command=os.getenv("MCP_PYTHON_PATH", "/Users/praison/miniconda3/envs/mcp/bin/python"),
args=[
os.getenv("STOCKPRICE_APP_PATH", "/Users/praison/stockprice/app.py"),
],

Comment on lines +58 to +59
except Exception as e:
self.result_queue.put((False, str(e)))

Choose a reason for hiding this comment

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

medium

Consider raising an exception with more context instead of putting a string in the queue. This will allow for better error handling and debugging.

Suggested change
except Exception as e:
self.result_queue.put((False, str(e)))
except Exception as e:
self.result_queue.put((False, e))

break
except Exception as e:
self.initialized.set() # Ensure we don't hang
self.result_queue.put((False, f"MCP initialization error: {str(e)}"))

Choose a reason for hiding this comment

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

medium

Consider raising an exception with more context instead of putting a string in the queue. This will allow for better error handling and debugging.

Suggested change
self.result_queue.put((False, f"MCP initialization error: {str(e)}"))
self.result_queue.put((False, e))

if not self.initialized.is_set():
self.initialized.wait(timeout=30)
if not self.initialized.is_set():
return "Error: MCP initialization timed out"

Choose a reason for hiding this comment

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

medium

Instead of returning a string, consider raising an exception to signal the timeout.

Suggested change
return "Error: MCP initialization timed out"
raise TimeoutError("MCP initialization timed out")

# Wait for result
success, result = self.result_queue.get()
if not success:
return f"Error: {result}"

Choose a reason for hiding this comment

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

medium

Instead of returning a string, consider raising the exception to signal the error.

Suggested change
return f"Error: {result}"
raise Exception(result)

Copy link

gitguardian bot commented Mar 26, 2025

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
16046208 Triggered Generic High Entropy Secret 531dd4b src/praisonai-agents/mcp-npx-brave.py View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Copy link

netlify bot commented Mar 26, 2025

Deploy Preview for praisonai canceled.

Name Link
🔨 Latest commit 5fc8c0b
🔍 Latest deploy log https://app.netlify.com/sites/praisonai/deploys/67e8349072174e00088e07be

Copy link

@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 (12)
src/praisonai-agents/mcp-agents.py (1)

1-10: Agent setup looks good but contains hardcoded paths

The code correctly imports and utilizes the new MCP functionality. However, it uses absolute paths which could cause portability issues.

Consider replacing hardcoded paths with environment variables or configuration settings:

-tools = MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")
+tools = MCP(os.getenv("PYTHON_PATH", "python") + " " + os.getenv("STOCKPRICE_APP_PATH", "./stockprice/app.py"))

Don't forget to add the import:

import os
src/praisonai-agents/mcp-agents-detailed.py (2)

1-13: Agent setup with MCP looks correct but contains hardcoded paths

The code correctly demonstrates the alternative way to instantiate the MCP class by providing the command and args separately, which is a good example. However, it also contains hardcoded paths that could cause portability issues.

Consider using environment variables or configuration files instead of hardcoded paths:

-    tools=MCP(
-        command="/Users/praison/miniconda3/envs/mcp/bin/python",
-        args=["/Users/praison/stockprice/app.py"]
-    )
+    tools=MCP(
+        command=os.getenv("PYTHON_PATH", "python"),
+        args=[os.getenv("STOCKPRICE_APP_PATH", "./stockprice/app.py")]
+    )

Don't forget to add the import:

import os

3-13: Example code could be improved with better error handling

While this example code demonstrates how to use the MCP class, it would be beneficial to add error handling for cases where the MCP server fails to initialize.

Consider adding a try-except block to handle potential exceptions:

+import os
 from praisonaiagents import Agent, MCP

+try:
     agent = Agent(
         instructions="""You are a helpful assistant that can check stock prices and perform other tasks.
     Use the available tools when relevant to answer user questions.""",
         llm="gpt-4o-mini",
         tools=MCP(
             command="/Users/praison/miniconda3/envs/mcp/bin/python",
             args=["/Users/praison/stockprice/app.py"]
         )
     )
    
     agent.start("What is the stock price of Tesla?")
+except Exception as e:
+    print(f"Error initializing agent: {e}")
src/praisonai-agents/mcp-multiagents.py (2)

3-11: Consider making script paths configurable for better portability.

Currently, the path to the Python interpreter and the app.py script is hardcoded. If you want this code to run outside your local environment, consider using environment variables or a configuration file to locate the Python binary and script path.

-    tools=MCP(
-        command="/Users/praison/miniconda3/envs/mcp/bin/python",
-        args=["/Users/praison/stockprice/app.py"]
-    )
+    import os
+    python_path = os.getenv("PYTHON_BIN", "/usr/bin/python")
+    stock_script = os.getenv("STOCK_SCRIPT_PATH", "/path/to/stockprice/app.py")
+    tools=MCP(
+        command=python_path,
+        args=[stock_script]
+    )

13-18: Avoid embedding API keys in source code.

Placing the Brave API key within the command string can expose sensitive information. Consider using environment variables or a secure secrets manager to protect credentials.

-    tools=MCP('npx -y @smithery/cli@latest install @smithery-ai/brave-search --client claude --config "{\"braveApiKey\":\"BSANfDaqLKO9wq7e08mrPth9ZlJvKtc\"}"')
+    brave_api_key = os.getenv("BRAVE_API_KEY", "REPLACE_ME")
+    tools=MCP(f'npx -y @smithery/cli@latest install @smithery-ai/brave-search --client claude --config "{{\\"braveApiKey\\":\\"{brave_api_key}\\"}}"')
src/praisonai-agents/mcp-test.py (2)

28-31: Consolidate nested async with statements.

Ruff (SIM117) suggests using a single with statement for multiple contexts. You can reduce indentation and slightly improve readability:

-    async with stdio_client(server_params) as (read, write):
-        async with ClientSession(read, write) as session:
+    async with stdio_client(server_params) as (read, write), ClientSession(read, write) as session:
🧰 Tools
🪛 Ruff (0.8.2)

30-31: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


57-59: Refine dictionary creation without calling .keys().

Ruff (SIM118) recommends using tool.inputSchema["properties"] directly to test membership. This is a minor performance and stylistic suggestion:

-params = {
-    key: "" for key in tool.inputSchema["properties"].keys()
-}
+params = {
+    key: "" for key in tool.inputSchema["properties"]
+}
🧰 Tools
🪛 Ruff (0.8.2)

58-58: Use key in dict instead of key in dict.keys()

Remove .keys()

(SIM118)

src/praisonai-agents/mcp-basic.py (3)

6-13: Consider making paths portable.

Hardcoded paths to your environment and script may limit portability. Use environment variables or config files to store these paths if portability is a concern.


15-26: Single async with statement recommended.

You can consolidate multiple async with blocks into one to follow best practices and linting recommendations.

🧰 Tools
🪛 Ruff (0.8.2)

17-18: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


47-51: Watch out for nested event loops in asyncio.run().

Calling asyncio.run(get_stock_price(symbol)) may fail if there's already an active event loop (e.g., in a larger async application). For broader usage, consider an approach that checks for or reuses an existing event loop.

src/praisonai-agents/praisonaiagents/mcp/mcp.py (2)

4-4: Remove unused imports.

Ruff identifies several imports not being used (time, Dict, Optional, Union, partial). Removing them keeps the code clean and eliminates unnecessary dependencies.

-import time
-from typing import Dict, Any, List, Optional, Callable, Iterable, Union
-from functools import wraps, partial
+from typing import Any, List, Callable, Iterable
+from functools import wraps

Also applies to: 7-8

🧰 Tools
🪛 Ruff (0.8.2)

4-4: time imported but unused

Remove unused import: time

(F401)


33-34: Consolidate nested with statements.

Ruff (SIM117) recommends using a single with statement for both stdio_client(self.server_params) and ClientSession(read, write).

-async with stdio_client(self.server_params) as (read, write):
-    async with ClientSession(read, write) as session:
+async with stdio_client(self.server_params) as (read, write), ClientSession(read, write) as session:
🧰 Tools
🪛 Ruff (0.8.2)

33-34: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between cbc6939 and 16684c8.

⛔ Files ignored due to path filters (1)
  • src/praisonai-agents/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • src/praisonai-agents/mcp-agents-detailed.py (1 hunks)
  • src/praisonai-agents/mcp-agents.py (1 hunks)
  • src/praisonai-agents/mcp-basic.py (1 hunks)
  • src/praisonai-agents/mcp-multiagents.py (1 hunks)
  • src/praisonai-agents/mcp-test.py (1 hunks)
  • src/praisonai-agents/praisonaiagents/__init__.py (2 hunks)
  • src/praisonai-agents/praisonaiagents/mcp/mcp.py (1 hunks)
  • src/praisonai-agents/pyproject.toml (1 hunks)
🧰 Additional context used
🧬 Code Definitions (4)
src/praisonai-agents/mcp-agents.py (1)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (1)
  • MCP (98-278)
src/praisonai-agents/praisonaiagents/__init__.py (1)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (1)
  • MCP (98-278)
src/praisonai-agents/mcp-multiagents.py (1)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (1)
  • MCP (98-278)
src/praisonai-agents/mcp-agents-detailed.py (1)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (1)
  • MCP (98-278)
🪛 Ruff (0.8.2)
src/praisonai-agents/mcp-test.py

30-31: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


58-58: Use key in dict instead of key in dict.keys()

Remove .keys()

(SIM118)

src/praisonai-agents/praisonaiagents/mcp/mcp.py

4-4: time imported but unused

Remove unused import: time

(F401)


7-7: typing.Dict imported but unused

Remove unused import

(F401)


7-7: typing.Optional imported but unused

Remove unused import

(F401)


7-7: typing.Union imported but unused

Remove unused import

(F401)


8-8: functools.partial imported but unused

Remove unused import: functools.partial

(F401)


33-34: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)

src/praisonai-agents/mcp-basic.py

17-18: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: test
🔇 Additional comments (10)
src/praisonai-agents/pyproject.toml (1)

7-7: Version increment looks good

The version has been properly incremented from 0.0.65 to 0.0.66, which is appropriate for the addition of the new MCP functionality.

src/praisonai-agents/praisonaiagents/__init__.py (2)

13-13: Import of MCP class looks good

The MCP class is correctly imported from the mcp module.


55-56: Correctly added MCP to exports

MCP has been appropriately added to the __all__ list, making it available when using from praisonaiagents import *.

src/praisonai-agents/mcp-multiagents.py (2)

1-2: Imports look good.

The import statement correctly references the required classes, and no issues are apparent with import ordering or code conventions.


20-21: LGTM!

Starting both agents to retrieve the stock price for Tesla and searching for weather looks correct. No further issues in this logic.

src/praisonai-agents/mcp-test.py (2)

1-6: No issues with imports.

All necessary modules are imported correctly for async usage, JSON handling, and MCP interactions.


15-26: Execution function is well-structured.

Good job providing error handling and returning a dictionary with the error message if an exception occurs. This helps keep your asynchronous calls robust.

src/praisonai-agents/mcp-basic.py (2)

1-5: Imports check out.

All imports are relevant for asynchronous operation and agent usage.


54-61: Agent logic is straightforward.

Using stock_price_tool for the agent tool and then calling start() with a Tesla query looks correct.

src/praisonai-agents/praisonaiagents/mcp/mcp.py (1)

275-278: Shutdown logic looks fine.

Calling self.runner.shutdown() in __del__ gracefully signals the MCP thread to stop, but be mindful that Python garbage collection timing is not guaranteed. Confirm the thread properly finishes without side effects in your environment.

@MervinPraison
Copy link
Owner Author

@coderabbitai generate docstrings

Copy link

coderabbitai bot commented Mar 26, 2025

✅ Actions performed

Docstrings generation started.

coderabbitai bot added a commit that referenced this pull request Mar 26, 2025
Docstrings generation was requested by @MervinPraison.

* #429 (comment)

The following files were modified:

* `src/praisonai-agents/mcp-basic.py`
* `src/praisonai-agents/mcp-test.py`
* `src/praisonai-agents/praisonaiagents/mcp/mcp.py`
Copy link

coderabbitai bot commented Mar 26, 2025

Note

Generated docstrings for this pull request at #430

@MervinPraison MervinPraison merged commit f3c0d4c into main Mar 29, 2025
2 of 6 checks passed
Copy link

@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: 3

🧹 Nitpick comments (20)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (4)

4-10: Remove unused imports to improve code cleanliness

Several imports are not used in the code:

  • time on line 4
  • Optional and Union from typing on line 9
  • partial from functools on line 10
- import time
  import inspect
  import shlex
  import logging
  import os
- from typing import Any, List, Optional, Callable, Iterable, Union
+ from typing import Any, List, Callable, Iterable
- from functools import wraps, partial
+ from functools import wraps
🧰 Tools
🪛 Ruff (0.8.2)

4-4: time imported but unused

Remove unused import: time

(F401)


9-9: typing.Optional imported but unused

Remove unused import

(F401)


9-9: typing.Union imported but unused

Remove unused import

(F401)


10-10: functools.partial imported but unused

Remove unused import: functools.partial

(F401)


35-36: Simplify nested with statements

You can combine the nested with statements into a single statement with multiple contexts for better readability.

-            async with stdio_client(self.server_params) as (read, write):
-                async with ClientSession(read, write) as session:
+            async with stdio_client(self.server_params) as (read, write), ClientSession(read, write) as session:
🧰 Tools
🪛 Ruff (0.8.2)

35-36: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


174-175: Use logging instead of print for warning messages

For consistency and better control over log output, use the logging system instead of print statements.

-            print("Warning: MCP initialization timed out")
+            logging.warning("MCP initialization timed out")

304-304: Use 'raise ... from e' to preserve the exception context

When re-raising exceptions, use the from syntax to preserve the original exception context, which helps with debugging.

-            raise RuntimeError(f"Failed to initialize NPX MCP tools: {e}")
+            raise RuntimeError(f"Failed to initialize NPX MCP tools: {e}") from e
🧰 Tools
🪛 Ruff (0.8.2)

304-304: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

src/praisonai-agents/mcp-npx-airbnb-agent-direct.py (2)

3-3: Consider using the same MCP class as other files

This file imports MCP from npx_mcp_wrapper_main, while other similar files import it directly from praisonaiagents. For consistency, consider using the same approach across all files.

-import npx_mcp_wrapper_main
+from praisonaiagents import MCP

Then update line 8:

-    tools=npx_mcp_wrapper_main.MCP(
+    tools=MCP(

18-18: Consider making this a reusable function rather than executing it directly

To make this script more reusable, consider wrapping the execution in a function and only running it when the script is invoked directly.

+def main():
+    search_agent.start("I want to book an apartment in Paris for 2 nights. 03/28 - 03/30 for 2 adults")
+
+
+if __name__ == "__main__":
+    main()
-search_agent.start("I want to book an apartment in Paris for 2 nights. 03/28 - 03/30 for 2 adults")
src/praisonai-agents/mcp-npx-airbnb.py (2)

16-16: Consider making this a reusable function rather than executing it directly

To make this script more reusable, consider wrapping the execution in a function and only running it when the script is invoked directly.

+def main():
+    search_agent.start("I want to book an apartment in Paris for 2 nights. 03/28 - 03/30 for 2 adults")
+
+
+if __name__ == "__main__":
+    main()
-search_agent.start("I want to book an apartment in Paris for 2 nights. 03/28 - 03/30 for 2 adults")

3-14: Consider code reuse for duplicate agent configurations

This agent configuration is duplicated across multiple files (mcp-npx-airbnb-agent-direct.py and mcp-npx-airbnb-stockprice.py). Consider extracting this common setup into a shared function or configuration file.

You could create a shared module with a function like:

# In a shared module like airbnb_utils.py
def create_airbnb_agent():
    return Agent(
        instructions="""You help book apartments on Airbnb.""",
        llm="gpt-4o-mini",
        tools=MCP(
            command="npx",
            args=[
                "-y",
                "@openbnb/mcp-server-airbnb",
                "--ignore-robots-txt",
            ]
        )
    )

Then import and use it in your scripts:

from airbnb_utils import create_airbnb_agent

search_agent = create_airbnb_agent()
src/praisonai-agents/mcp-npx-airbnb-stockprice.py (1)

25-25: Consider making this a reusable function rather than executing it directly

To make this script more reusable, consider wrapping the execution in a function and only running it when the script is invoked directly.

+def main():
+    search_agent.start("I want to book an apartment in Paris for 2 nights. 03/28 - 03/30 for 2 adults")
+    agent.start("What is the stock price of Tesla?")
+
+
+if __name__ == "__main__":
+    main()
-agent.start("What is the stock price of Tesla?")
src/praisonai-agents/mcp-npx-brave.py (2)

3-22: Add descriptive docstrings for the agent initialization.

Currently, the code lacks docstrings describing the purpose and usage of search_agent. Adding them will improve maintainability and help new contributors quickly understand how to configure and use this agent.


24-24: Consider capturing or validating the startup prompt.

The hard-coded prompt "Search more information about Praison AI" may be too narrow or might need dynamic customization in a real application. You could make it a parameter or configuration option for flexibility.

src/praisonai-agents/mcp_client_direct.py (2)

18-29: Provide docstrings for the main function.

Documenting the script’s usage, expected arguments, and outcomes would greatly assist developers in understanding how to run and integrate this MCP client.


33-60: Consider adding fallback or retry logic for connection failures.

Although exceptions are caught, it might be helpful to automatically retry or prompt users to re-enter credentials when a transient failure (e.g., network issue) occurs.

src/praisonai-agents/mcp_airbnb_client_direct.py (1)

1-9: Add docstrings for module-level clarity.

Include high-level documentation explaining the module’s purpose (booking through an MCP-based Airbnb server), and detail the steps needed to run it successfully.

src/praisonai-agents/mcp_wrapper.py (2)

30-47: Add return type annotations for better clarity.

Although the docstrings are thorough, adding explicit return types (e.g., -> ClientSession for connect_to_server) can aid type checkers and future maintainers.


81-242: Unit-test the execute_query flow with mock/mocked MCP sessions.

The logic is complex and includes branching for function calls, error handling, and mock responses. Adding unit tests will help ensure correctness and guard against regressions.

src/praisonai-agents/mcp_airbnb_full_direct.py (2)

22-46: Add a docstring for agent_loop for clarity.

Currently, agent_loop is missing a docstring. Providing an overview of its usage, input parameters, and return type will improve maintainability.


106-111: Combine nested context managers.

Static analysis (Ruff SIM117) suggests merging these nested with statements into a single block to enhance readability:

 async def run():
-    async with stdio_client(server_params) as (read, write):
-        async with ClientSession(read, write) as session:
+    async with stdio_client(server_params) as (read, write), \
+         ClientSession(read, write) as session:
         ...
🧰 Tools
🪛 Ruff (0.8.2)

107-111: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)

src/praisonai-agents/npx_mcp_wrapper_main.py (2)

49-142: Document concurrency concerns in _initialize_mcp_tools.

Creating and deleting a temporary script in this manner can introduce concurrency challenges (e.g., simultaneous writes, stale scripts) when multiple threads or processes run the wrapper concurrently. Consider adding these caveats to the docstring.


54-63: Handle missing npx gracefully.

If npx is not installed on the system, the code could fail abruptly. Consider verifying npx availability at startup, logging an error if it's missing.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 16684c8 and 531dd4b.

⛔ Files ignored due to path filters (1)
  • src/praisonai-agents/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • src/praisonai-agents/mcp-multiagents.py (1 hunks)
  • src/praisonai-agents/mcp-npx-airbnb-agent-direct.py (1 hunks)
  • src/praisonai-agents/mcp-npx-airbnb-stockprice.py (1 hunks)
  • src/praisonai-agents/mcp-npx-airbnb.py (1 hunks)
  • src/praisonai-agents/mcp-npx-brave.py (1 hunks)
  • src/praisonai-agents/mcp_airbnb_client_direct.py (1 hunks)
  • src/praisonai-agents/mcp_airbnb_full_direct.py (1 hunks)
  • src/praisonai-agents/mcp_client_direct.py (1 hunks)
  • src/praisonai-agents/mcp_wrapper.py (1 hunks)
  • src/praisonai-agents/npx_mcp_wrapper_main.py (1 hunks)
  • src/praisonai-agents/praisonaiagents/mcp/__init__.py (1 hunks)
  • src/praisonai-agents/praisonaiagents/mcp/mcp.py (1 hunks)
  • src/praisonai-agents/pyproject.toml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/praisonai-agents/praisonaiagents/mcp/init.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/praisonai-agents/pyproject.toml
  • src/praisonai-agents/mcp-multiagents.py
🧰 Additional context used
🧬 Code Definitions (5)
src/praisonai-agents/mcp-npx-airbnb-agent-direct.py (2)
src/praisonai-agents/npx_mcp_wrapper_main.py (1)
  • MCP (12-262)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (1)
  • MCP (100-319)
src/praisonai-agents/mcp_airbnb_full_direct.py (1)
src/praisonai-agents/mcp_airbnb_client_direct.py (1)
  • run (23-63)
src/praisonai-agents/mcp_airbnb_client_direct.py (2)
src/praisonai-agents/mcp_airbnb_full_direct.py (1)
  • run (106-117)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (1)
  • run (27-29)
src/praisonai-agents/mcp_wrapper.py (1)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (1)
  • call_tool (73-93)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (3)
src/praisonai-agents/mcp_airbnb_client_direct.py (1)
  • run (23-63)
src/praisonai-agents/mcp_airbnb_full_direct.py (1)
  • run (106-117)
src/praisonai-agents/npx_mcp_wrapper_main.py (3)
  • MCP (12-262)
  • wrapper (154-219)
  • _create_tool_wrapper (143-225)
🪛 Ruff (0.8.2)
src/praisonai-agents/mcp_airbnb_full_direct.py

107-111: Use a single with statement with multiple contexts instead of nested with statements

Combine with statements

(SIM117)

src/praisonai-agents/praisonaiagents/mcp/mcp.py

4-4: time imported but unused

Remove unused import: time

(F401)


9-9: typing.Optional imported but unused

Remove unused import

(F401)


9-9: typing.Union imported but unused

Remove unused import

(F401)


10-10: functools.partial imported but unused

Remove unused import: functools.partial

(F401)


35-36: Use a single with statement with multiple contexts instead of nested with statements

(SIM117)


304-304: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: test
  • GitHub Check: test
🔇 Additional comments (12)
src/praisonai-agents/praisonaiagents/mcp/mcp.py (7)

60-61: Consider raising an exception with more context instead of putting a string in the queue

This will allow for better error handling and debugging.

-                                    self.result_queue.put((False, str(e)))
+                                    self.result_queue.put((False, e))

71-71: Consider raising an exception with more context instead of putting a string in the queue

This will allow for better error handling and debugging.

-            self.result_queue.put((False, f"MCP initialization error: {str(e)}"))
+            self.result_queue.put((False, e))

78-78: Instead of returning a string, consider raising an exception to signal the timeout

This provides better error propagation and allows callers to catch specific exceptions.

-                return "Error: MCP initialization timed out"
+                raise TimeoutError("MCP initialization timed out")

86-86: Instead of returning a string, consider raising the exception to signal the error

Propagating exceptions allows for better error handling in the calling code.

-            return f"Error: {result}"
+            raise Exception(result)

100-131: Great docstring with clear examples and explanations

The class docstring is well-written, providing a clear explanation of the class's purpose and including practical examples of how to use it. This makes the API much more accessible to new users.


195-208: Good implementation of tool function generation

The implementation of _generate_tool_functions is clean and properly creates wrapper functions for each MCP tool. The method is well-documented and returns the correct type.


210-285: Well-structured tool wrapper creation with proper signature handling

The _create_tool_wrapper method does an excellent job of:

  1. Analyzing parameter schemas from the tool definition
  2. Creating appropriate type annotations
  3. Building a proper function signature
  4. Wrapping the template function to preserve metadata
  5. Handling both positional and keyword arguments

This is a robust implementation that ensures the generated functions behave like native Python functions.

src/praisonai-agents/mcp-npx-airbnb-agent-direct.py (1)

5-16: Agent configuration looks good

The agent is properly configured with clear instructions, an appropriate LLM model, and correctly formatted MCP tool arguments.

src/praisonai-agents/mcp-npx-airbnb-stockprice.py (1)

18-23: Stock price agent configuration has good instructions

The agent instructions clearly communicate its purpose and available functionality to the user. This is a good practice for clarity.

src/praisonai-agents/mcp_airbnb_client_direct.py (1)

23-63: Validate or sanitize user input for real scenarios.

The current script tests a static prompt for booking. In a production environment, user inputs may require validation (e.g., date ranges or location checks) before sending them to the MCP server.

src/praisonai-agents/mcp_airbnb_full_direct.py (1)

54-103: Verify behavior with multiple function calls.

The loop enforces a maximum of five tool calls. Any additional calls beyond that limit won't be processed. Confirm that truncating extra calls is the intended behavior.

src/praisonai-agents/npx_mcp_wrapper_main.py (1)

1-11: Good use of logging configuration.

The structured logging approach (level, message format, date format) ensures clearer diagnostics and troubleshooting.

instructions="""You are a helpful assistant that can check stock prices and perform other tasks.
Use the available tools when relevant to answer user questions.""",
llm="gpt-4o-mini",
tools = MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove hardcoded absolute paths

Using absolute paths specific to a user's system will prevent the code from working on other machines. Consider using relative paths or environment variables.

-    tools = MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")
+    tools = MCP("python", args=["stockprice/app.py"])

Alternatively, use environment variables:

import os
...
python_path = os.environ.get("MCP_PYTHON_PATH", "python")
app_path = os.environ.get("STOCKPRICE_APP_PATH", "stockprice/app.py")
tools = MCP(python_path, args=[app_path])

"--client",
"claude",
"--config",
'{"braveApiKey":"BSANfDaqLKO9wq7e08mrPth9ZlJvKtc"}'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Store API keys in environment variables or a secure store instead of plain text.

Embedding API credentials in the code poses a security risk. It's safer to reference them from environment variables:

- '{"braveApiKey":"BSANfDaqLKO9wq7e08mrPth9ZlJvKtc"}'
+ f'{{"braveApiKey":"{os.getenv("BRAVE_API_KEY")}"}}'
📝 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.

Suggested change
'{"braveApiKey":"BSANfDaqLKO9wq7e08mrPth9ZlJvKtc"}'
f'{{"braveApiKey":"{os.getenv("BRAVE_API_KEY")}"}}'

Comment on lines +197 to +216
try:
# Write the temporary script to a file
temp_script_path = os.path.join(os.path.dirname(__file__), f"_temp_call_mcp_tool_{tool_name}.py")
with open(temp_script_path, "w") as f:
f.write(temp_script)

# Run the temporary script to call the MCP tool
cmd = ["python", temp_script_path, self.command] + self.args + [tool_name, json.dumps(kwargs)]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=self.timeout)

# Remove the temporary script
os.remove(temp_script_path)

if result.returncode != 0:
logger.error(f"Error calling MCP tool {tool_name}: {result.stderr}")
return {"error": f"Failed to call MCP tool: {result.stderr}"}

# Parse the result from the script output
return json.loads(result.stdout.strip())

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve security and concurrency for temporary script creation.

Writing a Python script to disk for each invocation can pose race conditions in multi-tenant or parallel scenarios. An in-memory approach or a unique, ephemeral directory can reduce security risks and avoid collisions.

Would you like me to draft an in-memory approach or ephemeral file handling pattern?

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