search_local_indicators
Search locally cached World Bank indicator metadata to discover available economic and social data types before API queries, providing instant results without network calls.
Instructions
Search through local metadata for World Bank indicators (instant, offline).
This is a FAST alternative to search_datasets that searches through locally cached
metadata. Use this to discover what types of data are available before using the
API search.
How it works:
- Searches indicator names, codes, and descriptions
- Instant results (no API call)
- Returns relevance-ranked matches
Search tips:
- Use simple keywords: "unemployment", "poverty", "co2", "water"
- Search works on indicator names AND descriptions
- Case-insensitive
- More specific queries = better results
Example queries:
- "unemployment" → finds all unemployment-related indicators
- "mortality infant" → finds infant mortality indicators
- "internet" → finds internet usage indicators
- "renewable energy" → finds renewable energy indicators
Parameters:
- query: Search term (e.g., "unemployment", "gdp growth", "water access")
- limit: Maximum number of results to return (default: 20)
Returns: List of matching indicators with codes, names, descriptions, and relevance scores.
Note: This returns indicator codes but NOT database IDs. After finding an indicator,
use search_datasets with the indicator name to get the database ID needed for data retrieval.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| limit | No |
Implementation Reference
- src/world_bank_mcp/server.py:580-615 (handler)The MCP tool handler for 'search_local_indicators'. Includes @server.tool() registration decorator, type-hinted parameters defining the input schema, comprehensive docstring, and delegates to the search_local_metadata helper for implementation.@server.tool() def search_local_indicators(query: str, limit: int = 20) -> dict[str, Any]: """Search through local metadata for World Bank indicators (instant, offline). This is a FAST alternative to search_datasets that searches through locally cached metadata. Use this to discover what types of data are available before using the API search. How it works: - Searches indicator names, codes, and descriptions - Instant results (no API call) - Returns relevance-ranked matches Search tips: - Use simple keywords: "unemployment", "poverty", "co2", "water" - Search works on indicator names AND descriptions - Case-insensitive - More specific queries = better results Example queries: - "unemployment" → finds all unemployment-related indicators - "mortality infant" → finds infant mortality indicators - "internet" → finds internet usage indicators - "renewable energy" → finds renewable energy indicators Parameters: - query: Search term (e.g., "unemployment", "gdp growth", "water access") - limit: Maximum number of results to return (default: 20) Returns: List of matching indicators with codes, names, descriptions, and relevance scores. Note: This returns indicator codes but NOT database IDs. After finding an indicator, use search_datasets with the indicator name to get the database ID needed for data retrieval. """ return search_local_metadata(query, limit)
- src/world_bank_mcp/server.py:293-354 (helper)Core helper function implementing the search logic: loads local metadata, performs fuzzy search on indicator name/code/description with relevance scoring, sorts and limits results, formats output.def search_local_metadata(query: str, limit: int = 20) -> dict[str, Any]: """Search through local metadata (fast, offline)""" indicators = load_metadata() if not indicators: return { "success": False, "error": "Metadata file not found. Please ensure metadata_indicators.json exists." } query_lower = query.lower() results = [] # Search through indicators for indicator in indicators: name_lower = indicator["name"].lower() desc_lower = indicator["description"].lower() code_lower = indicator["code"].lower() # Calculate relevance score score = 0 # Exact match in code (highest priority) if query_lower == code_lower: score = 100 # Contains in code elif query_lower in code_lower: score = 90 # Exact word match in name elif query_lower in name_lower.split(): score = 80 # Contains in name (high priority) elif query_lower in name_lower: score = 70 # Contains in description (lower priority) elif query_lower in desc_lower: score = 40 else: continue results.append({ "indicator": indicator["code"], "name": indicator["name"], "description": indicator["description"][:200] + "..." if len(indicator["description"]) > 200 else indicator["description"], "source": indicator["source"][:100] + "..." if len(indicator["source"]) > 100 else indicator["source"], "relevance_score": score }) # Sort by relevance score results.sort(key=lambda x: x["relevance_score"], reverse=True) # Limit results results = results[:limit] return { "success": True, "query": query, "total_matches": len(results), "results": results, "note": "Local search - instant results from cached metadata" }