untag_assets
Remove a tag from multiple assets without deleting the tag. Specify tag ID and asset IDs to remove the tag-association.
Instructions
Remove a tag from multiple assets. The tag itself remains; only the association is removed. Side effect: removes tag-to-asset links.
Args:
tag_id: The tag UUID to remove from assets.
asset_ids: List of asset UUIDs to untag. Must not be empty.
Returns: JSON with tag_id, count untagged, and per-asset results.Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tag_id | Yes | ||
| asset_ids | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- The MCP tool handler for 'untag_assets'. Decorated with @mcp.tool(), it receives tag_id and asset_ids, validates non-empty, calls the client method, and returns JSON results.
@mcp.tool() async def untag_assets(ctx: Context, tag_id: str, asset_ids: list[str]) -> str: """Remove a tag from multiple assets. The tag itself remains; only the association is removed. Side effect: removes tag-to-asset links. Args: tag_id: The tag UUID to remove from assets. asset_ids: List of asset UUIDs to untag. Must not be empty. Returns: JSON with tag_id, count untagged, and per-asset results. """ if not asset_ids: return json.dumps({"error": "asset_ids cannot be empty."}) try: result = await _client(ctx).untag_assets(tag_id, asset_ids) return json.dumps({"tag_id": tag_id, "untagged": len(asset_ids), "result": result}, default=str) except httpx.HTTPStatusError as e: return json.dumps({"error": f"Immich API error: {e.response.status_code}", "detail": e.response.text[:200]}) - The ImmichClient helper method that performs the actual API call: sends a DELETE request to /tags/{tag_id}/assets with the list of asset IDs.
async def untag_assets(self, tag_id: str, asset_ids: list[str]) -> list[dict]: """Remove a tag from multiple assets.""" return await self._request( "DELETE", f"/tags/{tag_id}/assets", json={"ids": asset_ids} ) - src/immich_mcp_server/server.py:1225-1243 (registration)The tool is registered via the @mcp.tool() decorator on the handler function in server.py. No separate registration file exists.
@mcp.tool() async def untag_assets(ctx: Context, tag_id: str, asset_ids: list[str]) -> str: """Remove a tag from multiple assets. The tag itself remains; only the association is removed. Side effect: removes tag-to-asset links. Args: tag_id: The tag UUID to remove from assets. asset_ids: List of asset UUIDs to untag. Must not be empty. Returns: JSON with tag_id, count untagged, and per-asset results. """ if not asset_ids: return json.dumps({"error": "asset_ids cannot be empty."}) try: result = await _client(ctx).untag_assets(tag_id, asset_ids) return json.dumps({"tag_id": tag_id, "untagged": len(asset_ids), "result": result}, default=str) except httpx.HTTPStatusError as e: return json.dumps({"error": f"Immich API error: {e.response.status_code}", "detail": e.response.text[:200]}) - The input schema is defined by the function signature: tag_id (str) and asset_ids (list[str]). No separate schema file exists; the FastMCP framework derives the schema from type annotations.
@mcp.tool() async def untag_assets(ctx: Context, tag_id: str, asset_ids: list[str]) -> str: """Remove a tag from multiple assets. The tag itself remains; only the association is removed. Side effect: removes tag-to-asset links. Args: tag_id: The tag UUID to remove from assets. asset_ids: List of asset UUIDs to untag. Must not be empty. Returns: JSON with tag_id, count untagged, and per-asset results. """ if not asset_ids: return json.dumps({"error": "asset_ids cannot be empty."}) try: result = await _client(ctx).untag_assets(tag_id, asset_ids) return json.dumps({"tag_id": tag_id, "untagged": len(asset_ids), "result": result}, default=str) except httpx.HTTPStatusError as e: return json.dumps({"error": f"Immich API error: {e.response.status_code}", "detail": e.response.text[:200]})