player-widget-cache

player-widget-cache is a cursor rule for Cursor from Qencode-Corp/mcp. It costs 1,404 tokens per session, scanned A, original, MIT.

Project rules for preventing stale cached versions of MCP player widgets from being shown to users. A cache is a stored copy that can remain unchanged after the source has been updated.

In plain words
What is it for?
Use it when changing player or jobs-list widget HTML, content-security settings, metadata, or embed pages in the MCP project.
Why use it?
It explains when to manually change widget version values so clients fetch updated HTML, security settings, and metadata instead of an old copy.

Cursor rule for Cursor

Written for Cursor: installed under .cursor/. Also seen: mentions Codex.

Good fit Use it when changing player or jobs-list widget HTML, content-security settings, metadata, or embed pages in the MCP project.

Compare 6 cursor rules from other repositories ↓
Install with agentmods
npx agentmods add rules/qencode-corp/mcp/player-widget-cache
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Clone the repo
git clone --depth 1 https://github.com/Qencode-Corp/mcp

Made for: Cursor.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for player-widget-cache

README.md
[![agentmods](https://agentmods.dev/badge/rules/qencode-corp/mcp/player-widget-cache/github.svg)](https://agentmods.dev/rules/qencode-corp/mcp/player-widget-cache)
Your own site
<a href="https://agentmods.dev/rules/qencode-corp/mcp/player-widget-cache"><img src="https://agentmods.dev/badge/rules/qencode-corp/mcp/player-widget-cache/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for player-widget-cache

Your own site · 80×15
<a href="https://agentmods.dev/rules/qencode-corp/mcp/player-widget-cache"><img src="https://agentmods.dev/badge/rules/qencode-corp/mcp/player-widget-cache.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 1,404 This file is loaded in full into every session.
When invoked 1,404 The same file — it is already loaded in full.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.01404 $0.01404
Opus 5.5 $0.00562 $0.00562
Sonnet 5.5 $0.00281 $0.00281
Haiku 4.5 $0.00140 $0.00140

Measured 15d ago against content hash f866668a70d9, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade A, and why

player-widget-cache scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 15d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

.cursor/rules/player-widget-cache.mdc · 86 lines

How it starts

The opening of the file, as written. The whole thing — 86 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Player widget / MCP cache keys (ChatGPT)

ChatGPT caches MCP tools/list and ui:// widgets. Stale cache = missing tools, Failed to fetch template, or old HLS/CSP bugs.

The full host matrix (ChatGPT / Claude / Cursor / Grok / Codex), CSP lists, HLS routing, sizing, and the Grok proxy scrollbar are in docs/mcp-widgets.md. Read that before another CSS/height pass. This rule is the bump-the-version checklist plus the two facts that have cost days more than once.

Cache key is a hand-bumped constant

  • WIDGET_VERSION in widgets.py is a hand-bumped literal, and PLAYER_WIDGET_URI is built from it.
  • JOBS_WIDGET_VERSION in jobs_widget.py is a separate literal for the jobs-list card. Bump it when that HTML or its _meta changes — not when the player changes.
  • Bump it in the same change that touches the player HTML, its CSP/_meta, or /player-embed.html. Nothing busts the cache automatically.
  • A per-deploy id (Unix timestamp) was tried and removed: it changed the URI and every tool title on each restart, which showed up as version noise in the client's tool-permission list. Restarts vastly outnumber widget changes.
  • URI template ui://widget/qencode-player-{version}.html serves current HTML for any older id, including the timestamp-based ones already cached by live sessions — do not append them to PLAYER_WIDGET_LEGACY_URIS.

HLS is black / "CSP off" — check the SDK first, not the widget

Hard facts (OpenAI Apps SDK + MCP Apps spec):

  • MSE/HLS requires media-src blob: (+ worker-src blob:). There is no way around it — srcObject for MediaSource is Safari-only.
  • openai/widgetCSP arrays accept https origins only. Putting blob: / data: there fails the whole connector with 424 (every tool dies, not just the player). This one is hard — never put a scheme-source there.
  • ui.csp (Claude/Cursor) does carry blob:, because those hosts block frame-src, so in-widget MSE is their only HLS path. The earlier claim that a scheme-source poisons that allowlist came from prod while it ran mcp 1.19, where _meta was never sent at all — the list was not poisoned, it never arrived. If it ever does poison, the widget says policy LACKS player-static.
  • openai/widgetDomain must be set, or ChatGPT has no sandbox origin to bind the policy to and applies none of openai/widgetCSP (this is what the "CSP off" badge means). Never mirror it as ui.domain — Claude derives that itself and rejects a server-supplied value.
  • So inline HLS in the ChatGPT sandbox is only possible via frame_domains → nested /player-embed.html on the RS origin, which sets its own CSP.
  • Claude/Cursor block frame-src, so routing them through the embed breaks HLS that would have played. open_player gates prefer_nested_embed on the host: ChatGPT gets the nested embed, everyone else mounts MSE in-widget.
  • A manifest must be served from a public URL. A presigned one plays the playlist and 403s every relative segment, which looks like an endless spinner with nothing in any log. open_player rejects those (_require_self_contained_manifest); get_download_url always presigns, so it is the wrong tool for a manifest.

Read the full file on GitHub · 86 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 15d ago First seen · 86 lines · 1,404 tokens per session scan A f866668a70d9

Subscribe to this mod's changes

player-widget-cache is a cursor rule published in the GitHub repository Qencode-Corp/mcp (1 stars, last pushed 15d ago), licensed MIT. It adds 1,404 tokens to every session, about $0.0056 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-22.