strip_selected_exif_fields
Remove specified EXIF fields from an image. Select which fields to strip and save to a new file or overwrite the original.
Instructions
Remove selected EXIF fields from a single image path.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| image_path | Yes | ||
| field_names | Yes | ||
| output_path | No | ||
| overwrite | No | ||
| dry_run | No | ||
| include_comparison | No | ||
| write_report | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| source_path | Yes | ||
| output_path | Yes | ||
| removed_fields | Yes | ||
| removed_tag_count | Yes | ||
| notes | Yes | ||
| dry_run | Yes | ||
| comparison | Yes | ||
| report_path | Yes |
Implementation Reference
- src/exif_mcp_server/tools/clean.py:40-62 (handler)The MCP tool handler function 'strip_selected_exif_fields' — wraps the core logic via 'strip_exif_fields_from_file' with MCP error handling. Accepts parameters: image_path, field_names, output_path, overwrite, dry_run, include_comparison, write_report.
def strip_selected_exif_fields( image_path: str, field_names: list[str], output_path: str | None = None, overwrite: bool = False, dry_run: bool = False, include_comparison: bool = False, write_report: bool = False, ) -> StripSelectedExifResult: """Remove selected EXIF fields from a single image path.""" return run_with_mcp_error_handling( "strip_selected_exif_fields", lambda: strip_exif_fields_from_file( image_path=image_path, field_names=field_names, output_path=output_path, overwrite=overwrite, dry_run=dry_run, include_comparison=include_comparison, write_report=write_report, ), ) - The core implementation 'strip_exif_fields_from_file' — validates the image path, normalizes field names, matches tags via EXIF reader, removes selected fields using 'strip_selected_metadata', and builds the result dict (StripSelectedExifResult).
def strip_exif_fields_from_file( image_path: str, field_names: list[str], output_path: str | None = None, overwrite: bool = False, dry_run: bool = False, include_comparison: bool = False, write_report: bool = False, ) -> StripSelectedExifResult: """Remove selected EXIF fields from a single file without hidden side effects.""" source_path = validate_image_path(image_path) selected_fields = _normalized_selected_fields(field_names) target_path, notes = _resolve_output_path(source_path, output_path, overwrite) before_exif = _read_exif_map(source_path) if include_comparison or write_report else {} matched_tags = _matched_tag_details(source_path, selected_fields) remove_tags = [{"ifd": tag["ifd"], "id": tag["tag_id"]} for tag in matched_tags] removed_fields = sorted({tag["field_key"] for tag in matched_tags}) removed_tag_count = len(remove_tags) if dry_run: notes.append("Dry run only; no files were written.") else: if removed_tag_count > 0: image_bytes = source_path.read_bytes() cleaned_bytes, removed_count = strip_selected_metadata( image_bytes, source_path.name, remove_groups=[], remove_tags=remove_tags, ) if removed_count == -1: raise ExifWriteError( "Failed to selectively remove EXIF fields while preserving the remaining " "EXIF metadata." ) _write_image_bytes(source_path, target_path, cleaned_bytes) elif target_path != source_path: _write_image_bytes(source_path, target_path, source_path.read_bytes()) if removed_tag_count > 0: notes.append( "Dry run would remove selected EXIF fields from the output image." if dry_run else "Removed selected EXIF fields from the written image." ) else: notes.append( "Dry run found no matching EXIF fields to remove." if dry_run else "Source image did not contain the selected EXIF fields." ) result: StripSelectedExifResult = { "source_path": str(source_path), "output_path": str(target_path), "removed_fields": removed_fields, "removed_tag_count": removed_tag_count, "notes": notes, } if dry_run: result["dry_run"] = True if include_comparison or write_report: if dry_run: after_exif = { field_name: value for field_name, value in before_exif.items() if field_name not in set(removed_fields) } else: after_exif = _read_exif_map(target_path) comparison = _comparison_from_exif_maps(before_exif, after_exif) if include_comparison: result["comparison"] = comparison if write_report: if dry_run: notes.append("Dry run skipped writing the sidecar JSON report.") else: report_path = _sidecar_report_path(target_path) report_payload: dict[str, Any] = { "source_path": str(source_path), "output_path": str(target_path), "removed_fields": removed_fields, "removed_tag_count": removed_tag_count, "dry_run": False, "notes": notes, "comparison": comparison, } _write_json_report(report_path, report_payload, overwrite=overwrite) result["report_path"] = str(report_path) notes.append("Wrote sidecar JSON report.") return result - The 'StripSelectedExifResult' TypedDict schema — defines the return type for the strip_selected_exif_fields tool, including source_path, output_path, removed_fields, removed_tag_count, notes, dry_run, comparison, and report_path.
class StripSelectedExifResult(TypedDict): """Contract for selective EXIF field removal from one image.""" source_path: str output_path: str removed_fields: list[str] removed_tag_count: int notes: list[str] dry_run: NotRequired[bool] comparison: NotRequired["ExifComparison"] report_path: NotRequired[str] - src/exif_mcp_server/tools/clean.py:65-69 (registration)Registration of 'strip_selected_exif_fields' as an MCP tool via 'server.tool()(strip_selected_exif_fields)' in the 'register_clean_tools' function.
def register_clean_tools(server: Any) -> None: """Register single-file cleanup tools on the provided MCP server instance.""" server.tool()(strip_exif) server.tool()(strip_selected_exif_fields) - src/exif_mcp_server/tools/__init__.py:13-19 (registration)Top-level tool registration calling 'register_clean_tools(server)' which registers 'strip_selected_exif_fields' (and other clean tools) on the MCP server.
def register_all_tools(server: Any) -> None: """Register the initial EXIF tool set on an MCP server instance.""" register_inspection_tools(server) register_privacy_tools(server) register_clean_tools(server) register_batch_tools(server)