<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Mcp\Contracts;

/**
 * Opt-in refinement of {@see Tool::run()} for a tool that cannot act without knowing WHO is asking.
 *
 * Every read tool in this plugin is identity-free: it answers the same thing for every token.
 * `invoke_admin_action` is not — decision Q1 says it acts as the backend admin who approved the
 * OAuth consent, and that admin is recorded on the token
 * (`tnt_mcp_oauth_access_token.cUserId`, see {@see
 * \Plugin\tnt_mcp\src\Mcp\Backend\BackendIdentityFactory::forTokenUser()}). The token id is already
 * threaded through {@see \Plugin\tnt_mcp\src\Mcp\Server::dispatch()} for the audit log, so this
 * interface only asks for it to be handed to the tool as well.
 *
 * Narrow and optional for the same reason {@see PerCallEndpointClass} is: `Tool` is implemented
 * thirteen times over and must not grow a parameter twelve of them would ignore.
 *
 * A tool implementing this MUST make its inherited `run()` refuse rather than silently act without
 * an identity — a write path that guesses an admin is precisely the escalation
 * {@see \Plugin\tnt_mcp\src\Mcp\Backend\LegacyTokenException} exists to prevent.
 */
interface TokenAwareTool
{
    /**
     * @param array<string,mixed> $args    validated against `inputSchema()`
     * @param string              $tokenId the audit id of the presented token, exactly as
     *                                     {@see \Plugin\tnt_mcp\src\Mcp\Auth\TokenGuard::tokenId()}
     *                                     produced it
     * @return array<string,mixed> result payload for the MCP client
     */
    public function runForToken(array $args, string $tokenId): array;
}
