# Admira.tv · admira.tv — la capa Emitir (MCP) > Servidor MCP de Admira.tv (v2.3.0): el canal, conectado, FEDERADO y CONDICIONADO. Agentes (silicio) y > personas (carbono) consultan qué hay EN ANTENA en cada pantalla, el proof-of-play de cada > circuito, cómo poner una pantalla a emitir y la documentación del player nativo. Desde hoy, > además, admira.tv se coordina con CIRCUITOS EXTERNOS y viceversa: pedimos antena en sus > pantallas y ellos nos la ofrecen en las nuestras, con las mismas herramientas a los dos lados. > Y el PLAYER CONDICIONADO (Xtore): un tótem sin cámara emite su playlist y, cuando alguien pasa > por la Puerta Cam, contenido por las categorías de su productor; Zapatillas solo persona/coche/moto/bici, sin sexo/edad. Contrato de integración del player (usarlo sin modificarlo): https://admira.tv/mcp/player-contract.md Manual Android exhaustivo: https://admira.tv/mcp/android-player.md MCP player_info {platform:"android",section:"all"}; omitir platform conserva macOS. No existen tools player_install/player_resume/player_screenshot: instalación por ADB, mando con sesión autorizada. Ayuda para humanos: https://admira.tv/help/ (la guía de personas del canal y del CMS) ## Player virtual Xtore · música por defecto - Recuperación del análisis solicitado: ocultación, mute, más de 3 s sin fotogramas y resize proporcional suspenden; cada 500 ms se comprueba vista visible, misma fuente sin mute, fotograma nuevo, marcas válidas y ninguna inferencia pendiente. Pausa manual, desconexión, recalibración, formato incompatible o fallo del detector cancelan la intención. Puede inferir oculto con gemelo XpaceOS autorizado y latidos frescos; sin enlace se suspende. No obtiene nuevos permisos; reintenta play de la fuente existente. - Matriz local exclusiva xtore-virtual-zapatillas: persona = Berlin / Take My Breath Away (Top Gun), asset 1786533143983-n2y09e; coche/moto = Huey Lewis & The News / The Power of Love (Regreso al Futuro), asset 1786532932584-a1412h. Bici = Pixeria #998, AZUL Y NEGRO - Me estoy volviendo loco, vídeo 1789214248874-j6qqjo. URL observada: https://stock.admira.store/stock/1789214248874-j6qqjo/asset.mp4?v=8878237. Solo este condicional inicia al 50 % de la duración real en cada nueva activación/repetición; renovar presencia conserva posición sin reseek. No aplica a la base ni a otros players. Posiciona antes de reproducir; sin duración válida en 10 s o seek fallido permite inicio desde cero con aviso consola. Fallback no garantiza la mitad ni evita el permiso de sonido. Persona+bici confirmadas conservan ambos conteos: bici gana la música, no resta personas. Sin inferencia de sexo/edad/identidad. Misión DCL-0c79557c38bde9f05e2ec381; nueva regla de bici y arranque al 50 % incluidos en v.12.09.2026.r14.15:30; no estado en vivo. IDs resueltos contra catálogo vigente con medios reproducibles HTTPS; sin pieza válida sigue la base. No cambia reglas globales, hardware ni asociación de playlist. - Presencia visual confirmada: dos fotogramas fuertes (tres para bici de confianza baja), incluso si el sujeto queda quieto. Último fotograma y evidencia fuerte menores de 1,5 s; edad desde captura, no final de inferencia. Memoria de asociación hasta 8 s no es presencia. Tras un hueco se reconfirma sin contar de nuevo el mismo paso; weak no mantiene presencia. - Renovación cada 1000 ms; mismo asset conserva nodo y posición, ACK pendiente mantiene ID. Prioridad bici/moto/coche/persona; presencia/cajas caducan a1,5s. Solo coche/moto/bici retienen contenido2s adicionales (3,5s desde última evidencia fuerte), sin simular presencia. Repetir observaciones/sello observedAt no renueva cola; vehículos nuevos más prioritarios pueden ganar. Al caducar pasa a otra categoría vigente o neutral por timer independiente. Pausa/desconexión cancelan cola inmediatamente. Pruebas manuales siguen6s, no8s. TTL 6 s solo como respaldo del transporte (hijo revisa cada 2 s) y pruebas manuales desde clic, NO desde playing; la carga consume ese plazo. Neutral tras interrupción vuelve a base. Pruebas manuales UI en «Reglas musicales · probar», solo sin intención de análisis ni calibración; no suman capturas/pasos/histórico y se neutralizan al solicitar análisis. Estos botones NO son herramientas MCP. Misión DCL-cb51d8a1e6452a99de76f4e1. - Overlay local en ROI Puerta Cam: rectángulos, clase y #ID por trayectoria, con colores estables y estilo incierto al confirmar/continuidad breve. Etiquetas sin solapamiento; si no caben, se oculta texto, no cajas. No identidad, reidentificación ni almacenamiento. Expira a1,5s y se limpia al pausar/ocultar/desconectar/recalibrar. Solo categoría al player, no IDs, geometría, colores ni fotos. Patinete manual no produce overlay ni comando musical. Capturas ordinarias6s independientes; presencia quieta no genera pasos/fotos y no las renueva. Misión presencia DCL-ea4f046ffd30919c4c705137; documentación de implementación, no cámara real. - Preset de cámara/iPad/DS: autoguardado tras cada marcación válida en localStorage admira.xtore.zapatillas.calibration.v1 (geometría, dimensiones y fecha; 4096 caracteres). Se restaura después de compartir una fuente de proporción compatible (tolerancia 0,5 % sobre referencia fija), nunca concede permisos; el botón Arrancar cámara y análisis inicia con preset compatible y Compartir sin analizar mantiene inicio manual. Parciales admitidos. Local a navegador/origen, sin sincronización entre equipos, imágenes ni credenciales. Formato distinto exige remarcar; giros/zoom de igual proporción requieren revisión humana. Olvidar preset no borra contadores/histórico. Un fallo de guardado mantiene el anterior. - Ficha Contenido en antena (doble toque/Ctrl+I): X o Escape con foco dentro cierran; cabecera arrastrable o Tab y flechas (Mayús acelera), foco visible, toolbar sticky y scroll. Cierre/arrastre/ecualizador son comunes al player; no alteran la homografía exterior. La ficha usa el viewport del player: no se encoge con vídeos horizontales ni hereda su giro. - Mini mando exclusivo de Xtore musical, previo e integrado: anterior/siguiente/mute/repeat, solo instancia y lista actual, sin edición de playlist ni control de hardware. Repeat reinicia audio/vídeo al terminar naturalmente; navegación, cambio de pieza/contexto, error o sustitución por neutral/TTL lo desarman. No renueva presencia ni capturas. No disponible para imágenes, sincro/directo/standby ni otros perfiles. Cerrar no cancela loop. 1 de X = playlist efectiva (condicional único, 1 de 1), no prueba de emisión; AUDIO/LIVE/MUTE ocupa otra fila bajo las barras. Autoplay sigue requiriendo gesto. Son UI documentada, NO herramientas MCP nuevas. MCP local 0.2.11 / Help2026-09-12.9; no estado vivo ni despliegue. NO DESCARGADO = sin copia offline, no ausencia de reproducción online. - H oculta personas solo en previoROI+iPad en directo: botón o tecla con foco en analizador, fuera de campos. Fondo aprendido en regiones despejadas tras3frames estables, cajas dilatadas; áreas desconocidas cubiertas con trama/rótulo, no inventadas. Cajas/etiquetas se conservan mientras sean frescas. Memoria volátil, reversible; caduca1,5s sin frame y se reinicia en pausa/oculta/reencuadre/desconexión. Detector sigue sobre original; H oculta original de Capturas, recortes/Twins independientes. Sin IA externa ni anonimización garantizada, identidad, grabación o evidencia de seguridad. Patinete manual sin regla/orden automática. H y cola2s: misión DCL-b7723cea465ac94cb685d1de, incluidas en v.12.09.2026.r15.15:52; contrato, no estado en vivo. - ID persistente xtore-virtual-zapatillas: navegador sin hardware dedicado, registrado en Flota. - Analizador: https://admira.tv/videoanalytics/xtore/ — música independiente del vídeo en directo. - Playlist propia: https://admira.tv/parrilla/?project=admiranext&xpace=admiranext&device=xtore-virtual-zapatillas&playlist=default - Perfil del iframe: xtoreParent=1, xtoreMusic=1, screen exacto, muted=0; sandbox opaco. - Base: playlist Por defecto asociada tiene prioridad y conserva el orden. Sin asociación usa los últimos cinco contenidos reproducibles Pixeria con tag exacto #musica, normalizando mayúsculas, acentos, espacios exteriores y prefijo #. Admite audio/music/video/animation, no image/interactive/locucion; orden createdAt descendente, sin duplicados por ID o URL. Audios y vídeos musicales terminan con ended, no por una duración editorial. - Índice completo fijo: https://stock.admira.store/stock/index.json — máximo 2 MiB/10 s, filtrar antes de limitar a cinco, conservar último catálogo válido si falla la red. El helper genérico latest5 sin filtro no cambia el comportamiento de otros players. - La playlist se relee cada 30 s; editar exige sesión del portal. Fallo inicial de consulta = playlist-unavailable y reintento, no asumir que está vacía. Fallos posteriores conservan la última asociación válida. Playlist asignada no reproducible = playlist-empty, sin sustituirla por otra; sin asociación ni coincidencias #musica también espera contenido. - Solo el analizador activo envía presencia confirmada fresca (persona/coche/moto/bici), sin sexo, edad, identidad ni imágenes. Una regla con asset compatible interrumpe la música; no necesita un paso nuevo. Pausa inmediata, o ausencia sin otra categoría vigente (persona1,5s; coche/moto/bici3,5s incluyendo cola musical2s), retornan desde el inicio de la base; si no había interrupción, la canción continúa. - Audio-blocked exige clic o Enter/Espacio en el botón del iframe, sin forzar pantalla completa; audio/vídeo musical espera sin saltar ni diagnosticar códec por ese bloqueo. Playing no garantiza sonido físico. Playlist-empty/playlist-unavailable no son descarga ni emisión. media-state.musicSource = playlist | pixeria-musica identifica la base, no prueba reproducción. - Este iframe muestra estado en el visor, no publica proof-of-play/presencia a la flota. El registro y la playlist son persistentes; su alta no acredita online. - Registro: player_virtual_register/list. No usar el alta para asignar música, no modificar reglas de pantallas físicas. El piloto remoto xtanco-totem descrito debajo es distinto. - Help/contrato: https://admira.tv/help/#player-virtual · https://admira.tv/mcp/#player-virtual Sitio / docs: https://admira.tv/mcp/ Manifest máquina: https://admira.tv/mcp/manifest.json Versión: v.12.09.2026.r7.13:36 Repo del servidor: https://github.com/csilvasantin/admira-tv-mcp · Repo del sitio: https://github.com/csilvasantin/admira-tv ## Servidor MCP (cómo conectar) - Endpoint: https://mcp-tv.admira.store/mcp - Transporte: MCP Streamable HTTP (JSON-RPC 2.0 sobre POST /mcp; responde text/event-stream, o application/json si el cliente solo acepta JSON; admite lotes). Descriptor y salud en GET https://mcp-tv.admira.store/ → {ok, service:"admira-tv-mcp", server:{name,version}, tools, resources}. - Auth: LECTURA ABIERTA (sin clave). Lo que crea o cambia estado exige la clave de flota AdmiraNeXT (Authorization: Bearer ; cómo obtenerla: https://www.admiranext.com/mcp/#identidad). Un circuito externo se identifica con su clave de circuito cx_… (se la damos al registrarlo). - Claude Code: claude mcp add --transport http admiratv https://mcp-tv.admira.store/mcp - Config de cliente (JSON): {"mcpServers":{"admiratv":{"url":"https://mcp-tv.admira.store/mcp"}}} - Prueba rápida: curl -s https://mcp-tv.admira.store/mcp -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' ## Herramientas del canal - on_air {screen} — qué hay EN ANTENA ahora mismo en una pantalla: asset (título/tipo/url), audiencia por cámara (personas, edad, género) y si está conectada. screen: id de pantalla, p. ej. admiranext-mupi. - airtime_report {circuit} | {id} — proof-of-play. Con circuit: pases totales, segundos emitidos, desglose por tipo y por segmento de audiencia de un circuito nuestro. Con id (at_…): el de una antena federada: despachos, qué emite ahora cada pantalla (is_this) y estado. - channel_url {screen, circuit, format?, cam?, clean?, mode?, audience?, muted?} — construye la URL del canal de admira.tv para poner una pantalla a emitir. format "9:16" (por defecto) o "16:9"; cam activa la cámara/audiencia (por defecto false); clean modo limpio sin chrome (por defecto true); mode local|sync|conditional; audience "remote" = el canal lee el bus /audience/ y arranca en condicional blindado; muted=1. NO la construyas a mano: la detección de kiosko depende del UA. - player_info {section?} — documentación del player nativo de Admira.tv: overview, features, releases, install, config (all por defecto). Por defecto el de macOS (AdmiraSignageMac). - quien_soy — con qué identidad te ve el servidor: agente de flota, circuito externo o anónimo. ## Federación con circuitos externos (protocolo federacion/1) Un circuito es una red de pantallas con su agente. admira.tv es el circuito «admira». La coordinación es SIMÉTRICA: las mismas herramientas a los dos lados. Protocolo completo en el resource admiratv://federacion (o GET https://mcp-tv.admira.store/federacion.md). - circuit_info — ficha de admira.tv como circuito: formatos y piezas que aceptamos, canales, pantallas vivas, herramientas y cómo federarse. Lectura abierta. - circuits {external_only?} — directorio: nuestros canales (Canal AdmiraNeXT, CanalKiosk, CanalMetro, Canal Xtanco, GrandeGracia) con pantallas vivas, y los circuitos externos federados. Lectura abierta. - circuit_screens {circuit, limit?} — inventario de pantallas: de un canal nuestro (vivas + ubicaciones del mapa) o de un circuito externo (registradas y, si expone MCP, en vivo). Lectura abierta. - circuit_register {id, name, operator?, contact?, mcp_endpoint?, api_key?, screens?, capabilities?, status?, rotate_key?} — alta/actualización de un circuito externo; devuelve la clave cx_… con la que nos llamará (solo al crearla). api_key = la clave que ese circuito nos dio. EXIGE clave de flota. - request_airtime {circuit, asset{title,type:image|video|link,url,duration_s?}, screens?, from?, to?, note?} — NOSOTROS → ELLOS: pedimos antena en un circuito externo. Si tiene MCP y clave, se le entrega ya (llama a su offer_airtime con remote_id = nuestro id); si no, queda pendiente de entrega manual con su contacto. EXIGE clave de flota. - offer_airtime {asset, screens?, from?, to?, note?, remote_id?} — ELLOS → NOSOTROS: un circuito externo (Bearer cx_…) nos ofrece una pieza para nuestras pantallas. Queda «pending» hasta que un agente de AdmiraNeXT decida. Devuelve id at_… para seguirla. - airtime_decide {id, decision:accept|reject|stop, screens?, broadcast?, note?} — accept despacha la pieza DE VERDAD: entra en la playlist por defecto de cada pantalla del canal (que la relee en ≤30 s) o por /signage/push en pantallas del gemelo XpaceOS; estado «emitting». stop la retira. EXIGE clave de flota; la decisión queda firmada. - airtime_status {id} | {list:true, direction?, status?} — estado e historial de una antena; para una petición a un circuito con MCP, refresca preguntándole. Un circuito externo solo ve las suyas. Estados: requested → pending → accepted → emitting → stopped | rejected | failed. ### Para federar TU circuito con admira.tv Expón por MCP (Streamable HTTP) al menos offer_airtime y airtime_status con estos mismos nombres y campos (circuit_info y circuit_screens ayudan), dinos tu endpoint y una clave, y un agente de AdmiraNeXT te registra con circuit_register y te entrega tu clave cx_…. Implementación de referencia (Cloudflare Worker, ~90 líneas): carpeta espejo/ del repo admira-tv-mcp, desplegada en https://circuito-espejo.csilvasantin.workers.dev/ (circuito «espejo», acepta al vuelo, solo pruebas). ## Player condicionado · Xtore (v2.2.0 · tipología) Docs con ejemplos: https://admira.tv/mcp/#player-condicionado · guía para personas: https://admira.tv/help/#xtore Caso real: pantalla xtanco-totem, circuito xtanco, superficie metahuman del gemelo (FLT-100243 / FLT-100280). Flujo: Puerta Cam (pestaña compartida) → analizador local admira.tv/videoanalytics/xtore/ (COCO-SSD: person|car|motorcycle|bicycle) → POST /audience/ (bus, Durable Object AudienceBus, TTL 2 s) → canal.html?audience=remote sondea GET /audience/ cada 500 ms → carril. Carriles: person+m → Matrix (r-hombre) · person+f → TopGun (r-mujer) · person+u → Persona (r-persona) · car → Coche (r-coche) · motorcycle → Moto (r-moto) · bicycle → Bici (r-bici) · sin label fresco (2 s) → neutral, creative "playlist" = catch-all r-neutro (minCount 0, assets []) = PLAYLIST NORMAL, hold 6 s, fade 350 ms. Un kind no-person nunca casa reglas de sexo (su sex se normaliza a u). age_band omitido = unknown (nunca adult). Contrato del label (v3): {"kind":"person|car|motorcycle|bicycle","sex":"m|f|u", "age_band":"child|youth|adult|senior|unknown","confidence":0..1,"ts":ISO,"source":"≤80"} kind omitido = person; sex obligatorio solo si kind = person (el resto → u). Auth del POST: clave de flota (Authorization: Bearer | X-MCP-Key); Idempotency-Key honrada (misma clave → mismo event_id, últimas 50). 200 {ok,accepted:true,screen,event_id,decision:{lane,creative,kind,sex}} · 400 {error:"stale"} (ts anterior al último aceptado o fuera de la ventana de 2 s ±500 ms) · 401 {error:"clave de flota requerida"}. Rutas HTTP (base https://mcp-tv.admira.store, CORS abierto, Cache-Control: no-store): - GET /audience/ → {ok, screen, fresh, ttl_ms:2000, label|null, decision:{lane, creative, kind, sex, age_ms, hold_ms, since}, server_ts}. Público. - GET /audience//events?limit=20 → últimos eventos (publish, lane_change), recientes primero. Público. - GET /audience//stream → SSE: event hello al conectar; event audience {screen, fresh, lane, creative, kind, sex, age_ms, hold_ms, label, server_ts} en cada cambio de carril o publish; keepalive 15 s; event bye a los 5 min (reconectar). Público. - POST /audience/ → publica un label (contrato de arriba). Clave de flota. - GET /player/[?circuit=] → = tool player_embed: {screen, circuit, url_player, url_gemelo, iframe_html, aspect, postmessage:{in,out,origin_allowed}, bus:{get,post,events,stream,health}, lanes, sin_anuncio, briefs, contract}. Público. - GET /player//health → = player_conditional_status con reglas resumidas: {ok, screen, target, release, bus, mode:{id,mode}, rules:{count,ids,kinds,…}, events[10], contract, get_url, stream_url}. Herramientas (por defecto screen xtanco-totem, target xtanco): - player_xtore_map — mapa del caso: pantalla, circuito, superficie, URL del canal (mode=conditional&audience=remote), endpoints del bus, carriles y assets, contrato (ttl 2 s · neutro 6 s · fade 350 ms · debug off) y estado vivo (bus + modo + reglas). Lectura abierta. - player_conditional_set {target?, screen?, auto_assets? (default true), matrix_asset?, topgun_asset?, persona_asset?, coche_asset?, moto_asset?, bici_asset?, neutral_assets?[], with_age?, mode?:local|sync|conditional} — escribe en orden r-hombre (person,m) · r-mujer (person,f) · r-persona (person,any) · r-coche (car) · r-moto (motorcycle) · r-bici (bicycle) · r-neutro catch-all (kind any, minCount 0, assets [] = playlist) en omnipublicity /segmentation?target=, cada una con kind + tag 'kind:' (omnipublicity NO conserva kind: conserva tag e id; el canal lee rule.kind || tag || id). auto_assets resuelve cada carril buscando en el Stock (tope 200 por tipo, no pagina) el ítem cuyo externalRef empiece por admiranext:xtore: (matrix|topgun|persona|coche|moto|bici); si no, el arg; si no, placeholder (solo Matrix/Top Gun) y el resto SE OMITE (devuelve sin_anuncio + briefs). Fija el modo en /locations/mode (404 tolerado). SUSTITUYE el conjunto de reglas del target. Clave de flota. - player_consume_label {screen?, kind? (omitido = person), sex? (obligatorio si person), age_band?, confidence?, source?, ts?, idempotency_key?} — publica un label en el bus y devuelve la decisión de carril + poll_url + stream_url. = POST /audience. Clave de flota. - player_conditional_status {screen?, target?} — bus {fresh, ttl_ms, label, decision, server_ts}, mode, rules (kind decodificado de rule.kind || tag), últimos 10 events, tipologias, lanes con asset resuelto, con_anuncio, sin_anuncio, briefs, contract, get_url, stream_url. Lectura abierta. Alias: GET /player//health. - player_smoke {screen?} — 7 pasos con latencia: m → Matrix, f → Top Gun, car → Coche, motorcycle → Moto, bicycle → Bici, person+u → Persona y, tras el TTL, sin label → playlist. {ok, male_to_matrix, female_to_topgun, car_to_coche, motorcycle_to_moto, bicycle_to_bici, unknown_to_persona, neutral_playlist_ok, latency_ms, steps, get_url, stream_url}. No toca reglas ni modo. Clave de flota. - player_embed {screen?, circuit?} — url_player, url_gemelo, iframe_html 9:16, postmessage {in, out, origin_allowed}, bus {get, post, events, stream, health}, lanes con asset o null, sin_anuncio, briefs, contract. Lectura abierta. Alias HTTP: GET /player/[?circuit=]. Embeber el tótem: iframe_html de GET /player/ =