Check any token.
Not only ours. Paste an address and the checks run against chain state as it is right now — whether a mint selector exists in the bytecode, whether anybody still owns the contract, whether the liquidity position sits at a contract or a wallet.
Supply cannot be increased. A missing function cannot be proven by calling it — a call can revert for many reasons, and a hostile contract could revert selectively. So the deployed runtime bytecode is fetched and searched for the four-byte selectors a mint entry point would have to dispatch on: 40c10f19 for mint(address,uint256) and a0712d68 for mint(uint256). A selector that is not in the bytecode cannot be routed to.
No privileged caller. owner() is read directly. Zero means renounced; anything else is an address that can still make restricted calls.
Liquidity held by a contract. The position id comes from the factory's own array, then ownerOf is read from the Uniswap position manager and the holder is checked for code. A holder with no code is a wallet.
Sources published. Asked of the explorer. If the explorer does not answer, the result is unknown — never a pass.
You can reproduce all of it yourself. The bytecode check is one command: cast code <token> | grep -c 40c10f19.