Skip to content

Commit ebcef4c

Browse files
committed
Release v2.3.9
1 parent 810f3f0 commit ebcef4c

File tree

18 files changed

+1338
-18
lines changed

18 files changed

+1338
-18
lines changed

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
flask \
19-
"praisonai>=2.3.8" \
19+
"praisonai>=2.3.9" \
2020
"praisonai[api]" \
2121
gunicorn \
2222
markdown

docker/Dockerfile.chat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=2.3.8" \
19+
"praisonai>=2.3.9" \
2020
"praisonai[chat]" \
2121
"embedchain[github,youtube]"
2222

docker/Dockerfile.dev

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
2020
# Install Python packages (using latest versions)
2121
RUN pip install --no-cache-dir \
2222
praisonai_tools \
23-
"praisonai>=2.3.8" \
23+
"praisonai>=2.3.9" \
2424
"praisonai[ui]" \
2525
"praisonai[chat]" \
2626
"praisonai[realtime]" \

docker/Dockerfile.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=2.3.8" \
19+
"praisonai>=2.3.9" \
2020
"praisonai[ui]" \
2121
"praisonai[crewai]"
2222

src/praisonai-agents/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,8 @@ agent = Agent(tools=[my_tool])
657657

658658
Connect to MCP servers for extended capabilities.
659659

660+
### MCP Client (Consume MCP Servers)
661+
660662
```python
661663
from praisonaiagents import Agent, MCP
662664

@@ -683,6 +685,31 @@ agent = Agent(
683685
)
684686
```
685687

688+
### MCP Server (Expose Tools as MCP Server)
689+
690+
Expose your Python functions as MCP tools for external clients (Claude Desktop, Cursor, etc.).
691+
692+
```python
693+
from praisonaiagents.mcp import ToolsMCPServer
694+
695+
# Define your tools as regular Python functions
696+
def search_web(query: str, max_results: int = 5) -> dict:
697+
"""Search the web for information."""
698+
return {"results": [f"Result for {query}"]}
699+
700+
def calculate(expression: str) -> dict:
701+
"""Evaluate a mathematical expression."""
702+
return {"result": eval(expression)}
703+
704+
# Create and run MCP server
705+
server = ToolsMCPServer(name="my-tools")
706+
server.register_tools([search_web, calculate])
707+
server.run() # Starts stdio server (for Claude Desktop)
708+
709+
# Or run as SSE server for web clients
710+
# server.run_sse(host="0.0.0.0", port=8080)
711+
```
712+
686713
---
687714

688715
## Native Web Search
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
"""Example: Expose custom tools as MCP server.
2+
3+
This example demonstrates how to create an MCP server that exposes
4+
custom Python functions as MCP tools. These tools can then be used
5+
by any MCP client (Claude Desktop, Cursor, etc.).
6+
7+
Usage:
8+
# Run as stdio server (for Claude Desktop, etc.)
9+
python mcp_server_example.py
10+
11+
# Run as SSE server (for web clients)
12+
python mcp_server_example.py --sse --port 8080
13+
"""
14+
15+
import argparse
16+
from typing import List, Dict, Any
17+
18+
19+
# Define your custom tools as regular Python functions
20+
# Type hints and docstrings are used to generate MCP schemas
21+
22+
def search_web(query: str, max_results: int = 5) -> Dict[str, Any]:
23+
"""Search the web for information.
24+
25+
Args:
26+
query: The search query string
27+
max_results: Maximum number of results to return (default: 5)
28+
29+
Returns:
30+
Search results with titles and URLs
31+
"""
32+
# This is a mock implementation - replace with actual search logic
33+
return {
34+
"query": query,
35+
"results": [
36+
{"title": f"Result {i+1} for '{query}'", "url": f"https://example.com/{i+1}"}
37+
for i in range(max_results)
38+
]
39+
}
40+
41+
42+
def calculate(expression: str) -> Dict[str, Any]:
43+
"""Evaluate a mathematical expression.
44+
45+
Args:
46+
expression: A mathematical expression to evaluate (e.g., "2 + 2 * 3")
47+
48+
Returns:
49+
The result of the calculation
50+
"""
51+
try:
52+
# Safe evaluation of mathematical expressions
53+
# In production, use a proper math parser
54+
allowed_chars = set("0123456789+-*/.() ")
55+
if not all(c in allowed_chars for c in expression):
56+
return {"error": "Invalid characters in expression"}
57+
58+
result = eval(expression) # Note: Use safer alternative in production
59+
return {"expression": expression, "result": result}
60+
except Exception as e:
61+
return {"error": str(e)}
62+
63+
64+
def get_weather(city: str, units: str = "celsius") -> Dict[str, Any]:
65+
"""Get current weather for a city.
66+
67+
Args:
68+
city: Name of the city
69+
units: Temperature units - "celsius" or "fahrenheit" (default: celsius)
70+
71+
Returns:
72+
Weather information for the city
73+
"""
74+
# Mock implementation - replace with actual weather API
75+
return {
76+
"city": city,
77+
"temperature": 22 if units == "celsius" else 72,
78+
"units": units,
79+
"condition": "Sunny",
80+
"humidity": 45
81+
}
82+
83+
84+
def list_files(directory: str = ".", pattern: str = "*") -> List[str]:
85+
"""List files in a directory.
86+
87+
Args:
88+
directory: Directory path to list (default: current directory)
89+
pattern: Glob pattern to filter files (default: *)
90+
91+
Returns:
92+
List of file names matching the pattern
93+
"""
94+
import glob
95+
import os
96+
97+
try:
98+
full_pattern = os.path.join(directory, pattern)
99+
files = glob.glob(full_pattern)
100+
return [os.path.basename(f) for f in files]
101+
except Exception as e:
102+
return [f"Error: {str(e)}"]
103+
104+
105+
def main():
106+
parser = argparse.ArgumentParser(description="Run PraisonAI Tools as MCP Server")
107+
parser.add_argument("--sse", action="store_true", help="Use SSE transport instead of stdio")
108+
parser.add_argument("--port", type=int, default=8080, help="Port for SSE server (default: 8080)")
109+
parser.add_argument("--host", type=str, default="0.0.0.0", help="Host for SSE server")
110+
parser.add_argument("--debug", action="store_true", help="Enable debug logging")
111+
args = parser.parse_args()
112+
113+
# Import MCP server components
114+
from praisonaiagents.mcp import ToolsMCPServer
115+
116+
# Create server with custom name
117+
server = ToolsMCPServer(
118+
name="praisonai-custom-tools",
119+
debug=args.debug
120+
)
121+
122+
# Register all tools
123+
server.register_tools([
124+
search_web,
125+
calculate,
126+
get_weather,
127+
list_files
128+
])
129+
130+
# Print registered tools
131+
print(f"📦 Registered {len(server.tools)} tools:")
132+
for name in server.get_tool_names():
133+
print(f" - {name}")
134+
print()
135+
136+
# Run the server
137+
if args.sse:
138+
server.run_sse(host=args.host, port=args.port)
139+
else:
140+
server.run_stdio()
141+
142+
143+
if __name__ == "__main__":
144+
main()
Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,40 @@
11
"""
22
Model Context Protocol (MCP) integration for PraisonAI Agents.
33
4-
This package provides classes and utilities for connecting to MCP servers
5-
using different transport methods (stdio, SSE, etc.).
4+
This package provides classes and utilities for:
5+
- Connecting to MCP servers (as client) using different transports (stdio, SSE, etc.)
6+
- Exposing Python functions as MCP servers for external clients
7+
8+
Client Usage:
9+
from praisonaiagents.mcp import MCP
10+
11+
agent = Agent(
12+
tools=MCP("npx -y @modelcontextprotocol/server-weather")
13+
)
14+
15+
Server Usage:
16+
from praisonaiagents.mcp import ToolsMCPServer
17+
18+
def my_tool(query: str) -> str:
19+
'''Search for information.'''
20+
return f"Results for {query}"
21+
22+
server = ToolsMCPServer(name="my-tools")
23+
server.register_tool(my_tool)
24+
server.run() # Starts MCP server
625
"""
726
from .mcp import MCP
27+
from .mcp_server import ToolsMCPServer, launch_tools_mcp_server
28+
from .mcp_utils import function_to_mcp_schema, get_tool_metadata, python_type_to_json_schema
829

9-
__all__ = ["MCP"]
30+
__all__ = [
31+
# Client
32+
"MCP",
33+
# Server
34+
"ToolsMCPServer",
35+
"launch_tools_mcp_server",
36+
# Utilities
37+
"function_to_mcp_schema",
38+
"get_tool_metadata",
39+
"python_type_to_json_schema",
40+
]

0 commit comments

Comments
 (0)