yomi
OfficialYomi (読み) — el servidor MCP personal de LINE
Yomi es un servidor MCP de LINE de código abierto para tu cuenta personal. Lee, responde, envía imágenes y busca en cualquier conversación desde Claude o cualquier agente de IA local — sin navegador, sin cuenta de bot y sin el cliente propio de LINE.
El nombre se lee de más de una manera. 読み (yomi) — una lectura: no solo analizar tus mensajes, sino leer la situación, como haces tú. 詠み (yomi) — recitar: no lee en silencio, te lee las cosas de vuelta. Y 黄泉 (yomi) — el reino inalcanzable; el mismo yomi en 黄泉帰り (yomigaeri), "regresar de Yomi". Como un mensajero que se mueve entre dos reinos, Yomi atraviesa sellos y silencios para traer de vuelta a la luz mensajes que siguen siendo legibles en lo profundo de tus conversaciones. No invoca una historia ya perdida; ayuda a que lo que no ha desaparecido se vuelva a ver.
A diferencia del servidor MCP oficial de Bot de LINE, que conecta agentes de IA a una cuenta oficial de LINE a través de la Messaging API, Yomi se conecta a tu cuenta personal existente de LINE y a tus conversaciones como un dispositivo secundario.
Yomi habla directamente el protocolo TCompact-over-HTTPS de LINE, descifra los mensajes y
multimedia con Letter-Sealing (E2EE), y expone el resultado a cualquier agente de IA a
través de un pequeño servidor MCP stdio. Apunta Claude
Desktop (o cualquier cliente MCP) hacia él y el agente podrá ponerse al día con tu LINE
como lo harías tú: leer, responder, enviar una imagen, mencionar a alguien y buscar en todo
tu historial localmente — y, con get_insight, leer la situación: qué conversaciones
están esperando tu respuesta, quién une tu mundo y qué ha quedado pendiente.
Sin API oficial, sin cuenta de bot, sin webhook. Yomi inicia sesión como dispositivo secundario en tu propia cuenta.
Guías: ¿Qué es un servidor MCP de LINE? · LINE MCP 是什麼?Yomi、官方 Bot 與桌面自動化的差異.
No oficial. Yomi es un proyecto personal independiente, no afiliado ni respaldado por LINE. Su uso puede ir contra los Términos de Servicio de LINE, y ejecutar un cliente adicional en tu cuenta conlleva un riesgo de limitación de velocidad o suspensión. Está pensado para leer tu propia cuenta. Úsalo bajo tu propio riesgo. Consulta Aviso legal.
Primeros pasos
Vista previa de Native Desktop
Yomi Desktop pone la bandeja de entrada de LINE y el espacio de trabajo del agente local en
una sola aplicación nativa. Incluye su propio runtime: los usuarios no instalan Node, no
abren Terminal, no clonan este repositorio ni configuran YOMI_RUN_MJS. Native Desktop es
independiente de la extensión MCPB de Claude Desktop que se describe a continuación.
Plataforma | Paquete para usuarios generales | Estado de firma | Experiencia de instalación |
macOS 14+, Apple Silicon |
| Firmado con Developer ID y notarizado por Apple | Abrir DMG → arrastrar Yomi a Aplicaciones → abrir Yomi |
Windows 10/11 x64 |
| Aplicación de firma OSS de confianza en curso | La descarga sigue sin estar disponible hasta que la firma y la prueba de humo del instalador pasen |
El paquete de macOS se ha probado a través de la ruta real de aplicación descargada:
DMG en cuarentena, instalación en /Applications, evaluación de Gatekeeper, primer
arranque, actualización de mensajes con el runtime incluido y formulario de inicio de
sesión de LINE sin terminal. El instalador de Windows contiene el flujo equivalente de
inicio de sesión por teléfono/PIN dentro de la aplicación y se prueba en un runner nativo
de Windows antes del lanzamiento.
Las compilaciones de Desktop son experimentales y no oficiales. Los cambios de LINE pueden romperlas, y ejecutar un cliente adicional puede poner en riesgo una cuenta. Prefiere una cuenta de prueba y mantén una copia de seguridad actualizada. Los instaladores de vista previa se publican como pre-lanzamientos de GitHub solo después de que la firma de la plataforma esté disponible.
Consulta el proceso de lanzamiento de desktop, la política de firma de código y la política de privacidad.
Servidor MCP y extensión de Desktop
Necesitas Node.js y una cuenta de LINE. Yomi se ejecuta localmente
a través de npx; no necesitas clonar este repositorio, instalar Bun ni compilar nada.
Ejecuta primero node --version e instala la LTS actual si el comando no existe o la
versión no es compatible.
El índice de búsqueda local de Yomi usa el node:sqlite integrado de Node, por lo que
necesita v22.13 o más reciente — excepto v23.0–v23.3, que son más recientes que v22.13
pero aún carecen de ese módulo (se desmarcó tanto en 22.13.0 como en
23.4.0). Cualquier LTS actual es válida.
Esto es engines.node en package.json; el resto de Yomi funciona en Node más antiguo,
pero la búsqueda, el alcance y la captura no.
⚠️ Yomi necesita un cliente que lo ejecute en tu propia máquina. Las herramientas solo en la nube (ChatGPT, Claude.ai web) no pueden ejecutar Yomi. Configura Yomi en Claude Desktop o Claude Code y funcionará tanto en el chat como en Cowork, porque Desktop inicia Yomi en tu máquina y las sesiones locales de Cowork lo cargan. No le pidas a Cowork que instale Yomi por ti: el shell de Cowork se ejecuta dentro de una VM desechable, no en tu máquina, así que cualquier cosa que instale allí desaparece cuando termina la sesión. Sigue los pasos de abajo tú mismo, en tu propia terminal.
Elige el cliente que realmente usas y sigue solo esa sección. Claude Code y Claude Desktop tienen ajustes de MCP separados; configurar uno no configura el otro.
La ruta más fácil, y la única que no requiere línea de comandos en absoluto. Claude Desktop incluye su propio runtime de Node, así que no hay que instalar nada más.
Descarga el paquete para tu máquina desde el último lanzamiento:
Máquina
Archivo
Windows (Intel/AMD)
yomi-win32-x64.mcpbMac (Apple Silicon)
yomi-darwin-arm64.mcpbLinux (x64)
yomi-linux-x64.mcpbEn Claude Desktop, abre Settings → Extensions y arrastra el archivo descargado a esa página (o simplemente haz doble clic en el archivo).
Revisa lo que te pide, haz clic en Install.
Inicia una conversación y di "log in to LINE". Yomi muestra un formulario, introduces tu número de teléfono y lo confirmas en tu teléfono. Sin terminal en ningún momento.
Esto omite por completo el archivo de configuración, lo que también evita el error de MSIX de Windows que se describe a continuación.
Nota para usuarios de Cowork: no le pidas a Cowork que instale Yomi por ti. El shell de Cowork se ejecuta dentro de una VM desechable — no en tu máquina — y no escribirá en tu terminal real. Instala el paquete tú mismo con los tres clics de arriba; una vez instalado, las sesiones locales de Cowork pueden usar Yomi como cualquier otra herramienta.
Encuentra la ruta completa a
npx:macOS / Linux: which npx Windows: where npxAbre el archivo de configuración de Claude Desktop:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json⚠️ Windows: la ruta documentada puede no ser la que Claude realmente lee. Claude Desktop se distribuye como un paquete MSIX, cuyo sistema de archivos está virtualizado. La aplicación lee su configuración de
%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.jsonmientras que Settings → Developer → Edit Config abre el archivo no virtualizado
%APPDATA%\Claude\. Son dos archivos diferentes que nunca se sincronizan, así que una configuración correcta de Yomi escrita en la ruta documentada se ignora silenciosamente — sin error, sin registro, Yomi simplemente nunca aparece. Esto es claude-code#26073, aún abierto. Si Yomi no aparece después de un reinicio, escribe la misma configuración en la rutaLocalCachede arriba también. (No aplica a Claude Code, ni a Desktop instalado fuera de MSIX.)Añade Yomi bajo
mcpServers, reemplazando elcommandde ejemplo con la ruta completa impresa en el paso 1. En Windows, JSON requiere que cada\de la ruta se escriba como\\:
{
"mcpServers": {
"yomi": {
"command": "/opt/homebrew/bin/npx",
"args": ["@rikaidev/yomi"]
}
}
}Por ejemplo, una ruta de Windows puede verse como
"C:\\Program Files\\nodejs\\npx.cmd". Usa la ruta que informe tu propia
máquina en lugar de copiar cualquiera de los ejemplos a ciegas.
⚠️ El
npxque nombres aquí no decide qué Node ejecuta Yomi. En macOS y Linux,npxes un script que comienza con#!/usr/bin/env node, así que ejecuta elnodeque aparezca primero en elPATHde Claude Desktop — no el Node instalado junto alnpxal que acabas de apuntar. Desktop hereda suPATHde la sesión de escritorio, que a menudo no es la de tu terminal, y los gestores de versiones (nvm, fnm, asdf, volta, …) ponen su propionodepor delante de todo lo demás. Así quewhich npxpuede informar una instalación perfectamente moderna mientras Yomi sigue arrancando con un Node antiguo.El síntoma es específico: iniciar sesión, leer y enviar funcionan, pero la búsqueda, el alcance y la captura fallan, y el registro dice
No such built-in module: node:sqlite. Yomi imprime el runtime que realmente obtuvo en ese error — léelo en lugar de asumir.La solución es darle al servidor un
PATHcuya primera entrada contenga unnodecompatible:"yomi": { "command": "<the npx path from step 1>", "args": ["-y", "@rikaidev/yomi"], "env": { "PATH": "<dir holding a supported node><sep><a base PATH>" } }Separador:
:en macOS/Linux,;en Windows. Mantén una base utilizable después (/usr/local/bin:/usr/bin:/bino el equivalente de tu plataforma) — esto reemplaza elPATHdel servidor en lugar de anteponerlo, ynpxnecesita las herramientas habituales.Nombrar un
nodeabsoluto encommandno funciona, por muy plausible que parezca:npxlanza el bin propio del paquete como proceso hijo y resuelvenodedesdePATHde nuevo para él, así quecommandsolo elige quién ejecutanpx, no quién ejecuta Yomi. EstablecerPATHes lo que realmente llega al servidor.
¿Configurando esto con un agente de IA? Las configuraciones de MCP ahora las escriben
más los agentes que a mano, así que los pasos anteriores están redactados para un humano
que lee su propia máquina. Un agente debería resolver los valores en lugar de emitir
marcadores de posición, y esta configuración tiene una trampa que vale la pena señalar
directamente: nombrar npx en command no fija el runtime. Procedimiento:
Encuentra un Node que realmente tenga el módulo que el índice de Yomi necesita; no lo infieras a partir de un número de versión:
node -e 'require("node:sqlite")' && command -v node # POSIX
node -e "require('node:sqlite')" && where node # WindowsSi lanza una excepción, ese Node no sirve para búsqueda/alcance/captura. Prueba las otras instalaciones (which -a node, nvm ls, fnm list, …) hasta que una pase; solo entonces continúa.
Escribe el directorio de ese Node en
env.PATH, según el JSON anterior, y mantén unPATHbase después. Resuelve el directorio en la máquina de destino (dirnamede la ruta del paso 1); no copies un ejemplo de este README: son rutas de Homebrew para Apple Silicon y están mal en casi todas partes.
No pongas en su lugar un node absoluto en command. Parece la solución más robusta y no lo es: npx lanza el bin del paquete como un proceso hijo y vuelve a resolver node desde PATH para él, así que command solo decide quién ejecuta npx. Esto se midió, no se asumió: con un Node 20 primero en PATH, fijar command seguía dándole al servidor Node 20.
command -v también puede devolver un envoltorio en lugar de un binario real: los shims de heap, los envoltorios de npx locales y los stubs de gestores de versiones son comunes, y algunos se comportan de manera diferente según el directorio de trabajo del cliente. No intentes razonar cuál es el "real". El paso 3 lo resuelve.
Verifica con una herramienta que toque el índice.
yomi versionno es una verificación: imprime una cadena sin abrir SQLite, por lo que tiene éxito en un Node que no puede ejecutar búsquedas. Llama aget_scope_policy: necesita SQLite y no requiere inicio de sesión en LINE. Si devuelve el texto de la política, el runtime es correcto. Si falla, el error nombra el Node que realmente se ejecutó y lo que necesitaba.Cierra y vuelve a abrir Claude Desktop por completo. Confirma que Yomi está cargado en Configuración → Desarrollador antes que cualquier otra cosa: si Yomi no aparece allí, Claude nunca leyó tu configuración; en Windows, consulta la advertencia de MSIX en el paso 2. Una vez que aparezca, las herramientas están disponibles tanto en el chat como en las sesiones locales de Cowork.
No necesitas instalar Claude Code para esta configuración.
claude mcp add yomi -- npx @rikaidev/yomiInicia una nueva sesión de claude. Las herramientas de Yomi deberían aparecer automáticamente. Este comando configura solo Claude Code; no configura Claude Desktop.
Esta forma deja el runtime a PATH, lo cual está bien siempre que el node que resuelve tu sesión de claude sea uno compatible: es el mismo PATH que puedes ver, a diferencia del de Claude Desktop. Compruébalo con node -e 'require("node:sqlite")'. Si lanza una excepción, o prefieres no depender de PATH en absoluto, nombra el Node explícitamente:
claude mcp add yomi -e PATH="$(dirname "$(command -v node)"):$PATH" -- npx -y @rikaidev/yomiEn cualquier caso, verifica con get_scope_policy en lugar de yomi version: el comando de versión imprime una cadena sin abrir SQLite, por lo que pasa en un Node que no puede ejecutar búsquedas.
¿Ejecutando Claude Code dentro de un clon de este repositorio? Escribe la especificación
@rikaidev/yomi@latest. Sin una etiqueta,npxbusca primero un bin local, y en este repositoriopackage.jsondeclara"bin": {"yomi": ...}mientras que nada lo enlaza ennode_modules/.bin; así quenpxomite la instalación y muere consh: yomi: command not found. Una etiqueta explícita hace que obtenga el paquete publicado. Solo afecta a las copias de trabajo de Yomi; en cualquier otro lugar, la forma sin etiqueta está bien.
Esta configuración estándar funciona en la mayoría de los clientes MCP:
{
"mcpServers": {
"yomi": {
"command": "npx",
"args": ["@rikaidev/yomi"]
}
}
}Cursor Settings → MCP → Add new MCP Server → nómbralo yomi, tipo de comando, valor: npx @rikaidev/yomi
O añádelo a .cursor/mcp.json en la raíz de tu proyecto.
Añádelo a .vscode/mcp.json:
{
"servers": {
"yomi": {
"command": "npx",
"args": ["@rikaidev/yomi"]
}
}
}Añádelo a ~/.config/opencode/opencode.json:
{
"mcp": {
"yomi": {
"type": "local",
"command": ["npx", "@rikaidev/yomi"],
"enabled": true
}
}
}codex mcp add yomi npx @rikaidev/yomiO añádelo a ~/.codex/config.toml:
[mcp_servers.yomi]
command = "npx"
args = ["@rikaidev/yomi"]Añádelo a cline_mcp_settings.json:
{
"mcpServers": {
"yomi": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@rikaidev/yomi"]
}
}
}Añádelo a ~/.codeium/windsurf/mcp_config.json — el mismo JSON que la configuración estándar.
amp mcp add yomi -- npx @rikaidev/yomiAdvanced settings → Extensions → Add custom extension → nómbralo yomi, tipo STDIO, comando: npx @rikaidev/yomi
grok mcp add yomi -- npx @rikaidev/yomiPrimer inicio de sesión
Una vez conectado, dile al agente:
"Inicia sesión en LINE: mi número es +8869XXXXXXXX."
Aprueba el dispositivo en tu teléfono (consulta Iniciar sesión), y:
"Resume mi LINE no leído y dime quién está esperando una respuesta."
Related MCP server: line-desktop-mcp
Lo que puedes hacer
Yomi expone 20 herramientas a través de MCP (las que merece la pena nombrar; consulta las tablas). Los resultados de lectura grandes usan TOON, eficiente en tokens; los resultados de estado y escritura pequeños usan JSON compacto. Los errores siguen siendo texto plano y los medios usan contenido nativo de imagen/audio/recurso de MCP.
"Error honesto" a continuación significa un fallo explícito que nombra el problema (p. ej., missing_decrypt_material): Yomi nunca fabrica un respaldo, un marcador de posición ni un éxito falso.
Lectura
Tool | Does |
| De una sola vez: cada conversación con mensajes no leídos, cada una con sus últimos mensajes, descifrados con E2EE, nombres de remitentes resueltos. Diseñado para "resumir mis no leídos y sugerir próximos pasos". Solo lectura: nunca marca nada como leído. |
| Chats/grupos/salas con recuentos de no leídos y una vista previa descifrada del último mensaje. Los más recientes primero. |
| Una conversación, descifrada. Pagina más profundo con un cursor |
| Cualquier adjunto descifrado (imagen/vídeo/audio/archivo). Error honesto en no medios. |
| Búsqueda en la lista de amigos por subcadena de nombre, o la lista completa. Datos sin procesar de LINE: sin puntuación difusa, sin clasificación por afinidad. |
| Miembros de un grupo persistente. Las salas ad hoc sin registro de grupo fallan honestamente en lugar de devolver una lista vacía falsa. |
Información (lee la situación, no solo los mensajes)
Tool | Does |
| Un contexto de red compacto sobre tu índice local: la estructura sobre la que el agente razona, no un volcado de mensajes. Devuelve |
Escritura (estos realmente envían, no borradores)
Tool | Does |
| Envía un mensaje de texto E2EE ahora (clave por pares para 1:1, clave de grupo para grupos/salas). Los |
| Cifra, sube a LINE OBS y envía una imagen E2EE ahora. Funciona para 1:1, grupos y salas. Un envío por llamada. Falla honestamente si la clave no se puede resolver o si se rechaza la subida. |
| Envía un recibo de lectura que la otra parte puede ver. Solo explícito: leer mensajes y la captura en segundo plano nunca marcan nada como leído. |
Búsqueda (local, entre conversaciones: LINE no tiene tal primitiva)
Herramienta | Qué hace |
| Búsqueda híbrida en todas las conversaciones indexadas. Recopila automáticamente en el primer uso, diversifica los resultados entre chats y devuelve una pequeña ventana de contexto alrededor de cada coincidencia. Devuelve |
| Indexación masiva explícita en la base de datos local + incrustación para búsqueda semántica. Es la única herramienta que puede hacer capturas masivas; se ejecuta una vez por llamada, nunca con un temporizador. |
Alcance y privacidad (todo funciona sin conexión, no se necesita sesión de LINE)
Herramienta | Qué hace |
| Bloquear una conversación y purgar sus datos ya indexados. No solo captura futura: una lista de bloqueo que dejara datos antiguos en el índice sería una privacidad falsa. |
| Volver a permitir una conversación (no restaura los datos purgados). |
| Muestra la lista de bloqueo / la política de privacidad completa (leída de |
Sesión
Herramienta | Qué hace |
| Inicio de sesión sin contraseña en dispositivo secundario. Ver más abajo. |
Iniciar sesión
Requisito previo: en tu teléfono principal, activa 設定 › 我的帳號 › 允許自其他裝置登入 (Ajustes › Cuenta › Permitir inicio de sesión en otros dispositivos). Sin esto, LINE nunca ofrece a este dispositivo un aviso de inicio de sesión: esta es la causa más común de que un primer inicio de sesión parezca quedarse colgado.
⚠️ Límite de una sola sesión de escritorio: LINE solo permite una sesión de cliente de escritorio a la vez por cuenta. Como Yomi se conecta como dispositivo secundario de escritorio (
DESKTOPMAC), iniciar sesión en Yomi cerrará la sesión de tu aplicación oficial LINE Desktop (y volver a iniciar sesión en LINE Desktop invalidará la sesión de Yomi). No puedes usar Yomi y el cliente oficial LINE Desktop simultáneamente.
Solo necesitas darle al agente tu número de teléfono en formato E.164: él mismo proporciona la
región (p. ej. TW para un número +886) cuando llama a la herramienta.
Yomi gestiona el flujo sin contraseña (dispositivo secundario) de LINE. Cómo se presenta el inicio de sesión depende de tu cliente MCP:
Clientes con la capacidad MCP
elicitation—loginte pide tu teléfono/región, muestra el PIN en un diálogo y se bloquea hasta completarse. Una sola llamada, sin PIN transmitido a través del modelo. Tu número de teléfono nunca entra en la transcripción.Clientes sin esa capacidad (p. ej. Claude Desktop hoy) — dos llamadas.
login(con tu teléfono + región) devuelve el PIN en su resultado; introdúcelo en LINE en tu teléfono principal y aprueba el dispositivo; luego llama alogin_complete, que se bloquea hasta que el teléfono confirma. El agente debe llamar alogin_completeinmediatamente: es él quien espera, así que no hay nada que debas informar.Desde una terminal —
npx @rikaidev/yomi loginejecuta todo el flujo en stdout, PIN incluido. Siempre disponible como alternativa.
La única fecha límite que importa es la de LINE: tienes unos 3 minutos desde que se muestra el PIN para introducirlo y aprobar el dispositivo. El propio cliente de Yomi sigue escuchando durante muchos minutos más, así que un teléfono lento nunca es el fallo: solo la vida útil de 3 minutos del código de LINE lo es.
Una vez que has iniciado sesión, la sesión — incluido un certificado de inicio de sesión — se persiste (ver más abajo), y los futuros inicios de sesión se saltan el PIN por completo.
También hay una interfaz experimental de MCP Apps (una tarjeta
ui://yomi/login) para clientes que renderizan vistas interactivas. Es correcta según la especificación y se renderiza bajo MCP Inspector, pero algunos hosts obtienen el recurso sin completar el protocolo de la vista, por lo que es solo de visualización y nunca está en la ruta crítica — los flujos anteriores siempre funcionan independientemente.
Sesiones y credenciales
Yomi gestiona su propio inicio de sesión. Al arrancar, llama a resumeSession() una vez, leyendo la
sesión de LINE del Llavero de macOS (servicio dev.rikai.yomi.credentials, cuenta
line) y renovando silenciosamente el token si es necesario.
Credenciales de primera parte. El inicio de sesión sin contraseña persiste el token de autenticación, el token de renovación, el certificado, el MID y el propio par de claves E2EE — y luego los lee de nuevo para verificar que la escritura realmente se realizó. Un inicio de sesión que no se puede persistir falla de forma visible al iniciar sesión, no silenciosamente en el siguiente reinicio.
Sesión compartida. La sesión se almacena en la entrada canónica del llavero
dev.rikai.yomi.credentials(o en el almacén de credenciales local), lo que permite que Yomi MCP y Yomi Desktop compartan exactamente la misma sesión de inicio de sesión de LINE sin problemas.Nota de plataforma. En macOS, la sesión vive en el llavero de inicio de sesión. En Linux y Windows, Yomi actualmente recurre a un archivo JSON local: funcional, pero menos protegido que un almacén de secretos del sistema operativo, y menos probado que la ruta de macOS. Se planean backends nativos de almacenamiento seguro (libsecret / DPAPI); hasta entonces, trata una instalación que no sea de macOS en consecuencia.
Toda herramienta excepto login y las herramientas de alcance/búsqueda sin conexión devuelve un error
honesto cuando no hay sesión. Por lo demás, Yomi es un servidor de consultas puro: nunca sondea,
nunca rellena datos en segundo plano; cada llamada a una herramienta hace exactamente las solicitudes a LINE que
necesita, y collect_messages es la única vía que obtiene datos de muchos chats a la vez.
Búsqueda
LINE no tiene búsqueda entre conversaciones; Yomi construye una localmente. El índice es una
base de datos SQLite ignorada por git (data/search-index.db) en el repositorio — nada sale
de tu máquina.
La búsqueda es híbrida por diseño. Siempre ejecuta búsqueda por palabras clave FTS5 (bm25 sobre
texto preprocesado con bigramas, de modo que las subcadenas CJK sin límites de palabras están cubiertas) y,
cuando existen incrustaciones, búsqueda semántica, y luego fusiona las dos listas clasificadas mediante
Fusión de Rango Recíproco. La búsqueda puramente semántica pierde silenciosamente coincidencias exactas que
viven en mensajes no incrustados; la búsqueda puramente por palabras clave pierde paráfrasis; fusionar ambas
muestra un término exacto y una coincidencia de significado juntos. El campo mode de la respuesta
siempre informa qué métodos contribuyeron.
La clasificación semántica mantiene cada mensaje como su propio vector. Las pruebas con conversaciones reales indexadas de LINE encontraron que incrustar ventanas de conversación superpuestas diluía el mensaje central y reducía la calidad de recuperación. Por lo tanto, el contexto se añade solo después de la clasificación: Yomi limita que un solo chat inunde los resultados principales y expande cada ganador con dos mensajes a cada lado para que el agente vea el intercambio que dio significado a la coincidencia sin debilitar la propia incrustación.
La clasificación semántica usa Xenova/bge-small-zh-v1.5 (incrustación general de BAAI, pequeña,
principalmente en chino pero multilingüe) mediante transformers.js. La inferencia de incrustación se ejecuta
completamente en proceso en CPU: el texto de tus mensajes nunca se envía a ningún sitio.
La única salvedad es una descarga única del modelo: en el primer collect_messages o
search_messages, transformers.js descarga el modelo (~90 MB) de huggingface.co
y lo almacena en caché localmente; cada ejecución posterior es totalmente sin conexión. Esa primera descarga es
una solicitud HTTPS saliente a HuggingFace por los pesos del modelo: lleva tu IP y
qué modelo se está descargando, pero ningún contenido de mensajes ni datos de LINE. Si necesitas
Yomi completamente aislado, precarga la caché de transformers.js (o apúntala a un
directorio de modelos local) antes de la primera búsqueda para que nunca se haga ninguna llamada de red.
La realidad del dispositivo secundario (léelo antes de confiar en "no puedo obtener mensajes antiguos")
Yomi se ejecuta como un dispositivo secundario en tu cuenta. Eso determina lo que puede ver:
Los chats de grupo sin Letter Sealing son texto plano en el servidor de LINE — historial completo y medios, sin restricción.
Los chats de grupo con Letter Sealing son E2EE, y ahí la época importa. Un grupo así está cifrado con una clave de grupo compartida que rota (con cambios de membresía, o cuando un cliente aprovisiona una nueva). LINE solo entrega a un dispositivo la actual clave de grupo: no hay API para obtener una reemplazada. Así que un dispositivo secundario descifra mensajes de la época cuya clave posee en adelante; los mensajes enviados bajo una época anterior — antes de que Yomi obtuviera la clave actual — pueden volver indescifrables, incluso en un grupo cuyo historial anterior sí puede leer. Esto es inherente a las claves de grupo por época de Letter Sealing, no un error aquí. También puede cortar de lado: la época que tiene tu teléfono y la época que tiene Yomi no tienen por qué ser la misma, así que los dos dispositivos pueden leer cada uno una porción diferente del mismo grupo.
Instalar Yomi no rota nada por sí mismo, así que "antes de instalar Yomi" es el límite equivocado. Yomi solo resuelve una clave de grupo existente; nunca registra (crea) una, porque crearla rota el secreto compartido del grupo para cada miembro y deja varados todos los mensajes cifrados con la anterior. Así que una instalación nueva toma la clave actual y lee hasta la última rotación — que puede ser anterior a la instalación por meses. El límite es la última reconfiguración de clave, no tu fecha de instalación. Y una vez que Yomi ha visto una época, conserva esa clave, así que una rotación posterior a la instalación le permite leer ambos lados. Si un grupo vuelve indescifrable hasta hoy, eso no es esta limitación — por favor, repórtalo.
Los medios 1:1 usan el llavero E2EE a nivel de cuenta, que un dispositivo secundario posee por completo (LINE lo sincroniza durante el emparejamiento) — Yomi puede descifrar imágenes/archivos 1:1 que puede ver.
El relleno del historial 1:1 es la única limitación real. LINE no entrega a un dispositivo secundario el historial pasado de mensajes 1:1 como hace con los grupos. Los mensajes recibidos mientras Yomi está conectado se descifran con normalidad; desplazarse profundamente en el historial 1:1 anterior al emparejamiento puede volver vacío. Esto es una restricción del lado del servidor de LINE, no un error aquí.
Cuando el descifrado falla de verdad, Yomi devuelve un error explícito missing_decrypt_material
— nunca una tarjeta falsa o un marcador de posición. El silencio es honesto; un resultado fabricado no lo es.
Desarrollo
Para los colaboradores que trabajan en el código fuente de Yomi (requiere bun
o Node.js 24+ — .nvmrc fija el mismo 24 que instala CI, así que nvm use en este
directorio lo selecciona; ten en cuenta que nvm no lee engines, por eso los dos se
indican por separado y están protegidos por una prueba):
bun install # install dependencies (or npm install)
bun run.mjs # run the stdio MCP server
bun run.mjs login # run the login flow in a terminal
npm run build # tsc --noEmit — type-check only (Yomi ships & runs from src/)
npm test # bun testLa compilación solo verifica tipos y compila; este repositorio no se comunica con servidores LINE
en vivo como parte de su propia compilación. Conectar un cliente MCP y llamar a login es
lo que realmente inicia una sesión.
src/
line/ LINE protocol core: TCompact/Thrift codec, E2EE (Letter-Sealing,
group keys, media), Talk/Auth/Sync service clients, session state,
passwordless login flow.
auth/ Credential store (macOS Keychain, JSON-file fallback off-darwin).
search/ Local cross-conversation index (SQLite + FTS5) and the offline
embedding pipeline (transformers.js).
mcp/ The stdio server: tool schemas, handlers, the privacy-policy loader,
and the experimental MCP Apps login view (mcp/ui/).
util/ [TAG]-prefixed logger (stderr only — stdout is the MCP JSON-RPC stream).Todo lo que Yomi escribe para humanos va a stderr; stdout está reservado para el
flujo JSON-RPC de MCP. Un console.log suelto corrompe el protocolo: no añadas uno en
ninguna ruta a la que el servidor pueda llegar.
Privacidad
Por defecto, Yomi indexa todas tus conversaciones en el índice de búsqueda local, en el dispositivo, para que un agente pueda buscar en ellas: un valor predeterminado que lo captura todo, con opción de exclusión por chat. Nunca se sube nada; los únicos datos que salen de tu dispositivo son los que el propio agente muestra en sus respuestas. (La única llamada de red no relacionada con LINE que Yomi realiza es la descarga única del modelo de incrustación desde HuggingFace en la primera búsqueda: pesos del modelo entran, ningún contenido de mensaje sale; ver Búsqueda.) PRIVACY.md es la política canónica, y Yomi muestra ese mismo texto al agente al conectarse (y mediante get_scope_policy) para que pueda revelar el valor predeterminado antes de cualquier lectura masiva.
Descargo de responsabilidad
Yomi es un proyecto personal independiente y no oficial, creado para aprender y para acceder a la propia cuenta de LINE. No está afiliado, autorizado ni respaldado por LINE Corporation. "LINE" es una marca comercial de su respectivo propietario.
El uso de Yomi puede violar los Términos de Servicio de LINE, y operar un cliente adicional en una cuenta puede resultar en limitación de velocidad o suspensión de esa cuenta. Yomi está pensado para acceder a tu propia cuenta y datos. Eres el único responsable de cómo lo uses. El software se proporciona "tal cual", sin garantía de ningún tipo; ver LICENSE.
Agradecimientos
La implementación del protocolo LINE de Yomi se escribió con referencia a tres proyectos de código abierto, cuyos diseños de campos, ordenamiento de fragmentos E2EE, formas de solicitud y definiciones de Thrift informaron esta implementación independiente:
evex-dev/linejs (MIT) — formas de solicitud y el diseño de la carga útil E2EE de Letter-Sealing.
DeachSword/CHRLINE (BSD-3-Clause) — diseños de campos de protocolo y el flujo de inicio de sesión sin contraseña.
er1ce/LINE-Protocol (Apache-2.0) — definiciones de enumeraciones de Thrift (ContentType, MessageRelationType, ServiceCode).
Sus avisos de copyright y textos de licencia completos se reproducen en NOTICE, como exigen sus licencias.
Licencia
MIT
Available Tools
41 toolsaccept_invitationA
Accepts a group/chat invitation for your LINE account — you join the chat. Use for a group you were invited to (its chatId appears with invited status). One accept per call.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE group/room MID whose invitation to accept, as returned by list_conversations. |
add_friendA
Adds a person to your LINE friends by their MID (e.g. from get_group_members or find_contact). One add per call.
| Name | Required | Description | Default |
|---|---|---|---|
| mid | Yes | MID of the person to add as a friend, e.g. from get_group_members. |
block_contactA
Blocks a contact for your LINE account — they can no longer message you. Reversible with unblock_contact. One block per call.
| Name | Required | Description | Default |
|---|---|---|---|
| mid | Yes | MID of the contact to block. |
cancel_reactionA
Removes this account's reaction from a LINE message. Undoes a react_message. One cancellation per call.
| Name | Required | Description | Default |
|---|---|---|---|
| messageId | Yes | LINE message id whose reaction to remove, as returned by get_chat_messages. |
collect_messagesA
Bulk-fetch recent messages from LINE conversations into Yomi's local cross-conversation search index (LINE has no native cross-chat search). Fetches up to perChat per chat (default 100) for chatIds, or all conversations when omitted, and best-effort embeds them for semantic search — re-running also repairs any messages still missing a vector. A background capture loop keeps the index current on its own, so call this only to force a reconcile or backfill specific chats. Undecryptable messages are skipped, not fabricated.
| Name | Required | Description | Default |
|---|---|---|---|
| chatIds | No | LINE chat/group/room MIDs to collect from, as returned by list_conversations. Omit to collect from all conversations. | |
| perChat | No | Maximum recent messages to fetch per chat (default 100). |
create_groupA
Creates a new LINE group/room immediately with the given members (no message is sent). chatType 0 = group (invitees must accept before joining), 1 = room (members added directly); default 1. Provide name and mids (initial members, e.g. from find_contact). One create per call.
| Name | Required | Description | Default |
|---|---|---|---|
| mids | Yes | MIDs of the initial members to add. | |
| name | Yes | Name for the new group. | |
| chatType | No | LINE chat type: 0 = group (invite-based), 1 = room (direct add). Default 1. |
exclude_chatsA
Add conversations to Yomi's privacy denylist. Excluded chats are (1) skipped by future collect_messages/search_messages auto-collect — never fetched or indexed — and (2) PURGED now: their already-indexed messages and embeddings are deleted from the local index in the same call. A real privacy action, not just a future filter. Local-index operation; works without a live LINE session.
| Name | Required | Description | Default |
|---|---|---|---|
| chatIds | Yes | LINE chat/group/room MIDs to exclude, as returned by list_conversations. |
find_contactA
Find LINE friends whose display name contains name (case-insensitive substring). Returns each match's mid for send_message. Raw friend-list lookup — no ranking, no fuzzy scoring.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Substring to match against friends' display names, case-insensitive. |
get_chat_messagesA
Fetch messages from one LINE conversation. Text is E2EE-decrypted when keys are available; each message has fromName (resolved sender), a mediaType flag (image/video/audio/file) plus messageId for get_message_media, and mentions (LINE's raw contentMetadata.MENTION, or null — a literal "@name" in text is not itself a mention). Without before, returns the most recent count. With before (id/deliveredTime of the oldest message already seen), returns one older page — repeat to page further back.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | Maximum number of messages to return (default 50). | |
| before | No | Cursor to fetch messages older than this point. Use the id and/or deliveredTime of the oldest message already seen. | |
| chatId | Yes | LINE chat/group/room MID, as returned by list_conversations. |
get_group_membersA
List the members of one LINE group (mid + displayName each). Resolves persistent groups (c...); ad-hoc rooms (r...) without a group record return an honest error, never a fabricated empty list.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE group chat MID, as returned by list_conversations. |
get_insightA
A compact "what needs my attention" context network over the local index — you make the final call, this assembles the evidence cheaply. Nodes: connectors (people across ≥2 of your chats, with structural bridges) and relationships (per-conversation engagement, reply rhythm, recency). open: conversations whose latest message is NOT yours, ranked by how overdue they are relative to your usual reply rhythm there, each with fromName (last speaker), a preview of the latest message, overdueRatio/typicality, and a lastMessageId pointer. It carries NO message threads and makes NO judgement about addressee, nicknames, or open-request vs closing-ack — those are language understanding you do by reading each preview (a group message may be addressed to someone else, who then owns it), fetching the full thread with get_chat_messages only for the few worth it. Reads across all conversations (denylist-excluded dropped). Empty only when the index is empty.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | No | Optional focus: restrict `relationships` and `pending` to this chat (as returned by list_conversations). Omit to scan all conversations. | |
| sinceHours | No | Lookback window in hours, measured back from the newest captured message (not wall-clock). Default 504 (21 days). |
get_message_imageA
Download and decrypt one LINE image message. Legacy alias of get_message_media restricted to images; prefer get_message_media for video/audio/file.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID the message belongs to. Required to locate E2EE key material. | |
| preview | No | Fetch the smaller preview object instead of the full-resolution original. | |
| messageId | Yes | LINE message id, as returned by get_chat_messages. |
get_message_mediaA
Download and decrypt one LINE media message of any downloadable type (image, video, audio, file). Returns image/audio MCP content, or an embedded resource blob (with filename when known) for video/file. Non-media messages (text, sticker refs, unsupported types) return an honest error naming the content type — never fabricated bytes.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID the message belongs to. Required to locate E2EE key material. | |
| preview | No | Fetch the smaller preview object instead of the full-resolution original (images/video only). | |
| messageId | Yes | LINE message id, as returned by get_chat_messages. |
get_scope_policyA
Return Yomi's data-capture privacy policy (the disclosure to show the user) plus the current list of excluded conversations. Call this to show the user, in concrete terms, what Yomi captures by default and how to exclude conversations.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
get_unread_digestA
One-shot unread digest: every LINE conversation with unread messages (all pages of the inbox, newest activity first), each with its most recent messages (default 10), E2EE-decrypted, with resolved sender names. Saves calling list_conversations then get_chat_messages per chat. Read-only: never marks anything read, never touches the search index; denylist-excluded conversations are omitted. Returns an empty list when nothing is unread — never fabricated.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of unread conversations to return, most recently active first (default: all of them). | |
| perChat | No | Maximum recent messages to include per unread conversation (default 10). |
include_chatsA
Remove conversations from Yomi's denylist, re-allowing future capture. Does NOT restore data purged when the chat was excluded — capture resumes from empty history going forward. Local-index operation; works without a live LINE session.
| Name | Required | Description | Default |
|---|---|---|---|
| chatIds | Yes | LINE chat/group/room MIDs to re-include. |
invite_memberA
Invites members into a LINE group immediately. Invitees must accept before joining. Provide mids (from find_contact or get_group_members). One call per invite batch.
| Name | Required | Description | Default |
|---|---|---|---|
| mids | Yes | MIDs of the people to invite. | |
| chatId | Yes | LINE group/room MID to invite into, as returned by list_conversations. |
kick_memberA
Removes (kicks) members from a LINE group immediately — they lose access at once (re-adding needs a fresh invite); visible to every member. Provide mids (from get_group_members). One call per removal batch.
| Name | Required | Description | Default |
|---|---|---|---|
| mids | Yes | MIDs of the members to remove. | |
| chatId | Yes | LINE group/room MID to remove members from, as returned by list_conversations. |
leave_groupA
Makes THIS LINE account leave a group immediately — it loses access to the group and its history. One leave per call.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE group/room MID to leave, as returned by list_conversations. |
list_contactsA
List the authenticated user's full LINE friend list as-is (mid + displayName). No ranking, no interaction-frequency ordering.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
list_conversationsA
List LINE conversations (chats, groups, rooms) with unread counts, a preview of the last message, and a human-readable name (group title, or the other party's display name for a 1:1).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of conversations to return (default 20). |
list_excluded_chatsA
List the conversations currently on Yomi's privacy denylist. Returns [{ chatId, name }]; name is best-effort resolved when a live LINE session exists, otherwise null — never a fabricated placeholder. Local-index operation; works without a live LINE session.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
list_stickersA
List the sticker packages this LINE account OWNS — the only stickers it can send. Returns each package's packageId (STKPKGID), title, and version (STKVER). Get individual sticker ids via search_stickers, then send_sticker. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| language | No | Locale for package titles, e.g. 'en' or 'zh-Hant'. Defaults to 'en'. |
loginA
Log in to LINE via the passwordless secondary-device flow. Requires 設定 > 我的帳號 > 允許自其他裝置登入 enabled on the primary phone — with it off LINE never prompts that phone and NO login can succeed, so raise this with the human up front rather than after a failure. On MCP clients with form elicitation, this call first confirms that setting, then prompts for phone/region and PIN and completes login by itself; if the human says the setting is off, it returns the enabling steps without starting a login (relay them verbatim, then call login again). On clients without it (e.g. Claude Desktop), phone/region come from the arguments or a persisted login, and this returns as soon as LINE issues the PIN (or reports none needed) — then call login_complete IMMEDIATELY (do not wait for the human). LINE gives ~3 minutes from PIN display to confirm on the phone; login_complete blocks past that, so calling it late only wastes that window.
| Name | Required | Description | Default |
|---|---|---|---|
| phone | No | Phone number in E.164 form, e.g. +8869XXXXXXXX. Omit to be prompted (elicitation) or to reuse a persisted number. | |
| region | No | Region code, e.g. TW, JP, TH, ID, US. Omit to be prompted (elicitation) or to reuse a persisted region. |
login_completeA
Finish a passwordless login that login started on a client without form elicitation (not needed on form-elicitation-capable clients). No arguments. Call immediately after login returns — do not wait for the human. Blocks while they enter the PIN (skipped if a stored certificate is valid) and approve the device, then returns the profile. LINE's real deadline is ~3 minutes from PIN display. Errors if no login is pending.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
mark_readA
Send a LINE read receipt (mark a conversation read up to messageId, or the latest when omitted) — a real action the other party can see. Use ONLY when the user explicitly wants to mark a chat read; reading (get_chat_messages, get_unread_digest) and background capture never mark read. Fails honestly if there is nothing to mark.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID to mark read, as returned by list_conversations. | |
| messageId | No | Optional message id to mark read up to. Omit to mark read up to the latest message. |
preview_stickerA
Show sticker preview images (MCP image content from the public sticker CDN) so you and the user can SEE them before sending. Give a packageId (from list_stickers/search_stickers) to preview its first stickers, or add a stickerId to preview just one. Each image is labeled with its stickerId + packageId for send_sticker. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max stickers to preview when no stickerId is given (default 8). | |
| packageId | Yes | Sticker package id (STKPKGID) to preview. | |
| stickerId | No | Optional specific sticker id (STKID) to preview just that sticker. |
react_messageA
Adds a reaction to a LINE message, visible to the conversation. reactionType: 2 = 👍 LIKE, 3 = ❤️ LOVE, 4 = 😆 LAUGH, 5 = 😮 SURPRISE, 6 = 😢 SAD, 7 = 😡 ANGRY (default 2). One reaction per call.
| Name | Required | Description | Default |
|---|---|---|---|
| messageId | Yes | LINE message id to react to, as returned by get_chat_messages. | |
| reactionType | No | Predefined reaction: 2=👍LIKE, 3=❤️LOVE, 4=😆LAUGH, 5=😮SURPRISE, 6=😢SAD, 7=😡ANGRY. Default 2. |
rename_groupA
Renames a LINE group/chat immediately; the new name is visible to every member. Works on groups/rooms (chatId starting with c/r). One rename per call.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | New group name. | |
| chatId | Yes | LINE group/room MID to rename, as returned by list_conversations. |
search_messagesA
Search across your LINE messages. Hybrid ranking: FTS5 keyword search (covers every indexed message, so exact matches are never dropped) fused with semantic similarity when embeddings are available — the mode field reports which contributed (hybrid | semantic | keyword). If the index is empty and a session is live, it auto-collects all conversations first; a populated index searches locally with no network. Empty index with no session returns an honest notice, never a fabricated match list.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results to return (default 20). | |
| query | Yes | Search query. Plain keywords and natural-language descriptions both work — keyword matching catches exact terms, semantic matching catches paraphrases. |
search_stickersA
Search the account's OWNED sticker packages by title and expand each match into its individual sticker ids (STKID), ready for send_sticker. Case-insensitive substring match on the package title. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max matching packages to expand with sticker ids (default 8). | |
| query | Yes | Substring to match against owned package titles (case-insensitive). | |
| language | No | Locale for package titles to match against, e.g. 'en' or 'zh-Hant'. Defaults to 'en'. |
send_audioA
Sends an E2EE audio message to a LINE conversation immediately (same pipeline as send_file). Provide exactly one of filePath or audioBase64; optional durationMs sets the recipient player length. Works for 1:1/group/room. One send per call.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID to send to, as returned by list_conversations. | |
| fileName | No | Optional original filename (used for the upload name; defaults to the basename of filePath or audio.m4a). | |
| filePath | No | Local filesystem path to the audio file. Mutually exclusive with audioBase64. | |
| durationMs | No | Optional audio duration in milliseconds, for the recipient player progress bar. | |
| audioBase64 | No | Base64-encoded audio bytes. Mutually exclusive with filePath. |
send_contactA
Shares a LINE contact card to a conversation immediately — the recipient sees a tappable card for contactMid (e.g. from find_contact or get_group_members). displayName is optional (resolved from the mid when omitted). Works for 1:1/group/room. One send per call.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID to send to, as returned by list_conversations. | |
| contactMid | Yes | MID of the person whose contact card to share, as returned by find_contact or get_group_members. | |
| displayName | No | Optional display name for the card. Resolved from contactMid when omitted. |
send_fileA
Sends an E2EE file attachment (any type — .docx, .pdf, .zip, …) to a LINE conversation immediately (same pipeline as send_image; the original filename is sealed end-to-end). Works for 1:1/group/room; fails honestly if the key cannot be resolved or the upload is rejected. One send per call. Provide exactly one of filePath or fileBase64; fileName is required with fileBase64 (and overrides the basename when given with filePath).
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID to send to, as returned by list_conversations. | |
| fileName | No | Original filename shown to the recipient (sealed E2EE). Required with fileBase64; optional with filePath (defaults to its basename). | |
| filePath | No | Local filesystem path to the file. Mutually exclusive with fileBase64. | |
| fileBase64 | No | Base64-encoded file bytes. Mutually exclusive with filePath; requires fileName. |
send_imageA
Sends an E2EE image to a LINE conversation immediately (encrypt → upload to OBS → send). Works for 1:1/group/room; fails honestly if the key cannot be resolved or the upload is rejected. One send per call. Provide exactly one of imagePath or imageBase64.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID to send to, as returned by list_conversations. | |
| imagePath | No | Local filesystem path to the image file. Mutually exclusive with imageBase64. | |
| imageBase64 | No | Base64-encoded image bytes. Mutually exclusive with imagePath. |
send_locationA
Sends a location (map pin) to a LINE conversation immediately — latitude/longitude plus optional title (place name) and address. Works for 1:1/group/room. One send per call.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Optional place name shown on the pin. | |
| chatId | Yes | LINE chat/group/room MID to send to, as returned by list_conversations. | |
| address | No | Optional address shown under the pin. | |
| latitude | Yes | Latitude in decimal degrees. | |
| longitude | Yes | Longitude in decimal degrees. |
send_messageA
Sends a text message to a LINE conversation immediately (not a draft). Always E2EE (pairwise for 1:1, group key for group/room); fails honestly rather than sending plaintext if the key cannot be resolved. One send per call. To @mention someone, put the visible "@name " into text AND pass a matching mentions entry — without mentions, "@name" is plain text and notifies no one. Resolve MIDs via get_group_members or find_contact first.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Plain-text message body, including the literal "@name" text for any mentions — mentions only mark up text that is already there. | |
| chatId | Yes | LINE chat/group/room MID to send to, as returned by list_conversations. | |
| mentions | No | Optional @mentions. Each entry marks a span of `text` as a mention of one user, which LINE highlights and notifies. Omit to send `text` as plain, non-notifying text. | |
| replyToMessageId | No | Optional message id (from get_chat_messages) this replies to — LINE renders a quoted reply. Omit for a normal message. |
send_stickerA
Sends a LINE sticker to a conversation immediately, named by stickerId (STKID) + packageId (STKPKGID). Only OWNED stickers can be sent — get ids from search_stickers/list_stickers. Works for 1:1/group/room. One send per call.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID to send to, as returned by list_conversations. | |
| version | No | Sticker version (STKVER). Defaults to "1". | |
| packageId | Yes | LINE sticker package id (STKPKGID). | |
| stickerId | Yes | LINE sticker id (STKID). |
send_videoA
Sends an E2EE video to a LINE conversation immediately (same pipeline as send_file; uses LINE chunked video encryption so it plays and integrity-verifies on official clients). Provide exactly one of filePath or videoBase64; optional durationMs sets the scrubber length. Works for 1:1/group/room. One send per call.
| Name | Required | Description | Default |
|---|---|---|---|
| chatId | Yes | LINE chat/group/room MID to send to, as returned by list_conversations. | |
| fileName | No | Optional original filename (used for the upload name; defaults to the basename of filePath or video.mp4). | |
| filePath | No | Local filesystem path to the video file. Mutually exclusive with videoBase64. | |
| durationMs | No | Optional video duration in milliseconds, for the recipient player scrubber. | |
| videoBase64 | No | Base64-encoded video bytes. Mutually exclusive with filePath. |
unblock_contactA
Unblocks a previously blocked contact for your LINE account. Undoes block_contact. One unblock per call.
| Name | Required | Description | Default |
|---|---|---|---|
| mid | Yes | MID of the contact to unblock. |
unsend_messageA
Retracts (unsends) one of YOUR OWN LINE messages for everyone — deletes it from the conversation for all participants and CANNOT be undone. LINE allows unsending only your own messages. SAFETY GATE: you must pass confirm: true, or the call refuses so it can never fire by accident. One unsend per call.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | Yes | Must be true to proceed. Retraction is irreversible; the call refuses unless this is explicitly true. | |
| messageId | Yes | LINE message id to retract (must be your own), as returned by get_chat_messages. |
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.6.2- Changed
get_unread_digest1 field changed- changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum number of conversations to scan for unread (default 20)."New value: +"Maximum number of unread conversations to return, most recently active first (default: all of them)."
39 tool updates
v0.4.1- Added
accept_invitation - Added
add_friend - Added
cancel_reaction - Added
collect_messages - Added
create_group - Added
exclude_chats - Added
find_contact - Added
get_chat_messages - Added
get_group_members - Added
get_insight - Added
get_message_image - Added
get_message_media - Added
get_scope_policy - Added
get_unread_digest - Added
include_chats - Added
invite_member - Added
kick_member - Added
leave_group - Added
list_contacts - Added
list_conversations - Added
list_excluded_chats - Added
list_stickers - Added
login_complete - Added
mark_read - Added
preview_sticker - Added
react_message - Added
rename_group - Added
search_messages - Added
search_stickers - Added
send_audio - Added
send_contact - Added
send_file - Added
send_image - Added
send_location - Added
send_message - Added
send_sticker - Added
send_video - Added
unblock_contact - Added
unsend_message
38 tool updates
v0.3.0- Removed
accept_invitation - Removed
add_friend - Removed
cancel_reaction - Removed
collect_messages - Removed
create_group - Removed
exclude_chats - Removed
find_contact - Removed
get_chat_messages - Removed
get_group_members - Removed
get_message_image - Removed
get_message_media - Removed
get_scope_policy - Removed
get_unread_digest - Removed
include_chats - Removed
invite_member - Removed
kick_member - Removed
leave_group - Removed
list_contacts - Removed
list_conversations - Removed
list_excluded_chats - Removed
list_stickers - Removed
login_complete - Removed
mark_read - Removed
preview_sticker - Removed
react_message - Removed
rename_group - Removed
search_messages - Removed
search_stickers - Removed
send_audio - Removed
send_contact - Removed
send_file - Removed
send_image - Removed
send_location - Removed
send_message - Removed
send_sticker - Removed
send_video - Removed
unblock_contact - Removed
unsend_message
40 tool updates
v0.2.0- First observed
accept_invitation - First observed
add_friend - First observed
block_contact - First observed
cancel_reaction - First observed
collect_messages - First observed
create_group - First observed
exclude_chats - First observed
find_contact - First observed
get_chat_messages - First observed
get_group_members - First observed
get_message_image - First observed
get_message_media - First observed
get_scope_policy - First observed
get_unread_digest - First observed
include_chats - First observed
invite_member - First observed
kick_member - First observed
leave_group - First observed
list_contacts - First observed
list_conversations - First observed
list_excluded_chats - First observed
list_stickers - First observed
login - First observed
login_complete - First observed
mark_read - First observed
preview_sticker - First observed
react_message - First observed
rename_group - First observed
search_messages - First observed
search_stickers - First observed
send_audio - First observed
send_contact - First observed
send_file - First observed
send_image - First observed
send_location - First observed
send_message - First observed
send_sticker - First observed
send_video - First observed
unblock_contact - First observed
unsend_message
TDQS
Scored across 41 tools
Most tools target a distinct resource+action, and descriptions actively disambiguate the tricky clusters (get_unread_digest vs list_conversations vs get_insight; find_contact vs list_contacts; search_stickers vs list_stickers). The only real overlaps are the explicitly-flagged legacy alias get_message_image vs get_message_media and collect_messages vs search_messages' auto-collect, both of which are documented so an agent won't misselect.
Nearly every tool follows a clean snake_case verb_noun pattern (get_*, list_*, send_*, search_*, create_/rename_/invite_/kick_/leave_group, block_/unblock_contact). The send_* family, group-management family, and privacy family are each internally uniform. Only 'login' / 'login_complete' deviate slightly, which is negligible.
41 tools is heavy and sits well above the comfortable 3-15 range, largely because seven distinct send_* variants (message/image/file/audio/video/location/contact/sticker) plus a full login pair inflate the surface. Each tool is genuinely distinct and earns its place in a rich LINE domain, but some consolidation (e.g. a single send_media with a type param) would be reasonable.
The surface covers the full lifecycle: auth (login/login_complete), conversation listing/search/digest/insight, message fetch and media download, all outbound message types, group CRUD and membership, contact add/block/find, reactions/unsend, stickers, and a complete privacy denylist lifecycle (exclude/include/list/policy). No obvious dead ends for the stated purpose.
Maintenance
Related MCP Connectors
Read, search and reply to your WhatsApp chats from your AI, using your own number.
Email for AI agents: read, search and send from your Gmail, Outlook, Yahoo, iCloud or IMAP inbox.
WhatsApp for Claude, ChatGPT or any AI agent: search, reply and send. Personal or Business API.
Read-only WhatsApp MCP for your AI agent: it reads the chats you choose. Try the public demo.
Related MCP Servers
- AlicenseAqualityCmaintenanceOperate your LINE Official Account from any AI agent through natural language.37339 npm102MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI tools to read and send messages through LINE Desktop via MCP, supporting manual or automatic sending without official LINE API tokens.118 npm127MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI tools to read and send LINE messages by automating the LINE Desktop application, with macOS OCR-based reading and idle-aware scheduling.118 npm1MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to read, search, and reply to personal LINE messages, including end-to-end-encrypted chats and media, all decrypted locally.MIT