Skip to main content
Glama

Oxylabs MCP Server

Official
by oxylabs
import json import os from contextlib import asynccontextmanager import pytest from agno.agent import Agent from agno.models.google import Gemini from agno.models.openai import OpenAIChat from agno.tools.mcp import MCPTools MCP_SERVER = "local" # local, uvx MODELS_CONFIG = [ ("GOOGLE_API_KEY", "gemini"), # ("OPENAI_API_KEY", "openai"), ] def get_agent(model: str, oxylabs_mcp: MCPTools) -> Agent: if model == "gemini": model_ = Gemini(api_key=os.getenv("GOOGLE_API_KEY")) elif model == "openai": model_ = OpenAIChat(api_key=os.getenv("OPENAI_API_KEY")) else: raise ValueError(f"Unknown model: {model}") return Agent( model=model_, tools=[oxylabs_mcp], instructions=["Use MCP tools to fulfil the requests"], markdown=True, ) def get_models() -> list[str]: models = [] for env_var, model_name in MODELS_CONFIG: if os.getenv(env_var): models.append(model_name) return models @asynccontextmanager async def oxylabs_mcp_server(): if MCP_SERVER == "local": command = f"uv run --directory {os.getenv('LOCAL_OXYLABS_MCP_DIRECTORY')} oxylabs-mcp" elif MCP_SERVER == "uvx": command = "uvx oxylabs-mcp" else: raise ValueError(f"Unknown mcp server option: {MCP_SERVER}") async with MCPTools( command, env={ "OXYLABS_USERNAME": os.getenv("OXYLABS_USERNAME"), "OXYLABS_PASSWORD": os.getenv("OXYLABS_PASSWORD"), }, ) as mcp_server: yield mcp_server @pytest.mark.skipif(not os.getenv("OXYLABS_USERNAME"), reason="`OXYLABS_USERNAME` is not set") @pytest.mark.skipif(not os.getenv("OXYLABS_PASSWORD"), reason="`OXYLABS_PASSWORD` is not set") @pytest.mark.asyncio @pytest.mark.parametrize("model", get_models()) @pytest.mark.parametrize( ("query", "tool", "arguments", "expected_content"), [ ( "Search for iPhone 16 in google with parsed result", "google_search_scraper", { "query": "iPhone 16", "parse": True, }, "iPhone 16", ), ( "Search for iPhone 16 in google with render html", "google_search_scraper", { "query": "iPhone 16", "render": "html", }, "iPhone 16", ), ( "Search for iPhone 16 in google with browser rendering", "google_search_scraper", { "query": "iPhone 16", "render": "html", }, "iPhone 16", ), ( "Search for iPhone 16 in google with user agent type mobile", "google_search_scraper", { "query": "iPhone 16", "user_agent_type": "mobile", }, "iPhone 16", ), ( "Search for iPhone 16 in google starting from the second page", "google_search_scraper", { "query": "iPhone 16", "start_page": 2, }, "iPhone 16", ), ( "Search for iPhone 16 in google with United Kingdom domain", "google_search_scraper", { "query": "iPhone 16", "domain": "co.uk", }, "iPhone 16", ), ( "Search for iPhone 16 in google with Brazil geolocation", "google_search_scraper", { "query": "iPhone 16", "geo_location": "BR", }, "iPhone 16", ), ( "Search for iPhone 16 in google with French locale", "google_search_scraper", { "query": "iPhone 16", "locale": "fr-FR", }, "iPhone 16", ), ], ) async def test_basic_agent_prompts( model: str, query: str, tool: str, arguments: dict, expected_content: str, ): async with oxylabs_mcp_server() as mcp_server: agent = get_agent(model, mcp_server) response = await agent.arun(query) tool_calls = agent.memory.get_tool_calls(agent.session_id) # [tool_call, tool_call_result] assert len(tool_calls) == 2, "Extra tool calls found!" assert tool_calls[0]["function"]["name"] == tool assert json.loads(tool_calls[0]["function"]["arguments"]) == arguments assert expected_content in response.content @pytest.mark.asyncio @pytest.mark.parametrize("model", get_models()) async def test_complex_agent_prompt(model: str): async with oxylabs_mcp_server() as mcp_server: agent = get_agent(model, mcp_server) await agent.arun( "Go to oxylabs.io, look for career page, " "go to it and return all job titles in markdown format. " "Don't invent URLs, start from one provided." ) tool_calls = agent.memory.get_tool_calls(agent.session_id) assert len(tool_calls) == 4, f"Not enough tool_calls, got {len(tool_calls)}: {tool_calls}" oxylabs_page_call, _, careers_page_call, _ = agent.memory.get_tool_calls(agent.session_id) assert oxylabs_page_call["function"]["name"] == "universal_scraper" assert json.loads(oxylabs_page_call["function"]["arguments"]) == { "output_format": "links", "url": "https://oxylabs.io", } assert careers_page_call["function"]["name"] == "universal_scraper" assert json.loads(careers_page_call["function"]["arguments"]) == { "output_format": "md", "url": "https://career.oxylabs.io/", }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oxylabs/oxylabs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server