Compare commits

...
32 Commits
Author SHA1 Message Date
Mervin Praison dc393e1211 Merge pull request #456 from MervinPraison/develop
Increment version to 0.0.77 in `pyproject.toml` and update `markitdow…
2025-05-13 14:47:44 +01:00
MervinPraison fdff17faf9 MCP SSE Docs 2025-05-13 14:46:11 +01:00
MervinPraison b3d893fae1 Implement SSEMCPClient and SSEMCPTool for MCP server interaction, enhance logging configuration, and increment version to 0.0.77 in pyproject.toml and uv.lock for improved functionality. 2025-05-13 14:29:41 +01:00
MervinPraison d92dede515 Re-add mcp-sse-direct-agent.py without API key 2025-05-13 14:01:35 +01:00
MervinPraison a1882233dc mcp sse 2025-05-13 13:55:32 +01:00
MervinPraison c540ba34fb Increment version to 0.0.76 in pyproject.toml and update markitdown dependency to include all extras in uv.lock for enhanced functionality. 2025-04-08 12:05:03 +01:00
Mervin Praison 0abb1b659a Merge pull request #455 from MervinPraison/develop
Increment version to 0.0.75 in `pyproject.toml` and update Python com…
2025-04-08 11:49:15 +01:00
MervinPraison 81adb28688 Increment version to 0.0.75 in pyproject.toml and update Python compatibility requirements in uv.lock to support Python 3.11 and above. 2025-04-08 11:48:53 +01:00
Mervin Praison 5fbe6e948c Merge pull request #450 from ihsankursadunal/add-to-vector-store-fifth-positional-argument
RAG knowledge positional argument error fix
2025-04-08 11:48:11 +01:00
Mervin Praison 6128e4c885 Merge pull request #454 from MervinPraison/develop
Add new Databutton and Research agents in `databutton-mcp.py` and `mc…
2025-04-08 11:35:34 +01:00
MervinPraison 0e563989ed Add new Databutton and Research agents in databutton-mcp.py and mcp-llama4.py, respectively. Increment version to 0.0.74 in pyproject.toml and update Python requirements in uv.lock for compatibility with Python 3.13. 2025-04-08 11:34:37 +01:00
Mervin Praison 510a853e05 Merge pull request #453 from chonknick/update-chonkie-v102
Fix: breaking change with Chonkie `v1.0.2` — `WordChunker` not found
2025-04-08 11:32:13 +01:00
Bhavnick @ chonkie.ai d6084cb7ce Update chonkie dependency version to 1.0.2 in pyproject.toml and requirements.txt for improved compatibility. 2025-04-07 23:45:26 +05:30
Bhavnick @ chonkie.ai 8d4b1c411b Enhance chunking method: Disable unsupported context parameters and add warning for future support. Track in https://github.com/chonkie-inc/chonkie/issues/21 2025-04-07 23:38:37 +05:30
bhavnicksm 3be05c855b Fix: Remove WordChunker + Disable OverlapRefinery (temporarily) 2025-04-07 23:18:43 +05:30
bhavnicksm 3e5a2f76f4 Update chonkie version to the latest v1.0.2 2025-04-07 23:18:14 +05:30
ihsankursadunal 8eee881d2e RAG knowledge positional argument error fix 2025-04-06 13:09:35 +03:00
Mervin Praison d75f4be41a Merge pull request #448 from MervinPraison/develop
Develop
2025-04-03 06:47:51 +01:00
MervinPraison 9ea89448ef Increment version number to 0.0.73 in pyproject.toml and uv.lock to reflect recent updates. 2025-04-03 06:47:35 +01:00
MervinPraison 0a5e2df278 Merge PR #409: Support chat without stream while maintaining stream=True as default 2025-04-03 06:30:23 +01:00
MervinPraison cc3b64f89b fix: keep default stream=True while supporting stream=False option 2025-04-03 06:30:04 +01:00
Mervin Praison 546dc5a441 Merge pull request #391 from yiranwu0/main
Update AG2 reference
2025-04-02 21:44:22 +01:00
Mervin Praison bd7422c7ca Merge pull request #443 from MervinPraison/develop
Add WhatsApp and Perplexity MCP Integrations
2025-04-02 09:54:17 +01:00
MervinPraison 0c2c6da8dd Add WhatsApp and Perplexity MCP Integrations
- Included new MCP tools for WhatsApp and Perplexity in `mint.json` for enhanced functionality.
- Updated installation instructions in `openrouter.mdx` and `xai.mdx` to specify the correct package format.
- Added detailed documentation for WhatsApp and Perplexity integrations, including setup steps and example scripts.
- Incremented version number to 0.0.72 in `pyproject.toml` and `uv.lock` to reflect recent changes.
2025-04-02 09:54:02 +01:00
Mervin Praison b43688086f Merge pull request #442 from MervinPraison/develop
Update to version 2.1.1
2025-04-01 22:22:06 +01:00
MervinPraison 820619e8d9 Update to version 2.1.1
- Incremented version number to 2.1.1 in `pyproject.toml`, `praisonai.rb`, and `uv.lock` to reflect recent changes.
- Updated dependency version for `praisonaiagents` to 0.0.71 in `pyproject.toml` and `uv.lock`.
- Modified Dockerfile and deployment scripts to install the updated version of `praisonai`.
- Added new documentation files for various MCP integrations, including Anthropic, Gemini, Groq, Mistral, Ollama, OpenAI, and XAI.
- Introduced example scripts for each MCP integration to facilitate user understanding and implementation.
- Enhanced the LLM class to process tool results based on the original user query for improved response accuracy.
2025-04-01 22:21:50 +01:00
kevin666aa 798fe68908 update reference 2025-03-30 16:40:06 -04:00
kevin666aa 95796cd4c7 Merge remote-tracking branch 'upstream/main' 2025-03-30 16:22:40 -04:00
Yuga Sun eaf337b301 fix: remove default stream value for agent 2025-03-11 04:07:40 +00:00
Yuga Sun 2f73cf1882 fix: support chat without stream 2025-03-10 08:00:05 +00:00
kevin666aa 680949742e Merge remote-tracking branch 'upstream/main' 2025-02-13 15:44:32 -05:00
kevin666aa 560219dcd7 update 2025-02-13 13:39:48 -05:00
66 changed files with 12260 additions and 186 deletions

No files matched your search

+2 -2
View File
@@ -20,7 +20,7 @@
</div>
PraisonAI is a production-ready Multi-AI Agents framework with self-reflection, designed to create AI Agents to automate and solve problems ranging from simple tasks to complex challenges. By integrating PraisonAI Agents, AutoGen, and CrewAI into a low-code solution, it streamlines the building and management of multi-agent LLM systems, emphasising simplicity, customisation, and effective human-agent collaboration.
PraisonAI is a production-ready Multi-AI Agents framework with self-reflection, designed to create AI Agents to automate and solve problems ranging from simple tasks to complex challenges. By integrating PraisonAI Agents, AG2 (Formerly AutoGen), and CrewAI into a low-code solution, it streamlines the building and management of multi-agent LLM systems, emphasising simplicity, customisation, and effective human-agent collaboration.
<div align="center">
<a href="https://docs.praison.ai">
@@ -548,7 +548,7 @@ uv pip install -r pyproject.toml --extra "crewai,autogen"
## Other Features
- 🔄 Use CrewAI or AutoGen Framework
- 🔄 Use CrewAI or AG2 (Formerly AutoGen) Framework
- 💻 Chat with ENTIRE Codebase
- 🎨 Interactive UIs
- 📄 YAML-based Configuration
+1 -1
View File
@@ -1,6 +1,6 @@
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install flask praisonai==2.1.0 gunicorn markdown
RUN pip install flask praisonai==2.1.1 gunicorn markdown
EXPOSE 8080
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
+1 -1
View File
@@ -30,7 +30,7 @@ Features:
- Built-in tools
- Structured workflows
### AutoGen Integration
### AG2 (Formerly AutoGen) Integration
Requires installation with:
```bash
pip install "praisonai[autogen]"
+4 -4
View File
@@ -23,7 +23,7 @@ from praisonai.auto import AutoGenerator
### praisonai.agents_generator
Framework-specific agent generation and orchestration:
- CrewAI support (requires `praisonai[crewai]`)
- AutoGen support (requires `praisonai[autogen]`)
- AG2 (Formerly AutoGen) support (requires `praisonai[autogen]`)
```python
from praisonai.agents_generator import AgentsGenerator
@@ -51,7 +51,7 @@ pip install praisonai
# Framework-specific installations
pip install "praisonai[crewai]" # Install with CrewAI support
pip install "praisonai[autogen]" # Install with AutoGen support
pip install "praisonai[autogen]" # Install with AG2 support
pip install "praisonai[crewai,autogen]" # Install both frameworks
# Additional features
@@ -71,9 +71,9 @@ When installing with `pip install "praisonai[crewai]"`, you get:
- Task delegation capabilities
- Sequential and parallel task execution
### AutoGen
### AG2 (Formerly AutoGen)
When installing with `pip install "praisonai[autogen]"`, you get:
- AutoGen framework support
- AG2 framework support
- PraisonAI tools integration
- Multi-agent conversation capabilities
- Code execution environment
+1 -1
View File
@@ -110,7 +110,7 @@ Loads environment variables from .env file or system and sets them.</p>
file.write(&#34;FROM python:3.11-slim\n&#34;)
file.write(&#34;WORKDIR /app\n&#34;)
file.write(&#34;COPY . .\n&#34;)
file.write(&#34;RUN pip install flask praisonai==2.1.0 gunicorn markdown\n&#34;)
file.write(&#34;RUN pip install flask praisonai==2.1.1 gunicorn markdown\n&#34;)
file.write(&#34;EXPOSE 8080\n&#34;)
file.write(&#39;CMD [&#34;gunicorn&#34;, &#34;-b&#34;, &#34;0.0.0.0:8080&#34;, &#34;api:app&#34;]\n&#39;)
+2 -2
View File
@@ -65,14 +65,14 @@ def basic(): # Basic Mode
def advanced(): # Advanced Mode with options
praisonai = PraisonAI(
agent_file="agents.yaml",
framework="autogen",
framework="autogen", # use AG2 framework (Formerly AutoGen)
)
praisonai.run()
def auto(): # Full Automatic Mode
praisonai = PraisonAI(
auto="Create a movie script about car in mars",
framework="autogen"
framework="autogen" # use AG2 framework
)
print(praisonai.framework)
praisonai.run()
+7 -6
View File
@@ -1,12 +1,13 @@
---
title: "AutoGen with PraisonAI"
description: "Guide for using AutoGen framework with PraisonAI, including installation, setup, and multi-agent conversation capabilities"
title: "AG2 with PraisonAI"
description: "Guide for using AG2 framework with PraisonAI, including installation, setup, and multi-agent conversation capabilities"
icon: "robot"
---
# AutoGen with PraisonAI
# AG2 with PraisonAI
Low-code solution to run AutoGen with integrated tools and features.
Low-code solution to run AG2 with integrated tools and features.
AutoGen is being evolved into AG2, check the new look [here](https://docs.ag2.ai/docs/Home/)
## Installation
@@ -16,7 +17,7 @@ pip install "praisonai[autogen]"
```
This installation includes:
- AutoGen framework
- AG2 framework
- PraisonAI tools integration
- Multi-agent conversation capabilities
- Code execution environment
@@ -27,7 +28,7 @@ This installation includes:
# Set your OpenAI API key
export OPENAI_API_KEY=xxxxxxxxxx
# Initialize with AutoGen
# Initialize with AG2
praisonai --framework autogen --init "Create a Movie Script About Cat in Mars"
# Run the agents
+6 -6
View File
@@ -1,7 +1,7 @@
---
title: "Praison AI"
sidebarTitle: "Home"
description: "Comprehensive guide to PraisonAI - an AI Agents Framework with Self Reflection, combining PraisonAI Agents, AutoGen, and CrewAI for building multi-agent LLM systems"
description: "Comprehensive guide to PraisonAI - an AI Agents Framework with Self Reflection, combining PraisonAI Agents, AG2 (Formerly AutoGen), and CrewAI for building multi-agent LLM systems"
icon: "house"
openGraph:
url: "/"
@@ -46,7 +46,7 @@ seo:
</div>
<Tip>
PraisonAI combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration.
PraisonAI combines PraisonAI Agents, AG2 (Formerly AutoGen), and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration.
</Tip>
## Key Features
@@ -56,7 +56,7 @@ seo:
Automated creation and management of AI agents with self-reflection capabilities
</Card>
<Card title="Framework Integration" icon="puzzle-piece">
Seamless integration with CrewAI and AutoGen frameworks
Seamless integration with CrewAI and AG2 frameworks
</Card>
<Card title="LLM Support" icon="brain">
Support for 100+ Language Learning Models
@@ -301,8 +301,8 @@ seo:
<Card title="CrewAI Framework" icon="users-gear" href="/framework/crewai">
Build collaborative AI teams with CrewAI integration
</Card>
<Card title="AutoGen Framework" icon="robot" href="/framework/autogen">
Create autonomous agent networks using AutoGen
<Card title="AG2 Framework" icon="robot" href="/framework/autogen">
Create autonomous agent networks using AG2 (Formerly AutoGen)
</Card>
<Card title="Multimodal Agents" icon="icons" href="/framework/multimodalagents">
Work with agents that can process text, images, and other data types
@@ -316,7 +316,7 @@ seo:
<CardGroup cols={3}>
<Card title="Multi Agents UI" icon="users" href="/ui/ui">
Work with CrewAI or AutoGen multi-agent systems
Work with CrewAI or AG2 multi-agent systems
</Card>
<Card title="Chat Interface" icon="comments" href="/ui/chat">
Chat with 100+ LLMs using a single AI Agent
+5 -5
View File
@@ -1,7 +1,7 @@
---
title: "Praison AI"
sidebarTitle: "Home"
description: "PraisonAI is a production-ready Multi-AI Agents framework with self-reflection, designed to create AI Agents to automate and solve problems ranging from simple tasks to complex challenges. By integrating PraisonAI Agents, AutoGen, and CrewAI into a low-code solution, it streamlines the building and management of multi-agent LLM systems, emphasising simplicity, customisation, and effective human-agent collaboration."
description: "PraisonAI is a production-ready Multi-AI Agents framework with self-reflection, designed to create AI Agents to automate and solve problems ranging from simple tasks to complex challenges. By integrating PraisonAI Agents, AG2 (Formerly AutoGen), and CrewAI into a low-code solution, it streamlines the building and management of multi-agent LLM systems, emphasising simplicity, customisation, and effective human-agent collaboration."
icon: "house"
openGraph:
url: "/"
@@ -45,7 +45,7 @@ seo:
Automated creation and management of AI agents with self-reflection capabilities
</Card>
<Card title="Framework Integration" icon="puzzle-piece">
Seamless integration with CrewAI and AutoGen frameworks
Seamless integration with CrewAI and AG2 frameworks
</Card>
<Card title="LLM Support" icon="brain">
Support for 100+ Language Learning Models
@@ -711,8 +711,8 @@ flowchart LR
<Card title="CrewAI Framework" icon="users-gear" href="/framework/crewai">
Build collaborative AI teams with CrewAI integration
</Card>
<Card title="AutoGen Framework" icon="robot" href="/framework/autogen">
Create autonomous agent networks using AutoGen
<Card title="AG2 Framework" icon="robot" href="/framework/autogen">
Create autonomous agent networks using AG2 (Formerly AutoGen)
</Card>
<Card title="Multimodal Agents" icon="icons" href="/framework/multimodalagents">
Work with agents that can process text, images, and other data types
@@ -726,7 +726,7 @@ flowchart LR
<CardGroup cols={3}>
<Card title="Multi Agents UI" icon="users" href="/ui/ui">
Work with CrewAI or AutoGen multi-agent systems
Work with CrewAI or AG2 multi-agent systems
</Card>
<Card title="Chat Interface" icon="comments" href="/ui/chat">
Chat with 100+ LLMs using a single AI Agent
+93
View File
@@ -0,0 +1,93 @@
---
title: "Anthropic MCP Integration"
sidebarTitle: "Anthropic"
description: "Guide for integrating Anthropic's Claude models with PraisonAI agents using MCP"
icon: "a"
---
## Add Anthropic Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Airbnb MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#FF5A5F,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set API Key">
Set your Anthropic API key as an environment variable in your terminal:
```zsh
export ANTHROPIC_API_KEY=your_anthropic_api_key_here
```
</Step>
<Step title="Create a file">
Create a new file `anthropic_airbnb.py` with the following code:
```python
from praisonaiagents import Agent, MCP
import os
# Get API key from environment variable
anthropic_api_key = os.environ.get("ANTHROPIC_API_KEY")
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="anthropic/claude-3-7-sonnet-20250219",
tools=MCP(
command="npx",
args=["-y", "@openbnb/mcp-server-airbnb", "--ignore-robots-txt"],
env={"ANTHROPIC_API_KEY": anthropic_api_key}
)
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
```
</Step>
<Step title="Install Dependencies">
Make sure you have Node.js installed, as the MCP server requires it:
```bash
pip install "praisonaiagents[llm]"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python anthropic_airbnb.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Node.js installed on your system
- Anthropic API key
</Note>
## Features
<CardGroup cols={2}>
<Card title="Claude 3.7 Sonnet" icon="brain">
Leverage Anthropic's powerful Claude 3.7 Sonnet model.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Airbnb Search" icon="hotel">
Search for accommodations on Airbnb with natural language queries.
</Card>
<Card title="Environment Variables" icon="key">
Securely pass API keys using environment variables.
</Card>
</CardGroup>
+93
View File
@@ -0,0 +1,93 @@
---
title: "Gemini MCP Integration"
sidebarTitle: "Gemini"
description: "Guide for integrating Google's Gemini models with PraisonAI agents using MCP"
icon: "google"
---
## Add Gemini Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Airbnb MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#FF5A5F,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set API Key">
Set your Google API key as an environment variable in your terminal:
```zsh
export GOOGLE_API_KEY=your_google_api_key_here
```
</Step>
<Step title="Create a file">
Create a new file `gemini_airbnb.py` with the following code:
```python
from praisonaiagents import Agent, MCP
import os
# Get API key from environment variable
google_api_key = os.environ.get("GOOGLE_API_KEY")
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="gemini/gemini-2.5-pro-exp-03-25",
tools=MCP(
command="npx",
args=["-y", "@openbnb/mcp-server-airbnb", "--ignore-robots-txt"],
env={"GOOGLE_API_KEY": google_api_key}
)
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
```
</Step>
<Step title="Install Dependencies">
Make sure you have Node.js installed, as the MCP server requires it:
```bash
pip install "praisonaiagents[llm]"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python gemini_airbnb.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Node.js installed on your system
- Google API key for Gemini models
</Note>
## Features
<CardGroup cols={2}>
<Card title="Gemini 2.5 Pro" icon="brain">
Leverage Google's advanced Gemini 2.5 Pro model.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Airbnb Search" icon="hotel">
Search for accommodations on Airbnb with natural language queries.
</Card>
<Card title="Environment Variables" icon="key">
Securely pass API keys using environment variables.
</Card>
</CardGroup>
+85
View File
@@ -0,0 +1,85 @@
---
title: "Groq MCP Integration"
sidebarTitle: "Groq"
description: "Guide for integrating Groq models with PraisonAI agents using MCP"
icon: "bolt"
---
## Add Groq Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Airbnb MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#FF5A5F,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set API Key">
Set your Groq API key as an environment variable in your terminal:
```bash
export GROQ_API_KEY=your_groq_api_key_here
```
</Step>
<Step title="Create a file">
Create a new file `groq_airbnb.py` with the following code:
```python
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="groq/llama-3.2-90b-vision-preview",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
```
</Step>
<Step title="Install Dependencies">
Make sure you have Node.js installed, as the MCP server requires it:
```bash
pip install "praisonaiagents[llm]"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python groq_airbnb.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Node.js installed on your system
- Groq API key
</Note>
## Features
<CardGroup cols={2}>
<Card title="Ultra-Fast Inference" icon="bolt">
Utilize Groq's high-performance LPU inference for rapid responses.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Airbnb Search" icon="hotel">
Search for accommodations on Airbnb with natural language queries.
</Card>
<Card title="Advanced Models" icon="brain">
Access to Llama 3.2 90B and other powerful models.
</Card>
</CardGroup>
+93
View File
@@ -0,0 +1,93 @@
---
title: "Mistral MCP Integration"
sidebarTitle: "Mistral"
description: "Guide for integrating Mistral models with PraisonAI agents using MCP"
icon: "wind"
---
## Add Mistral Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Airbnb MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#FF5A5F,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set API Key">
Set your Mistral API key as an environment variable in your terminal:
```zsh
export MISTRAL_API_KEY=your_mistral_api_key_here
```
</Step>
<Step title="Create a file">
Create a new file `mistral_airbnb.py` with the following code:
```python
from praisonaiagents import Agent, MCP
import os
# Get API key from environment variable
mistral_api_key = os.environ.get("MISTRAL_API_KEY")
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="mistral/mistral-large-latest",
tools=MCP(
command="npx",
args=["-y", "@openbnb/mcp-server-airbnb", "--ignore-robots-txt"],
env={"MISTRAL_API_KEY": mistral_api_key}
)
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
```
</Step>
<Step title="Install Dependencies">
Make sure you have Node.js installed, as the MCP server requires it:
```bash
pip install "praisonaiagents[llm]"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python mistral_airbnb.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Node.js installed on your system
- Mistral API key
</Note>
## Features
<CardGroup cols={2}>
<Card title="Mistral Large" icon="brain">
Leverage Mistral's powerful large language model.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Airbnb Search" icon="hotel">
Search for accommodations on Airbnb with natural language queries.
</Card>
<Card title="Environment Variables" icon="key">
Securely pass API keys using environment variables.
</Card>
</CardGroup>
+90
View File
@@ -0,0 +1,90 @@
---
title: "Ollama Python MCP Integration"
sidebarTitle: "Ollama Python"
description: "Guide for integrating Ollama models with Python MCP servers using PraisonAI agents"
icon: "python"
---
## Add Ollama Python Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Stock Price MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#3776AB,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set Up Ollama">
Make sure you have Ollama installed and running locally:
```bash
# Install Ollama from https://ollama.ai/
# Pull the llama3.2 model
ollama pull llama3.2
```
</Step>
<Step title="Create a file">
Create a new file `ollama_stock.py` with the following code:
```python
from praisonaiagents import Agent, MCP
stock_agent = Agent(
instructions="""You are a Stock Price Assistant.""",
llm="ollama/llama3.2",
tools=MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")
)
# NOTE: Python Path replace with yours: /Users/praison/miniconda3/envs/mcp/bin/python
# NOTE: app.py file path, replace it with yours: /Users/praison/stockprice/app.py
stock_agent.start("What is the Stock Price of Apple?")
```
</Step>
<Step title="Install Dependencies">
Make sure you have the required packages installed:
```bash
pip install "praisonaiagents[llm]" yfinance mcp
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python ollama_stock.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Ollama installed and running locally
- yfinance and mcp packages installed
</Note>
## Features
<CardGroup cols={2}>
<Card title="Local LLM" icon="server">
Run models locally using Ollama without relying on external APIs.
</Card>
<Card title="Stock Data" icon="chart-line">
Retrieve real-time stock price information using the yfinance library.
</Card>
<Card title="Python MCP" icon="python">
Use Python-based MCP servers for custom tool functionality.
</Card>
<Card title="Privacy-Focused" icon="shield-alt">
Keep sensitive data local with on-device inference.
</Card>
</CardGroup>
+87
View File
@@ -0,0 +1,87 @@
---
title: "Ollama MCP Integration"
sidebarTitle: "Ollama"
description: "Guide for integrating Ollama models with PraisonAI agents using MCP"
icon: "dragon"
---
## Add Ollama Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Airbnb MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#FF5A5F,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set Up Ollama">
Make sure you have Ollama installed and running locally:
```bash
# Install Ollama from https://ollama.ai/
# Pull the llama3.2 model
ollama pull llama3.2
```
</Step>
<Step title="Create a file">
Create a new file `ollama_airbnb.py` with the following code:
```python
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="ollama/llama3.2",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
```
</Step>
<Step title="Install Dependencies">
Make sure you have Node.js installed, as the MCP server requires it:
```bash
pip install "praisonaiagents[llm]"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python ollama_airbnb.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Node.js installed on your system
- Ollama installed and running locally
</Note>
## Features
<CardGroup cols={2}>
<Card title="Local LLM" icon="server">
Run models locally using Ollama without relying on external APIs.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Airbnb Search" icon="hotel">
Search for accommodations on Airbnb with natural language queries.
</Card>
<Card title="Privacy-Focused" icon="shield-alt">
Keep sensitive data local with on-device inference.
</Card>
</CardGroup>
+128
View File
@@ -0,0 +1,128 @@
---
title: "OpenAI MCP Integration"
sidebarTitle: "OpenAI"
description: "Guide for integrating OpenAI models with PraisonAI agents using MCP"
icon: "folder-open"
---
## Add OpenAI Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Airbnb MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#FF5A5F,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set API Key">
Set your OpenAI API key as an environment variable in your terminal:
```zsh
export OPENAI_API_KEY=your_openai_api_key_here
```
</Step>
<Step title="Create a file">
Create a new file `openai_airbnb.py` with the following code:
```python
from praisonaiagents import Agent, MCP
import os
# Get API key from environment variable
openai_api_key = os.environ.get("OPENAI_API_KEY")
search_agent = 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"],
env={"OPENAI_API_KEY": openai_api_key}
)
)
search_agent.start("I want to book an apartment in Paris for 2 nights. 03/28 - 03/30 for 2 adults")
```
</Step>
<Step title="Install Dependencies">
Make sure you have Node.js installed, as the MCP server requires it:
```zsh
pip install praisonaiagents
```
</Step>
<Step title="Run the Agent">
Execute your script:
```zsh
python openai_airbnb.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Node.js installed on your system
- OpenAI API key (for the agent's LLM)
</Note>
## Gradio UI
```python
from praisonaiagents import Agent, MCP
import gradio as gr
import os
# Get API key from environment variable
openai_api_key = os.environ.get("OPENAI_API_KEY")
def search_airbnb(query):
agent = 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"],
env={"OPENAI_API_KEY": openai_api_key}
)
)
result = agent.start(query)
return f"## Airbnb Search Results\n\n{result}"
demo = gr.Interface(
fn=search_airbnb,
inputs=gr.Textbox(placeholder="I want to book an apartment in Paris for 2 nights..."),
outputs=gr.Markdown(),
title="Airbnb Booking Assistant",
description="Enter your booking requirements below:"
)
if __name__ == "__main__":
demo.launch()
```
## Features
<CardGroup cols={2}>
<Card title="GPT-4o-mini" icon="brain">
Uses OpenAI's efficient GPT-4o-mini model for optimal performance.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Airbnb Search" icon="hotel">
Search for accommodations on Airbnb with natural language queries.
</Card>
<Card title="Environment Variables" icon="key">
Securely pass API keys using environment variables.
</Card>
</CardGroup>
+85
View File
@@ -0,0 +1,85 @@
---
title: "OpenRouter MCP Integration"
sidebarTitle: "OpenRouter"
description: "Guide for integrating OpenRouter models with PraisonAI agents using MCP"
icon: "network-wired"
---
## Add OpenRouter Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Airbnb MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#FF5A5F,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set API Key">
Set your OpenRouter API key as an environment variable in your terminal:
```bash
export OPENROUTER_API_KEY=your_openrouter_api_key_here
```
</Step>
<Step title="Create a file">
Create a new file `openrouter_airbnb.py` with the following code:
```python
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="openrouter/google/gemini-2.0-flash-exp:free",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
```
</Step>
<Step title="Install Dependencies">
Make sure you have Node.js installed, as the MCP server requires it:
```bash
pip install "praisonaiagents[llm]"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python openrouter_airbnb.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Node.js installed on your system
- OpenRouter API key
</Note>
## Features
<CardGroup cols={2}>
<Card title="Model Flexibility" icon="layer-group">
Access to various models through OpenRouter's unified API.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Airbnb Search" icon="hotel">
Search for accommodations on Airbnb with natural language queries.
</Card>
<Card title="Cost Effective" icon="money-bill">
Use free tier models like Gemini Flash through OpenRouter.
</Card>
</CardGroup>
+91
View File
@@ -0,0 +1,91 @@
---
title: "Perplexity MCP Integration"
sidebarTitle: "Perplexity"
description: "Guide for integrating Perplexity search with PraisonAI agents using MCP"
icon: "magnifying-glass"
---
## Add Perplexity Search Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Perplexity MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#4B0082,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set API Key">
Set your Perplexity API key as an environment variable in your terminal:
```bash
export PERPLEXITY_API_KEY=your_perplexity_api_key_here
```
</Step>
<Step title="Create a file">
Create a new file `perplexity_search.py` with the following code:
```python
from praisonaiagents import Agent, MCP
import os
# Get API key from environment variable
api_key = os.getenv("PERPLEXITY_API_KEY")
agent = Agent(
instructions="You are a helpful assistant that can search the web for information. Use the available tools when relevant to answer user questions.",
llm="gpt-4o-mini",
tools=MCP("uvx perplexity-mcp",
env={"PERPLEXITY_API_KEY": api_key, "PERPLEXITY_MODEL": "sonar" })
)
result = agent.start("What is the latest news on AI?, Pass only the query parameter to the tool")
print(result)
```
</Step>
<Step title="Install Dependencies">
Make sure you have the required packages installed:
```bash
pip install "praisonaiagents[llm]"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python perplexity_search.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Perplexity API key
</Note>
## Features
<CardGroup cols={2}>
<Card title="Web Search" icon="globe">
Search the web for real-time information using Perplexity's powerful search API.
</Card>
<Card title="Sonar Model" icon="radar">
Utilize Perplexity's Sonar model for high-quality search results.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Environment Variables" icon="key">
Securely pass API keys using environment variables.
</Card>
</CardGroup>
+248
View File
@@ -0,0 +1,248 @@
---
title: "MCP SSE Integration"
sidebarTitle: "MCP SSE"
description: "Guide for integrating Server-Sent Events (SSE) with PraisonAI agents using MCP"
icon: "server"
---
## Add SSE Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[SSE MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#4169E1,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Create a client file">
```python
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You are a weather agent that can provide weather information for a given city.""",
llm="gpt-4o-mini",
tools=MCP("http://localhost:8080/sse")
)
search_agent.start("What is the weather in London?")
```
</Step>
<Step title="Set Up SSE MCP Server">
```python
# python mcp-sse-direct-server.py --host 127.0.0.1 --port 8080
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
from starlette.applications import Starlette
from mcp.server.sse import SseServerTransport
from starlette.requests import Request
from starlette.routing import Mount, Route
from mcp.server import Server
import uvicorn
import argparse
import logging
import os
import inspect
# Set up logging based on environment variable
log_level = os.environ.get("LOGLEVEL", "info").upper()
logging.basicConfig(level=getattr(logging, log_level))
logger = logging.getLogger("mcp-server")
# Initialize FastMCP server for simple tools (SSE)
mcp = FastMCP("simple-tools")
@mcp.tool()
async def get_greeting(name: str) -> str:
"""Get a personalized greeting.
Args:
name: Name of the person to greet
"""
logger.debug(f"get_greeting called with name: {name}")
return f"Hello, {name}! Welcome to our MCP SSE server."
@mcp.tool()
async def get_weather(city: str) -> str:
"""Get a simulated weather report for a city.
Args:
city: Name of the city
"""
logger.debug(f"get_weather called with city: {city}")
# This is a mock implementation
weather_data = {
"Paris": "Sunny with a temperature of 22°C",
"London": "Rainy with a temperature of 15°C",
"New York": "Cloudy with a temperature of 18°C",
"Tokyo": "Clear skies with a temperature of 25°C",
"Sydney": "Partly cloudy with a temperature of 20°C"
}
return weather_data.get(city, f"Weather data not available for {city}")
def create_starlette_app(mcp_server: Server, *, debug: bool = False) -> Starlette:
"""Create a Starlette application that can serve the provided mcp server with SSE."""
sse = SseServerTransport("/messages/")
async def handle_sse(request: Request) -> None:
logger.debug(f"SSE connection request received from {request.client}")
async with sse.connect_sse(
request.scope,
request.receive,
request._send, # noqa: SLF001
) as (read_stream, write_stream):
await mcp_server.run(
read_stream,
write_stream,
mcp_server.create_initialization_options(),
)
return Starlette(
debug=debug,
routes=[
Route("/sse", endpoint=handle_sse),
Mount("/messages/", app=sse.handle_post_message),
],
)
if __name__ == "__main__":
mcp_server = mcp._mcp_server # noqa: WPS437
parser = argparse.ArgumentParser(description='Run MCP SSE-based server')
parser.add_argument('--host', default='localhost', help='Host to bind to')
parser.add_argument('--port', type=int, default=8080, help='Port to listen on')
args = parser.parse_args()
print(f"Starting MCP SSE server on {args.host}:{args.port}")
# Hardcode the tool names since we know what they are
tool_names = ["get_greeting", "get_weather"]
print(f"Available tools: {', '.join(tool_names)}")
# Bind SSE request handling to MCP server
starlette_app = create_starlette_app(mcp_server, debug=True)
uvicorn.run(starlette_app, host=args.host, port=args.port)
```
</Step>
<Step title="Install Dependencies">
Make sure you have the required packages installed:
```bash
pip install "praisonaiagents[llm]" mcp starlette uvicorn httpx
```
</Step>
<Step title="Export API Key">
```bash
export OPENAI_API_KEY="your_api_key"
```
</Step>
<Step title="Run the Server and Agent">
First, start the SSE server:
```bash
python mcp-sse-direct-server.py --host 127.0.0.1 --port 8080
```
Then, in a new terminal, run the agent:
```bash
python weather_agent.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- MCP server dependencies
</Note>
## Alternative LLM Integrations
### Using Groq with SSE
```python
from praisonaiagents import Agent, MCP
weather_agent = Agent(
instructions="""You are a weather agent that can provide weather information for a given city.""",
llm="groq/llama-3.2-90b-vision-preview",
tools=MCP("http://localhost:8080/sse")
)
weather_agent.start("What is the weather in London?")
```
### Using Ollama with SSE
```python
from praisonaiagents import Agent, MCP
weather_agent = Agent(
instructions="""You are a weather agent that can provide weather information for a given city.""",
llm="ollama/llama3.2",
tools=MCP("http://localhost:8080/sse")
)
weather_agent.start("What is the weather in London? Use get_weather tool, city is the required parameter.")
```
## Gradio UI Integration
Create a Gradio UI for your weather service:
```python
from praisonaiagents import Agent, MCP
import gradio as gr
def get_weather_info(query):
weather_agent = Agent(
instructions="""You are a weather agent that can provide weather information for a given city.""",
llm="gpt-4o-mini",
tools=MCP("http://localhost:8080/sse")
)
result = weather_agent.start(query)
return f"## Weather Information\n\n{result}"
demo = gr.Interface(
fn=get_weather_info,
inputs=gr.Textbox(placeholder="What's the weather in London?"),
outputs=gr.Markdown(),
title="Weather MCP Agent",
description="Ask about the weather in any major city:"
)
if __name__ == "__main__":
demo.launch()
```
## Features
<CardGroup cols={2}>
<Card title="Real-time Updates" icon="bolt">
Receive server-sent events in real-time from your AI agent.
</Card>
<Card title="Multi-Agent Support" icon="users">
Combine SSE with other MCP tools for complex workflows.
</Card>
<Card title="Multiple LLM Options" icon="brain">
Use with OpenAI, Groq, Ollama, or other supported LLMs.
</Card>
<Card title="Gradio UI" icon="window">
Create user-friendly interfaces for your SSE integrations.
</Card>
</CardGroup>
+185
View File
@@ -0,0 +1,185 @@
---
title: "WhatsApp MCP Integration"
sidebarTitle: "WhatsApp"
description: "Guide for integrating WhatsApp messaging with PraisonAI agents using MCP"
icon: "whatsapp"
---
## Add WhatsApp Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[WhatsApp MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#25D366,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set Up WhatsApp MCP Server">
Clone and set up the WhatsApp MCP server:
```bash
git clone https://github.com/lharries/whatsapp-mcp.git
cd whatsapp-mcp
cd whatsapp-bridge
go run main.go
```
</Step>
<Step title="Create a file">
Create a new file `whatsapp_message.py` with the following code:
```python
from praisonaiagents import Agent, MCP
whatsapp_agent = Agent(
instructions="Whatsapp Agent",
llm="gpt-4o-mini",
tools=MCP("python /path/to/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
whatsapp_agent.start("Send Hello to Mervin Praison")
```
Note: Replace `/path/to/whatsapp-mcp` with the actual path to your WhatsApp MCP server.
</Step>
<Step title="Install Dependencies">
Make sure you have the required packages installed:
```bash
pip install "praisonaiagents[llm]" mcp gradio
```
</Step>
<Step title="Export API Key">
```bash
export OPENAI_API_KEY="your_api_key"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python whatsapp_message.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- WhatsApp MCP server set up and configured
</Note>
## Multi-Agent Integration
You can also combine WhatsApp with other MCP tools, such as Airbnb search:
```python
from praisonaiagents import Agent, Agents, MCP
airbnb_agent = Agent(
instructions="""Search for Apartments in Paris for 2 nights on Airbnb. 04/28 - 04/30 for 2 adults""",
llm="gpt-4o-mini",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
whatsapp_agent = Agent(
instructions="""Send AirBnb Search Result to 'Mervin Praison'""",
llm="gpt-4o-mini",
tools=MCP("python /path/to/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
agents = Agents(agents=[airbnb_agent, whatsapp_agent])
agents.start()
```
## Alternative LLM Integrations
### Using Groq with WhatsApp
```python
from praisonaiagents import Agent, MCP
whatsapp_agent = Agent(
instructions="Whatsapp Agent",
llm="groq/llama-3.2-90b-vision-preview",
tools=MCP("python /path/to/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
whatsapp_agent.start("Send Hello to Mervin Praison")
```
### Using Ollama with WhatsApp
```python
from praisonaiagents import Agent, MCP
whatsapp_agent = Agent(
instructions="Whatsapp Agent",
llm="ollama/llama3.2",
tools=MCP("python /path/to/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
whatsapp_agent.start("Send Hello to Mervin Praison. Use send_message tool, recipient and message are the required parameters.")
```
## Gradio UI Integration
Create a Gradio UI for your WhatsApp and Airbnb integration:
```python
from praisonaiagents import Agent, Agents, MCP
import gradio as gr
def search_airbnb(query):
airbnb_agent = Agent(
instructions=query+" on Airbnb",
llm="gpt-4o-mini",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
whatsapp_agent = Agent(
instructions="""Send AirBnb Search Result to 'Mervin Praison'. Don't include Phone Number in Response, but include the AirBnb Search Result""",
llm="gpt-4o-mini",
tools=MCP("python /path/to/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
agents = Agents(agents=[airbnb_agent, whatsapp_agent])
result = agents.start()
return f"## Airbnb Search Results\n\n{result}"
demo = gr.Interface(
fn=search_airbnb,
inputs=gr.Textbox(placeholder="I want to book an apartment in Paris for 2 nights..."),
outputs=gr.Markdown(),
title="WhatsApp MCP Agent",
description="Enter your booking requirements below:"
)
if __name__ == "__main__":
demo.launch()
```
## Features
<CardGroup cols={2}>
<Card title="WhatsApp Messaging" icon="message">
Send messages to WhatsApp contacts directly from your AI agent.
</Card>
<Card title="Multi-Agent Support" icon="users">
Combine WhatsApp with other MCP tools for complex workflows.
</Card>
<Card title="Multiple LLM Options" icon="brain">
Use with OpenAI, Groq, Ollama, or other supported LLMs.
</Card>
<Card title="Gradio UI" icon="window">
Create user-friendly interfaces for your WhatsApp integrations.
</Card>
</CardGroup>
+85
View File
@@ -0,0 +1,85 @@
---
title: "xAI MCP Integration"
sidebarTitle: "xAI"
description: "Guide for integrating XAI's Grok model with PraisonAI agents using MCP"
icon: "robot"
---
## Add XAI Tool to AI Agent
```mermaid
flowchart LR
In[In] --> Agent[AI Agent]
Agent --> Tool[Airbnb MCP]
Tool --> Agent
Agent --> Out[Out]
style In fill:#8B0000,color:#fff
style Agent fill:#2E8B57,color:#fff
style Tool fill:#FF5A5F,color:#fff
style Out fill:#8B0000,color:#fff
```
## Quick Start
<Steps>
<Step title="Set API Key">
Set your XAI API key as an environment variable in your terminal:
```bash
export XAI_API_KEY=your_xai_api_key_here
```
</Step>
<Step title="Create a file">
Create a new file `xai_airbnb.py` with the following code:
```python
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="xai/grok-2-latest",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
```
</Step>
<Step title="Install Dependencies">
Make sure you have Node.js installed, as the MCP server requires it:
```bash
pip install "praisonaiagents[llm]"
```
</Step>
<Step title="Run the Agent">
Execute your script:
```bash
python xai_airbnb.py
```
</Step>
</Steps>
<Note>
**Requirements**
- Python 3.10 or higher
- Node.js installed on your system
- XAI API key (for the Grok model)
</Note>
## Features
<CardGroup cols={2}>
<Card title="Grok Integration" icon="robot">
Uses XAI's Grok model for advanced natural language understanding.
</Card>
<Card title="MCP Integration" icon="plug">
Seamless integration with Model Context Protocol.
</Card>
<Card title="Airbnb Search" icon="hotel">
Search for accommodations on Airbnb with natural language queries.
</Card>
<Card title="NPM Package" icon="js">
Leverages the official Airbnb MCP server package.
</Card>
</CardGroup>
+12
View File
@@ -238,6 +238,18 @@
"group": "MCP",
"pages": [
"mcp/airbnb",
"mcp/sse",
"mcp/ollama",
"mcp/groq",
"mcp/openrouter",
"mcp/xai",
"mcp/openai",
"mcp/anthropic",
"mcp/gemini",
"mcp/mistral",
"mcp/whatsapp",
"mcp/perplexity",
"mcp/ollama-python",
"mcp/bravesearch",
"mcp/custom",
"mcp/sequential-thinking",
+5 -5
View File
@@ -1,10 +1,10 @@
---
title: "Auto Generation Mode"
description: "Guide to PraisonAI's automatic agent generation feature, supporting both CrewAI and AutoGen frameworks for automated task execution"
description: "Guide to PraisonAI's automatic agent generation feature, supporting both CrewAI and AG2 frameworks for automated task execution"
icon: "robot"
---
PraisonAI supports automatic agent generation with PraisonAI Agents, CrewAI and AutoGen frameworks.
PraisonAI supports automatic agent generation with PraisonAI Agents, CrewAI and AG2 frameworks.
## Installation
@@ -17,7 +17,7 @@ pip install praisonai
# For CrewAI
pip install "praisonai[crewai]"
# For AutoGen
# For AG2 (Formerly AutoGen)
pip install "praisonai[autogen]"
# For both frameworks
@@ -36,7 +36,7 @@ praisonai --auto "create a movie script about Dog in Moon"
praisonai --framework crewai --auto "create a movie script about Dog in Moon"
```
### With AutoGen
### With AG2
```bash
praisonai --framework autogen --auto "create a movie script about Dog in Moon"
```
@@ -49,7 +49,7 @@ praisonai --framework autogen --auto "create a movie script about Dog in Moon"
- Built-in tools integration
- Structured agent-task relationships
### AutoGen
### AG2 (Formerly AutoGen)
- Multi-agent conversation capabilities
- Code execution environment
- Built-in tools integration
+2 -2
View File
@@ -28,13 +28,13 @@ Includes:
- Task delegation capabilities
- Sequential and parallel task execution
### AutoGen Support
### AG2 Support
```bash
pip install "praisonai[autogen]"
```
Includes:
- AutoGen framework
- AG2 framework
- PraisonAI tools integration
- Multi-agent conversation capabilities
- Code execution environment
+1 -1
View File
@@ -21,7 +21,7 @@ icon: "hand-wave"
Create and orchestrate sophisticated multi-agent systems with ease
</Card>
<Card title="Framework Integration" icon="puzzle-piece">
Seamlessly integrates AutoGen and CrewAI capabilities
Seamlessly integrates AG2 and CrewAI capabilities
</Card>
<Card title="Low-Code Design" icon="code">
Build complex AI systems with minimal coding required
+3 -3
View File
@@ -1,6 +1,6 @@
---
title: "TL;DR"
description: "Quick start guide for PraisonAI with CrewAI, AutoGen, and UI setup instructions"
description: "Quick start guide for PraisonAI with CrewAI, AG2 (Formerly AutoGen), and UI setup instructions"
icon: "bolt"
---
@@ -32,10 +32,10 @@ praisonai --framework crewai --init "create a movie script about dog in moon"
praisonai --framework crewai
```
## Quick Start with AutoGen
## Quick Start with AG2
```bash
# Install with AutoGen support
# Install with AG2 support
pip install "praisonai[autogen]"
# Set your API key
+1 -1
View File
@@ -71,7 +71,7 @@ To run the PraisonAI tool, simply type the following command in your terminal:
praisonai
```
If you want to run the `autogen` framework, use:
If you want to run the AG2 framework (Formerly AutoGen), use:
```bash
praisonai --framework autogen
+1 -1
View File
@@ -18,7 +18,7 @@ icon: "comments"
| Interface | Description | URL |
|---|---|---|
| **UI** | Multi Agents such as CrewAI or AutoGen | [https://docs.praison.ai/ui/ui](https://docs.praison.ai/ui/ui) |
| **UI** | Multi Agents such as CrewAI or AG2 | [https://docs.praison.ai/ui/ui](https://docs.praison.ai/ui/ui) |
| **Chat** | Chat with 100+ LLMs, single AI Agent | [https://docs.praison.ai/ui/chat](https://docs.praison.ai/ui/chat) |
| **Code** | Chat with entire Codebase, single AI Agent | [https://docs.praison.ai/ui/code](https://docs.praison.ai/ui/code) |
+1 -1
View File
@@ -20,7 +20,7 @@ PraisonAI Code helps you to interact with your whole codebase using the power of
| Interface | Description | URL |
|---|---|---|
| **UI** | Multi Agents such as CrewAI or AutoGen | [https://docs.praison.ai/ui/ui](https://docs.praison.ai/ui/ui) |
| **UI** | Multi Agents such as CrewAI or AG2 | [https://docs.praison.ai/ui/ui](https://docs.praison.ai/ui/ui) |
| **Chat** | Chat with 100+ LLMs, single AI Agent | [https://docs.praison.ai/ui/chat](https://docs.praison.ai/ui/chat) |
| **Code** | Chat with entire Codebase, single AI Agent | [https://docs.praison.ai/ui/code](https://docs.praison.ai/ui/code) |
+1 -1
View File
@@ -11,7 +11,7 @@ icon: "browser"
|---|---|---|
| **Streamlit** | Create interactive web apps with Python | [https://docs.praison.ai/ui/streamlit](/ui/streamlit) |
| **Gradio** | Build machine learning web apps rapidly | [https://docs.praison.ai/ui/gradio](/ui/gradio) |
| **UI** | Multi Agents such as CrewAI or AutoGen | [https://docs.praison.ai/ui/ui](/ui/ui) |
| **UI** | Multi Agents such as CrewAI or AG2 | [https://docs.praison.ai/ui/ui](/ui/ui) |
| **Chat** | Chat with 100+ LLMs, single AI Agent | [https://docs.praison.ai/ui/chat](/ui/chat) |
| **Code** | Chat with entire Codebase, single AI Agent | [https://docs.praison.ai/ui/code](/ui/code) |
+15
View File
@@ -0,0 +1,15 @@
from praisonaiagents import Agent, MCP
import os
# Databutton API key
databutton_api_key = os.getenv("DATABUTTON_API_KEY")
# Create databutton agent
databutton_agent = Agent(
instructions="""You are a helpful assistant that can interact with Databutton.
Use the available tools when relevant to answer user questions.""",
llm="gpt-4o-mini",
tools=MCP("uvx databutton-app-mcp@latest", env={"DATABUTTON_API_KEY": databutton_api_key})
)
databutton_agent.start("Get the current stock price for AAPL, Tesla, and Amazon")
+6 -3
View File
@@ -1,9 +1,12 @@
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
stock_agent = Agent(
instructions="""You are a Stock Price Assistant.""",
llm="ollama/llama3.2",
tools=MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")
)
search_agent.start("What is the Stock Price of Apple?")
# NOTE: Python Path replace with yours: /Users/praison/miniconda3/envs/mcp/bin/python
# NOTE: app.py file path, replace it with yours: /Users/praison/stockprice/app.py
stock_agent.start("What is the Stock Price of Apple?")
+9
View File
@@ -0,0 +1,9 @@
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="openrouter/google/gemini-2.0-flash-exp:free",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
+14
View File
@@ -0,0 +1,14 @@
from praisonaiagents import Agent, MCP
import os
api_key = os.getenv("PERPLEXITY_API_KEY")
agent = Agent(
instructions="You are a helpful assistant that can search the web for information. Use the available tools when relevant to answer user questions.",
llm="gpt-4o-mini",
tools=MCP("uvx perplexity-mcp",
env={"PERPLEXITY_API_KEY": api_key, "PERPLEXITY_MODEL": "sonar" })
)
result = agent.start("What is the latest news on AI?, Pass only the query parameter to the tool")
print(result)
+9
View File
@@ -0,0 +1,9 @@
from praisonaiagents import Agent, MCP
whatsapp_agent = Agent(
instructions="Whatsapp Agent",
llm="groq/llama-3.2-90b-vision-preview",
tools=MCP("python /Users/praison/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
whatsapp_agent.start("Send Hello to Mervin Praison")
+9
View File
@@ -0,0 +1,9 @@
from praisonaiagents import Agent, MCP
whatsapp_agent = Agent(
instructions="Whatsapp Agent",
llm="gpt-4o-mini",
tools=MCP("python /Users/praison/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
whatsapp_agent.start("Send Hello to Mervin Praison")
+17
View File
@@ -0,0 +1,17 @@
from praisonaiagents import Agent, Agents, MCP
airbnb_agent = Agent(
instructions="""Search for Apartments in Paris for 2 nights on Airbnb. 04/28 - 04/30 for 2 adults""",
llm="gpt-4o-mini",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
whatsapp_agent = Agent(
instructions="""Send AirBnb Search Result to 'Mervin Praison'""",
llm="gpt-4o-mini",
tools=MCP("python /Users/praison/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
agents = Agents(agents=[airbnb_agent, whatsapp_agent])
agents.start()
+9
View File
@@ -0,0 +1,9 @@
from praisonaiagents import Agent, MCP
whatsapp_agent = Agent(
instructions="Whatsapp Agent",
llm="ollama/llama3.2",
tools=MCP("python /Users/praison/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
whatsapp_agent.start("Send Hello to Mervin Praison. Use send_message tool, recipient and message are the required parameters.")
+31
View File
@@ -0,0 +1,31 @@
from praisonaiagents import Agent, Agents, MCP
import gradio as gr
def search_airbnb(query):
airbnb_agent = Agent(
instructions=query+" on Airbnb",
llm="gpt-4o-mini",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
whatsapp_agent = Agent(
instructions="""Send AirBnb Search Result to 'Mervin Praison'. Don't include Phone Number in Response, but include the AirBnb Search Result""",
llm="gpt-4o-mini",
tools=MCP("python /Users/praison/whatsapp-mcp/whatsapp-mcp-server/main.py")
)
agents = Agents(agents=[airbnb_agent, whatsapp_agent])
result = agents.start()
return f"## Airbnb Search Results\n\n{result}"
demo = gr.Interface(
fn=search_airbnb,
inputs=gr.Textbox(placeholder="I want to book an apartment in Paris for 2 nights..."),
outputs=gr.Markdown(),
title="WhatsApp MCP Agent",
description="Enter your booking requirements below:"
)
if __name__ == "__main__":
demo.launch()
+9
View File
@@ -0,0 +1,9 @@
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You help book apartments on Airbnb.""",
llm="xai/grok-2-latest",
tools=MCP("npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt")
)
search_agent.start("MUST USE airbnb_search Tool to Search. Search for Apartments in Paris for 2 nights. 04/28 - 04/30 for 2 adults. All Your Preference")
Generated
+9735
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -3,7 +3,7 @@ class Praisonai < Formula
desc "AI tools for various AI applications"
homepage "https://github.com/MervinPraison/PraisonAI"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/2.1.0.tar.gz"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/2.1.1.tar.gz"
sha256 "1828fb9227d10f991522c3f24f061943a254b667196b40b1a3e4a54a8d30ce32" # Replace with actual SHA256 checksum
license "MIT"
+1 -1
View File
@@ -56,7 +56,7 @@ class CloudDeployer:
file.write("FROM python:3.11-slim\n")
file.write("WORKDIR /app\n")
file.write("COPY . .\n")
file.write("RUN pip install flask praisonai==2.1.0 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.1.1 gunicorn markdown\n")
file.write("EXPOSE 8080\n")
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
+1 -1
View File
@@ -1,4 +1,4 @@
# Only try to import autogen_tools if either CrewAI or AutoGen is available
# Only try to import autogen_tools if either CrewAI or AG2 is available
CREWAI_AVAILABLE = False
AUTOGEN_AVAILABLE = False
PRAISONAI_TOOLS_AVAILABLE = False
+4 -4
View File
@@ -1,6 +1,6 @@
[project]
name = "PraisonAI"
version = "2.1.0"
version = "2.1.1"
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
readme = "README.md"
license = ""
@@ -12,7 +12,7 @@ dependencies = [
"rich>=13.7",
"markdown>=3.5",
"pyparsing>=3.0.0",
"praisonaiagents>=0.0.70",
"praisonaiagents>=0.0.71",
"python-dotenv>=0.19.0",
"instructor>=1.3.3",
"PyYAML>=6.0",
@@ -85,7 +85,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.7", "crewai"]
[tool.poetry]
name = "PraisonAI"
version = "2.1.0"
version = "2.1.1"
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human–agent collaboration."
authors = ["Mervin Praison"]
license = ""
@@ -103,7 +103,7 @@ python = ">=3.10,<3.13"
rich = ">=13.7"
markdown = ">=3.5"
pyparsing = ">=3.0.0"
praisonaiagents = ">=0.0.70"
praisonaiagents = ">=0.0.71"
python-dotenv = ">=0.19.0"
instructor = ">=1.3.3"
PyYAML = ">=6.0"
+3 -3
View File
@@ -12,7 +12,7 @@ print_message() {
print_usage() {
echo "Usage: $0 [-u|--ui] [-c|--chat] [-d|--code] [-r|--realtime] [-a|--all] [--run] [--quick] [--model MODEL] [--base URL]"
echo "Options:"
echo " -u, --ui Install UI dependencies for Multi Agents (CrewAI/AutoGen)"
echo " -u, --ui Install UI dependencies for Multi Agents (CrewAI/AG2)"
echo " -c, --chat Install Chat interface for single AI Agent"
echo " -d, --code Install Code interface for codebase interaction"
echo " -r, --realtime Install Realtime voice interaction interface"
@@ -97,8 +97,8 @@ run_ui_interface() {
if [ -z "$prompt" ]; then
prompt="create a movie script about dog in moon"
fi
read -p "Use AutoGen framework? (y/N): " use_autogen
if [[ $use_autogen =~ ^[Yy]$ ]]; then
read -p "Use AG2 (Formerly AutoGen) framework? (y/N): " use_ag2
if [[ $use_ag2 =~ ^[Yy]$ ]]; then
praisonai --framework autogen --init "$prompt"
else
praisonai --init "$prompt"
+2 -1
View File
@@ -84,4 +84,5 @@ build
*.mp4
*.png
graph.py
chroma_db/
chroma_db/
.qodo
+83
View File
@@ -0,0 +1,83 @@
# MCP SSE Server and Client Implementation
This project demonstrates a working pattern for SSE-based MCP (Model Context Protocol) servers and clients. It consists of three main components:
1. **server.py**: An SSE-based MCP server that provides simple tools
2. **client.py**: A standalone client that connects to the server and uses its tools with Claude
3. **mcp-sse.py**: A client using praisonaiagents that connects to the server and uses its tools with OpenAI
## Tools Provided by the Server
The server implements two simple tools:
- **get_greeting**: Returns a personalized greeting for a given name
- **get_weather**: Returns simulated weather data for a given city
## Setup and Usage
### Prerequisites
Make sure you have the required packages installed:
```bash
pip install praisonaiagents mcp httpx starlette uvicorn anthropic python-dotenv
```
### Running the Server
First, start the MCP SSE server:
```bash
python server.py
```
By default, the server runs on 0.0.0.0:8080, but you can customize the host and port:
```bash
python server.py --host 127.0.0.1 --port 8081
```
### Running the Standalone Client
The standalone client uses Claude to interact with the MCP server tools:
```bash
# Set your Anthropic API key
export ANTHROPIC_API_KEY=your_api_key_here
# Run the client
python client.py http://0.0.0.0:8080/sse
```
You'll see a prompt where you can type queries for Claude to process using the MCP tools.
### Running the praisonaiagents Client
The praisonaiagents client uses OpenAI to interact with the MCP server tools:
```bash
# Set your OpenAI API key
export OPENAI_API_KEY=your_api_key_here
# Run the client
python mcp-sse.py
```
This will automatically send a query about the weather in Paris to the agent.
## How It Works
1. The server exposes MCP tools via an SSE endpoint
2. Clients connect to this endpoint and discover available tools
3. When a user makes a query, the client:
- For client.py: Uses Claude to determine which tool to call
- For mcp-sse.py: Uses OpenAI to determine which tool to call
4. The client executes the tool call against the server
5. The result is returned to the user
This pattern allows for decoupled processes where the MCP server can run independently of clients, making it suitable for cloud-native applications.
## Customizing
- To add more tools to the server, define new functions with the `@mcp.tool()` decorator in `server.py`
- To change the client's behavior, update the instructions and query in `mcp-sse.py`
+12
View File
@@ -0,0 +1,12 @@
from praisonaiagents import Agent, MCP
import os
brave_api_key = os.getenv("BRAVE_API_KEY")
research_agent = Agent(
instructions="Research Agent",
llm="groq/meta-llama/llama-4-scout-17b-16e-instruct",
tools=MCP("npx -y @modelcontextprotocol/server-brave-search", env={"BRAVE_API_KEY": brave_api_key})
)
research_agent.start("What is the latest research on the topic of AI and its impact on society?")
@@ -0,0 +1,9 @@
from praisonaiagents import Agent, MCP
stock_agent = Agent(
instructions="""You are a Stock Price Assistant.""",
llm="ollama/llama3.2",
tools=MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")
)
stock_agent.start("What is the Stock Price of Apple?")
@@ -0,0 +1,222 @@
import os
import logging
import asyncio
import time
import sys
import inspect
import json
from typing import List, Dict, Any, Optional, Callable
from contextlib import AsyncExitStack
from mcp import ClientSession
from mcp.client.sse import sse_client
from praisonaiagents import Agent
# Set up logging based on environment variable
log_level = os.environ.get("LOGLEVEL", "info").upper()
logging.basicConfig(level=getattr(logging, log_level))
logger = logging.getLogger("mcp-client")
# Create a custom prompt that explicitly mentions the tools
system_prompt = """You are a helpful assistant that can provide greetings and check weather information.
You have access to the following tools:
1. get_greeting(name: str) - Get a personalized greeting for a given name
2. get_weather(city: str) - Get weather information for a city (Paris, London, New York, Tokyo, Sydney)
When asked about weather, always use the get_weather tool with the appropriate city.
When asked for a greeting, always use the get_greeting tool with the appropriate name.
"""
# Global event loop for async operations
event_loop = None
def get_event_loop():
"""Get or create a global event loop."""
global event_loop
if event_loop is None or event_loop.is_closed():
event_loop = asyncio.new_event_loop()
asyncio.set_event_loop(event_loop)
return event_loop
class SSEMCPTool:
"""A wrapper for an MCP tool that can be used with praisonaiagents."""
def __init__(self, name: str, description: str, session: ClientSession, input_schema: Optional[Dict[str, Any]] = None):
self.name = name
self.__name__ = name # Required for Agent to recognize it as a tool
self.__qualname__ = name # Required for Agent to recognize it as a tool
self.__doc__ = description # Required for Agent to recognize it as a tool
self.description = description
self.session = session
self.input_schema = input_schema or {}
# Create a signature based on input schema
params = []
if input_schema and 'properties' in input_schema:
for param_name in input_schema['properties']:
params.append(
inspect.Parameter(
name=param_name,
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
default=inspect.Parameter.empty if param_name in input_schema.get('required', []) else None,
annotation=str # Default to string
)
)
self.__signature__ = inspect.Signature(params)
def __call__(self, **kwargs):
"""Synchronous wrapper for the async call."""
logger.debug(f"Tool {self.name} called with args: {kwargs}")
# Use the global event loop
loop = get_event_loop()
# Run the async call in the event loop
future = asyncio.run_coroutine_threadsafe(self._async_call(**kwargs), loop)
try:
# Wait for the result with a timeout
return future.result(timeout=30)
except Exception as e:
logger.error(f"Error calling tool {self.name}: {e}")
return f"Error: {str(e)}"
async def _async_call(self, **kwargs):
"""Call the tool with the provided arguments."""
logger.debug(f"Async calling tool {self.name} with args: {kwargs}")
try:
result = await self.session.call_tool(self.name, kwargs)
# Extract text from result
if hasattr(result, 'content') and result.content:
if hasattr(result.content[0], 'text'):
return result.content[0].text
return str(result.content[0])
return str(result)
except Exception as e:
logger.error(f"Error in _async_call for {self.name}: {e}")
raise
def to_openai_tool(self):
"""Convert the tool to OpenAI format."""
return {
"type": "function",
"function": {
"name": self.name,
"description": self.description,
"parameters": self.input_schema
}
}
class SSEMCPClient:
"""A client for connecting to an MCP server over SSE."""
def __init__(self, server_url: str):
self.server_url = server_url
self.session = None
self.tools = []
self._initialize()
def _initialize(self):
"""Initialize the connection and tools."""
# Use the global event loop
loop = get_event_loop()
# Start a background thread to run the event loop
def run_event_loop():
asyncio.set_event_loop(loop)
loop.run_forever()
import threading
self.loop_thread = threading.Thread(target=run_event_loop, daemon=True)
self.loop_thread.start()
# Run the initialization in the event loop
future = asyncio.run_coroutine_threadsafe(self._async_initialize(), loop)
self.tools = future.result(timeout=30)
async def _async_initialize(self):
"""Asynchronously initialize the connection and tools."""
logger.debug(f"Connecting to MCP server at {self.server_url}")
# Create SSE client
self._streams_context = sse_client(url=self.server_url)
streams = await self._streams_context.__aenter__()
self._session_context = ClientSession(*streams)
self.session = await self._session_context.__aenter__()
# Initialize
await self.session.initialize()
# List available tools
logger.debug("Listing tools...")
response = await self.session.list_tools()
tools_data = response.tools
logger.debug(f"Found {len(tools_data)} tools: {[tool.name for tool in tools_data]}")
# Create tool wrappers
tools = []
for tool in tools_data:
input_schema = tool.inputSchema if hasattr(tool, 'inputSchema') else None
wrapper = SSEMCPTool(
name=tool.name,
description=tool.description if hasattr(tool, 'description') else f"Call the {tool.name} tool",
session=self.session,
input_schema=input_schema
)
tools.append(wrapper)
return tools
def __iter__(self):
"""Return an iterator over the tools."""
return iter(self.tools)
def main():
# Server URL
server_url = "http://0.0.0.0:8080/sse"
try:
# Connect to the MCP server
client = SSEMCPClient(server_url)
if not client.tools:
logger.error("No tools found on the server")
return
logger.info(f"Connected to server with {len(client.tools)} tools: {[tool.name for tool in client.tools]}")
# Create OpenAI-compatible tool definitions
openai_tools = [tool.to_openai_tool() for tool in client.tools]
logger.debug(f"OpenAI tools: {json.dumps(openai_tools, indent=2)}")
# Create an agent with the tools
assistant_agent = Agent(
instructions=system_prompt,
llm="openai/gpt-4o-mini",
tools=client.tools,
verbose=True
)
# Start the agent with a query
logger.info("Starting agent with query about weather in Paris")
result = assistant_agent.chat(
"Hello! Can you tell me what the weather is like in Paris today?",
tools=openai_tools
)
logger.info(f"Agent response: {result}")
except Exception as e:
logger.error(f"Error: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()
@@ -0,0 +1,120 @@
# python mcp-sse-direct-client.py http://0.0.0.0:8080/sse
import asyncio
import json
import os
import sys
from typing import Optional
from contextlib import AsyncExitStack
from mcp import ClientSession
from mcp.client.sse import sse_client
from dotenv import load_dotenv
load_dotenv() # load environment variables from .env
class MCPClient:
def __init__(self):
# Initialize session and client objects
self.session: Optional[ClientSession] = None
self.exit_stack = AsyncExitStack()
async def connect_to_sse_server(self, server_url: str):
"""Connect to an MCP server running with SSE transport"""
# Store the context managers so they stay alive
self._streams_context = sse_client(url=server_url)
streams = await self._streams_context.__aenter__()
self._session_context = ClientSession(*streams)
self.session: ClientSession = await self._session_context.__aenter__()
# Initialize
await self.session.initialize()
# List available tools to verify connection
print("Initialized SSE client...")
print("Listing tools...")
response = await self.session.list_tools()
tools = response.tools
print("\nConnected to server with tools:", [tool.name for tool in tools])
# Print tool descriptions
for tool in tools:
print(f"\n{tool.name}: {tool.description}")
if hasattr(tool, 'inputSchema') and tool.inputSchema:
print(f" Parameters: {json.dumps(tool.inputSchema, indent=2)}")
async def cleanup(self):
"""Properly clean up the session and streams"""
if hasattr(self, '_session_context'):
await self._session_context.__aexit__(None, None, None)
if hasattr(self, '_streams_context'):
await self._streams_context.__aexit__(None, None, None)
async def process_query(self, query: str) -> str:
"""Process a query by directly calling the appropriate tool"""
query = query.strip().lower()
if query.startswith("hello") or query.startswith("hi"):
# Extract name or use a default
parts = query.split()
name = parts[1] if len(parts) > 1 else "there"
# Call the greeting tool
print(f"\nCalling get_greeting with name: {name}")
result = await self.session.call_tool("get_greeting", {"name": name})
return result.content[0].text if hasattr(result, 'content') and result.content else str(result)
elif "weather" in query:
# Try to extract city name
city = None
for known_city in ["Paris", "London", "New York", "Tokyo", "Sydney"]:
if known_city.lower() in query.lower():
city = known_city
break
if not city:
return "I couldn't identify a city in your query. Please mention a city like Paris, London, New York, Tokyo, or Sydney."
# Call the weather tool
print(f"\nCalling get_weather with city: {city}")
result = await self.session.call_tool("get_weather", {"city": city})
return result.content[0].text if hasattr(result, 'content') and result.content else str(result)
else:
return "I can help with greetings or weather information. Try asking something like 'Hello John' or 'What's the weather in Paris?'"
async def chat_loop(self):
"""Run an interactive chat loop"""
print("\nMCP Client Started!")
print("Type your queries or 'quit' to exit.")
while True:
try:
query = input("\nQuery: ").strip()
if query.lower() == 'quit':
break
response = await self.process_query(query)
print("\n" + response)
except Exception as e:
print(f"\nError: {str(e)}")
async def main():
if len(sys.argv) < 2:
print("Usage: python client.py <URL of SSE MCP server (i.e. http://localhost:8081/sse)>")
sys.exit(1)
client = MCPClient()
try:
await client.connect_to_sse_server(server_url=sys.argv[1])
await client.chat_loop()
finally:
await client.cleanup()
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,95 @@
# python mcp-sse-direct-server.py --host 127.0.0.1 --port 8080
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
from starlette.applications import Starlette
from mcp.server.sse import SseServerTransport
from starlette.requests import Request
from starlette.routing import Mount, Route
from mcp.server import Server
import uvicorn
import argparse
import logging
import os
import inspect
# Set up logging based on environment variable
log_level = os.environ.get("LOGLEVEL", "info").upper()
logging.basicConfig(level=getattr(logging, log_level))
logger = logging.getLogger("mcp-server")
# Initialize FastMCP server for simple tools (SSE)
mcp = FastMCP("simple-tools")
@mcp.tool()
async def get_greeting(name: str) -> str:
"""Get a personalized greeting.
Args:
name: Name of the person to greet
"""
logger.debug(f"get_greeting called with name: {name}")
return f"Hello, {name}! Welcome to our MCP SSE server."
@mcp.tool()
async def get_weather(city: str) -> str:
"""Get a simulated weather report for a city.
Args:
city: Name of the city
"""
logger.debug(f"get_weather called with city: {city}")
# This is a mock implementation
weather_data = {
"Paris": "Sunny with a temperature of 22°C",
"London": "Rainy with a temperature of 15°C",
"New York": "Cloudy with a temperature of 18°C",
"Tokyo": "Clear skies with a temperature of 25°C",
"Sydney": "Partly cloudy with a temperature of 20°C"
}
return weather_data.get(city, f"Weather data not available for {city}")
def create_starlette_app(mcp_server: Server, *, debug: bool = False) -> Starlette:
"""Create a Starlette application that can serve the provided mcp server with SSE."""
sse = SseServerTransport("/messages/")
async def handle_sse(request: Request) -> None:
logger.debug(f"SSE connection request received from {request.client}")
async with sse.connect_sse(
request.scope,
request.receive,
request._send, # noqa: SLF001
) as (read_stream, write_stream):
await mcp_server.run(
read_stream,
write_stream,
mcp_server.create_initialization_options(),
)
return Starlette(
debug=debug,
routes=[
Route("/sse", endpoint=handle_sse),
Mount("/messages/", app=sse.handle_post_message),
],
)
if __name__ == "__main__":
mcp_server = mcp._mcp_server # noqa: WPS437
parser = argparse.ArgumentParser(description='Run MCP SSE-based server')
parser.add_argument('--host', default='localhost', help='Host to bind to')
parser.add_argument('--port', type=int, default=8080, help='Port to listen on')
args = parser.parse_args()
print(f"Starting MCP SSE server on {args.host}:{args.port}")
# Hardcode the tool names since we know what they are
tool_names = ["get_greeting", "get_weather"]
print(f"Available tools: {', '.join(tool_names)}")
# Bind SSE request handling to MCP server
starlette_app = create_starlette_app(mcp_server, debug=True)
uvicorn.run(starlette_app, host=args.host, port=args.port)
+9
View File
@@ -0,0 +1,9 @@
from praisonaiagents import Agent, MCP
search_agent = Agent(
instructions="""You are a weather agent that can provide weather information for a given city.""",
llm="openai/gpt-4o-mini",
tools=MCP("http://localhost:8080/sse")
)
search_agent.start("What is the weather in London?")
@@ -530,11 +530,21 @@ Your Goal: {self.goal}
from ..mcp.mcp import MCP
if isinstance(self.tools, MCP):
logging.debug(f"Looking for MCP tool {function_name}")
# Check if any of the MCP tools match the function name
for mcp_tool in self.tools.runner.tools:
if hasattr(mcp_tool, 'name') and mcp_tool.name == function_name:
logging.debug(f"Found matching MCP tool: {function_name}")
return self.tools.runner.call_tool(function_name, arguments)
# Handle SSE MCP client
if hasattr(self.tools, 'is_sse') and self.tools.is_sse:
if hasattr(self.tools, 'sse_client'):
for tool in self.tools.sse_client.tools:
if tool.name == function_name:
logging.debug(f"Found matching SSE MCP tool: {function_name}")
return tool(**arguments)
# Handle stdio MCP client
elif hasattr(self.tools, 'runner'):
# Check if any of the MCP tools match the function name
for mcp_tool in self.tools.runner.tools:
if hasattr(mcp_tool, 'name') and mcp_tool.name == function_name:
logging.debug(f"Found matching MCP tool: {function_name}")
return self.tools.runner.call_tool(function_name, arguments)
# Try to find the function in the agent's tools list first
func = None
@@ -770,7 +780,7 @@ Your Goal: {self.goal}
display_error(f"Error in chat completion: {e}")
return None
def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pydantic=None, reasoning_steps=False):
def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pydantic=None, reasoning_steps=False, stream=True):
# Log all parameter values when in debug mode
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
param_info = {
@@ -815,7 +825,11 @@ Your Goal: {self.goal}
logging.debug("Converting MCP tool to OpenAI format")
openai_tool = tool_param.to_openai_tool()
if openai_tool:
tool_param = [openai_tool]
# Handle both single tool and list of tools
if isinstance(openai_tool, list):
tool_param = openai_tool
else:
tool_param = [openai_tool]
logging.debug(f"Converted MCP tool: {tool_param}")
# Pass everything to LLM class
@@ -912,7 +926,7 @@ Your Goal: {self.goal}
agent_tools=agent_tools
)
response = self._chat_completion(messages, temperature=temperature, tools=tools if tools else None, reasoning_steps=reasoning_steps)
response = self._chat_completion(messages, temperature=temperature, tools=tools if tools else None, reasoning_steps=reasoning_steps, stream=stream)
if not response:
return None
@@ -949,7 +963,7 @@ Your Goal: {self.goal}
"content": "Function returned an empty output"
})
response = self._chat_completion(messages, temperature=temperature)
response = self._chat_completion(messages, temperature=temperature, stream=stream)
if not response:
return None
response_text = response.choices[0].message.content.strip()
@@ -1019,7 +1033,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
logging.debug(f"{self.name} reflection count {reflection_count + 1}, continuing reflection process")
messages.append({"role": "user", "content": "Now regenerate your response using the reflection you made"})
response = self._chat_completion(messages, temperature=temperature, tools=None, stream=True)
response = self._chat_completion(messages, temperature=temperature, tools=None, stream=stream)
response_text = response.choices[0].message.content.strip()
reflection_count += 1
continue # Continue the loop for more reflections
@@ -1199,7 +1213,7 @@ Your Goal: {self.goal}
model=self.llm,
messages=messages,
temperature=temperature,
tools=formatted_tools
tools=formatted_tools,
)
result = await self._achat_completion(response, tools)
if logging.getLogger().getEffectiveLevel() == logging.DEBUG:
@@ -45,7 +45,7 @@ def process_video(video_path: str, seconds_per_frame=2):
return base64_frames
class PraisonAIAgents:
def __init__(self, agents, tasks=None, verbose=0, completion_checker=None, max_retries=5, process="sequential", manager_llm=None, memory=False, memory_config=None, embedder=None, user_id=None, max_iter=10):
def __init__(self, agents, tasks=None, verbose=0, completion_checker=None, max_retries=5, process="sequential", manager_llm=None, memory=False, memory_config=None, embedder=None, user_id=None, max_iter=10, stream=True):
# Add check at the start if memory is requested
if memory:
try:
@@ -68,8 +68,8 @@ class PraisonAIAgents:
for agent in agents:
agent.user_id = self.user_id
self.agents = agents
self.tasks = {}
self.agents: List[Agent] = agents
self.tasks: Dict[int, Task] = {}
if max_retries < 3:
max_retries = 3
self.completion_checker = completion_checker if completion_checker else self.default_completion_checker
@@ -77,6 +77,7 @@ class PraisonAIAgents:
self.verbose = verbose
self.max_retries = max_retries
self.process = process
self.stream = stream
# Check for manager_llm in environment variable if not provided
self.manager_llm = manager_llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o')
@@ -665,7 +666,8 @@ Context:
task_prompt,
tools=task.tools,
output_json=task.output_json,
output_pydantic=task.output_pydantic
output_pydantic=task.output_pydantic,
stream=self.stream,
)
if agent_output:
@@ -7,7 +7,6 @@ class Chunking:
CHUNKER_PARAMS = {
'token': ['chunk_size', 'chunk_overlap', 'tokenizer'],
'word': ['chunk_size', 'chunk_overlap', 'tokenizer_or_token_counter'],
'sentence': ['chunk_size', 'chunk_overlap', 'tokenizer_or_token_counter'],
'recursive': ['chunk_size', 'tokenizer_or_token_counter'],
'semantic': ['chunk_size', 'embedding_model'],
@@ -19,9 +18,8 @@ class Chunking:
def SUPPORTED_CHUNKERS(self) -> Dict[str, Any]:
"""Lazy load chunker classes."""
try:
from chonkie.chunker import (
from chonkie import (
TokenChunker,
WordChunker,
SentenceChunker,
SemanticChunker,
SDPMChunker,
@@ -35,7 +33,6 @@ class Chunking:
return {
'token': TokenChunker,
'word': WordChunker,
'sentence': SentenceChunker,
'semantic': SemanticChunker,
'sdpm': SDPMChunker,
@@ -114,63 +111,82 @@ class Chunking:
return self._chunker
def _get_overlap_refinery(self, context_size: Optional[int] = None, **kwargs):
"""Lazy load the overlap refinery."""
try:
from chonkie.refinery import OverlapRefinery
except ImportError:
raise ImportError("Failed to import OverlapRefinery from chonkie.refinery")
# NOTE: OverlapRefinery is not supported, disabled for now
# As soon as Chonkie is updated to support it, we can re-enable it!
# Track in https://github.com/chonkie-inc/chonkie/issues/21
# def _get_overlap_refinery(self, context_size: Optional[int] = None, **kwargs):
# """Lazy load the overlap refinery."""
# try:
# from chonkie.refinery import OverlapRefinery
# except ImportError:
# raise ImportError("Failed to import OverlapRefinery from chonkie.refinery")
if context_size is None:
context_size = self.chunk_overlap
# if context_size is None:
# context_size = self.chunk_overlap
return OverlapRefinery(
context_size=context_size,
tokenizer=self.chunker.tokenizer,
**kwargs
)
# return OverlapRefinery(
# context_size=context_size,
# tokenizer=self.chunker.tokenizer,
# **kwargs
# )
def add_overlap_context(
self,
chunks: List[Any],
context_size: int = None,
mode: str = "suffix",
merge_context: bool = True
) -> List[Any]:
"""Add overlap context to chunks using OverlapRefinery."""
refinery = self._get_overlap_refinery(
context_size=context_size,
mode=mode,
merge_context=merge_context
)
return refinery.refine(chunks)
# def add_overlap_context(
# self,
# chunks: List[Any],
# context_size: int = None,
# mode: str = "suffix",
# merge_context: bool = True
# ) -> List[Any]:
# """Add overlap context to chunks using OverlapRefinery."""
# refinery = self._get_overlap_refinery(
# context_size=context_size,
# mode=mode,
# merge_context=merge_context
# )
# return refinery.refine(chunks)
def chunk(
self,
text: Union[str, List[str]],
add_context: bool = False,
context_params: Optional[Dict[str, Any]] = None
# Disable context for now, as it's not supported
# add_context: bool = False,
# context_params: Optional[Dict[str, Any]] = None
**kwargs # Added to maintain compatibility with the original `chunk` method signature
) -> Union[List[Any], List[List[Any]]]:
"""Chunk text using the configured chunking strategy."""
chunks = self.chunker(text)
if add_context:
context_params = context_params or {}
if isinstance(text, str):
chunks = self.add_overlap_context(chunks, **context_params)
else:
chunks = [self.add_overlap_context(c, **context_params) for c in chunks]
# NOTE: OverlapRefinery is not supported, disabled for now
# As soon as Chonkie is updated to support it, we can re-enable it!
# Track in https://github.com/chonkie-inc/chonkie/issues/21
# if add_context:
# context_params = context_params or {}
# if isinstance(text, str):
# chunks = self.add_overlap_context(chunks, **context_params)
# else:
# chunks = [self.add_overlap_context(c, **context_params) for c in chunks]
if 'add_context' in kwargs or 'context_params' in kwargs:
import warnings
warnings.warn(
"The `add_context` and `context_params` parameters are currently not supported for Chonkie as of version 1.0.2. They would be added in the future. Track in https://github.com/chonkie-inc/chonkie/issues/21",
UserWarning
)
return chunks
def __call__(
self,
text: Union[str, List[str]],
add_context: bool = False,
context_params: Optional[Dict[str, Any]] = None
# Disable context for now, as it's not supported
# add_context: bool = False,
# context_params: Optional[Dict[str, Any]] = None
**kwargs # Added to maintain compatibility with the original `chunk` method signature
) -> Union[List[Any], List[List[Any]]]:
"""Make the Chunking instance callable."""
return self.chunk(text, add_context, context_params)
return self.chunk(text, **kwargs)
def __repr__(self) -> str:
"""String representation of the Chunking instance."""
@@ -17,7 +17,7 @@ class CustomMemory:
}).from_config(config)
@staticmethod
def _add_to_vector_store(self, messages, metadata, filters):
def _add_to_vector_store(self, messages, metadata, filters, infer):
# Custom implementation that doesn't use LLM
parsed_messages = "\n".join([msg["content"] for msg in messages])
@@ -293,6 +293,12 @@ class LLM:
if isinstance(tool, dict) and 'type' in tool and tool['type'] == 'function':
logging.debug(f"Using pre-formatted OpenAI tool: {tool['function']['name']}")
formatted_tools.append(tool)
# Handle lists of tools (e.g. from MCP.to_openai_tool())
elif isinstance(tool, list):
for subtool in tool:
if isinstance(subtool, dict) and 'type' in subtool and subtool['type'] == 'function':
logging.debug(f"Using pre-formatted OpenAI tool from list: {subtool['function']['name']}")
formatted_tools.append(subtool)
elif callable(tool):
tool_def = self._generate_tool_definition(tool.__name__)
if tool_def:
@@ -520,8 +526,16 @@ class LLM:
if ('name' in json_response or 'function' in json_response) and not any(word in response_text.lower() for word in ['summary', 'option', 'result', 'found']):
logging.debug("Detected Ollama returning only tool call JSON, making follow-up call to process results")
# Create a prompt that asks the model to process the tool results
follow_up_prompt = f"I've searched for apartments and found these results. Please analyze them and provide a summary of the best options:\n\n{json.dumps(tool_result, indent=2)}\n\nPlease format your response as a nice summary with the top options."
# Create a prompt that asks the model to process the tool results based on original context
# Extract the original user query from messages
original_query = ""
for msg in messages:
if msg.get("role") == "user":
original_query = msg.get("content", "")
break
# Create a shorter follow-up prompt
follow_up_prompt = f"Results:\n{json.dumps(tool_result, indent=2)}\nProvide Answer to this Original Question based on the above results: '{original_query}'"
# Make a follow-up call to process the results
follow_up_messages = [
@@ -1091,8 +1105,16 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
if ('name' in json_response or 'function' in json_response) and not any(word in response_text.lower() for word in ['summary', 'option', 'result', 'found']):
logging.debug("Detected Ollama returning only tool call JSON in async mode, making follow-up call to process results")
# Create a prompt that asks the model to process the tool results
follow_up_prompt = f"I've searched for apartments and found these results. Please analyze them and provide a summary of the best options:\n\n{json.dumps(tool_result, indent=2)}\n\nPlease format your response as a nice summary with the top options."
# Create a prompt that asks the model to process the tool results based on original context
# Extract the original user query from messages
original_query = ""
for msg in messages:
if msg.get("role") == "user":
original_query = msg.get("content", "")
break
# Create a shorter follow-up prompt
follow_up_prompt = f"Results:\n{json.dumps(tool_result, indent=2)}\nProvide Answer to this Original Question based on the above results: '{original_query}'"
# Make a follow-up call to process the results
follow_up_messages = [
@@ -1,5 +1,8 @@
"""
Model Context Protocol (MCP) integration for PraisonAI Agents.
This package provides classes and utilities for connecting to MCP servers
using different transport methods (stdio, SSE, etc.).
"""
from .mcp import MCP
+83 -35
View File
@@ -6,6 +6,7 @@ import inspect
import shlex
import logging
import os
import re
from typing import Any, List, Optional, Callable, Iterable, Union
from functools import wraps, partial
@@ -126,6 +127,13 @@ class MCP:
tools=MCP("/path/to/python /path/to/app.py")
)
# Method 3: Using an SSE endpoint
agent = Agent(
instructions="You are a helpful assistant...",
llm="gpt-4o-mini",
tools=MCP("http://localhost:8080/sse")
)
agent.start("What is the stock price of Tesla?")
```
"""
@@ -139,6 +147,7 @@ class MCP:
- The command to run the MCP server (e.g., Python path)
- A complete command string (e.g., "/path/to/python /path/to/app.py")
- For NPX: 'npx' command with args for smithery tools
- An SSE URL (e.g., "http://localhost:8080/sse")
args: Arguments to pass to the command (when command_or_string is the command)
command: Alternative parameter name for backward compatibility
timeout: Timeout in seconds for MCP server initialization and tool calls (default: 60)
@@ -149,7 +158,44 @@ class MCP:
if command_or_string is None and command is not None:
command_or_string = command
# Handle the single string format
# Set up logging - default to WARNING level to hide INFO messages
if debug:
logging.getLogger("mcp-wrapper").setLevel(logging.DEBUG)
logging.getLogger("mcp-sse").setLevel(logging.DEBUG)
logging.getLogger("mcp.client").setLevel(logging.DEBUG)
logging.getLogger("sse").setLevel(logging.DEBUG)
logging.getLogger("mcp-server").setLevel(logging.DEBUG)
logging.getLogger("mcp-client").setLevel(logging.DEBUG)
logging.getLogger("_client").setLevel(logging.DEBUG)
logging.getLogger("httpx").setLevel(logging.DEBUG)
logging.getLogger("llm").setLevel(logging.DEBUG)
else:
# Set all MCP-related loggers to WARNING level by default
logging.getLogger("mcp-wrapper").setLevel(logging.WARNING)
logging.getLogger("mcp-sse").setLevel(logging.WARNING)
logging.getLogger("mcp.client").setLevel(logging.WARNING)
logging.getLogger("sse").setLevel(logging.WARNING)
logging.getLogger("mcp-server").setLevel(logging.WARNING)
logging.getLogger("mcp-client").setLevel(logging.WARNING)
logging.getLogger("_client").setLevel(logging.WARNING)
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("llm").setLevel(logging.WARNING)
# Store additional parameters
self.timeout = timeout
self.debug = debug
# Check if this is an SSE URL
if isinstance(command_or_string, str) and re.match(r'^https?://', command_or_string):
# Import the SSE client implementation
from .mcp_sse import SSEMCPClient
self.sse_client = SSEMCPClient(command_or_string, debug=debug)
self._tools = list(self.sse_client.tools)
self.is_sse = True
self.is_npx = False
return
# Handle the single string format for stdio client
if isinstance(command_or_string, str) and args is None:
# Split the string into command and args using shell-like parsing
parts = shlex.split(command_or_string)
@@ -162,7 +208,9 @@ class MCP:
# Use the original format with separate command and args
cmd = command_or_string
arguments = args or []
# Set up stdio client
self.is_sse = False
self.server_params = StdioServerParameters(
command=cmd,
args=arguments,
@@ -173,13 +221,6 @@ class MCP:
# Wait for initialization
if not self.runner.initialized.wait(timeout=30):
print("Warning: MCP initialization timed out")
# Store additional parameters
self.timeout = timeout
self.debug = debug
if debug:
logging.getLogger("mcp-wrapper").setLevel(logging.DEBUG)
# Automatically detect if this is an NPX command
self.is_npx = cmd == 'npx' or (isinstance(cmd, str) and os.path.basename(cmd) == 'npx')
@@ -199,6 +240,9 @@ class MCP:
Returns:
List[Callable]: Functions that can be used as tools
"""
if self.is_sse:
return list(self.sse_client.tools)
tool_functions = []
for tool in self.runner.tools:
@@ -303,8 +347,6 @@ class MCP:
logging.error(f"Failed to initialize NPX MCP tools: {e}")
raise RuntimeError(f"Failed to initialize NPX MCP tools: {e}")
def __iter__(self) -> Iterable[Callable]:
"""
Allow the MCP instance to be used directly as an iterable of tools.
@@ -320,37 +362,43 @@ class MCP:
provider/model format (e.g., "openai/gpt-4o-mini").
Returns:
dict: OpenAI-compatible tool definition
dict or list: OpenAI-compatible tool definition(s)
"""
if self.is_sse and hasattr(self, 'sse_client') and self.sse_client.tools:
# Return all tools from SSE client
return self.sse_client.to_openai_tools()
# For simplicity, we'll convert the first tool only if multiple exist
# More complex implementations could handle multiple tools
if not self.runner.tools:
if not hasattr(self, 'runner') or not self.runner.tools:
logging.warning("No MCP tools available to convert to OpenAI format")
return None
# Get the first tool's schema
tool = self.runner.tools[0]
# Convert all tools to OpenAI format
openai_tools = []
for tool in self.runner.tools:
# Create OpenAI tool definition
parameters = {}
if hasattr(tool, 'inputSchema') and tool.inputSchema:
parameters = tool.inputSchema
else:
# Create a minimal schema if none exists
parameters = {
"type": "object",
"properties": {},
"required": []
}
openai_tools.append({
"type": "function",
"function": {
"name": tool.name,
"description": tool.description if hasattr(tool, 'description') else f"Call the {tool.name} tool",
"parameters": parameters
}
})
# Create OpenAI tool definition
parameters = {}
if hasattr(tool, 'inputSchema') and tool.inputSchema:
parameters = tool.inputSchema
else:
# Create a minimal schema if none exists
parameters = {
"type": "object",
"properties": {},
"required": []
}
return {
"type": "function",
"function": {
"name": tool.name,
"description": tool.description if hasattr(tool, 'description') else f"Call the {tool.name} tool",
"parameters": parameters
}
}
return openai_tools
def __del__(self):
"""Clean up resources when the object is garbage collected."""
@@ -0,0 +1,184 @@
"""
SSE (Server-Sent Events) client implementation for MCP (Model Context Protocol).
This module provides the necessary classes and functions to connect to an MCP server
over SSE transport.
"""
import asyncio
import logging
import threading
import inspect
import json
from typing import List, Dict, Any, Optional, Callable, Iterable
from mcp import ClientSession
from mcp.client.sse import sse_client
logger = logging.getLogger("mcp-sse")
# Global event loop for async operations
_event_loop = None
def get_event_loop():
"""Get or create a global event loop."""
global _event_loop
if _event_loop is None or _event_loop.is_closed():
_event_loop = asyncio.new_event_loop()
asyncio.set_event_loop(_event_loop)
return _event_loop
class SSEMCPTool:
"""A wrapper for an MCP tool that can be used with praisonaiagents."""
def __init__(self, name: str, description: str, session: ClientSession, input_schema: Optional[Dict[str, Any]] = None):
self.name = name
self.__name__ = name # Required for Agent to recognize it as a tool
self.__qualname__ = name # Required for Agent to recognize it as a tool
self.__doc__ = description # Required for Agent to recognize it as a tool
self.description = description
self.session = session
self.input_schema = input_schema or {}
# Create a signature based on input schema
params = []
if input_schema and 'properties' in input_schema:
for param_name in input_schema['properties']:
params.append(
inspect.Parameter(
name=param_name,
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
default=inspect.Parameter.empty if param_name in input_schema.get('required', []) else None,
annotation=str # Default to string
)
)
self.__signature__ = inspect.Signature(params)
def __call__(self, **kwargs):
"""Synchronous wrapper for the async call."""
logger.debug(f"Tool {self.name} called with args: {kwargs}")
# Use the global event loop
loop = get_event_loop()
# Run the async call in the event loop
future = asyncio.run_coroutine_threadsafe(self._async_call(**kwargs), loop)
try:
# Wait for the result with a timeout
return future.result(timeout=30)
except Exception as e:
logger.error(f"Error calling tool {self.name}: {e}")
return f"Error: {str(e)}"
async def _async_call(self, **kwargs):
"""Call the tool with the provided arguments."""
logger.debug(f"Async calling tool {self.name} with args: {kwargs}")
try:
result = await self.session.call_tool(self.name, kwargs)
# Extract text from result
if hasattr(result, 'content') and result.content:
if hasattr(result.content[0], 'text'):
return result.content[0].text
return str(result.content[0])
return str(result)
except Exception as e:
logger.error(f"Error in _async_call for {self.name}: {e}")
raise
def to_openai_tool(self):
"""Convert the tool to OpenAI format."""
return {
"type": "function",
"function": {
"name": self.name,
"description": self.description,
"parameters": self.input_schema
}
}
class SSEMCPClient:
"""A client for connecting to an MCP server over SSE."""
def __init__(self, server_url: str, debug: bool = False):
"""
Initialize an SSE MCP client.
Args:
server_url: The URL of the SSE MCP server
debug: Whether to enable debug logging
"""
self.server_url = server_url
self.debug = debug
self.session = None
self.tools = []
# Set up logging
if debug:
logger.setLevel(logging.DEBUG)
else:
# Set to WARNING by default to hide INFO messages
logger.setLevel(logging.WARNING)
self._initialize()
def _initialize(self):
"""Initialize the connection and tools."""
# Use the global event loop
loop = get_event_loop()
# Start a background thread to run the event loop
def run_event_loop():
asyncio.set_event_loop(loop)
loop.run_forever()
self.loop_thread = threading.Thread(target=run_event_loop, daemon=True)
self.loop_thread.start()
# Run the initialization in the event loop
future = asyncio.run_coroutine_threadsafe(self._async_initialize(), loop)
self.tools = future.result(timeout=30)
async def _async_initialize(self):
"""Asynchronously initialize the connection and tools."""
logger.debug(f"Connecting to MCP server at {self.server_url}")
# Create SSE client
self._streams_context = sse_client(url=self.server_url)
streams = await self._streams_context.__aenter__()
self._session_context = ClientSession(*streams)
self.session = await self._session_context.__aenter__()
# Initialize
await self.session.initialize()
# List available tools
logger.debug("Listing tools...")
response = await self.session.list_tools()
tools_data = response.tools
logger.debug(f"Found {len(tools_data)} tools: {[tool.name for tool in tools_data]}")
# Create tool wrappers
tools = []
for tool in tools_data:
input_schema = tool.inputSchema if hasattr(tool, 'inputSchema') else None
wrapper = SSEMCPTool(
name=tool.name,
description=tool.description if hasattr(tool, 'description') else f"Call the {tool.name} tool",
session=self.session,
input_schema=input_schema
)
tools.append(wrapper)
return tools
def __iter__(self):
"""Return an iterator over the tools."""
return iter(self.tools)
def to_openai_tools(self):
"""Convert all tools to OpenAI format."""
return [tool.to_openai_tool() for tool in self.tools]
+10 -5
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.0.70"
version = "0.0.77"
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
authors = [
{ name="Mervin Praison" }
@@ -13,10 +13,14 @@ dependencies = [
"pydantic",
"rich",
"openai",
"mcp==1.6.0"
"mcp>=1.6.0"
]
[project.optional-dependencies]
mcp = [
"mcp>=1.6.0"
]
memory = [
"chromadb>=0.5.23"
]
@@ -24,8 +28,8 @@ memory = [
knowledge = [
"mem0ai>=0.1.0",
"chromadb==0.5.23",
"markitdown",
"chonkie>=0.5.0"
"markitdown[all]",
"chonkie>=1.0.2"
]
# Add LLM dependencies
@@ -38,5 +42,6 @@ llm = [
all = [
"praisonaiagents[memory]",
"praisonaiagents[knowledge]",
"praisonaiagents[llm]"
"praisonaiagents[llm]",
"praisonaiagents[mcp]"
]
+1 -1
View File
@@ -9,7 +9,7 @@ chromadb>=0.5.23
# Knowledge dependencies
mem0ai>=0.1.0
markitdown
chonkie>=0.5.0
chonkie>=1.0.2
# Development dependencies
python-dotenv>=0.19.0
+14 -21
View File
@@ -170,19 +170,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5d/35/be73b6015511aa0173ec595fc579133b797ad532996f2998fd6b8d1bbe6b/audioop_lts-0.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:78bfb3703388c780edf900be66e07de5a3d4105ca8e8720c5c4d67927e0b15d0", size = 23918 },
]
[[package]]
name = "autotiktokenizer"
version = "0.2.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "huggingface-hub" },
{ name = "tiktoken" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a6/1a/c6f494750dc67c2e5b06b91ae9565d46adb384f25f61a7136ff79dd02413/autotiktokenizer-0.2.2.tar.gz", hash = "sha256:f0954f14cedfe538b96ba0eed2e39996378c0bdf649fd977d6a047e419e05fdb", size = 15401 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d8/7b/c34469a1495d755bac1c80fbf3c0c2c29eb03ffe61172d889426025173bd/autotiktokenizer-0.2.2-py3-none-any.whl", hash = "sha256:ebbf15d9d5516fcb3287a8153bd8efbcc932f9c99089b2357255413cf37815d9", size = 8957 },
]
[[package]]
name = "backoff"
version = "2.2.1"
@@ -361,15 +348,15 @@ wheels = [
[[package]]
name = "chonkie"
version = "0.4.1"
version = "1.0.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "autotiktokenizer" },
{ name = "tokenizers" },
{ name = "tqdm" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2e/94/4a1bc8bdf06e7327bb256abb85767647125286c9bbc7cbcd77a550b96d63/chonkie-0.4.1.tar.gz", hash = "sha256:164216efa01af02e750e7cb218cea87918a18f83ebbd8f020b25557f1ed36aa9", size = 43284 }
sdist = { url = "https://files.pythonhosted.org/packages/69/7c/5fe68d5eec5e741ad63721c9ffda4264c24aeebc2bd6f545bffb710a0389/chonkie-1.0.2.tar.gz", hash = "sha256:70515ed439ca6840ab7eb0e2f5abeab6feecbfca592317b1f91dd1a7986597d4", size = 42693 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c0/b5/c0d77500a413794773edb630bdc7061121c237a4eaf6ce222226c200d603/chonkie-0.4.1-py3-none-any.whl", hash = "sha256:af7d95d17f4ed60a26e32f0bad60f807287e3301189114755d727657ed2ef964", size = 51193 },
{ url = "https://files.pythonhosted.org/packages/94/21/d2785bbce3a162c675c3b719a3b6cafe3798fce75ea8af8128f7708031e1/chonkie-1.0.2-py3-none-any.whl", hash = "sha256:f8157099f22f2132395303e547232d9a4eccd9053298062ec472d9d4d88f4da9", size = 50706 },
]
[[package]]
@@ -1896,7 +1883,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.70"
version = "0.0.77"
source = { editable = "." }
dependencies = [
{ name = "mcp" },
@@ -1911,6 +1898,7 @@ all = [
{ name = "chromadb" },
{ name = "litellm" },
{ name = "markitdown" },
{ name = "mcp" },
{ name = "mem0ai" },
{ name = "pydantic" },
]
@@ -1924,22 +1912,27 @@ llm = [
{ name = "litellm" },
{ name = "pydantic" },
]
mcp = [
{ name = "mcp" },
]
memory = [
{ name = "chromadb" },
]
[package.metadata]
requires-dist = [
{ name = "chonkie", marker = "extra == 'knowledge'" },
{ name = "chonkie", marker = "extra == 'knowledge'", specifier = ">=1.0.2" },
{ name = "chromadb", marker = "extra == 'knowledge'", specifier = "==0.5.23" },
{ name = "chromadb", marker = "extra == 'memory'", specifier = ">=0.5.23" },
{ name = "litellm", marker = "extra == 'llm'", specifier = ">=1.50.0" },
{ name = "markitdown", marker = "extra == 'knowledge'" },
{ name = "mcp", specifier = "==1.6.0" },
{ name = "markitdown", extras = ["all"], marker = "extra == 'knowledge'" },
{ name = "mcp", specifier = ">=1.6.0" },
{ name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.6.0" },
{ name = "mem0ai", marker = "extra == 'knowledge'", specifier = ">=0.1.0" },
{ name = "openai" },
{ name = "praisonaiagents", extras = ["knowledge"], marker = "extra == 'all'" },
{ name = "praisonaiagents", extras = ["llm"], marker = "extra == 'all'" },
{ name = "praisonaiagents", extras = ["mcp"], marker = "extra == 'all'" },
{ name = "praisonaiagents", extras = ["memory"], marker = "extra == 'all'" },
{ name = "pydantic" },
{ name = "pydantic", marker = "extra == 'llm'", specifier = ">=2.4.2" },
Generated
+5 -5
View File
@@ -3079,7 +3079,7 @@ wheels = [
[[package]]
name = "praisonai"
version = "2.1.0"
version = "2.1.1"
source = { editable = "." }
dependencies = [
{ name = "instructor" },
@@ -3218,7 +3218,7 @@ requires-dist = [
{ name = "plotly", marker = "extra == 'realtime'", specifier = ">=5.24.0" },
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.7" },
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.7" },
{ name = "praisonaiagents", specifier = ">=0.0.70" },
{ name = "praisonaiagents", specifier = ">=0.0.71" },
{ name = "pyautogen", marker = "extra == 'autogen'", specifier = ">=0.2.19" },
{ name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" },
{ name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" },
@@ -3271,7 +3271,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.70"
version = "0.0.71"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mcp" },
@@ -3279,9 +3279,9 @@ dependencies = [
{ name = "pydantic" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a6/7f/f94506669bfff29034d7c00ac9ea3d3a15b8809fbb290d6ad9425729b73d/praisonaiagents-0.0.70.tar.gz", hash = "sha256:06335940410f644852cbcf1b38d0b13ed3a3606e217ed1d4cff0b61edd1e120e", size = 111475 }
sdist = { url = "https://files.pythonhosted.org/packages/ac/ea/bdeaeb6f2b9d2598bc8daba175c4521f3e24e85ea26a8de90f48b1b63bd7/praisonaiagents-0.0.71.tar.gz", hash = "sha256:b6024cb73251f32a122825521a46a79519e67deb7c012f49da04f71d4d7c6b8d", size = 112123 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ca/da/2a11fb1338a122b7b9b17fa544d90d704a81477b9d7c723890dfa52a500d/praisonaiagents-0.0.70-py3-none-any.whl", hash = "sha256:d25b97bc3ae51d32512d373396d41068456a93194e9705a7fe70d1022db6e9a0", size = 131227 },
{ url = "https://files.pythonhosted.org/packages/5b/47/9a4e58542de19eadf4e9dc30b5e4bbbfd53fefb109a3a5c7c688de12bd1a/praisonaiagents-0.0.71-py3-none-any.whl", hash = "sha256:bc4a49b2ecddfe0a2c6cedd08d9c74467b29296810f7acc374008af515d93a9e", size = 131902 },
]
[[package]]