Skip to main content
Glama
smeet666

mcp-stashbox

Find scenes by fingerprint

find_by_fingerprint
Read-only

Match files to stash-box records using MD5, OSHASH, or PHASH fingerprints to identify scenes across configured catalogues.

Instructions

Identify a file from the hashes held for it, across every configured stash-box catalogue. MD5 and OSHASH name the bytes of a file; PHASH states a likeness a re-encode, a crop or another scene from one shoot can satisfy. Each record reached is answered as one card, read on every catalogue that holds it.

Input Schema

NameRequiredDescriptionDefault
preferNoThe order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied.
sourcesNo
sectionsNoThe blocks read beside the record's own fields, which come back whatever is written here. Each name adds a block, and 'basic' asks for those fields alone.
fingerprintsYes

Output Schema

NameRequiredDescriptionDefault
askedYes
notesYes
cachedNo
matchesYes
unmatchedYesThe hashes put to a catalogue that answered, which reached no record there. A catalogue named as unasked says nothing about them either way.
per_sourceYes
match_countYesOne per card here. Every hash that reached a record names it on one card, and a record reached both by an exact hash and by a perceptual one stands as two, since the two claim different things about it. Read records_named for how many files were named, which counts each once.
not_searchedYesHashes and the catalogues that answered without searching their algorithm, so they were never put to those. Nobody looked there, which is no evidence about the files behind them.
resemblancesYesMatches a perceptual hash reached, each a likeness and no claim about any file's bytes.
unattributedYesRecords the catalogues answered with that carry none of the hashes asked. Which hash reached them is unknown, so they stand as no match and are counted apart.
records_namedYesDistinct records an exact hash named. Two hashes reaching one record count once, and a perceptual match names no record.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changedv2.1.0
    • removedOutput schema / properties / matches / items / properties / scene / properties / counts / additionalProperties / items / properties / value / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / matches / items / properties / scene / properties / counts / additionalProperties / items / properties / value / type
      Added value: +[
      +  "number",
      +  "null"
      +]
  2. Changed6 schema fields changedv1.0.0
    • changedInput schema / properties / prefer / description
      Previous value: -"The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied."New value: +"The order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied."
    • changedOutput schema / properties / match_count / description
      Previous value: -"One per record reached, whatever number of hashes reached it."New value: +"One per card here. Every hash that reached a record names it on one card, and a record reached both by an exact hash and by a perceptual one stands as two, since the two claim different things about it. Read records_named for how many files were named, which counts each once."
    • changedOutput schema / properties / matches / items / properties / scene / properties / held_by / description
      Previous value: -"Every catalogue asked, with the identifier the record carries there."New value: +"Every catalogue asked, with the identifier the record carries there. This is where what each of them did with the record is read: the state says which of the three it met, and the reason says why it was not asked or what went wrong."
    • changedOutput schema / properties / per_source / items / properties / index_total / description
      Previous value: -"What its own index holds for this question, the rows on this page included."New value: +"What its own index holds for the question it received, the rows on this page included. A narrowing it could not receive, or received in part, leaves that question wider than the one written."
    • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
      Previous value: -"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."New value: +"Narrowings that shaped no part of the request this catalogue received, whether its route declares no field for one or nothing written was left for one to decide."
    • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part / description
      Added value: +"Narrowings it received short of what was written, the rest of the list naming records another catalogue minted. It answered a wider question than the one asked."
  3. Changed57 schema fields changedv0.9.0
    • removedInput schema / properties / fingerprints / description
      Removed value: -"Every fingerprint held for one file. A file carries one hash per algorithm, so a longer list is an inventory rather than a question."
    • addedInput schema / properties / fingerprints / items / additionalProperties
      Added value: +false
    • removedInput schema / properties / fingerprints / items / properties / hash / description
      Removed value: -"The fingerprint as the hashing tool produced it."
    • addedInput schema / properties / fingerprints / items / properties / hash / minLength
      Added value: +1
    • changedInput schema / properties / fingerprints / maxItems
      Previous value: -10New value: +25
    • addedInput schema / properties / prefer
      Added value: +{
      +  "description": "The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied.",
      +  "items": {
      +    "enum": [
      +      "stashdb",
      +      "tpdb",
      +      "fansdb",
      +      "pmv",
      +      "javstash"
      +    ],
      +    "type": "string"
      +  },
      +  "maxItems": 5,
      +  "minItems": 1,
      +  "type": "array"
      +}
    • addedInput schema / properties / sections
      Added value: +{
      +  "description": "The blocks read beside the record's own fields, which come back whatever is written here. Each name adds a block, and 'basic' asks for those fields alone.",
      +  "items": {
      +    "enum": [
      +      "basic",
      +      "fingerprints",
      +      "images"
      +    ],
      +    "type": "string"
      +  },
      +  "maxItems": 3,
      +  "minItems": 1,
      +  "type": "array"
      +}
    • removedInput schema / properties / sources / description
      Removed value: -"Narrow to named catalogues. Every configured catalogue is asked by default."
    • addedInput schema / properties / sources / items / enum
      Added value: +[
      +  "stashdb",
      +  "tpdb",
      +  "fansdb",
      +  "pmv",
      +  "javstash"
      +]
    • addedInput schema / properties / sources / maxItems
      Added value: +5
    • addedInput schema / properties / sources / minItems
      Added value: +1
    • addedOutput schema / properties / cached
      Added value: +{
      +  "type": "boolean"
      +}
    • changedOutput schema / properties / match_count / description
      Previous value: -"Matches returned: one per scene per fingerprint it carries."New value: +"One per record reached, whatever number of hashes reached it."
    • removedOutput schema / properties / matches / items / properties / algorithm
      Removed value: -{
      -  "enum": [
      -    "MD5",
      -    "OSHASH",
      -    "PHASH"
      -  ],
      -  "type": "string"
      -}
    • removedOutput schema / properties / matches / items / properties / fingerprint
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "additionalProperties": false,
      -      "properties": {
      -        "algorithm": {
      -          "enum": [
      -            "MD5",
      -            "OSHASH",
      -            "PHASH"
      -          ],
      -          "type": "string"
      -        },
      -        "contested": {
      -          "anyOf": [
      -            {
      -              "type": "boolean"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "description": "Whether the reports reach the submissions. Null where the catalogue publishes no report count: a fingerprint nobody has disputed and one on a catalogue that counts no disputes are different things."
      -        },
      -        "duration_seconds": {
      -          "anyOf": [
      -            {
      -              "type": "number"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ]
      -        },
      -        "hash": {
      -          "type": "string"
      -        },
      -        "reports": {
      -          "anyOf": [
      -            {
      -              "type": "number"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "description": "How many people reported against it. Null on a catalogue that records no reports, which is an unknown contest and never an absence of one."
      -        },
      -        "submissions": {
      -          "anyOf": [
      -            {
      -              "type": "number"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "description": "How many people entered this fingerprint. Null where the catalogue counts none."
      -        }
      -      },
      -      "required": [
      -        "algorithm",
      -        "hash",
      -        "duration_seconds",
      -        "submissions",
      -        "reports",
      -        "contested"
      -      ],
      -      "type": "object"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ]
      -}
    • changedOutput schema / properties / matches / items / properties / match_kind / description
      Previous value: -"'exact_file' means the same file, byte for byte. 'perceptual_similarity' means images that resemble each other, which covers a re-encode, a crop and a different scene from one shoot, and is no evidence that two files are the same."New value: +"'exact_file' names the same bytes. 'perceptual_similarity' covers a re-encode, a crop and another scene from one shoot, and is no evidence that two files are the same."
    • addedOutput schema / properties / matches / items / properties / matched_by
      Added value: +{
      +  "description": "Every hash that reached this record, each naming the catalogues it reached it on. A hash a catalogue does not search reached nothing there.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "algorithm": {
      +        "enum": [
      +          "MD5",
      +          "OSHASH",
      +          "PHASH"
      +        ],
      +        "type": "string"
      +      },
      +      "hash": {
      +        "type": "string"
      +      },
      +      "sources": {
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "hash",
      +      "algorithm",
      +      "sources"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / matches / items / properties / scene / properties / counts
      Added value: +{
      +  "additionalProperties": {
      +    "items": {
      +      "additionalProperties": false,
      +      "properties": {
      +        "source": {
      +          "type": "string"
      +        },
      +        "state": {
      +          "enum": [
      +            "answered",
      +            "failed",
      +            "absent"
      +          ],
      +          "type": "string"
      +        },
      +        "value": {
      +          "anyOf": [
      +            {
      +              "type": "number"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        }
      +      },
      +      "required": [
      +        "source",
      +        "value",
      +        "state"
      +      ],
      +      "type": "object"
      +    },
      +    "type": "array"
      +  },
      +  "description": "Counts, one entry per catalogue asked and never added together. A null is read with the state beside it: a catalogue that publishes no such count, one that could not answer, and one nobody asked are three different facts.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / matches / items / properties / scene / properties / fields
      Added value: +{
      +  "additionalProperties": {
      +    "anyOf": [
      +      {
      +        "additionalProperties": false,
      +        "properties": {
      +          "agreed_by": {
      +            "description": "The catalogues that published this reading. Two agreeing is evidence of its own.",
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "disagreed": {
      +            "description": "The readings nobody preferred, published rather than dropped: choosing between them is a policy, and a policy applied in silence is a claim nobody can check.",
      +            "items": {
      +              "additionalProperties": false,
      +              "properties": {
      +                "source": {
      +                  "type": "string"
      +                },
      +                "value": {}
      +              },
      +              "required": [
      +                "source",
      +                "value"
      +              ],
      +              "type": "object"
      +            },
      +            "type": "array"
      +          },
      +          "value": {
      +            "description": "The reading the preference named, null where none published one."
      +          }
      +        },
      +        "required": [
      +          "value",
      +          "agreed_by"
      +        ],
      +        "type": "object"
      +      },
      +      {
      +        "items": {
      +          "additionalProperties": false,
      +          "properties": {
      +            "also_at": {
      +              "description": "What this same record is called on another catalogue, from a link joining the two.",
      +              "items": {
      +                "additionalProperties": false,
      +                "properties": {
      +                  "id": {
      +                    "type": "string"
      +                  },
      +                  "source": {
      +                    "type": "string"
      +                  }
      +                },
      +                "required": [
      +                  "source",
      +                  "id"
      +                ],
      +                "type": "object"
      +              },
      +              "type": "array"
      +            },
      +            "published_by": {
      +              "description": "Every catalogue that published this very record. A shared name is no join, so an entry one catalogue minted names that one.",
      +              "items": {
      +                "type": "string"
      +              },
      +              "type": "array"
      +            },
      +            "same_name_as": {
      +              "description": "A record another catalogue published under a matching name. A resemblance, never a join.",
      +              "items": {
      +                "additionalProperties": false,
      +                "properties": {
      +                  "id": {
      +                    "type": "string"
      +                  },
      +                  "source": {
      +                    "type": "string"
      +                  }
      +                },
      +                "required": [
      +                  "source",
      +                  "id"
      +                ],
      +                "type": "object"
      +              },
      +              "type": "array"
      +            },
      +            "value": {}
      +          },
      +          "required": [
      +            "value",
      +            "published_by"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      }
      +    ]
      +  },
      +  "description": "Each field of the record. A scalar carries the catalogues that said it; a list is the union, each entry naming who published it.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • addedOutput schema / properties / matches / items / properties / scene / properties / held_by
      Added value: +{
      +  "description": "Every catalogue asked, with the identifier the record carries there.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "error": {
      +        "type": "string"
      +      },
      +      "id": {
      +        "type": "string"
      +      },
      +      "reason": {
      +        "type": "string"
      +      },
      +      "retrieved_at": {
      +        "description": "The moment this client read it there.",
      +        "type": "string"
      +      },
      +      "source": {
      +        "type": "string"
      +      },
      +      "source_url": {
      +        "description": "The address it was read at, which credits it.",
      +        "type": "string"
      +      },
      +      "state": {
      +        "enum": [
      +          "answered",
      +          "failed",
      +          "absent"
      +        ],
      +        "type": "string"
      +      },
      +      "status": {
      +        "description": "What the identifier addresses there now. A folded record is held elsewhere.",
      +        "enum": [
      +          "established",
      +          "merged",
      +          "deleted"
      +        ],
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "source",
      +      "state"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • removedOutput schema / properties / matches / items / properties / scene / properties / id
      Removed value: -{
      -  "type": "string"
      -}
    • addedOutput schema / properties / matches / items / properties / scene / properties / kind
      Added value: +{
      +  "type": "string"
      +}
    • addedOutput schema / properties / matches / items / properties / scene / properties / notes
      Added value: +{
      +  "description": "What this answer does not establish, which is what makes it safe to act on.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • removedOutput schema / properties / matches / items / properties / scene / properties / performers
      Removed value: -{
      -  "items": {
      -    "type": "string"
      -  },
      -  "type": "array"
      -}
    • addedOutput schema / properties / matches / items / properties / scene / properties / preferred
      Added value: +{
      +  "description": "The order the readings were preferred in. This is the policy that was applied, whether or not every catalogue in it answered.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / matches / items / properties / scene / properties / read_from
      Added value: +{
      +  "description": "The catalogues that answered, in the order they were preferred. A policy and an outcome are two facts, and a reader deciding whether to change the policy needs both.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • removedOutput schema / properties / matches / items / properties / scene / properties / release_date
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "additionalProperties": false,
      -      "properties": {
      -        "precision": {
      -          "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
      -          "enum": [
      -            "day",
      -            "month",
      -            "year"
      -          ],
      -          "type": "string"
      -        },
      -        "value": {
      -          "description": "The date exactly as the catalogue publishes it.",
      -          "type": "string"
      -        }
      -      },
      -      "required": [
      -        "value",
      -        "precision"
      -      ],
      -      "type": "object"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ]
      -}
    • removedOutput schema / properties / matches / items / properties / scene / properties / source
      Removed value: -{
      -  "type": "string"
      -}
    • removedOutput schema / properties / matches / items / properties / scene / properties / source_url
      Removed value: -{
      -  "type": "string"
      -}
    • removedOutput schema / properties / matches / items / properties / scene / properties / studio
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "string"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ]
      -}
    • removedOutput schema / properties / matches / items / properties / scene / properties / title
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "string"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ]
      -}
    • changedOutput schema / properties / matches / items / properties / scene / required
      Previous value: -[
      -  "id",
      -  "source",
      -  "title",
      -  "release_date",
      -  "studio",
      -  "performers",
      -  "source_url"
      -]New value: +[
      +  "kind",
      +  "fields",
      +  "counts",
      +  "held_by",
      +  "preferred",
      +  "read_from",
      +  "notes"
      +]
    • changedOutput schema / properties / matches / items / required
      Previous value: -[
      -  "algorithm",
      -  "match_kind",
      -  "scene",
      -  "fingerprint"
      -]New value: +[
      +  "scene",
      +  "matched_by",
      +  "match_kind"
      +]
    • addedOutput schema / properties / not_searched
      Added value: +{
      +  "description": "Hashes and the catalogues that answered without searching their algorithm, so they were never put to those. Nobody looked there, which is no evidence about the files behind them.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "algorithm": {
      +        "type": "string"
      +      },
      +      "hash": {
      +        "type": "string"
      +      },
      +      "sources": {
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "hash",
      +      "algorithm",
      +      "sources"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / per_source / items / properties / algorithms_not_searched
      Added value: +{
      +  "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / per_source / items / properties / count / description
      Previous value: -"Rows this catalogue contributed to this page."New value: +"Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes."
    • addedOutput schema / properties / per_source / items / properties / error / enum
      Added value: +[
      +  "not_found",
      +  "invalid_input",
      +  "rate_limited",
      +  "parse_failure",
      +  "network_error",
      +  "timeout"
      +]
    • removedOutput schema / properties / per_source / items / properties / fields_searched
      Removed value: -{
      -  "description": "The fields the text index read. Absent where no text index was consulted.",
      -  "items": {
      -    "type": "string"
      -  },
      -  "type": "array"
      -}
    • changedOutput schema / properties / per_source / items / properties / index_total / description
      Previous value: -"What this catalogue's index holds for the question, beyond the page returned."New value: +"What its own index holds for this question, the rows on this page included."
    • addedOutput schema / properties / per_source / items / properties / index_total_over_any_word
      Added value: +{
      +  "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
      +  "type": "boolean"
      +}
    • changedOutput schema / properties / per_source / items / properties / moment / description
      Previous value: -"Which step failed, for a catalogue that failed."New value: +"Which moment failed."
    • addedOutput schema / properties / per_source / items / properties / name / description
      Added value: +"The name that catalogue calls itself."
    • addedOutput schema / properties / per_source / items / properties / narrowings_naming_no_record
      Added value: +{
      +  "description": "Narrowings written only with identifiers another catalogue minted.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
      Previous value: -"Narrowings this catalogue could not receive. A row of its satisfying one of them does so by chance."New value: +"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."
    • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part
      Added value: +{
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / per_source / items / properties / reason / description
      Added value: +"Why it was not asked, or what went wrong."
    • addedOutput schema / properties / per_source / items / properties / records
      Added value: +{
      +  "description": "Distinct records behind its rows.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / per_source / items / properties / skipped / description
      Added value: +"Rows it answered with that this client could not read and left out."
    • addedOutput schema / properties / per_source / items / properties / source / description
      Added value: +"The catalogue this row is about."
    • changedOutput schema / properties / per_source / items / properties / state / description
      Previous value: -"'answered' is a catalogue that looked, and a count of zero there means it found nothing. 'failed' could not answer. 'absent' was never asked. An answer holding rows from some catalogues is no evidence about the others."New value: +"'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world."
    • addedOutput schema / properties / per_source / items / properties / unattributed / description
      Added value: +"Records it answered with while carrying none of what was asked about."
    • addedOutput schema / properties / records_named
      Added value: +{
      +  "description": "Distinct records an exact hash named. Two hashes reaching one record count once, and a perceptual match names no record.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / resemblances
      Added value: +{
      +  "description": "Matches a perceptual hash reached, each a likeness and no claim about any file's bytes.",
      +  "type": "number"
      +}
    • removedOutput schema / properties / scenes_matched
      Removed value: -{
      -  "description": "Distinct scenes behind those matches.",
      -  "type": "number"
      -}
    • changedOutput schema / properties / unattributed / description
      Previous value: -"Scenes a catalogue answered with while returning none of the fingerprints asked for. Which hash reached them is unknown, which is kept apart from a catalogue that found nothing."New value: +"Records the catalogues answered with that carry none of the hashes asked. Which hash reached them is unknown, so they stand as no match and are counted apart."
    • addedOutput schema / properties / unmatched
      Added value: +{
      +  "description": "The hashes put to a catalogue that answered, which reached no record there. A catalogue named as unasked says nothing about them either way.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "algorithm": {
      +        "type": "string"
      +      },
      +      "hash": {
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "hash",
      +      "algorithm"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "asked",
      -  "matches",
      -  "match_count",
      -  "scenes_matched",
      -  "unattributed",
      -  "per_source",
      -  "notes"
      -]New value: +[
      +  "matches",
      +  "match_count",
      +  "records_named",
      +  "resemblances",
      +  "unattributed",
      +  "unmatched",
      +  "not_searched",
      +  "asked",
      +  "per_source",
      +  "notes"
      +]
  4. Changed5 schema fields changedv0.2.1
    • addedOutput schema / properties / match_count / description
      Added value: +"Matches returned: one per scene per fingerprint it carries."
    • addedOutput schema / properties / per_source / items / properties / skipped
      Added value: +{
      +  "type": "number"
      +}
    • addedOutput schema / properties / per_source / items / properties / unattributed
      Added value: +{
      +  "type": "number"
      +}
    • addedOutput schema / properties / scenes_matched
      Added value: +{
      +  "description": "Distinct scenes behind those matches.",
      +  "type": "number"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "asked",
      -  "matches",
      -  "match_count",
      -  "unattributed",
      -  "per_source",
      -  "notes"
      -]New value: +[
      +  "asked",
      +  "matches",
      +  "match_count",
      +  "scenes_matched",
      +  "unattributed",
      +  "per_source",
      +  "notes"
      +]
  5. First observedv0.1.1

TDQS

A3.8/5.0
Behavior4/5

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

With readOnlyHint and openWorldHint already declared, the description adds real context: the query fans out to every configured catalogue, results come back as aggregated cards, and where catalogues disagree on a field the preference order decides. It does not address failure modes when a catalogue is unreachable, but the cross-catalogue merge behavior is well disclosed.

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?

Three sentences, each doing distinct work — purpose, hash semantics, result shape — with the core action front-loaded. The phrasing is ornate and the closing sentence ('answered as one card, read on every catalogue that holds it') is convoluted enough to cost a point, but there is no filler.

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

Completeness4/5

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

An output schema exists, so return-value detail is not required, and the description still conveys the aggregate-card shape and preference ordering. The main gap is the sources parameter, which is never explained beyond the implicit 'every configured catalogue' default, and no guidance on empty results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

At 50% schema coverage, the description carries meaningful weight: the fingerprints items have no schema documentation at all, and the description supplies the exact semantics of all three algorithms, including the fuzzy nature of PHASH. It also implies that omitting sources queries every configured catalogue, which compensates for that field having no schema description.

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?

States a specific verb and resource: identify a file from its hashes across all configured stash-box catalogues. It is clearly distinct from the text-based search_scenes sibling, though the drift between the title ('Find scenes') and the description ('Identify a file') leaves a small ambiguity about what exactly is returned.

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 gives genuinely useful guidance on which hash type to supply — MD5/OSHASH for exact byte identity, PHASH for perceptual likeness across re-encodes and crops — which is effectively a when-to-use rule per algorithm. However, it never says when to reach for this tool over search_scenes, nor what to do when nothing matches.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.