Skip to main content
Glama

unified_search

Search across Microsoft 365 resources like messages, events, files, and sites using a single API query. Specify entity types or search all available data for comprehensive results.

Instructions

Search across multiple Microsoft 365 resources using the modern search API

entity_types can include: 'message', 'event', 'drive', 'driveItem', 'list', 'listItem', 'site'
If not specified, searches across all available types.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
account_idYes
entity_typesNo
limitNo
queryYes

Implementation Reference

  • The main handler function for the 'unified_search' tool. It accepts a query, account_id, optional entity_types and limit, calls graph.search_query, categorizes results by entity type (message, event, driveItem, other), and returns a dictionary of lists grouped by type.
    @mcp.tool
    def unified_search(
        query: str,
        account_id: str,
        entity_types: list[str] | None = None,
        limit: int = 50,
    ) -> dict[str, list[dict[str, Any]]]:
        """Search across multiple Microsoft 365 resources using the modern search API
    
        entity_types can include: 'message', 'event', 'drive', 'driveItem', 'list', 'listItem', 'site'
        If not specified, searches across all available types.
        """
        if not entity_types:
            entity_types = ["message", "event", "driveItem"]
    
        results = {entity_type: [] for entity_type in entity_types}
    
        items = list(graph.search_query(query, entity_types, account_id, limit))
    
        for item in items:
            resource_type = item.get("@odata.type", "").split(".")[-1]
    
            if resource_type == "message":
                results.setdefault("message", []).append(item)
            elif resource_type == "event":
                results.setdefault("event", []).append(item)
            elif resource_type in ["driveItem", "file", "folder"]:
                results.setdefault("driveItem", []).append(item)
            else:
                results.setdefault("other", []).append(item)
    
        return {k: v for k, v in results.items() if v}
  • Supporting utility function 'search_query' that implements the Microsoft Graph /search/query API call with pagination handling via 'from' parameter and yields search hit resources. Directly called by unified_search.
    def search_query(
        query: str,
        entity_types: list[str],
        account_id: str | None = None,
        limit: int = 50,
        fields: list[str] | None = None,
    ) -> Iterator[dict[str, Any]]:
        """Use the modern /search/query API endpoint"""
        payload = {
            "requests": [
                {
                    "entityTypes": entity_types,
                    "query": {"queryString": query},
                    "size": min(limit, 25),
                    "from": 0,
                }
            ]
        }
    
        if fields:
            payload["requests"][0]["fields"] = fields
    
        items_returned = 0
    
        while True:
            result = request("POST", "/search/query", account_id, json=payload)
    
            if not result or "value" not in result:
                break
    
            for response in result["value"]:
                if "hitsContainers" in response:
                    for container in response["hitsContainers"]:
                        if "hits" in container:
                            for hit in container["hits"]:
                                if limit and items_returned >= limit:
                                    return
                                yield hit["resource"]
                                items_returned += 1
    
            if "@odata.nextLink" in result:
                break
    
            has_more = False
            for response in result.get("value", []):
                for container in response.get("hitsContainers", []):
                    if container.get("moreResultsAvailable"):
                        has_more = True
                        break
    
            if not has_more:
                break
    
            payload["requests"][0]["from"] += payload["requests"][0]["size"]
  • The server entrypoint imports the FastMCP instance 'mcp' from tools.py (where all @mcp.tool decorators register the tools including unified_search) and calls mcp.run() to start the MCP server, making the tool available.
    from .tools import mcp
    
    
    def main() -> None:
        if not os.getenv("MICROSOFT_MCP_CLIENT_ID"):
            print(
                "Error: MICROSOFT_MCP_CLIENT_ID environment variable is required",
                file=sys.stderr,
            )
            sys.exit(1)
    
        mcp.run()
Behavior2/5

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

No annotations are provided, so the description carries full burden. It mentions the modern search API and entity_types scope, but doesn't disclose critical behavioral traits: whether this is read-only or has side effects, authentication requirements, rate limits, pagination behavior (limit parameter hints at it), error handling, or what the output looks like. The description adds some context but leaves significant gaps for a search tool.

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

Conciseness4/5

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

The description is appropriately concise with two sentences: the first states the core purpose, the second details entity_types. It's front-loaded with the main function. No wasted words, though it could be slightly more structured (e.g., bullet points for entity_types).

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

Completeness2/5

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

Given no annotations, no output schema, and 0% schema coverage for a 4-parameter tool, the description is incomplete. It covers entity_types well but misses critical context: authentication needs, output format, error handling, and usage distinctions from sibling tools. For a search tool with multiple parameters and siblings, this leaves the agent under-informed.

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?

Schema description coverage is 0%, so the description must compensate. It adds meaningful semantics for entity_types by listing possible values and stating default behavior, which clarifies beyond the schema's generic array/null type. However, it doesn't explain account_id, query, or limit parameters, leaving three of four parameters with minimal guidance. The value added is partial.

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 tool's purpose: 'Search across multiple Microsoft 365 resources using the modern search API.' It specifies the verb ('search') and resource scope ('multiple Microsoft 365 resources'), though it doesn't explicitly differentiate from sibling search tools like search_contacts or search_emails beyond mentioning broader scope.

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 usage context by mentioning it searches 'across multiple Microsoft 365 resources' and listing entity_types, suggesting it's for cross-resource searches. However, it doesn't explicitly state when to use this vs. the more specific sibling search tools (e.g., search_emails for email-only searches), nor does it mention prerequisites like authentication.

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

Related 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/elyxlz/microsoft-mcp'

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