unfile_document
Remove a document from a folder in IBM Content Manager using folder and document identifiers to manage document organization.
Instructions
Unfile a document from a folder in the content repository. This tool interfaces with the GraphQL API to unfile document from folder with the provided ids.
:param folder_id_or_path string Yes The unique identifier or path for the folder. If not provided, an error will be returned. :param document_id string Yes The unique identifier for the document. If not provided, an error will be returned.
:returns: If successful, return the folder id. Else, return a ToolError instance that describes the error.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| folder_id_or_path | Yes | ||
| document_id | Yes |
Implementation Reference
- src/cs_mcp_server/tools/folders.py:208-210 (registration)MCP tool registration decorator for unfile_document.@mcp.tool( name="unfile_document", )
- Core implementation of the unfile_document tool: validates inputs, resolves folder ID if path, queries for ReferentialContainmentRelationship (RCR) between folder and document, deletes the RCR if found and unique.async def unfile_document( folder_id_or_path: str, document_id: str ) -> Union[str, ToolError]: """ Unfile a document from a folder in the content repository. This tool interfaces with the GraphQL API to unfile document from folder with the provided ids. :param folder_id_or_path string Yes The unique identifier or path for the folder. If not provided, an error will be returned. :param document_id string Yes The unique identifier for the document. If not provided, an error will be returned. :returns: If successful, return the folder id. Else, return a ToolError instance that describes the error. """ method_name = "unfile_document" try: # check folder id or path and documetn id if not folder_id_or_path: return ToolError( message=f"unfile_document failed: folder id or path is a required input.", ) if not document_id: return ToolError( message=f"unfile_document failed: document id is a required input.", ) mutation = """ query rcr($repo:String!,$where_clause: String!) { repositoryObjects(repositoryIdentifier:$repo from: "ReferentialContainmentRelationship" where : $where_clause) { independentObjects { ... on ReferentialContainmentRelationship { id tail { id } head { id } } } } } """ formatted_folder_value = "" if is_guid_with_braces(folder_id_or_path): formatted_folder_value = f"({folder_id_or_path})" else: formatted_folder_value = lookup_folder_id( folder_name=folder_id_or_path, graphql_client=graphql_client ) if type(formatted_folder_value) is ToolError: return formatted_folder_value formatted_document_value = f"({document_id})" condition_string = ( f"tail = {formatted_folder_value} and head = {formatted_document_value}" ) var = { "repo": graphql_client.object_store, "where_clause": condition_string, } response = graphql_client.execute(query=mutation, variables=var) # handling exception if "errors" in response: return ToolError( message=f"unfile_document failed: got err {response}.", ) return_rcr = response["data"]["repositoryObjects"]["independentObjects"] return_id = "" if len(return_rcr) > 0: if len(return_rcr) > 1: return ToolError( message=f"unfile_document failed: this document has been filed more than once in the folder.", ) return_id = return_rcr[0]["id"] else: return ToolError( message=f"unfile_document failed: no such document in the folder.", ) mutation = """ mutation deleteRcr($repo:String!, $id:String!) { deleteReferentialContainmentRelationship(repositoryIdentifier: $repo, identifier:$id ) { id } } """ var = {"repo": graphql_client.object_store, "id": return_id} response = await graphql_client.execute_async(query=mutation, variables=var) if "errors" in response: return ToolError( message=f"unfile_document failed: got err {response}.", ) return response["data"]["deleteReferentialContainmentRelationship"]["id"] except Exception as e: error_traceback = traceback.format_exc(limit=TRACEBACK_LIMIT) logger.error( f"{method_name} failed: {e.__class__.__name__} - {str(e)}\n{error_traceback}" ) return ToolError( message=f"{method_name} failed: got err {e}. Trace available in server logs.", )
- Docstring providing input/output schema and description for the unfile_document tool.""" Unfile a document from a folder in the content repository. This tool interfaces with the GraphQL API to unfile document from folder with the provided ids. :param folder_id_or_path string Yes The unique identifier or path for the folder. If not provided, an error will be returned. :param document_id string Yes The unique identifier for the document. If not provided, an error will be returned. :returns: If successful, return the folder id. Else, return a ToolError instance that describes the error. """
- Helper function used to resolve folder path/name to ID via GraphQL query.def lookup_folder_id( folder_name: str, graphql_client: GraphQLClient ) -> Union[str, ToolError]: """ Retrieves the folder id for the given folder name. """ query = """ query folder($repo:String!, $folder_name: String!) { folder(repositoryIdentifier:$repo identifier:$folder_name) { id } } """ vars = {"repo": graphql_client.object_store, "folder_name": folder_name} response = graphql_client.execute( query, vars ) # Changed from execute_graphql to execute if "errors" in response: return ToolError( message=f"lookup_folder_id failed: got err {response}.", ) else: return response["data"]["folder"]["id"]
- Helper function to check if folder_id_or_path is a GUID with braces, used to decide whether to lookup ID.def is_guid_with_braces(input_string): """ Check if a string is a valid GUID/UUID with curly braces. Args: input_string (str): The string to check Returns: bool: True if the string is a valid GUID with curly braces, False otherwise """ # Check if string starts with '{' and ends with '}' if not (input_string.startswith("{") and input_string.endswith("}")): return False # Remove the curly braces guid_string = input_string[1:-1] # Pattern for UUID: 8-4-4-4-12 hexadecimal digits pattern = r"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" # Case-insensitive match if re.match(pattern, guid_string, re.IGNORECASE): return True # Alternative validation using uuid module try: uuid_obj = uuid.UUID(guid_string) return str(uuid_obj) == guid_string.lower() except ValueError: return False