Skip to main content
Glama

Graphistry MCP

Official
by graphistry
test_server.py16.4 kB
""" Tests for the Graphistry MCP server. """ import json import os from typing import Dict, Any import pytest import graphistry from dotenv import load_dotenv from graphistry_mcp_server.server import mcp # Load environment variables from .env file load_dotenv() # Set up test environment password = os.getenv("GRAPHISTRY_PASSWORD") username = os.getenv("GRAPHISTRY_USERNAME") if not password or not username: raise ValueError("GRAPHISTRY_PASSWORD and GRAPHISTRY_USERNAME must be set in .env file") print(f"\nInitializing Graphistry with username: {username}") graphistry.register(api=3, protocol="https", server="hub.graphistry.com", username=username, password=password) def parse_mcp_response(response: Any) -> Dict[str, Any]: """Parse MCP response into a dictionary.""" if isinstance(response, list) and len(response) > 0: content = response[0] if hasattr(content, 'text'): return json.loads(content.text) return response @pytest.mark.asyncio async def test_list_tools() -> None: """Test that list_tools returns a list of valid tool definitions.""" print("\nTesting list_tools...") tools = await mcp.list_tools() print(f"Found {len(tools)} tools") assert isinstance(tools, list) assert len(tools) > 0 # Check that each tool has the required structure for tool in tools: print(f"Checking tool: {tool.name}") assert hasattr(tool, 'name') assert hasattr(tool, 'description') assert hasattr(tool, 'inputSchema') print("✓ list_tools test passed") @pytest.mark.asyncio async def test_visualize_graph() -> None: """Test that the visualize_graph tool works with basic parameters.""" print("\nTesting visualize_graph...") # Create a simple test graph test_params = { "data_format": "edge_list", "edges": [ {"source": "A", "target": "B"}, {"source": "B", "target": "C"}, {"source": "C", "target": "A"} ], "title": "Test Triangle Graph" } print(f"Creating graph with params: {test_params}") result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) result_dict = parse_mcp_response(result) print(f"Got result: {result_dict}") assert isinstance(result_dict, dict) assert "graph_id" in result_dict assert "title" in result_dict assert "url" in result_dict print("✓ visualize_graph test passed") @pytest.mark.asyncio async def test_get_graph_info() -> None: """Test that get_graph_info returns valid information about a graph.""" print("\nTesting get_graph_info...") # First create a graph test_params = { "data_format": "edge_list", "edges": [ {"source": "A", "target": "B"}, {"source": "B", "target": "C"} ] } print("Creating test graph...") graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_result_dict = parse_mcp_response(graph_result) graph_id = graph_result_dict["graph_id"] print(f"Created graph with ID: {graph_id}") assert graph_id is not None # Now get info about the graph print("Getting graph info...") info_result = await mcp.call_tool("get_graph_info", {"graph_id": graph_id}) info_result_dict = parse_mcp_response(info_result) print(f"Got graph info: {info_result_dict}") assert isinstance(info_result_dict, dict) assert "node_count" in info_result_dict assert "edge_count" in info_result_dict assert info_result_dict["edge_count"] == 2 print("✓ get_graph_info test passed") @pytest.mark.asyncio async def test_apply_layout() -> None: """Test that apply_layout successfully changes the graph layout.""" print("\nTesting apply_layout...") # First create a graph test_params = { "data_format": "edge_list", "edges": [ {"source": "A", "target": "B"}, {"source": "B", "target": "C"}, {"source": "C", "target": "D"} ] } print("Creating test graph...") graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_result_dict = parse_mcp_response(graph_result) graph_id = graph_result_dict["graph_id"] print(f"Created graph with ID: {graph_id}") assert graph_id is not None # Now apply a layout print("Applying force-directed layout...") layout_result = await mcp.call_tool("apply_layout", { "graph_id": graph_id, "layout": "force_directed" }) layout_result_dict = parse_mcp_response(layout_result) print(f"Got layout result: {layout_result_dict}") assert isinstance(layout_result_dict, dict) assert "graph_id" in layout_result_dict assert "url" in layout_result_dict print("✓ apply_layout test passed") @pytest.mark.asyncio async def test_detect_patterns() -> None: """Test that detect_patterns can analyze graph patterns.""" print("\nTesting detect_patterns...") # First create a graph test_params = { "data_format": "edge_list", "edges": [ {"source": "A", "target": "B"}, {"source": "B", "target": "C"}, {"source": "C", "target": "A"}, {"source": "D", "target": "E"} ] } print("Creating test graph...") graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_result_dict = parse_mcp_response(graph_result) graph_id = graph_result_dict["graph_id"] print(f"Created graph with ID: {graph_id}") assert graph_id is not None # Now detect patterns print("Running centrality analysis...") pattern_result = await mcp.call_tool("detect_patterns", { "graph_id": graph_id, "analysis_type": "centrality" }) pattern_result_dict = parse_mcp_response(pattern_result) print(f"Got pattern analysis results: {pattern_result_dict}") assert isinstance(pattern_result_dict, dict) assert "degree_centrality" in pattern_result_dict assert "betweenness_centrality" in pattern_result_dict assert "closeness_centrality" in pattern_result_dict print("✓ detect_patterns test passed") @pytest.mark.asyncio async def test_encode_point_color() -> None: print("\nTesting encode_point_color...") test_params = { "edges": [ {"source": "A", "target": "B", "type": "mac"}, {"source": "B", "target": "C", "type": "macbook"} ], "title": "Color Test Graph" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] color_result = await mcp.call_tool("encode_point_color", { "graph_id": graph_id, "column": "type", "categorical_mapping": {"mac": "#F99", "macbook": "#99F"}, "default_mapping": "silver" }) color_dict = parse_mcp_response(color_result) print(f"encode_point_color result: {color_dict}") assert "graph_id" in color_dict and "url" in color_dict @pytest.mark.asyncio async def test_encode_point_size() -> None: print("\nTesting encode_point_size...") test_params = { "edges": [ {"source": "A", "target": "B", "score": 10}, {"source": "B", "target": "C", "score": 20} ], "title": "Size Test Graph" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] size_result = await mcp.call_tool("encode_point_size", { "graph_id": graph_id, "column": "score" }) size_dict = parse_mcp_response(size_result) print(f"encode_point_size result: {size_dict}") assert "graph_id" in size_dict and "url" in size_dict @pytest.mark.asyncio async def test_encode_point_icon() -> None: print("\nTesting encode_point_icon...") test_params = { "edges": [ {"source": "A", "target": "B", "type": "macbook"}, {"source": "B", "target": "C", "type": "mac"} ], "title": "Icon Test Graph" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] icon_result = await mcp.call_tool("encode_point_icon", { "graph_id": graph_id, "column": "type", "categorical_mapping": {"macbook": "laptop", "mac": "desktop"}, "default_mapping": "question" }) icon_dict = parse_mcp_response(icon_result) print(f"encode_point_icon result: {icon_dict}") assert "graph_id" in icon_dict and "url" in icon_dict @pytest.mark.asyncio async def test_encode_point_badge() -> None: print("\nTesting encode_point_badge...") test_params = { "edges": [ {"source": "A", "target": "B", "type": "macbook"}, {"source": "B", "target": "C", "type": "mac"} ], "title": "Badge Test Graph" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] badge_result = await mcp.call_tool("encode_point_badge", { "graph_id": graph_id, "column": "type", "position": "TopRight", "categorical_mapping": {"macbook": "laptop", "mac": "desktop"}, "default_mapping": "question" }) badge_dict = parse_mcp_response(badge_result) print(f"encode_point_badge result: {badge_dict}") assert "graph_id" in badge_dict and "url" in badge_dict @pytest.mark.asyncio async def test_apply_ring_categorical_layout() -> None: print("\nTesting apply_ring_categorical_layout...") # Graphistry expects the ring column ('group') to be present in the nodes table for ring_categorical_layout test_params = { "edges": [ {"source": "A", "target": "B", "group": "g1"}, {"source": "B", "target": "C", "group": "g2"} ], "nodes": [ {"id": "A", "group": "g1"}, {"id": "B", "group": "g2"}, {"id": "C", "group": "g2"} ], "node_id": "id", "title": "Ring Cat Layout Test" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] layout_result = await mcp.call_tool("apply_ring_categorical_layout", { "graph_id": graph_id, "ring_col": "group" }) layout_dict = parse_mcp_response(layout_result) print(f"apply_ring_categorical_layout result: {layout_dict}") assert "graph_id" in layout_dict and "url" in layout_dict @pytest.mark.asyncio async def test_apply_group_in_a_box_layout() -> None: print("\nTesting apply_group_in_a_box_layout...") test_params = { "edges": [ {"source": "A", "target": "B"}, {"source": "B", "target": "C"} ], "nodes": [ {"id": "A"}, {"id": "B"}, {"id": "C"} ], "node_id": "id", "title": "Group in a Box Test" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] layout_result = await mcp.call_tool("apply_group_in_a_box_layout", { "graph_id": graph_id }) layout_dict = parse_mcp_response(layout_result) print(f"apply_group_in_a_box_layout result: {layout_dict}") assert "graph_id" in layout_dict and "url" in layout_dict @pytest.mark.asyncio async def test_apply_modularity_weighted_layout() -> None: print("\nTesting apply_modularity_weighted_layout...") test_params = { "edges": [ {"source": "A", "target": "B"}, {"source": "B", "target": "C"} ], "nodes": [ {"id": "A"}, {"id": "B"}, {"id": "C"} ], "node_id": "id", "title": "Modularity Weighted Layout Test" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] layout_result = await mcp.call_tool("apply_modularity_weighted_layout", { "graph_id": graph_id }) layout_dict = parse_mcp_response(layout_result) print(f"apply_modularity_weighted_layout result: {layout_dict}") assert "graph_id" in layout_dict and "url" in layout_dict @pytest.mark.asyncio async def test_apply_ring_continuous_layout() -> None: print("\nTesting apply_ring_continuous_layout...") # Graphistry expects the ring column ('score') to be present in the nodes table for ring_continuous_layout test_params = { "edges": [ {"source": "A", "target": "B", "score": 1.0}, {"source": "B", "target": "C", "score": 2.0} ], "nodes": [ {"id": "A", "score": 1.0}, {"id": "B", "score": 2.0}, {"id": "C", "score": 2.0} ], "node_id": "id", "title": "Ring Continuous Layout Test" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] layout_result = await mcp.call_tool("apply_ring_continuous_layout", { "graph_id": graph_id, "ring_col": "score" }) layout_dict = parse_mcp_response(layout_result) print(f"apply_ring_continuous_layout result: {layout_dict}") assert "graph_id" in layout_dict and "url" in layout_dict @pytest.mark.asyncio async def test_apply_time_ring_layout() -> None: print("\nTesting apply_time_ring_layout...") # Graphistry expects the time column ('created_at') to be present in the nodes table for time_ring_layout test_params = { "edges": [ {"source": "A", "target": "B", "created_at": "2024-01-01T00:00:00"}, {"source": "B", "target": "C", "created_at": "2024-01-02T00:00:00"} ], "nodes": [ {"id": "A", "created_at": "2024-01-01T00:00:00"}, {"id": "B", "created_at": "2024-01-02T00:00:00"}, {"id": "C", "created_at": "2024-01-02T00:00:00"} ], "node_id": "id", "title": "Time Ring Layout Test" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] layout_result = await mcp.call_tool("apply_time_ring_layout", { "graph_id": graph_id, "time_col": "created_at" }) layout_dict = parse_mcp_response(layout_result) print(f"apply_time_ring_layout result: {layout_dict}") assert "graph_id" in layout_dict and "url" in layout_dict @pytest.mark.asyncio async def test_apply_tree_layout() -> None: print("\nTesting apply_tree_layout...") test_params = { "edges": [ {"source": "A", "target": "B"}, {"source": "B", "target": "C"} ], "nodes": [ {"id": "A"}, {"id": "B"}, {"id": "C"} ], "node_id": "id", "title": "Tree Layout Test" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] layout_result = await mcp.call_tool("apply_tree_layout", { "graph_id": graph_id }) layout_dict = parse_mcp_response(layout_result) print(f"apply_tree_layout result: {layout_dict}") assert "graph_id" in layout_dict and "url" in layout_dict @pytest.mark.asyncio async def test_set_graph_settings() -> None: print("\nTesting set_graph_settings...") test_params = { "edges": [ {"source": "A", "target": "B"}, {"source": "B", "target": "C"} ], "nodes": [ {"id": "A"}, {"id": "B"}, {"id": "C"} ], "node_id": "id", "title": "Settings Test Graph" } graph_result = await mcp.call_tool("visualize_graph", {"graph_data": test_params}) graph_id = parse_mcp_response(graph_result)["graph_id"] settings_result = await mcp.call_tool("set_graph_settings", { "graph_id": graph_id, "url_params": {"pointSize": 0.5, "play": 0} }) settings_dict = parse_mcp_response(settings_result) print(f"set_graph_settings result: {settings_dict}") assert "graph_id" in settings_dict and "url" in settings_dict

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/graphistry/graphistry-mcp'

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