XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

Add MCP server implementation with web search, scraping, and image generation tools

Co-authored-by: hlohaus <983577+hlohaus@users.noreply.github.com>

e1214e43
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
提交于

代码差异

10 个文件 +964 -2
Modified etc/unittest/__main__.py +1 -0
@@ -15,5 +15,6 @@ from .retry_provider import *
15 15 from .thinking import *
16 16 from .web_search import *
17 17 from .models import *
18 from .mcp import *
18 19
19 20 unittest.main()
Added etc/unittest/mcp.py +166 -0
@@ -0,0 +1,166 @@
1 from __future__ import annotations
2
3 import json
4 import unittest
5
6 from g4f.mcp.server import MCPServer, MCPRequest
7 from g4f.mcp.tools import WebSearchTool, WebScrapeTool, ImageGenerationTool
8
9 try:
10 from ddgs import DDGS, DDGSError
11 from bs4 import BeautifulSoup
12 has_requirements = True
13 except ImportError:
14 has_requirements = False
15
16
17 class TestMCPServer(unittest.IsolatedAsyncioTestCase):
18 """Test cases for MCP server"""
19
20 async def test_server_initialization(self):
21 """Test that server initializes correctly"""
22 server = MCPServer()
23 self.assertIsNotNone(server)
24 self.assertEqual(server.server_info["name"], "gpt4free-mcp-server")
25 self.assertEqual(len(server.tools), 3)
26 self.assertIn('web_search', server.tools)
27 self.assertIn('web_scrape', server.tools)
28 self.assertIn('image_generation', server.tools)
29
30 async def test_initialize_request(self):
31 """Test initialize method"""
32 server = MCPServer()
33 request = MCPRequest(
34 jsonrpc="2.0",
35 id=1,
36 method="initialize",
37 params={}
38 )
39 response = await server.handle_request(request)
40 self.assertEqual(response.jsonrpc, "2.0")
41 self.assertEqual(response.id, 1)
42 self.assertIsNotNone(response.result)
43 self.assertEqual(response.result["protocolVersion"], "2024-11-05")
44 self.assertIn("serverInfo", response.result)
45
46 async def test_tools_list(self):
47 """Test tools/list method"""
48 server = MCPServer()
49 request = MCPRequest(
50 jsonrpc="2.0",
51 id=2,
52 method="tools/list",
53 params={}
54 )
55 response = await server.handle_request(request)
56 self.assertEqual(response.jsonrpc, "2.0")
57 self.assertEqual(response.id, 2)
58 self.assertIsNotNone(response.result)
59 self.assertIn("tools", response.result)
60 self.assertEqual(len(response.result["tools"]), 3)
61
62 # Check tool structure
63 tool_names = [tool["name"] for tool in response.result["tools"]]
64 self.assertIn("web_search", tool_names)
65 self.assertIn("web_scrape", tool_names)
66 self.assertIn("image_generation", tool_names)
67
68 async def test_ping(self):
69 """Test ping method"""
70 server = MCPServer()
71 request = MCPRequest(
72 jsonrpc="2.0",
73 id=3,
74 method="ping",
75 params={}
76 )
77 response = await server.handle_request(request)
78 self.assertEqual(response.jsonrpc, "2.0")
79 self.assertEqual(response.id, 3)
80 self.assertIsNotNone(response.result)
81
82 async def test_invalid_method(self):
83 """Test invalid method returns error"""
84 server = MCPServer()
85 request = MCPRequest(
86 jsonrpc="2.0",
87 id=4,
88 method="invalid_method",
89 params={}
90 )
91 response = await server.handle_request(request)
92 self.assertEqual(response.jsonrpc, "2.0")
93 self.assertEqual(response.id, 4)
94 self.assertIsNotNone(response.error)
95 self.assertEqual(response.error["code"], -32601)
96
97 async def test_tool_call_invalid_tool(self):
98 """Test calling non-existent tool"""
99 server = MCPServer()
100 request = MCPRequest(
101 jsonrpc="2.0",
102 id=5,
103 method="tools/call",
104 params={
105 "name": "nonexistent_tool",
106 "arguments": {}
107 }
108 )
109 response = await server.handle_request(request)
110 self.assertEqual(response.jsonrpc, "2.0")
111 self.assertEqual(response.id, 5)
112 self.assertIsNotNone(response.error)
113 self.assertEqual(response.error["code"], -32601)
114
115
116 class TestMCPTools(unittest.IsolatedAsyncioTestCase):
117 """Test cases for MCP tools"""
118
119 def setUp(self) -> None:
120 if not has_requirements:
121 self.skipTest('MCP tools requirements not installed')
122
123 async def test_web_search_tool_schema(self):
124 """Test WebSearchTool schema"""
125 tool = WebSearchTool()
126 self.assertIsNotNone(tool.description)
127 self.assertIsNotNone(tool.input_schema)
128 self.assertEqual(tool.input_schema["type"], "object")
129 self.assertIn("query", tool.input_schema["properties"])
130 self.assertIn("query", tool.input_schema["required"])
131
132 async def test_web_scrape_tool_schema(self):
133 """Test WebScrapeTool schema"""
134 tool = WebScrapeTool()
135 self.assertIsNotNone(tool.description)
136 self.assertIsNotNone(tool.input_schema)
137 self.assertEqual(tool.input_schema["type"], "object")
138 self.assertIn("url", tool.input_schema["properties"])
139 self.assertIn("url", tool.input_schema["required"])
140
141 async def test_image_generation_tool_schema(self):
142 """Test ImageGenerationTool schema"""
143 tool = ImageGenerationTool()
144 self.assertIsNotNone(tool.description)
145 self.assertIsNotNone(tool.input_schema)
146 self.assertEqual(tool.input_schema["type"], "object")
147 self.assertIn("prompt", tool.input_schema["properties"])
148 self.assertIn("prompt", tool.input_schema["required"])
149
150 async def test_web_search_missing_query(self):
151 """Test web search with missing query parameter"""
152 tool = WebSearchTool()
153 result = await tool.execute({})
154 self.assertIn("error", result)
155
156 async def test_web_scrape_missing_url(self):
157 """Test web scrape with missing url parameter"""
158 tool = WebScrapeTool()
159 result = await tool.execute({})
160 self.assertIn("error", result)
161
162 async def test_image_generation_missing_prompt(self):
163 """Test image generation with missing prompt parameter"""
164 tool = ImageGenerationTool()
165 result = await tool.execute({})
166 self.assertIn("error", result)
Modified g4f/cli/__init__.py +13 -1
@@ -78,12 +78,22 @@ def run_api_args(args):
78 78 log_config=args.log_config,
79 79 )
80 80
81 def get_mcp_parser():
82 mcp_parser = ArgumentParser(description="Run the MCP (Model Context Protocol) server")
83 mcp_parser.add_argument("--debug", "-d", action="store_true", help="Enable verbose logging.")
84 return mcp_parser
85
86 def run_mcp_args(args):
87 from ..mcp.server import main as mcp_main
88 mcp_main()
89
81 90 def main():
82 91 parser = argparse.ArgumentParser(description="Run gpt4free", exit_on_error=False)
83 92 subparsers = parser.add_subparsers(dest="mode", help="Mode to run the g4f in.")
84 93 subparsers.add_parser("api", parents=[get_api_parser()], add_help=False)
85 94 subparsers.add_parser("gui", parents=[gui_parser()], add_help=False)
86 95 subparsers.add_parser("client", parents=[get_parser()], add_help=False)
96 subparsers.add_parser("mcp", parents=[get_mcp_parser()], add_help=False)
87 97
88 98 try:
89 99 args = parser.parse_args()
@@ -93,8 +103,10 @@ def main():
93 103 run_gui_args(args)
94 104 elif args.mode == "client":
95 105 run_client_args(args)
106 elif args.mode == "mcp":
107 run_mcp_args(args)
96 108 else:
97 raise argparse.ArgumentError(None, "No valid mode specified. Use 'api', 'gui', or 'client'.")
109 raise argparse.ArgumentError(None, "No valid mode specified. Use 'api', 'gui', 'client', or 'mcp'.")
98 110 except argparse.ArgumentError:
99 111 try:
100 112 run_client_args(get_parser(exit_on_error=False).parse_args(), exit_on_error=False)
Added g4f/mcp/README.md +283 -0
@@ -0,0 +1,283 @@
1 # gpt4free MCP Server
2
3 A Model Context Protocol (MCP) server implementation for gpt4free that provides AI assistants with access to web search, scraping, and image generation capabilities.
4
5 ## Overview
6
7 The gpt4free MCP server exposes three main tools:
8
9 1. **Web Search** - Search the web using DuckDuckGo
10 2. **Web Scraping** - Extract and clean text content from web pages
11 3. **Image Generation** - Generate images from text prompts using various AI providers
12
13 ## Installation
14
15 The MCP server is included with gpt4free. No additional installation is required beyond the base gpt4free package.
16
17 ```bash
18 pip install -e .
19 ```
20
21 ## Usage
22
23 ### Running the MCP Server
24
25 Start the MCP server using:
26
27 ```bash
28 python -m g4f.mcp
29 ```
30
31 Or using the g4f command:
32
33 ```bash
34 g4f mcp
35 ```
36
37 The server communicates over stdin/stdout using JSON-RPC 2.0 protocol.
38
39 ### Configuration for AI Assistants
40
41 To use this MCP server with an AI assistant like Claude Desktop, add the following to your MCP configuration:
42
43 **For Claude Desktop** (`claude_desktop_config.json`):
44
45 ```json
46 {
47 "mcpServers": {
48 "gpt4free": {
49 "command": "python",
50 "args": ["-m", "g4f.mcp"]
51 }
52 }
53 }
54 ```
55
56 **For VS Code with Cline**:
57
58 ```json
59 {
60 "mcpServers": {
61 "gpt4free": {
62 "command": "python",
63 "args": ["-m", "g4f.mcp"],
64 "disabled": false
65 }
66 }
67 }
68 ```
69
70 ## Available Tools
71
72 ### web_search
73
74 Search the web for information.
75
76 **Parameters:**
77 - `query` (string, required): The search query
78 - `max_results` (integer, optional): Maximum number of results (default: 5)
79
80 **Example:**
81 ```json
82 {
83 "name": "web_search",
84 "arguments": {
85 "query": "latest AI developments 2024",
86 "max_results": 5
87 }
88 }
89 ```
90
91 ### web_scrape
92
93 Scrape and extract text content from a web page.
94
95 **Parameters:**
96 - `url` (string, required): The URL to scrape
97 - `max_words` (integer, optional): Maximum words to extract (default: 1000)
98
99 **Example:**
100 ```json
101 {
102 "name": "web_scrape",
103 "arguments": {
104 "url": "https://example.com/article",
105 "max_words": 1000
106 }
107 }
108 ```
109
110 ### image_generation
111
112 Generate images from text prompts.
113
114 **Parameters:**
115 - `prompt` (string, required): Description of the image to generate
116 - `model` (string, optional): Image model to use (default: "flux")
117 - `width` (integer, optional): Image width in pixels (default: 1024)
118 - `height` (integer, optional): Image height in pixels (default: 1024)
119
120 **Example:**
121 ```json
122 {
123 "name": "image_generation",
124 "arguments": {
125 "prompt": "A serene mountain landscape at sunset",
126 "width": 1024,
127 "height": 1024
128 }
129 }
130 ```
131
132 ## Protocol Details
133
134 The MCP server implements the Model Context Protocol using JSON-RPC 2.0 over stdio transport.
135
136 ### Supported Methods
137
138 - `initialize` - Initialize connection with the server
139 - `tools/list` - List all available tools
140 - `tools/call` - Execute a tool with given arguments
141 - `ping` - Health check
142
143 ### Example Request/Response
144
145 **Request:**
146 ```json
147 {
148 "jsonrpc": "2.0",
149 "id": 1,
150 "method": "tools/call",
151 "params": {
152 "name": "web_search",
153 "arguments": {
154 "query": "Python programming tutorials",
155 "max_results": 3
156 }
157 }
158 }
159 ```
160
161 **Response:**
162 ```json
163 {
164 "jsonrpc": "2.0",
165 "id": 1,
166 "result": {
167 "content": [
168 {
169 "type": "text",
170 "text": "{\"query\": \"Python programming tutorials\", \"results\": [...], \"count\": 3}"
171 }
172 ]
173 }
174 }
175 ```
176
177 ## Requirements
178
179 The MCP server requires the following dependencies (included in gpt4free):
180
181 - `aiohttp` - For async HTTP requests
182 - `beautifulsoup4` - For web scraping
183 - `ddgs` - For web search
184
185 These are automatically installed with:
186
187 ```bash
188 pip install -r requirements.txt
189 ```
190
191 ## Error Handling
192
193 The server returns standard JSON-RPC error responses:
194
195 - `-32601`: Method not found
196 - `-32602`: Invalid parameters
197 - `-32603`: Internal error
198
199 Errors specific to tools are returned in the result object with an `error` field.
200
201 ## Development
202
203 ### Project Structure
204
205 ```
206 g4f/mcp/
207 ├── __init__.py # Package initialization
208 ├── __main__.py # CLI entry point
209 ├── server.py # MCP server implementation
210 ├── tools.py # Tool implementations
211 └── README.md # This file
212 ```
213
214 ### Adding New Tools
215
216 To add a new tool:
217
218 1. Create a new class inheriting from `MCPTool` in `tools.py`
219 2. Implement the required properties and methods
220 3. Register the tool in `MCPServer.__init__()` in `server.py`
221
222 Example:
223
224 ```python
225 class MyNewTool(MCPTool):
226 @property
227 def description(self) -> str:
228 return "Description of what the tool does"
229
230 @property
231 def input_schema(self) -> Dict[str, Any]:
232 return {
233 "type": "object",
234 "properties": {
235 "param1": {
236 "type": "string",
237 "description": "Parameter description"
238 }
239 },
240 "required": ["param1"]
241 }
242
243 async def execute(self, arguments: Dict[str, Any]) -> Any:
244 # Implementation
245 pass
246 ```
247
248 ## Troubleshooting
249
250 ### Server Won't Start
251
252 Make sure all dependencies are installed:
253 ```bash
254 pip install -r requirements.txt
255 ```
256
257 ### Tools Return Errors
258
259 Check that:
260 - Network connectivity is available for web search and scraping
261 - URLs are valid and accessible
262 - Image generation providers are not rate-limited
263
264 ### Debug Mode
265
266 The server writes diagnostic information to stderr. To see debug output:
267 ```bash
268 python -m g4f.mcp 2> debug.log
269 ```
270
271 ## License
272
273 This MCP server is part of the gpt4free project and is licensed under the GNU General Public License v3.0.
274
275 ## Contributing
276
277 Contributions are welcome! Please see the main gpt4free repository for contribution guidelines.
278
279 ## Related Links
280
281 - [gpt4free Repository](https://github.com/xtekky/gpt4free)
282 - [Model Context Protocol Specification](https://modelcontextprotocol.io/)
283 - [MCP Documentation](https://modelcontextprotocol.io/docs)
Added g4f/mcp/__init__.py +13 -0
@@ -0,0 +1,13 @@
1 """MCP (Model Context Protocol) Server for gpt4free
2
3 This module provides an MCP server implementation that exposes gpt4free capabilities
4 through the Model Context Protocol standard, allowing AI assistants to access:
5 - Web search functionality
6 - Web scraping capabilities
7 - Image generation using various providers
8 """
9
10 from .server import MCPServer
11 from .tools import WebSearchTool, WebScrapeTool, ImageGenerationTool
12
13 __all__ = ['MCPServer', 'WebSearchTool', 'WebScrapeTool', 'ImageGenerationTool']
Added g4f/mcp/__main__.py +9 -0
@@ -0,0 +1,9 @@
1 """Main entry point for gpt4free MCP server
2
3 This module provides the main entry point for running the MCP server.
4 """
5
6 from .server import main
7
8 if __name__ == "__main__":
9 main()
Added g4f/mcp/claude_desktop_config.example.json +9 -0
@@ -0,0 +1,9 @@
1 {
2 "mcpServers": {
3 "gpt4free": {
4 "command": "python",
5 "args": ["-m", "g4f.mcp"],
6 "description": "gpt4free MCP server providing web search, scraping, and image generation"
7 }
8 }
9 }
Added g4f/mcp/server.py +202 -0
@@ -0,0 +1,202 @@
1 """MCP Server implementation using stdio transport
2
3 This module implements a Model Context Protocol (MCP) server that communicates
4 over standard input/output using JSON-RPC 2.0. The server exposes tools for:
5 - Web search
6 - Web scraping
7 - Image generation
8 """
9
10 from __future__ import annotations
11
12 import sys
13 import json
14 import asyncio
15 from typing import Any, Dict, List, Optional
16 from dataclasses import dataclass, asdict
17
18 from .tools import WebSearchTool, WebScrapeTool, ImageGenerationTool
19
20
21 @dataclass
22 class MCPRequest:
23 """MCP request following JSON-RPC 2.0 format"""
24 jsonrpc: str = "2.0"
25 id: Optional[int | str] = None
26 method: Optional[str] = None
27 params: Optional[Dict[str, Any]] = None
28
29
30 @dataclass
31 class MCPResponse:
32 """MCP response following JSON-RPC 2.0 format"""
33 jsonrpc: str = "2.0"
34 id: Optional[int | str] = None
35 result: Optional[Any] = None
36 error: Optional[Dict[str, Any]] = None
37
38
39 class MCPServer:
40 """Model Context Protocol server for gpt4free
41
42 This server exposes gpt4free capabilities through the MCP standard,
43 allowing AI assistants to utilize web search, scraping, and image generation.
44 """
45
46 def __init__(self):
47 """Initialize MCP server with available tools"""
48 self.tools = {
49 'web_search': WebSearchTool(),
50 'web_scrape': WebScrapeTool(),
51 'image_generation': ImageGenerationTool(),
52 }
53 self.server_info = {
54 "name": "gpt4free-mcp-server",
55 "version": "1.0.0",
56 "description": "MCP server providing web search, scraping, and image generation capabilities"
57 }
58
59 def get_tool_list(self) -> List[Dict[str, Any]]:
60 """Get list of available tools with their schemas"""
61 tool_list = []
62 for name, tool in self.tools.items():
63 tool_list.append({
64 "name": name,
65 "description": tool.description,
66 "inputSchema": tool.input_schema
67 })
68 return tool_list
69
70 async def handle_request(self, request: MCPRequest) -> MCPResponse:
71 """Handle incoming MCP request"""
72 try:
73 method = request.method
74 params = request.params or {}
75
76 # Handle MCP protocol methods
77 if method == "initialize":
78 result = {
79 "protocolVersion": "2024-11-05",
80 "serverInfo": self.server_info,
81 "capabilities": {
82 "tools": {}
83 }
84 }
85 return MCPResponse(jsonrpc="2.0", id=request.id, result=result)
86
87 elif method == "tools/list":
88 result = {
89 "tools": self.get_tool_list()
90 }
91 return MCPResponse(jsonrpc="2.0", id=request.id, result=result)
92
93 elif method == "tools/call":
94 tool_name = params.get("name")
95 tool_arguments = params.get("arguments", {})
96
97 if tool_name not in self.tools:
98 return MCPResponse(
99 jsonrpc="2.0",
100 id=request.id,
101 error={
102 "code": -32601,
103 "message": f"Tool not found: {tool_name}"
104 }
105 )
106
107 tool = self.tools[tool_name]
108 result = await tool.execute(tool_arguments)
109
110 return MCPResponse(
111 jsonrpc="2.0",
112 id=request.id,
113 result={
114 "content": [
115 {
116 "type": "text",
117 "text": json.dumps(result, indent=2)
118 }
119 ]
120 }
121 )
122
123 elif method == "ping":
124 return MCPResponse(jsonrpc="2.0", id=request.id, result={})
125
126 else:
127 return MCPResponse(
128 jsonrpc="2.0",
129 id=request.id,
130 error={
131 "code": -32601,
132 "message": f"Method not found: {method}"
133 }
134 )
135
136 except Exception as e:
137 return MCPResponse(
138 jsonrpc="2.0",
139 id=request.id,
140 error={
141 "code": -32603,
142 "message": f"Internal error: {str(e)}"
143 }
144 )
145
146 async def run(self):
147 """Run the MCP server with stdio transport"""
148 # Write server info to stderr for debugging
149 sys.stderr.write(f"Starting {self.server_info['name']} v{self.server_info['version']}\n")
150 sys.stderr.flush()
151
152 while True:
153 try:
154 # Read line from stdin
155 line = await asyncio.get_event_loop().run_in_executor(
156 None, sys.stdin.readline
157 )
158
159 if not line:
160 break
161
162 # Parse JSON-RPC request
163 request_data = json.loads(line)
164 request = MCPRequest(
165 jsonrpc=request_data.get("jsonrpc", "2.0"),
166 id=request_data.get("id"),
167 method=request_data.get("method"),
168 params=request_data.get("params")
169 )
170
171 # Handle request
172 response = await self.handle_request(request)
173
174 # Write response to stdout
175 response_dict = {
176 "jsonrpc": response.jsonrpc,
177 "id": response.id
178 }
179 if response.result is not None:
180 response_dict["result"] = response.result
181 if response.error is not None:
182 response_dict["error"] = response.error
183
184 sys.stdout.write(json.dumps(response_dict) + "\n")
185 sys.stdout.flush()
186
187 except json.JSONDecodeError as e:
188 sys.stderr.write(f"JSON decode error: {e}\n")
189 sys.stderr.flush()
190 except Exception as e:
191 sys.stderr.write(f"Error: {e}\n")
192 sys.stderr.flush()
193
194
195 def main():
196 """Main entry point for MCP server"""
197 server = MCPServer()
198 asyncio.run(server.run())
199
200
201 if __name__ == "__main__":
202 main()
Added g4f/mcp/tools.py +264 -0
@@ -0,0 +1,264 @@
1 """MCP Tools for gpt4free
2
3 This module provides MCP tool implementations that wrap gpt4free capabilities:
4 - WebSearchTool: Web search using ddg search
5 - WebScrapeTool: Web page scraping and content extraction
6 - ImageGenerationTool: Image generation using various AI providers
7 """
8
9 from __future__ import annotations
10
11 import asyncio
12 from typing import Any, Dict
13 from abc import ABC, abstractmethod
14
15
16 class MCPTool(ABC):
17 """Base class for MCP tools"""
18
19 @property
20 @abstractmethod
21 def description(self) -> str:
22 """Tool description"""
23 pass
24
25 @property
26 @abstractmethod
27 def input_schema(self) -> Dict[str, Any]:
28 """JSON schema for tool input parameters"""
29 pass
30
31 @abstractmethod
32 async def execute(self, arguments: Dict[str, Any]) -> Any:
33 """Execute the tool with given arguments"""
34 pass
35
36
37 class WebSearchTool(MCPTool):
38 """Web search tool using gpt4free's search capabilities"""
39
40 @property
41 def description(self) -> str:
42 return "Search the web for information using DuckDuckGo. Returns search results with titles, URLs, and snippets."
43
44 @property
45 def input_schema(self) -> Dict[str, Any]:
46 return {
47 "type": "object",
48 "properties": {
49 "query": {
50 "type": "string",
51 "description": "The search query to execute"
52 },
53 "max_results": {
54 "type": "integer",
55 "description": "Maximum number of results to return (default: 5)",
56 "default": 5
57 }
58 },
59 "required": ["query"]
60 }
61
62 async def execute(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
63 """Execute web search"""
64 from ..tools.web_search import do_search
65
66 query = arguments.get("query", "")
67 max_results = arguments.get("max_results", 5)
68
69 if not query:
70 return {
71 "error": "Query parameter is required"
72 }
73
74 try:
75 # Perform search
76 result, sources = await do_search(
77 prompt=query,
78 query=query,
79 instructions=""
80 )
81
82 # Format results
83 search_results = []
84 if sources:
85 for i, source in enumerate(sources[:max_results]):
86 search_results.append({
87 "title": source.get("title", ""),
88 "url": source.get("url", ""),
89 "snippet": source.get("snippet", "")
90 })
91
92 return {
93 "query": query,
94 "results": search_results,
95 "count": len(search_results)
96 }
97
98 except Exception as e:
99 return {
100 "error": f"Search failed: {str(e)}"
101 }
102
103
104 class WebScrapeTool(MCPTool):
105 """Web scraping tool using gpt4free's scraping capabilities"""
106
107 @property
108 def description(self) -> str:
109 return "Scrape and extract text content from a web page URL. Returns cleaned text content with optional word limit."
110
111 @property
112 def input_schema(self) -> Dict[str, Any]:
113 return {
114 "type": "object",
115 "properties": {
116 "url": {
117 "type": "string",
118 "description": "The URL of the web page to scrape"
119 },
120 "max_words": {
121 "type": "integer",
122 "description": "Maximum number of words to extract (default: 1000)",
123 "default": 1000
124 }
125 },
126 "required": ["url"]
127 }
128
129 async def execute(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
130 """Execute web scraping"""
131 from ..tools.fetch_and_scrape import fetch_and_scrape
132 from aiohttp import ClientSession
133
134 url = arguments.get("url", "")
135 max_words = arguments.get("max_words", 1000)
136
137 if not url:
138 return {
139 "error": "URL parameter is required"
140 }
141
142 try:
143 # Scrape the URL
144 async with ClientSession() as session:
145 content = await fetch_and_scrape(
146 session=session,
147 url=url,
148 max_words=max_words,
149 add_source=True
150 )
151
152 if not content:
153 return {
154 "error": "Failed to scrape content from URL"
155 }
156
157 return {
158 "url": url,
159 "content": content,
160 "word_count": len(content.split())
161 }
162
163 except Exception as e:
164 return {
165 "error": f"Scraping failed: {str(e)}"
166 }
167
168
169 class ImageGenerationTool(MCPTool):
170 """Image generation tool using gpt4free's image generation capabilities"""
171
172 @property
173 def description(self) -> str:
174 return "Generate images from text prompts using AI image generation providers. Returns base64-encoded image data."
175
176 @property
177 def input_schema(self) -> Dict[str, Any]:
178 return {
179 "type": "object",
180 "properties": {
181 "prompt": {
182 "type": "string",
183 "description": "The text prompt describing the image to generate"
184 },
185 "model": {
186 "type": "string",
187 "description": "The image generation model to use (default: flux)",
188 "default": "flux"
189 },
190 "width": {
191 "type": "integer",
192 "description": "Image width in pixels (default: 1024)",
193 "default": 1024
194 },
195 "height": {
196 "type": "integer",
197 "description": "Image height in pixels (default: 1024)",
198 "default": 1024
199 }
200 },
201 "required": ["prompt"]
202 }
203
204 async def execute(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
205 """Execute image generation"""
206 from ..client import AsyncClient
207 from ..image import to_data_uri
208 import base64
209
210 prompt = arguments.get("prompt", "")
211 model = arguments.get("model", "flux")
212 width = arguments.get("width", 1024)
213 height = arguments.get("height", 1024)
214
215 if not prompt:
216 return {
217 "error": "Prompt parameter is required"
218 }
219
220 try:
221 # Generate image using gpt4free client
222 client = AsyncClient()
223
224 response = await client.images.generate(
225 model=model,
226 prompt=prompt,
227 width=width,
228 height=height
229 )
230
231 # Get the image data
232 if response and hasattr(response, 'data') and response.data:
233 image_data = response.data[0]
234
235 # Convert to base64 if needed
236 if hasattr(image_data, 'url'):
237 image_url = image_data.url
238
239 # Check if it's already a data URI
240 if image_url.startswith('data:'):
241 return {
242 "prompt": prompt,
243 "model": model,
244 "width": width,
245 "height": height,
246 "image": image_url
247 }
248 else:
249 return {
250 "prompt": prompt,
251 "model": model,
252 "width": width,
253 "height": height,
254 "image_url": image_url
255 }
256
257 return {
258 "error": "Image generation failed: No image data in response"
259 }
260
261 except Exception as e:
262 return {
263 "error": f"Image generation failed: {str(e)}"
264 }
Modified setup.py +4 -1
@@ -114,7 +114,10 @@ setup(
114 114 install_requires=INSTALL_REQUIRE,
115 115 extras_require=EXTRA_REQUIRE,
116 116 entry_points={
117 'console_scripts': ['g4f=g4f.cli:main'],
117 'console_scripts': [
118 'g4f=g4f.cli:main',
119 'g4f-mcp=g4f.mcp.server:main',
120 ],
118 121 },
119 122 url='https://github.com/xtekky/gpt4free', # Link to your GitHub repository
120 123 project_urls={