Skip to main content
Glama
Azhar-obenan

Obenan MCP Server

by Azhar-obenan

search_locations_by_name

Find locations by name to retrieve detailed information for selection and further use.

Instructions

Search for locations containing a specific name and allow selection to get details

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
search_termYesTerm to search for in location names
access_tokenNoAccess token for Obenan API. Optional if OBENAN_LOGIN_ACCESS_TOKEN environment variable is set.

Implementation Reference

  • Implementation of the search_locations_by_name tool handler which fetches locations from the Obenan API and filters them by a search term, optionally displaying details if only one result is found.
    async def handle_search_locations_by_name(
        arguments: dict[str, Any] | None
    ) -> list[types.TextContent]:
        # Get search term from arguments
        search_term = arguments.get("search_term")
        if not search_term:
            return [types.TextContent(
                type="text", 
                text="❌ Error: Search term is required to search for locations"
            )]
        
        # Get token from environment variable or from arguments
        access_token = os.environ.get("OBENAN_LOGIN_ACCESS_TOKEN")
        if not access_token:
            return [types.TextContent(
                type="text", 
                text="❌ Error: Access token is required. Either provide it as an argument or set the OBENAN_LOGIN_ACCESS_TOKEN environment variable."
            )]
        
        try:
            # First fetch all locations
            url = "https://stagingapi.obenan.com/api/v1/location/search?isLocationPage=false&isListingPage=true"
            headers = {"Authorization": f"Bearer {access_token}"}
            
            response = requests.get(url, headers=headers)
            
            if response.status_code == 200:
                data = response.json()
                
                # Format the response for better readability
                formatted_response = f"πŸ” Searching for locations containing: '{search_term}'\n\n"
                
                # Extract and filter locations
                matching_locations = []
                
                if data and isinstance(data, dict) and "data" in data:
                    if isinstance(data["data"], dict) and "results" in data["data"]:
                        locations = data["data"]["results"]
                        
                        if locations and isinstance(locations, list):
                            # Filter locations by search term
                            for loc in locations:
                                name = loc.get("name", "")
                                if search_term.lower() in name.lower():
                                    matching_locations.append(loc)
                
                # Display matching locations
                if matching_locations:
                    formatted_response += f"Found {len(matching_locations)} matching location(s):\n\n"
                    
                    for i, loc in enumerate(matching_locations):
                        name = loc.get("name", "Unknown")
                        location_id = loc.get("id", "Unknown")
                        formatted_response += f"{i+1}. {name} (ID: {location_id})\n"
                    
                    # Add instructions for getting details
                    formatted_response += "\nπŸ“‹ To get details for a specific location, use the get_location_details tool with the location ID.\n"
                    formatted_response += "Example: get_location_details({\"location_id\": \"[ID_FROM_ABOVE]\"})"
                    
                    # If there's only one result, automatically show details
                    if len(matching_locations) == 1:
                        location_id = matching_locations[0].get("id")
                        formatted_response += f"\n\nAutomatically fetching details for the only match: {matching_locations[0].get('name')}\n"
                        formatted_response += "==============================================\n\n"
                        
                        # Get location details
                        detail_url = f"https://stagingapi.obenan.com/api/v1/location/{location_id}"
                        detail_headers = {
                            "Authorization": f"Bearer {access_token}",
                            "Origin": "https://stagingapp.obenan.com"
                        }
                        
                        detail_response = requests.get(detail_url, headers=detail_headers)
                        
                        if detail_response.status_code == 200:
                            detail_data = detail_response.json()
                            
                            # Format the details
                            if detail_data and isinstance(detail_data, dict) and "data" in detail_data:
                                # Check if data.data is a dict with location fields or if it has a nested 'result' field
                                location_data = detail_data["data"]
                                
                                # If location_data has a 'result' field, use that instead
                                if isinstance(location_data, dict) and "result" in location_data:
                                    location_data = location_data["result"]
                                
                                # Basic information
                                name = location_data.get("name", "Unknown")
                                formatted_response += f"Name: {name}\n"
                                internal_name = location_data.get("internalName", "Unknown")
                                formatted_response += f"Internal Name: {internal_name}\n"
                                
                                # Address information
                                address_line1 = location_data.get("addressLine1", "")
                                address_line2 = location_data.get("addressLine2", "")
                                city = location_data.get("city", "")
                                postal_code = location_data.get("postalCode", "")
                                country_code = location_data.get("countryCode", "")
                                
                                address_parts = []
                                if address_line1:
                                    address_parts.append(address_line1)
                                if address_line2 and address_line2 != "null":
                                    address_parts.append(address_line2)
                                if city:
                                    address_parts.append(city)
                                if postal_code:
                                    address_parts.append(postal_code)
                                if country_code:
                                    address_parts.append(country_code)
                                
                                address_str = ", ".join(filter(None, address_parts))
                                formatted_response += f"Address: {address_str}\n"
                                
                                # Contact information
                                formatted_response += f"Phone: {location_data.get('telephone', 'N/A')}\n"
                                formatted_response += f"Email: {location_data.get('businessEmail', 'N/A')}\n"
                                formatted_response += f"Website: {location_data.get('website', 'N/A')}\n\n"
                        else:
                            formatted_response += f"\nCould not fetch details automatically: HTTP {detail_response.status_code}\n"
                else:
                    formatted_response += f"No locations found matching '{search_term}'.\n"
                
                return [types.TextContent(type="text", text=formatted_response)]
                
            else:
                error_msg = f"❌ Failed to search locations: HTTP {response.status_code}\n{response.text[:500]}"
                return [types.TextContent(type="text", text=error_msg)]
                
        except Exception as e:
            error_trace = traceback.format_exc()
            return [types.TextContent(
                type="text",
                text=f"🚨 Error searching locations: {str(e)}\n\n{error_trace[:500]}"
            )]
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure but fails to specify what the tool returns (list of locations? IDs only? how many results?), pagination behavior, search matching logic (partial, case-sensitive), or rate limits. The 'allow selection' phrase suggests interactive behavior but doesn't clarify the actual API mechanics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is brief (11 words) and front-loads the primary action, but the second clause 'and allow selection to get details' is structurally awkward and semantically vague. It attempts to pack workflow guidance into a single sentence, resulting in confusing phrasing that could be interpreted as the tool having interactive UI capabilities.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter search tool without output schema, the description covers the minimum viable use case but leaves significant gaps. It doesn't describe the return format (critical since no output schema exists), result limits, or the relationship to fetch_my_locations. Adequate but clearly incomplete given the lack of structured metadata.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the schema adequately documents both search_term and access_token without requiring additional description text. The description mentions no parameters explicitly, but the schema compensates fully, meeting the baseline expectation for this dimension.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the core action ('Search for locations') and filtering criteria ('containing a specific name'). However, the phrase 'allow selection to get details' is ambiguousβ€”it's unclear if the tool performs selection or merely returns candidates for selection via the sibling get_location_details tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies a workflow (search β†’ get details) but doesn't explicitly state when to use this tool versus fetch_my_locations. It hints at using results with get_location_details via 'allow selection to get details,' but lacks explicit 'when to use/when not to use' guidance or clear differentiation from the sibling that fetches 'my locations'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/Azhar-obenan/review-analyzer-mcp-server'

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