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

XFEstudio/gpt4free

Add CORS support to MCP server and tools; enhance image URL handling in tools

a4923529
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

4 个文件 +29 -12
Modified g4f/cli/__init__.py +2 -1
@@ -84,11 +84,12 @@ def get_mcp_parser():
84 84 mcp_parser.add_argument("--http", action="store_true", help="Use HTTP transport instead of stdio.")
85 85 mcp_parser.add_argument("--host", default="0.0.0.0", help="Host to bind HTTP server to (default: 0.0.0.0)")
86 86 mcp_parser.add_argument("--port", type=int, default=8765, help="Port to bind HTTP server to (default: 8765)")
87 mcp_parser.add_argument("--origin", type=str, default=None, help="Origin URL for CORS (default: None)")
87 88 return mcp_parser
88 89
89 90 def run_mcp_args(args):
90 91 from ..mcp.server import main as mcp_main
91 mcp_main(http=args.http, host=args.host, port=args.port)
92 mcp_main(http=args.http, host=args.host, port=args.port, origin=args.origin)
92 93
93 94 def main():
94 95 parser = argparse.ArgumentParser(description="Run gpt4free", exit_on_error=False)
Modified g4f/gui/server/backend_api.py +6 -4
@@ -356,11 +356,13 @@ class Backend_Api(Api):
356 356 if response.startswith("/media/"):
357 357 media_dir = get_media_dir()
358 358 filename = os.path.basename(response.split("?")[0])
359 try:
360 return send_from_directory(os.path.abspath(media_dir), filename)
361 finally:
362 if not cache_id:
359 if not cache_id:
360 try:
361 return send_from_directory(os.path.abspath(media_dir), filename)
362 finally:
363 363 os.remove(os.path.join(media_dir, filename))
364 else:
365 return redirect(response)
364 366 elif response.startswith("https://") or response.startswith("http://"):
365 367 return redirect(response)
366 368 if do_filter:
Modified g4f/mcp/server.py +10 -5
@@ -31,6 +31,7 @@ class MCPRequest:
31 31 id: Optional[Union[int, str]] = None
32 32 method: Optional[str] = None
33 33 params: Optional[Dict[str, Any]] = None
34 origin: Optional[str] = None
34 35
35 36
36 37 @dataclass
@@ -101,6 +102,7 @@ class MCPServer:
101 102 elif method == "tools/call":
102 103 tool_name = params.get("name")
103 104 tool_arguments = params.get("arguments", {})
105 tool_arguments.setdefault("origin", request.origin)
104 106
105 107 if tool_name not in self.tools:
106 108 return MCPResponse(
@@ -173,7 +175,7 @@ class MCPServer:
173 175 jsonrpc=request_data.get("jsonrpc", "2.0"),
174 176 id=request_data.get("id"),
175 177 method=request_data.get("method"),
176 params=request_data.get("params")
178 params=request_data.get("params"),
177 179 )
178 180
179 181 # Handle request
@@ -199,7 +201,7 @@ class MCPServer:
199 201 sys.stderr.write(f"Error: {e}\n")
200 202 sys.stderr.flush()
201 203
202 async def run_http(self, host: str = "0.0.0.0", port: int = 8765):
204 async def run_http(self, host: str = "0.0.0.0", port: int = 8765, origin: Optional[str] = None):
203 205 """Run the MCP server with HTTP transport
204 206
205 207 Args:
@@ -218,12 +220,15 @@ class MCPServer:
218 220 try:
219 221 # Parse JSON-RPC request from POST body
220 222 request_data = await request.json()
223 if origin is None:
224 request_origin = request.headers.get("origin")
221 225
222 226 mcp_request = MCPRequest(
223 227 jsonrpc=request_data.get("jsonrpc", "2.0"),
224 228 id=request_data.get("id"),
225 229 method=request_data.get("method"),
226 params=request_data.get("params")
230 params=request_data.get("params"),
231 origin=request_origin
227 232 )
228 233
229 234 # Handle request
@@ -295,7 +300,7 @@ class MCPServer:
295 300 await runner.cleanup()
296 301
297 302
298 def main(http: bool = False, host: str = "0.0.0.0", port: int = 8765):
303 def main(http: bool = False, host: str = "0.0.0.0", port: int = 8765, origin: Optional[str] = None):
299 304 """Main entry point for MCP server
300 305
301 306 Args:
@@ -305,7 +310,7 @@ def main(http: bool = False, host: str = "0.0.0.0", port: int = 8765):
305 310 """
306 311 server = MCPServer()
307 312 if http:
308 asyncio.run(server.run_http(host, port))
313 asyncio.run(server.run_http(host, port, origin))
309 314 else:
310 315 asyncio.run(server.run())
311 316
Modified g4f/mcp/tools.py +11 -2
@@ -11,6 +11,8 @@ from __future__ import annotations
11 11 from typing import Any, Dict
12 12 from abc import ABC, abstractmethod
13 13
14 from aiohttp import ClientSession
15
14 16
15 17 class MCPTool(ABC):
16 18 """Base class for MCP tools"""
@@ -278,6 +280,8 @@ class ImageGenerationTool(MCPTool):
278 280 "image": image_url
279 281 }
280 282 else:
283 if arguments.get("origin") and image_url.startswith("/media/"):
284 image_url = f"{arguments.get('origin')}{image_url}"
281 285 return {
282 286 "prompt": prompt,
283 287 "model": model,
@@ -437,8 +441,13 @@ class TextToAudioTool(MCPTool):
437 441 encoded_prompt = prompt.replace(" ", "%20") # Basic space encoding
438 442
439 443 # Construct the Pollinations AI text-to-speech URL
440 base_url = "https://text.pollinations.ai"
441 audio_url = f"{base_url}/{encoded_prompt}?voice={voice}"
444 audio_url = f"/backend-api/v2/create?provider=Gemini&model=gemini-audio&cache=true&prompt={encoded_prompt}"
445
446 if arguments.get("origin"):
447 audio_url = f"{arguments.get('origin')}{audio_url}"
448 async with ClientSession() as session:
449 async with session.get(audio_url, max_redirects=0) as resp:
450 audio_url = str(resp.url)
442 451
443 452 return {
444 453 "prompt": prompt,