Skip to main content
Glama
ibm-ecm

IBM Core Content Services MCP Server

Official
by ibm-ecm

lookup_documents_by_name

Search for documents in IBM FileNet Content Manager using keywords from document names. Returns matching documents with confidence scores for selection.

Instructions

:param keywords: Up to 3 words from the user's message that might contain the document's name. Avoid using very common words such as "and", "or", "the", etc. :param class_symbolic_name: If specified, a specific document class to look in for matching documents. The root Document class is used by default. Specify a class only if the user indicates that the documents should belong to a specific class. Use the determine_class tool to lookup the class symbolic name based on the user's message.

:returns: A list of matching documents, or a ToolError if no matches are found or there is some other problem. Each match is a DocumentMatch object with information about the document including its name and a confidence score.

Description: This tool will execute a search to lookup documents by name. A list of the most likely documents matching the keywords is returned. Use this list to select the appropriate document based on the user's message.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
keywordsYes
class_symbolic_nameNo

Implementation Reference

  • Primary handler for the 'lookup_documents_by_name' tool. Decorated with @mcp.tool for registration. Performs GraphQL search on document names using LIKE conditions for keywords, filters by version status, scores matches using fuzzy token similarity, and returns up to MAX_SEARCH_RESULTS DocumentMatch objects sorted by score.
    @mcp.tool( name="lookup_documents_by_name", ) async def lookup_documents_by_name( keywords: List[str], class_symbolic_name: Optional[str] = None, ) -> Union[List[DocumentMatch], ToolError]: """ :param keywords: Up to 3 words from the user's message that might contain the document's name. Avoid using very common words such as "and", "or", "the", etc. :param class_symbolic_name: If specified, a specific document class to look in for matching documents. The root Document class is used by default. Specify a class only if the user indicates that the documents should belong to a specific class. Use the determine_class tool to lookup the class symbolic name based on the user's message. :returns: A list of matching documents, or a ToolError if no matches are found or there is some other problem. Each match is a DocumentMatch object with information about the document including its name and a confidence score. Description: This tool will execute a search to lookup documents by name. A list of the most likely documents matching the keywords is returned. Use this list to select the appropriate document based on the user's message. """ method_name = "lookup_documents_by_name" if not class_symbolic_name: class_symbolic_name = DEFAULT_DOCUMENT_CLASS class_data = get_class_metadata_tool( graphql_client, class_symbolic_name=class_symbolic_name, metadata_cache=metadata_cache, ) # Check if we got an error instead of class data if isinstance(class_data, ToolError): return class_data logger.debug( msg=f"class_data.name_property_symbolic_name = {class_data.name_property_symbolic_name}" ) if class_data.name_property_symbolic_name is None: return ToolError( message=f"Class {class_symbolic_name} does not have a name property", ) keyword_conditions: list[str] = [] for keyword in keywords: # query_conditions.append( # f"LOWER({class_data.name_property_symbolic_name}) LIKE %{keyword.lower()}%" # ) keyword_conditions.append( "LOWER(" + class_data.name_property_symbolic_name + ") LIKE '%" + keyword.lower() + "%'" ) keyword_conditions_string: str = " OR ".join(keyword_conditions) logger.debug("keyword_conditions_string: str = " + keyword_conditions_string) # Include condition to search only against commonly retrieved documents -- released if any; in-process version if any; initial reservation where_statement: str = ( f"(VersionStatus = {VERSION_STATUS_RELEASED} OR (VersionStatus = {VERSION_STATUS_IN_PROCESS} AND MajorVersionNumber = {INITIAL_MAJOR_VERSION}) OR (VersionStatus = {VERSION_STATUS_RESERVATION} AND MajorVersionNumber = {INITIAL_MAJOR_VERSION} AND MinorVersionNumber = {INITIAL_MINOR_VERSION})) AND (" + keyword_conditions_string + ")" ) logger.debug("where_statement: str = " + where_statement) query_text = """ query documentsByNameSearch( $object_store_name: String!, $class_name: String!, $where_statement: String!) { documents( repositoryIdentifier: $object_store_name, from: $class_name, where: $where_statement ) { documents { className id name majorVersionNumber minorVersionNumber versionStatus } } }""" var = { "object_store_name": graphql_client.object_store, "where_statement": where_statement, "class_name": class_symbolic_name, } docs: list[dict] try: response = await graphql_client.execute_async( query=query_text, variables=var ) if "errors" in response: logger.error("GraphQL error: %s", response["errors"]) return ToolError(message=f"{method_name} failed: {response['errors']}") docs = response["data"]["documents"]["documents"] except Exception as e: return ToolError( message=f"Error executing search: {str(e)}", ) logger.debug(f"Search for documents returned {len(docs)} documents") matches: list[Any] = [] for doc in docs: match_score: float = score_document(doc, keywords) logger.debug( msg=f"document {doc['name']} matched with score of {match_score}" ) if match_score > 0: matches.append((doc, match_score)) # Sort matches by score (highest first) matches.sort(key=lambda x: x[1], reverse=True) # if we found matches, return up to the maximum matches max_results = MAX_SEARCH_RESULTS if matches: doc_matches: list[DocumentMatch] = [] # Convert all available matches (up to max) to DocumentMatch objects for doc, score in matches[:max_results]: doc_name = doc["name"] logger.debug( f"Document {doc_name} selected with matched score of {score}" ) match: DocumentMatch = DocumentMatch( id=doc["id"], name=doc["name"], class_name=doc["className"], score=score, ) doc_matches.append(match) return doc_matches return ToolError( message=f"No document matching keywords {keywords} found in the class '{class_symbolic_name}'", suggestions=[ "Try using different keywords", "Check if the keywords are spelled correctly", "Ask the user for the specific document they want to use", ], )
  • Pydantic model defining the structure of each returned document match, used as output schema for the tool.
    class DocumentMatch(BaseModel): """Information about a document that matches a search.""" class_name: str = Field( default="Document", description="Class identifier for the document" ) id: str = Field(description="The id of the document") name: Optional[str] = Field(default=None, description="The name of the document") score: float = Field( description="The match score, higher values indicate better matches" )
  • Call to register_search_tools function during core server tool registration, which defines and registers the lookup_documents_by_name tool.
    register_search_tools(mcp, graphql_client, metadata_cache)
  • Call to register_search_tools function during full server tool registration, which defines and registers the lookup_documents_by_name tool.
    register_search_tools(mcp, graphql_client, metadata_cache)
  • Helper function to compute match score for a document against keywords, delegating to score_name for fuzzy matching logic.
    def score_document(doc: dict, keywords: List[str]) -> float: """ Advanced scoring method that uses tokenization and fuzzy matching to find the best document match. This scoring algorithm works by: 1. Tokenizing text (breaking CamelCase and snake_case into individual words) 2. Performing fuzzy matching between keywords and tokens 3. Giving bonuses for exact matches and for matching multiple keywords :param doc: The document to score. A dictionary returned from the graphql search. :param keywords: The keywords to match against :return: A score indicating how well the document matches the keywords """ # Convert all text to lowercase for case-insensitive matching name = doc["name"].lower() match_score: float = score_name(name, keywords) return match_score

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/ibm-ecm/ibm-content-services-mcp-server'

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