Add MCP server tests, documentation, and README updates

Co-authored-by: hlohaus <983577+hlohaus@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-11-01 05:10:49 +00:00
parent e1214e4372
commit 0c2a2b00c3
3 changed files with 285 additions and 0 deletions

View file

@ -204,6 +204,39 @@ python -m g4f --port 8080 --debug
python -m g4f.cli gui --port 8080 --debug
```
### MCP Server
GPT4Free now includes a Model Context Protocol (MCP) server that allows AI assistants like Claude to access web search, scraping, and image generation capabilities.
**Starting the MCP server:**
```bash
# Using g4f command
g4f mcp
# Or using Python module
python -m g4f.mcp
```
**Configuring with Claude Desktop:**
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"gpt4free": {
"command": "python",
"args": ["-m", "g4f.mcp"]
}
}
}
```
**Available MCP Tools:**
- `web_search` - Search the web using DuckDuckGo
- `web_scrape` - Extract text content from web pages
- `image_generation` - Generate images from text prompts
For detailed MCP documentation, see [g4f/mcp/README.md](g4f/mcp/README.md)
### Optional provider login (desktop within container)
- Accessible at:
```

View file

@ -0,0 +1,149 @@
#!/usr/bin/env python
"""Interactive MCP server test
This script simulates a client sending requests to the MCP server
and demonstrates how the tools work.
"""
import json
import sys
import asyncio
from io import StringIO
async def simulate_mcp_client():
"""Simulate an MCP client interacting with the server"""
print("MCP Server Interactive Test")
print("=" * 70)
print("\nThis test simulates JSON-RPC 2.0 messages between client and server.")
print("The MCP server uses stdio transport for communication.\n")
from g4f.mcp.server import MCPServer, MCPRequest
server = MCPServer()
# Test sequence of requests
test_requests = [
{
"name": "Initialize Connection",
"request": {
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
}
},
{
"name": "List Available Tools",
"request": {
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
},
{
"name": "Ping Server",
"request": {
"jsonrpc": "2.0",
"id": 3,
"method": "ping",
"params": {}
}
},
]
for test in test_requests:
print(f"\n{'' * 70}")
print(f"Test: {test['name']}")
print(f"{'' * 70}")
# Show request
print("\nClient Request:")
print(json.dumps(test['request'], indent=2))
# Create request object
req_data = test['request']
request = MCPRequest(
jsonrpc=req_data.get("jsonrpc", "2.0"),
id=req_data.get("id"),
method=req_data.get("method"),
params=req_data.get("params")
)
# Handle request
response = await server.handle_request(request)
# Show response
print("\nServer Response:")
response_dict = {
"jsonrpc": response.jsonrpc,
"id": response.id
}
if response.result is not None:
response_dict["result"] = response.result
if response.error is not None:
response_dict["error"] = response.error
print(json.dumps(response_dict, indent=2))
await asyncio.sleep(0.1) # Small delay between requests
print(f"\n{'' * 70}")
print("Interactive Test Complete!")
print(f"{'' * 70}\n")
print("Tool Descriptions:")
print("-" * 70)
for name, tool in server.tools.items():
print(f"\n{name}")
print(f" {tool.description}")
schema = tool.input_schema
if 'required' in schema:
print(f" Required: {', '.join(schema['required'])}")
if 'properties' in schema:
optional = [k for k in schema['properties'].keys() if k not in schema.get('required', [])]
if optional:
print(f" Optional: {', '.join(optional)}")
print(f"\n{'' * 70}")
print("How to Use the MCP Server:")
print(f"{'' * 70}\n")
print("1. Start the server:")
print(" $ python -m g4f.mcp")
print(" or")
print(" $ g4f mcp")
print()
print("2. Configure in Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):")
print(' {')
print(' "mcpServers": {')
print(' "gpt4free": {')
print(' "command": "python",')
print(' "args": ["-m", "g4f.mcp"]')
print(' }')
print(' }')
print(' }')
print()
print("3. Or test via stdin/stdout:")
print(' $ echo \'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}\' | python -m g4f.mcp')
print()
print("The server will:")
print(" • Read JSON-RPC requests from stdin (one per line)")
print(" • Process the request and execute tools if needed")
print(" • Write JSON-RPC responses to stdout (one per line)")
print(" • Write debug/error messages to stderr")
print()
if __name__ == "__main__":
try:
asyncio.run(simulate_mcp_client())
except KeyboardInterrupt:
print("\n\nTest interrupted by user.")
sys.exit(0)

View file

@ -0,0 +1,103 @@
#!/usr/bin/env python
"""Test script for MCP server
This script tests the MCP server by simulating client interactions.
It sends JSON-RPC requests and verifies responses.
"""
import json
import sys
import asyncio
from g4f.mcp.server import MCPServer, MCPRequest
async def test_mcp_server():
"""Test MCP server functionality"""
server = MCPServer()
print("Testing MCP Server...")
print("=" * 60)
# Test 1: Initialize
print("\n1. Testing initialize request...")
init_request = MCPRequest(
jsonrpc="2.0",
id=1,
method="initialize",
params={}
)
response = await server.handle_request(init_request)
print(f" Response ID: {response.id}")
print(f" Protocol Version: {response.result['protocolVersion']}")
print(f" Server Name: {response.result['serverInfo']['name']}")
print(" ✓ Initialize test passed")
# Test 2: List tools
print("\n2. Testing tools/list request...")
list_request = MCPRequest(
jsonrpc="2.0",
id=2,
method="tools/list",
params={}
)
response = await server.handle_request(list_request)
print(f" Number of tools: {len(response.result['tools'])}")
for tool in response.result['tools']:
print(f" - {tool['name']}: {tool['description'][:50]}...")
print(" ✓ Tools list test passed")
# Test 3: Ping
print("\n3. Testing ping request...")
ping_request = MCPRequest(
jsonrpc="2.0",
id=3,
method="ping",
params={}
)
response = await server.handle_request(ping_request)
print(f" Response ID: {response.id}")
print(" ✓ Ping test passed")
# Test 4: Invalid method
print("\n4. Testing invalid method request...")
invalid_request = MCPRequest(
jsonrpc="2.0",
id=4,
method="invalid_method",
params={}
)
response = await server.handle_request(invalid_request)
if response.error:
print(f" Error code: {response.error['code']}")
print(f" Error message: {response.error['message']}")
print(" ✓ Invalid method test passed")
# Test 5: Tool schemas
print("\n5. Testing tool input schemas...")
list_request = MCPRequest(
jsonrpc="2.0",
id=5,
method="tools/list",
params={}
)
response = await server.handle_request(list_request)
for tool in response.result['tools']:
print(f" Tool: {tool['name']}")
schema = tool['inputSchema']
required = schema.get('required', [])
properties = schema.get('properties', {})
print(f" Required params: {', '.join(required)}")
print(f" All params: {', '.join(properties.keys())}")
print(" ✓ Tool schemas test passed")
print("\n" + "=" * 60)
print("All tests passed! ✓")
print("\nMCP server is working correctly.")
print("\nTo use the server, run:")
print(" python -m g4f.mcp")
print(" or")
print(" g4f mcp")
if __name__ == "__main__":
asyncio.run(test_mcp_server())