# Native views and discovery evaluation

## Functional operations dashboards

`get_operations_dashboard` returns an organization-scoped overview.
`render_retailhardhat_dashboard` attaches the shared MCP Apps resource. Authorized
location selection, independent budget/opening/bid/approval panels, navigation,
refresh, sortable/searchable tables and read-only record drill-downs work inside
the host iframe. Bid comparisons require a location. Ungranted workflows are
omitted; failed panels expose errors instead of zero counts.

`get_budget_category_details` reads current line items for an exact source and
category, `get_bid_details` inspects a bid, and `get_opening_record_details`
inspects a location, task or permit with its corresponding module scope. All
use the existing tenant-bound, authorized routes. They do not infer overlapping
budget equivalence, currency, readiness or awarding decisions. Large scans and
detail tables disclose incompleteness.

Host capabilities enable full-screen mode and Ask assistant; optional OpenAI
APIs provide equivalent enhancements. Ask assistant sends a checked read-tool
reference only on user click, with any record text labelled untrusted. UI
preferences never retain record datasets, financial facts or location IDs.
Unsupported hosts still receive structured/text snapshots.

Dashboards never approve or execute sensitive actions. When policy requires it, human review stays in
RetailHardHat Settings > MCP through the checked canonical HTTPS link.
Real provider-account verification, publication and directory submission remain
separate: protocol-host tests do not establish consumer-platform acceptance.

Native amount columns retain cents without inferring a currency symbol. Missing
actual costs remain unknown rather than zero.

RetailHardHat keeps one authenticated MCP server. Its shared UI uses the official
MCP Apps SDK, with optional OpenAI metadata and preference persistence. It does
not require separate OpenAI, Anthropic, or Gemini model SDK implementations.

## Tools

| Tool | Purpose | Required modules |
| --- | --- | --- |
| `summarize_budget_overruns` | Source/category estimates, actuals, positive line overruns, missing actuals | budgets |
| `identify_opening_blockers` | Overdue incomplete site tasks, rejected/expired permits | sites + tasks + permits |
| `compare_site_bids` | Recorded bid comparisons grouped by category/project/RFP | bids |
| `summarize_pending_actions` | Unexpired pending/approved requests belonging to this connection | No additional module |
| `render_retailhardhat_view` | Fetch and display one of the four workflows | Selected workflow's modules |
| `get_connected_account` | Current account label, organization, role, permitted modules | No additional module |

Every tool requires the existing authenticated connection and live actor checks.
The render tool accepts `workflow` (`budget_overruns`, `opening_blockers`,
`bid_comparison`, `pending_actions`) and optional location UUID `siteId`.
Bid comparison requires a site ID. Pending actions reject site filtering.
Use summary tools for analysis; request the render tool for an interactive view.
Do not invent IDs: resolve location names with `list_sites` first.

Business tools, two approval controls and summary/dashboard/drill-down helpers
are described by the live `/api/mcp-public/reference`. Actual availability depends
on original grants, narrowing policies and access mode; sharing, record-scope
and usage limits also apply at execution.

See [Security policies](../mcp/security.md). Outcome reports above 100 array entries
require export permission in both policies, even when the helper is read-only.

## Shared UI

The resource `ui://retailhardhat/operations-v1.html` is served through authenticated
MCP `resources/read`, with MIME type `text/html;profile=mcp-app`. Tool metadata
links it through `_meta.ui.resourceUri`. Source is in `lib/mcp-app-ui`; the API
build bundles it into `dist/mcp-ui.html`. The isolated dependency graph prevents
the UI SDK's Zod 4 requirements from replacing existing app form dependencies.

The view handles loading/errors/empty data, search, sorting, selection context,
mobile scrolling, host theme changes, and read-only refresh through
`App.callServerTool`. It never receives bearer tokens, fetches APIs directly,
approves actions, or executes writes. The approval-review link is restricted to
the configured published origin and `/settings?tab=mcp`.

Optional ChatGPT widget-state support stores only search/sort preferences, not
authoritative business records. Unsupported clients still get complete textual
and structured results. Gemini consumer-app widget rendering is not claimed.

Reports explicitly warn about incomplete scans (at most 500 records per list),
unknown actual costs, overlapping location/project budgets, and unevaluated
critical-path or bid-scope equivalence. Do not claim zero signals certifies
opening readiness or that the cheapest bid is the best contractor.

## Repeatable discovery tests

From the workspace root:

```sh
# Print the synthetic direct, indirect, and negative test prompts.
pnpm --filter @workspace/scripts exec tsx src/mcp/evaluate-discovery.ts

# Opt-in model tool-selection benchmark; never executes tools.
pnpm --filter @workspace/scripts exec tsx src/mcp/evaluate-discovery.ts --live

# Score normalized captures from an actual connected provider.
pnpm --filter @workspace/scripts exec tsx src/mcp/evaluate-discovery.ts \
  --results /absolute/path/to/captures.json --provider Claude
```

The default catalogue URL is `http://localhost:80/api/mcp-public/catalogue`.
For a published-server evaluation, supply `--catalogue-url` with that server's
public catalogue URL. `--case CASE_ID` narrows a smoke test; `--model MODEL`
changes the model benchmark. The endpoint contains static tool schemas only,
not user records or credentials.

Capture format:

```json
[
  {
    "caseId": "budget-direct",
    "toolCalls": [
      { "name": "summarize_budget_overruns", "arguments": {} }
    ]
  },
  { "caseId": "personal-budget", "toolCalls": [] }
]
```

Missing cases fail. Input schemas, expected workflow/site ID, unwanted
activations, direct/indirect accuracy, and negative specificity are checked.
Results are written to `generated-artifacts/mcp` and excluded from Git/deploy.
Only use synthetic prompts and IDs in captures; never include tokens or private
tool results.

The live benchmark uses a focused outcome-plus-common-baseline tool set via the
Replit OpenAI proxy. It is **not** the ChatGPT consumer runtime, Claude, Gemini,
or the full tool catalogue. It does not establish recommendation ranking.

## Real-provider acceptance checklist

1. Publish the current server and complete actual provider account linking.
2. Test direct, indirect, and negative prompts in each provider using a
   populated review tenant. Record actual tool choices without private results.
3. In an MCP Apps host, test all four views, dark/light theme, search/sort,
   refresh, expired authorization, and the human-review link.
4. In non-UI clients, verify structured/text responses and truthful warnings.
5. Verify scoped denial, rejection, revocation, and one-time human-approved
   execution independently of UI. Provider confirmations never replace the
   RetailHardHat approval policy.
6. Complete directory review/publication. Claude's directory listing is what
   makes a connector eligible for Suggested Connectors. Registry publication
   or passing this benchmark alone does not do that.

No SDK, metadata wording, or passing test guarantees directory acceptance or
automatic app recommendations.
