We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Rudra-ravi/wikipedia-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""
Tests for Google ADK compatibility - ensuring tool schemas don't use anyOf alongside other fields.
"""
import pytest
import asyncio
import json
from wikipedia_mcp.server import create_server
from tests.tool_helpers import get_tool, get_tools
class TestGoogleADKCompatibility:
"""Test that all tools generate Google ADK compatible schemas."""
@pytest.mark.asyncio
async def test_all_tools_schemas_compatible(self):
"""Test that all tool schemas are compatible with Google ADK agents."""
server = create_server()
tools = await get_tools(server)
# Tools that previously had anyOf issues
problematic_tools = [
"summarize_article_for_query",
"summarize_article_section",
"extract_key_facts",
]
for expected_tool in problematic_tools:
assert expected_tool in tools, f"Expected tool '{expected_tool}' to be registered"
for tool_name in tools:
tool_obj = await get_tool(server, tool_name)
schema = tool_obj.parameters
# Check each parameter for anyOf usage
for param_name, param_schema in schema.get("properties", {}).items():
assert (
"anyOf" not in param_schema
), f"Tool '{tool_name}' parameter '{param_name}' uses anyOf which is incompatible with Google ADK"
# Verify that if a default is provided, the schema is simple
if "default" in param_schema:
# Should only have: type, default, title (and optionally description)
allowed_keys = {"type", "default", "title", "description"}
actual_keys = set(param_schema.keys())
unexpected_keys = actual_keys - allowed_keys
assert (
not unexpected_keys
), f"Tool '{tool_name}' parameter '{param_name}' has unexpected keys: {unexpected_keys}"
@pytest.mark.asyncio
async def test_all_tools_have_readonly_annotations(self):
"""All tools should include MCP behavior annotations for clients."""
server = create_server()
tools = await get_tools(server)
for tool_name in tools:
tool_obj = await get_tool(server, tool_name)
annotations = tool_obj.annotations
assert annotations is not None, f"Tool '{tool_name}' must define annotations"
assert annotations.readOnlyHint is True
assert annotations.idempotentHint is True
assert annotations.openWorldHint is True
assert annotations.destructiveHint is False
@pytest.mark.asyncio
async def test_all_canonical_tools_have_wikipedia_aliases(self):
"""Each canonical tool should expose a wikipedia_* alias."""
server = create_server()
tools = await get_tools(server)
canonical_tools = [
"search_wikipedia",
"test_wikipedia_connectivity",
"get_article",
"get_summary",
"summarize_article_for_query",
"summarize_article_section",
"extract_key_facts",
"get_related_topics",
"get_sections",
"get_links",
"get_coordinates",
]
for tool_name in canonical_tools:
assert tool_name in tools
assert f"wikipedia_{tool_name}" in tools
@pytest.mark.asyncio
async def test_all_tools_have_object_output_schema(self):
"""Output schemas should be explicit object schemas."""
server = create_server()
tools = await get_tools(server)
for tool_name in tools:
tool_obj = await get_tool(server, tool_name)
assert isinstance(tool_obj.output_schema, dict)
assert tool_obj.output_schema.get("type") == "object"
@pytest.mark.asyncio
async def test_summarize_article_for_query_schema(self):
"""Test specific schema for summarize_article_for_query tool."""
server = create_server()
tool_obj = await get_tool(server, "summarize_article_for_query")
schema = tool_obj.parameters
# Check max_length parameter specifically
max_length_param = schema["properties"]["max_length"]
assert max_length_param["type"] == "integer"
assert max_length_param["default"] == 250
assert "anyOf" not in max_length_param
if "title" in max_length_param:
assert max_length_param["title"] == "Max Length"
# Check required parameters
assert set(schema["required"]) == {"title", "query"}
@pytest.mark.asyncio
async def test_summarize_article_section_schema(self):
"""Test specific schema for summarize_article_section tool."""
server = create_server()
tool_obj = await get_tool(server, "summarize_article_section")
schema = tool_obj.parameters
# Check max_length parameter specifically
max_length_param = schema["properties"]["max_length"]
assert max_length_param["type"] == "integer"
assert max_length_param["default"] == 150
assert "anyOf" not in max_length_param
if "title" in max_length_param:
assert max_length_param["title"] == "Max Length"
# Check required parameters
assert set(schema["required"]) == {"title", "section_title"}
@pytest.mark.asyncio
async def test_extract_key_facts_schema(self):
"""Test specific schema for extract_key_facts tool."""
server = create_server()
tool_obj = await get_tool(server, "extract_key_facts")
schema = tool_obj.parameters
# Check topic_within_article parameter specifically
topic_param = schema["properties"]["topic_within_article"]
assert topic_param["type"] == "string"
assert topic_param["default"] == ""
assert "anyOf" not in topic_param
if "title" in topic_param:
assert topic_param["title"] == "Topic Within Article"
# Check count parameter
count_param = schema["properties"]["count"]
assert count_param["type"] == "integer"
assert count_param["default"] == 5
# Check required parameters
assert set(schema["required"]) == {"title"}
def test_empty_string_to_none_conversion(self):
"""Test the conversion logic for empty string to None."""
# This tests the logic used in extract_key_facts tool
def convert_topic(topic_within_article: str):
return topic_within_article if topic_within_article.strip() else None
# Test cases
assert convert_topic("") is None
assert convert_topic(" ") is None # whitespace only
assert convert_topic("general") == "general"
assert convert_topic("history") == "history"
assert convert_topic(" history ") == " history " # preserve as-is
@pytest.mark.asyncio
async def test_tool_compatibility_json_serialization(self):
"""Test that all tool schemas can be properly JSON serialized for Google ADK."""
server = create_server()
tools = await get_tools(server)
for tool_name in tools:
tool_obj = await get_tool(server, tool_name)
schema = tool_obj.parameters
# Should be able to serialize to JSON without issues
json_str = json.dumps(schema)
# Should be able to deserialize back
parsed_schema = json.loads(json_str)
assert parsed_schema == schema
# Ensure no complex nested anyOf structures
def check_no_anyof_recursively(obj):
if isinstance(obj, dict):
for key, value in obj.items():
if key == "anyOf":
# If anyOf exists, it should be the only schema key
schema_keys = set(obj.keys()) - {
"title",
"description",
"default",
}
if len(schema_keys) > 1:
return False
if not check_no_anyof_recursively(value):
return False
elif isinstance(obj, list):
for item in obj:
if not check_no_anyof_recursively(item):
return False
return True
assert check_no_anyof_recursively(
schema
), f"Tool '{tool_name}' has complex anyOf structure incompatible with Google ADK"