MCP Research Friend Server

oficial

Herramientas de investigación, incluyendo un almacén de documentos respaldado por Sqlite

Documentación

Research Friend

Un asistente amigable para herramientas de IA que necesitan buscar cosas en la web y gestionar un archivo local de investigación.

Research Friend es un servidor MCP que brinda a tus herramientas de IA la capacidad de obtener páginas web y buscar en internet. Utiliza un navegador web real en segundo plano, por lo que funciona incluso con sitios web modernos que dependen en gran medida de JavaScript. También incluye un "archivo" local para almacenar documentos, extraer texto y buscar en toda tu biblioteca.

Para aprovechar todas sus funciones, necesitarás un cliente MCP que admita prompts (común) y sampling (menos común). Estamos desarrollando Research Friend junto con Chabeau, que admite ambos.

¿Qué puede hacer?

  • Obtener páginas web con un navegador real (incluyendo sitios con mucho JavaScript)
  • Obtener PDFs y extraer su contenido de texto
  • Buscar en la web a través de DuckDuckGo o Google
  • Mantener un archivo local de documentos para buscar, listar y extraer

Primeros pasos

Necesitarás Node.js versión 20 o superior instalado en tu computadora.

1. Instalar dependencias

Abre una terminal en esta carpeta y ejecuta:

npm install

2. Instalar soporte para navegador

Research Friend usa Playwright para controlar un navegador web. Después de instalar las dependencias, necesitarás instalar el navegador:

npx playwright install chromium

Esto descarga una copia de Chromium que Playwright utilizará. Es independiente de cualquier navegador que ya tengas instalado.

3. Iniciar el servidor

node src/index.js

El servidor se comunica a través de stdio (entrada/salida estándar), que es como los clientes MCP se conectan a él.

Agregar a tu cliente MCP

La forma de agregar Research Friend depende del cliente MCP que estés usando. Aquí tienes un ejemplo general de cómo podría verse la configuración:

[[mcp_servers]]
id = "research-friend"
command = "node"
args = ["/path/to/mcp-research-friend/src"]
transport = "stdio"

Reemplaza /path/to/mcp-research-friend con la ruta real a esta carpeta en tu computadora.

Herramientas

Herramientas web

friendly_web_fetch

Obtiene una página web y devuelve su contenido. Por defecto, devuelve markdown con enlaces preservados — ideal para LLMs. Usa Readability para extraer el contenido principal (eliminando navegación, anuncios, etc.). Para PDFs, paginación o búsqueda dentro del contenido, usa friendly_web_extract en su lugar.

Parámetros:

  • url (requerido) - La dirección web a obtener
  • outputFormat - Formato de salida: markdown (predeterminado), text, o html
  • waitMs - Tiempo extra para esperar después de que la página cargue, en caso de que el contenido aparezca lentamente
  • timeoutMs - Cuánto tiempo esperar antes de rendirse (predeterminado: 15 segundos)
  • maxChars - Cantidad máxima de contenido a devolver (predeterminado: 40,000 caracteres)
  • includeHtml - Establecer en true para devolver también el HTML sin procesar junto con el contenido
  • headless - Establecer en false para ver la ventana del navegador (útil para depuración)

Devuelve:

  • url - La URL que fue solicitada
  • finalUrl - La URL después de cualquier redirección
  • title - El título de la página
  • content - El contenido extraído (en el formato solicitado)
  • html - HTML sin procesar (solo si includeHtml es verdadero)
  • meta - Metadatos de la página (descripción, autor, fecha de publicación, etc.)
  • fetchedAt - Marca de tiempo ISO de cuándo se obtuvo la página
  • truncated - Si el contenido fue truncado para ajustarse a maxChars

friendly_search

Busca en la web y devuelve una lista de resultados.

Parámetros:

  • query (requerido) - Qué buscar
  • engine - Qué motor de búsqueda usar (duckduckgo o google)
  • maxResults - Cuántos resultados devolver (predeterminado: 10, máximo: 50)
  • timeoutMs - Cuánto tiempo esperar antes de rendirse (predeterminado: 15 segundos)
  • headless - Establecer en false para ver la ventana del navegador

Devuelve:

  • query - La consulta de búsqueda que se usó
  • engine - Qué motor de búsqueda se usó
  • results - Arreglo de resultados, cada uno con title, url, y snippet
  • searchedAt - Marca de tiempo ISO de cuándo se realizó la búsqueda
  • fallback_result_html - HTML sin procesar de la página (solo se incluye si no se encontraron resultados)
  • debug_info - Información de diagnóstico sobre el intento de búsqueda

Manejo de CAPTCHA: Si se detecta un CAPTCHA mientras se ejecuta en modo sin cabeza, la herramienta reintenta automáticamente con una ventana de navegador visible. Esto te da la oportunidad de resolver el CAPTCHA manualmente. El campo debug_info.retried indica si se usó este respaldo.

friendly_web_extract

Extrae contenido de una URL. Detecta automáticamente si la URL apunta a un PDF o a una página web y maneja cada uno apropiadamente.

Parámetros:

  • url (requerido) - La URL a obtener (PDF o página web)
  • maxChars - Cantidad máxima de texto a devolver (predeterminado: 40,000 caracteres)
  • offset - Posición de carácter desde la cual comenzar (predeterminado: 0). Úsalo para paginar a través de contenido extenso.
  • search - Buscar una frase y devolver coincidencias con contexto circundante en lugar del contenido completo
  • contextChars - Caracteres de contexto alrededor de cada coincidencia de búsqueda (predeterminado: 200)
  • waitMs - Tiempo extra para esperar después de la carga de la página para contenido dinámico (solo páginas web)
  • timeoutMs - Cuánto tiempo esperar antes de rendirse (predeterminado: 15 segundos, solo páginas web)
  • headless - Establecer en false para ver la ventana del navegador (solo páginas web)

Devuelve (modo normal):

  • url - La URL que fue solicitada
  • contentType - Ya sea pdf o html
  • title - El título de la página/documento
  • author - El autor del PDF (solo PDFs, si está disponible)
  • creationDate - Cuándo se creó el PDF (solo PDFs, si está disponible)
  • pageCount - Número de páginas (solo PDFs)
  • totalChars - Total de caracteres (úselo con offset para paginar)
  • offset - El desplazamiento que se usó
  • content - El contenido de texto extraído
  • fetchedAt - Marca de tiempo ISO
  • truncated - Si queda más contenido después de este fragmento

Devuelve (modo búsqueda):

  • url, contentType, title, totalChars, fetchedAt - Igual que arriba
  • search - La frase de búsqueda que se usó
  • matchCount - Número de coincidencias encontradas
  • matches - Arreglo de coincidencias, cada una con position, context, prefix, y suffix

friendly_web_ask

Obtiene una URL (PDF o página web) y hace que un LLM responda preguntas al respecto. Detecta automáticamente el tipo de contenido. El documento se procesa en un contexto separado, manteniendo tu conversación principal compacta.

Parámetros:

  • url (requerido) - La URL a obtener (PDF o página web)
  • ask (requerido) - Pregunta o instrucción para el LLM (resumir, extraer información, responder preguntas, etc.)
  • askMaxInputTokens - Tokens de entrada máximos por llamada al LLM (predeterminado: 150,000)
  • askMaxOutputTokens - Tokens de salida máximos por llamada al LLM (predeterminado: 4,096)
  • askTimeout - Tiempo de espera en milisegundos (predeterminado: 300,000 = 5 minutos)
  • askSplitAndSynthesize - Para documentos grandes: dividir en fragmentos, procesar cada uno, luego sintetizar resultados (predeterminado: falso). Advertencia: consume muchos tokens.
  • waitMs - Tiempo extra para esperar después de la carga de la página para contenido dinámico (solo páginas web)
  • timeoutMs - Cuánto tiempo esperar antes de rendirse (predeterminado: 15 segundos, solo páginas web)
  • headless - Establecer en false para ver la ventana del navegador (solo páginas web)

Devuelve:

  • url - La URL que fue solicitada
  • contentType - Ya sea pdf o html
  • title - El título de la página/documento
  • totalChars - Total de caracteres en el documento
  • ask - La instrucción que se dio
  • answer - La respuesta del LLM
  • model - El modelo que generó la respuesta
  • chunksProcessed - Número de fragmentos procesados (1 para documentos pequeños, más cuando se usa askSplitAndSynthesize)
  • fetchedAt - Marca de tiempo ISO

El modo Ask usa muestreo MCP para que un LLM procese el documento con cualquier instrucción. Esto es útil para:

  • Documentos grandes que abrumarían el contexto
  • Mantener bajos los costos de tokens en la conversación principal

Cuando askSplitAndSynthesize está habilitado, los documentos que exceden askMaxInputTokens se dividen automáticamente en fragmentos superpuestos. Cada fragmento se procesa por separado, y los resultados se sintetizan en una sola respuesta coherente. La respuesta final se proporciona en el mismo idioma que tu solicitud, independientemente del idioma del documento.

Archivo de documentos

El archivo es una biblioteca local de documentos con capacidad de búsqueda. Admite PDFs, archivos HTML y texto plano (Markdown/TXT). Cuando agregas un documento, Research Friend almacena el archivo original, extrae texto (para PDFs/HTML) y guarda metadatos en una base de datos local. Las búsquedas usan ripgrep internamente para una coincidencia rápida y consciente de frases.

Ubicación del archivo

El archivo reside en ~/.research-friend/:

  • inbox/ - Coloca archivos aquí para ser procesados
  • store/ - Almacenamiento organizado de documentos y texto extraído
  • stash.db - Base de datos de metadatos

Tipos de archivo admitidos

  • PDF: .pdf (texto extraído)
  • HTML: .html, .htm (texto extraído)
  • Markdown: .md, .markdown (almacenado como texto plano)
  • Texto: .txt (almacenado como texto plano)

Herramientas del archivo

stash_open_inbox

Abre la carpeta de bandeja de entrada del archivo en tu administrador de archivos para facilitar el arrastrar y soltar.

Devuelve:

  • opened - Si se envió la solicitud de apertura de carpeta
  • inboxPath - Ruta absoluta a la bandeja de entrada
  • command - Comando del SO utilizado
  • args - Argumentos del comando utilizados

stash_process_inbox

Procesa archivos en inbox/, los clasifica en temas, extrae texto y almacena resultados. Para documentos largos, la clasificación usa secciones muestreadas (inicio/medio/final más algunos fragmentos aleatorios) para mejorar la precisión del tema.

Devuelve:

  • processed - Arreglo de nombres de archivo procesados exitosamente
  • errors - Cualquier error encontrado
  • documents - Arreglo de registros de documentos creados

reindex_stash

Regenera resúmenes, reasigna temas y actualiza metadatos almacenados para documentos archivados. Si ids se omite o está vacío, todos los documentos se reindexan.

Parámetros:

  • ids - IDs de documentos a reindexar (opcional)

Devuelve:

  • reindexed - IDs de documentos reindexados
  • errors - Cualquier error encontrado
  • documents - Arreglo de registros de documentos actualizados

stash_list

Lista documentos en el archivo.

Parámetros:

  • topic - Filtrar por un tema (opcional)
  • limit - Máximo de resultados (predeterminado: 50)
  • offset - Desplazamiento de paginación (predeterminado: 0)

Devuelve:

  • type - all o topic
  • totalDocuments - Total de documentos (solo cuando type es all)
  • count - Resultados devueltos después de la paginación
  • offset - Desplazamiento de paginación utilizado
  • limit - Límite de paginación utilizado
  • topics - Resumen de temas conocidos y conteo de documentos
  • documents - Lista de documentos con metadatos (incluye isPrimary al listar un tema)

stash_search

Busca nombres de archivo y contenido en todo el archivo. Todos los términos de búsqueda deben estar presentes (lógica AND). Las coincidencias de nombre de archivo se listan primero. Usa comillas para frases exactas.

Parámetros:

  • query (requerido) - Términos de búsqueda. Usa comillas para frases: "sparkling wine"
  • topic - Filtrar por un tema (opcional)
  • ids - Filtrar por IDs de documentos específicos (opcional)
  • limit - Máximo de documentos a devolver (predeterminado: 20)
  • offset - Desplazamiento de paginación (predeterminado: 0)
  • maxMatchesPerDoc - Máximo de coincidencias por documento (predeterminado: 50)
  • context - Líneas de contexto alrededor de cada coincidencia (predeterminado: 1, máx: 5). Controla tanto qué tan cerca deben aparecer los términos para coincidir como cuánto texto circundante se devuelve. Devuelve:
  • totalMatches - Total de documentos coincidentes antes de la paginación
  • count - Resultados devueltos después de la paginación
  • results - Array de documentos, cada uno con:
    • id, filename, fileType, summary, charCount, createdAt
    • matchType - filename, content o filename+content
    • matches - Array de { line, context } para cada ubicación de coincidencia

Usa los valores de line con stash_extract para saltar directamente a las ubicaciones de coincidencia.

stash_extract

Extrae contenido de un documento guardado para leerlo. Usa los números de línea de los resultados de stash_search para saltar directamente a las coincidencias.

Parámetros:

  • id (requerido) - ID del documento de stash_list/stash_search
  • maxChars - Cantidad máxima de texto a devolver (por defecto: 40,000 caracteres)
  • offset - Posición de carácter desde donde empezar (mutuamente excluyente con line)
  • line - Número de línea desde donde empezar (mutuamente excluyente con offset)

Devuelve:

  • id, filename, fileType, summary - Metadatos del documento
  • totalChars - Total de caracteres en el documento
  • offset - Desplazamiento de carácter (incluido al usar line como referencia)
  • line - Número de línea (solo cuando se usó el parámetro line)
  • content - El contenido de texto extraído
  • truncated - Si queda más contenido después de este fragmento

stash_ask

Haz que un LLM responda preguntas sobre un documento guardado. El documento se procesa en un contexto separado, manteniendo tu conversación principal compacta.

Parámetros:

  • id (requerido) - ID del documento de stash_list/stash_search
  • ask (requerido) - Pregunta o instrucción para el LLM
  • askMaxInputTokens - Tokens de entrada máximos por llamada al LLM (por defecto: 150,000)
  • askMaxOutputTokens - Tokens de salida máximos por llamada al LLM (por defecto: 4,096)
  • askTimeout - Tiempo de espera en milisegundos (por defecto: 300,000 = 5 minutos)
  • askSplitAndSynthesize - Para documentos grandes: dividir en fragmentos, procesar cada uno y luego sintetizar resultados (por defecto: false)

Devuelve:

  • id, filename, fileType, summary - Metadatos del documento
  • totalChars - Total de caracteres en el documento
  • ask - La instrucción que se dio
  • answer - La respuesta del LLM
  • model - El modelo que generó la respuesta
  • chunksProcessed - Número de fragmentos procesados

Flujo típico

  1. Suelta archivos en ~/.research-friend/inbox/
  2. Ejecuta stash_process_inbox
  3. Usa stash_list para explorar temas
  4. Usa stash_search para encontrar documentos relevantes
  5. Usa stash_extract para leer un documento específico, o stash_ask para hacer preguntas sobre él

Solución de problemas

"El navegador se cerró inesperadamente" o errores similares

Intenta reinstalar el navegador:

npx playwright install chromium --force

En Linux, es posible que también necesites dependencias del sistema:

npx playwright install-deps chromium

El servidor no inicia

Asegúrate de estar usando Node.js 20 o más reciente:

node --version

Si tu versión es más antigua, visita nodejs.org para descargar una más nueva.

Licencia

MIT