Skip to main content
Glama

Smithsonian Open Access MCP Server

by molanojustin
MIT License
233
2
  • Apple
  • Linux
test_utils.py8.53 kB
""" Tests for the utils module. """ import logging from unittest.mock import MagicMock import pytest from smithsonian_mcp.utils import mask_api_key, resolve_museum_code def test_mask_api_key(): """Test that the API key is masked.""" params = {"api_key": "12345"} masked_params = mask_api_key(params) assert masked_params["api_key"] == "****" def test_mask_api_key_no_key(): """Test that the params are not changed if there is no API key.""" params = {"foo": "bar"} masked_params = mask_api_key(params) assert masked_params == params def test_resolve_museum_code_exact_match(): """Test exact matches from MUSEUM_MAP.""" assert resolve_museum_code("asian art") == "FSG" assert resolve_museum_code("american art") == "SAAM" assert resolve_museum_code("natural history") == "NMNH" def test_resolve_museum_code_case_insensitive(): """Test case insensitive matching.""" assert resolve_museum_code("ASIAN ART") == "FSG" assert resolve_museum_code("Asian Art") == "FSG" def test_resolve_museum_code_with_prefixes(): """Test matching with common prefixes removed.""" assert resolve_museum_code("Smithsonian Asian Art Museum") == "FSG" assert resolve_museum_code("National Museum of Natural History") == "NMNH" assert resolve_museum_code("Smithsonian American Art Museum") == "SAAM" def test_resolve_museum_code_partial_match(): """Test partial matching when input contains map key.""" assert resolve_museum_code("Asian Art Museum") == "FSG" assert resolve_museum_code("American Art Museum") == "SAAM" def test_resolve_museum_code_direct_codes(): """Test direct museum code matching.""" assert resolve_museum_code("SAAM") == "SAAM" assert resolve_museum_code("FSG") == "FSG" assert resolve_museum_code("NMNH") == "NMNH" def test_resolve_museum_code_word_overlap(): """Test word-based matching for significant overlap.""" assert resolve_museum_code("Hirshhorn Museum") == "HMSG" assert resolve_museum_code("Portrait Gallery") == "NPG" def test_resolve_museum_code_no_match(): """Test that invalid museum names return None.""" assert resolve_museum_code("Invalid Museum") is None assert resolve_museum_code("") is None assert resolve_museum_code(" ") is None def test_resolve_museum_code_edge_cases(): """Test edge cases and variations.""" # Should handle extra spaces assert resolve_museum_code(" asian art ") == "FSG" # Should handle museum name variations assert resolve_museum_code("Freer and Sackler") == "FSG" assert resolve_museum_code("Cooper Hewitt") == "CHNDM" def test_resolve_museum_code_expanded_map(): """Test the expanded MUSEUM_MAP with full museum names.""" # Full Smithsonian museum names assert resolve_museum_code("Smithsonian Asian Art Museum") == "FSG" assert resolve_museum_code("Smithsonian American Art Museum") == "SAAM" assert resolve_museum_code("Smithsonian Natural History Museum") == "NMNH" assert resolve_museum_code("National Museum of Asian Art") == "FSG" assert resolve_museum_code("Freer and Sackler Galleries") == "FSG" assert resolve_museum_code("Hirshhorn Museum and Sculpture Garden") == "HMSG" assert resolve_museum_code("National Museum of African American History and Culture") == "NMAAHC" @pytest.mark.asyncio async def test_construct_url_from_record_id(): """Test URL construction from record_id.""" from smithsonian_mcp.utils import construct_url_from_record_id from unittest.mock import patch, AsyncMock # Test with valid record_id - NMAH url = await construct_url_from_record_id("nmah_1448973") assert url == "https://americanhistory.si.edu/collections/object/nmah_1448973" # Test FSG (uses accession identifier) url = await construct_url_from_record_id("fsg_F1900.47") assert url == "https://asia.si.edu/object/F1900.47" # Test museums that construct URLs directly (record_ID and accession identifiers with plain base_url) test_cases = [ ("nmaahc_2022.91.10ab", "https://nmaahc.si.edu/object/nmaahc_2022.91.10ab"), ("nmnhmineralsciences_17183750", "https://naturalhistory.si.edu/object/nmnhmineralsciences_17183750"), ("nmnhpaleobiology_17134484", "https://naturalhistory.si.edu/object/nmnhpaleobiology_17134484"), ("nmnhanthropology_8352715", "https://naturalhistory.si.edu/object/nmnhanthropology_8352715"), ("nmnheducation_10841904", "https://naturalhistory.si.edu/object/nmnheducation_10841904"), ("nmnhinvertebratezoology_14688577", "https://naturalhistory.si.edu/object/nmnhinvertebratezoology_14688577"), ("npg_NPG.2002.184", "https://npg.si.edu/object/npg_NPG.2002.184"), ("npm_0.293996.232", "https://postalmuseum.si.edu/object/npm_0.293996.232"), ("siris_arc_403511", "https://siarchives.si.edu/collections/siris_arc_403511"), ] for record_id, expected_url in test_cases: url = await construct_url_from_record_id(record_id) assert url == expected_url, f"Failed for {record_id}: expected {expected_url}, got {url}" # Test museums that require API data (guid, record_link, url, idsId, or template variables in base_url) api_required_cases = [ "saam_30913", # uses {record_link} in base_url "nasm_nv913e903df", # uses {record_link} in base_url "hmsg_66.1608", # uses url identifier "nmafa_ys7a3f230ba", # uses {guid} in base_url "nmai_ws69d7d97b6", # uses {record_link} in base_url "acm_dl8b7ab6959", # uses {guid} in base_url "nzp_20190815_002RP", # uses idsId identifier "chndm_33665", # uses {record_link} in base_url "nmnhbirds_352f6df2a", # uses {guid} in base_url "nmnhbotany_32cbf4c79", # uses {guid} in base_url "nmnhento_339e344dc", # uses {guid} in base_url "nmnhfishes_3ccbe2c66", # uses {guid} in base_url "nmnhherps_359523727", # uses {guid} in base_url "nmnhmammals_30b523759", # uses {guid} in base_url ] # Mock the API fallback to return None with patch('smithsonian_mcp.utils._get_url_from_api_record_id', return_value=None): for record_id in api_required_cases: url = await construct_url_from_record_id(record_id) # With mocked API returning None, these should return None assert url is None, f"Expected None for API-required museum {record_id}, got {url}" # Test with invalid record_id (no underscore) url = await construct_url_from_record_id("invalid") assert url is None # Test with empty record_id url = await construct_url_from_record_id("") assert url is None # Test with None url = await construct_url_from_record_id(None) assert url is None # Test unknown museum (should fall back to API, mocked to return None) with patch('smithsonian_mcp.utils._get_url_from_api_record_id', return_value=None): url = await construct_url_from_record_id("unknown_123") assert url is None @pytest.mark.asyncio async def test_bert_puppet_parsing(): """Test parsing of bert puppet response to validate record_id extraction.""" import json from smithsonian_mcp.api_client import SmithsonianAPIClient from smithsonian_mcp.api_client import create_client # Load the bert puppet response with open("tests/bert_puppet_response.json", "r") as f: response_data = json.load(f) # Parse the object client = SmithsonianAPIClient() obj = client._parse_object_data(response_data["response"]) # Validate the parsed data assert obj.id == "ld1-1643398912743-1643398933001-0" assert obj.record_id == "nmah_1448973" assert obj.title == "Bert Puppet" assert obj.unit_code == "NMAH" # Test URL construction from record_id from smithsonian_mcp.utils import construct_url_from_record_id url = await construct_url_from_record_id(obj.record_id) assert url == "https://americanhistory.si.edu/collections/object/nmah_1448973" # Test museum website lookup client = await create_client() units = await client.get_units() nmah_unit = next((u for u in units if u.code == "NMAH"), None) assert nmah_unit is not None assert str(nmah_unit.website) == "https://americanhistory.si.edu/" await client.disconnect()

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/molanojustin/smithsonian-mcp'

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