Skip to main content
Glama

🗞️ bome-navaja

Servidor MCP para el Boletín Oficial de la Ciudad Autónoma de Melilla (BOME)

Python MCP Licencia

Pregunta por el BOME en lenguaje natural: lista boletines, lee artículos y PDF completos, busca en vivo con la misma lógica que el sitio, consulta al instante un índice local de sumarios y llega hasta 1985 con el portal antiguo de melilla.es.


📑 Índice


Related MCP server: BOE & EUR-Lex MCP Server

🧭 Qué es

bome-navaja es un programa local que tu cliente de IA (Claude Desktop, Claude Code…) lanza en tu máquina y con el que habla por el protocolo MCP. Le da al modelo acceso a bomemelilla.es: el calendario de boletines, el árbol de artículos de cada boletín, el texto completo de artículos y boletines, los PDF, el buscador del sitio y un índice local de sumarios para búsquedas instantáneas.

Cobertura (la de bomemelilla.es):

Periodo

Qué hay

Desde el 3 de enero de 2014

Los boletines ordinarios (BOME-B) y extraordinarios (BOME-BX), en el calendario y con su árbol de artículos (antes de 2018 faltan boletines)

Desde finales de 2016

Sumario de cada artículo, texto HTML completo y PDF

2014–2016

Los artículos no tienen sumario ni texto, y los PDF del boletín y de los artículos no se pueden descargar (el sitio responde 404 aunque muestre el botón). En bomemelilla.es solo se puede buscar dentro del contenido con buscar_bomes y ambito="contenido"

Para lo anterior a 2018, y para todo lo anterior a 2014, está el portal antiguo de melilla.es: boletines del 3 de enero de 1985 al 12 de marzo de 2021, con sumarios de artículos desde ~1991 y el PDF de cada página. Sus sumarios de 1991–2017 también se pueden guardar en el índice local.

bome-navaja solo lee datos públicos: no inicia sesión, no usa credenciales y no envía nada al sitio más allá de las consultas.


🧰 Herramientas

Todas devuelven un objeto con ok. Si algo falla devuelven ok: false, un error en castellano y un error_code estable (no_encontrado, cve_invalido, busqueda_invalida, lectura_invalida, argumento_invalido, error_http, sitio_bloqueando, pausa_preventiva, indice_no_disponible, y para el portal antiguo url_pdf_invalida y boletin_ambiguo…). Los mensajes de error nombran el sitio que falló (bomemelilla.es o melilla.es); nunca rompen la conversación con una excepción.

Grupo

Herramienta

Para qué sirve

Navegar

listar_bomes

Boletines publicados entre dos fechas (por defecto, los últimos 30 días; como mucho 500, del más reciente al más antiguo), cada uno con su origen; antes del 13 de marzo de 2021 añade los que solo tiene el portal antiguo

ver_bome

Un boletín con su árbol departamento → consejería → organismo → artículos; con recuperar_ocultos busca los artículos que la página omite

ver_sumario

La vista web del sumario, con la primera página de cada artículo (algunos sumarios son texto libre y dan 0 entradas: usa ver_bome)

resolver_cve

URL canónica de cualquier CVE (boletín, artículo, sumario o página). El resolutor del sitio confunde los artículos y páginas de extraordinarios (BOME-AX, BOME-PX) con los ordinarios: para BOME-AX el boletín se busca aparte, y para BOME-PX se devuelve la URL de su PDF

listar_consejerias

Consejerías de un departamento con su id, para filtrar búsquedas

listar_organismos

Organismos de una consejería con su id, para filtrar búsquedas

Leer y descargar

leer_articulo

Texto completo de un artículo, paginado

leer_boletin

Texto completo de un boletín entero (su PDF) con sus metadatos, paginado

leer_pdf

Texto del PDF de cualquier CVE, o de un PDF del portal antiguo con url, paginado

descargar_pdf

Guarda el PDF de un CVE (o de una url del portal antiguo) en la caché local y devuelve su ruta

Buscar en vivo

buscar_bomes

El buscador avanzado del sitio: devuelve boletines, 10 por página

buscar_articulos

Devuelve artículos: busca boletines, abre cada uno y se queda con los artículos cuyo sumario coincide

Índice local

buscar_en_indice

Búsqueda instantánea de artículos en el índice local de sumarios (bomemelilla.es y, una vez indexado, el portal antiguo), cada uno con su origen

estado_indice

Qué hay indexado de cada origen y cómo va la sincronización

sincronizar_indice

Arranca en segundo plano la sincronización del índice: de bomemelilla.es o, con origen="melilla.es", del portal antiguo

cancelar_sincronizacion

Pide parar la sincronización en curso, sea del origen que sea

Portal antiguo

buscar_bome_antiguo

Búsqueda literal de artículos en melilla.es (1985–2021), con sumario y PDF de cada página

ver_bome_antiguo

Un boletín del portal antiguo (por CVE o dboid): PDF entero y artículos con sus páginas

Servidor

estado_servidor

Versión, rutas de datos, SQLite disponible, guardias de los dos sitios y configuración, sin tocar la red

Los CVE tienen la forma BOME-L-AAAA-N: BOME-B-2026-6416 (boletín), BOME-BX-2026-41 (extraordinario), BOME-A-2026-1051 (artículo), BOME-S-2026-6416 (sumario), BOME-P-2026-4784 (página), BOME-PX-2021-362 (página de un extraordinario). Se aceptan en minúsculas y con espacios.


🔍 Cómo busca el sitio (y por qué importa)

Todo lo que sigue está medido contra el sitio real, no deducido de su interfaz. Condiciona cómo hay que redactar las búsquedas.

Regla

Consecuencia

Coincidencia literal por subcadena, sin distinguir tildes ni mayúsculas (la ñ cuenta como n)

"nombra" encuentra «nombramiento»; "cese" encuentra «cese», «ceses» y también «procese»

Sin sinónimos ni variantes

Busca "cese", no "destitución": esta última da 0 resultados porque el BOME no la usa. El orden de las palabras importa

El sitio ignora el texto si no recibe fecha de inicio (from)

El servidor la envía siempre (por defecto, desde el 2014-01-01 hasta hoy)

Los términos unidos con Y y los de «no contiene» se evalúan dentro de un mismo artículo

"personal eventual" Y "hacienda" no encuentra boletines donde esas palabras están en artículos distintos

El sitio ignora el O entre términos (lo trata como Y)

buscar_bomes rechaza el O; úsalo con buscar_articulos o buscar_en_indice, que lo aplican ellas mismas

Los criterios numéricos son exactos

Boletín 6416, artículo 1051, página 4784 o año 2025; 641 no encuentra el 6416

El buscador devuelve boletines, no artículos

buscar_articulos abre cada boletín para quedarse con los artículos que coinciden

La página de un boletín a veces omite artículos

buscar_articulos (y el índice) detectan los huecos de numeración y leen esos artículos de su propia página

Ejemplo: «nombramientos y ceses de personal eventual»

«Personal eventual» y «cese» deben estar en el mismo artículo; para incluir también los nombramientos hace falta un O, así que la herramienta es buscar_articulos (o buscar_en_indice si el índice ya está sincronizado). Los términos forman grupos Y separados por cada "operador": "o":

{
  "texto": "personal eventual",
  "terminos": [
    {"texto": "cese"},
    {"texto": "personal eventual", "operador": "o"},
    {"texto": "nombramiento"}
  ],
  "max_bomes": 50
}

Se lee así: (personal eventual Y cese) O (personal eventual Y nombramiento). El servidor lanza una búsqueda en el sitio por cada grupo, junta los boletines sin repetir, del más reciente al más antiguo, y devuelve cada artículo con su CVE, sumario, departamento, consejería, organismo, url y pdf_url.

Solo para los ceses, sin el O, basta con:

{"texto": "personal eventual", "terminos": [{"texto": "cese"}]}

Con esta última consulta, el sitio devolvió 12 boletines el 23 de septiembre de 2026.

TIP

buscar_articulos es lenta a propósito: una petición por boletín, con una pausa de cortesía. Está acotada por max_bomes (por defecto 20, máximo 100) y max_articulos (por defecto 100, máximo 500). Mira truncado y total_bomes antes de concluir que no hay más. Con O, total_bomes suma los resultados de cada grupo y puede contar un boletín dos veces: total_bomes_exacto es false en ese caso. Los boletines que el sitio encontró pero donde ningún sumario coincide (por ejemplo, los de 2014–2016, que no tienen sumarios) salen en bomes_sin_coincidencia.

Para buscar dentro del texto de las páginas (la única vía para 2014–2016), usa buscar_bomes con ambito="contenido"; devuelve boletines, no artículos.


📇 Índice local de sumarios

Un fichero SQLite en tu máquina con los sumarios de todos los artículos, indexado con FTS5 y el tokenizador trigram. Responde al instante y admite Y, O y «no contiene» dentro del mismo artículo, igual que buscar_articulos, pero sin tocar el sitio.

Guarda dos orígenes: bomemelilla.es (desde 2018 por defecto) y, si lo indexas, el portal antiguo de melilla.es (1991–2017 por defecto). Cada artículo de buscar_en_indice trae su origen ("bomemelilla.es" o "melilla.es"); en los del portal antiguo, url es la ficha del boletín en melilla.es y pdf_url el PDF de la página del artículo (se lee con leer_pdf y url).

coincidencia: fragmento o palabra

coincidencia

Regla

"cese" encuentra

"ano" encuentra

"fragmento" (por defecto)

Subcadena, igual que el sitio

cese, ceses, procese

año, humanos

"palabra"

Cada frase debe empezar una palabra (puede acabar a mitad de palabra)

cese, ceses

año

En los dos modos se ignoran tildes y mayúsculas, y un * final se acepta pero no cambia nada. Los términos de menos de 3 caracteres (p. ej. "de") no caben en un índice de trigramas: se resuelven recorriendo los sumarios, y funcionan igual. Otros parámetros: desde/hasta, extraordinario, consejeria (parte del nombre, sin tildes), orden ("fecha" o "relevancia", esta última aproximada), limite (máximo 200) y desplazamiento; siguiente da el desplazamiento de la página siguiente.

Sincronizar

  • Solo se sincroniza cuando el modelo llama a sincronizar_indice. El servidor nunca recorre el sitio por su cuenta, ni al arrancar.

  • La herramienta vuelve al instante; la sincronización sigue en segundo plano, del boletín más reciente al más antiguo.

  • Por defecto cubre desde el 1 de enero de 2018 hasta hoy. Antes de 2018 bomemelilla.es está incompleto e inestable (faltan boletines, sus páginas rotas responden HTTP 500 y de ahí vienen los bloqueos del cortafuegos) y casi no hay sumarios que buscar; esos boletines se consultan mejor en el portal antiguo de melilla.es. Puedes pedir un desde anterior, pero no es recomendable.

  • Va despacio a propósito (por defecto, ~2–3 s entre peticiones) y cada ejecución indexa como mucho 250 boletines (los más recientes; parámetro max_boletines), unos 15–20 minutos (más si el sitio responde con errores; ver abajo). El rango por defecto (~1.100 boletines desde 2018) necesita varias ejecuciones: si el estado final trae pendientes_tras_limite mayor que 0, vuelve a sincronizar más tarde. Espaciar las ejecuciones es más amable con el sitio. El índice completo ocupa del orden de 40–50 MB.

  • Es reanudable: cada boletín se guarda en cuanto se procesa. Si se corta, la siguiente llamada continúa donde quedó. Por defecto también reindexa los boletines de los últimos 7 días (reindexar_recientes_dias) y reintenta los que fallaron (reintentar_errores), salvo los roto.

  • Sigue el progreso con estado_indice (hechos, total_planificado, eta_segundos, rotos). Mientras tanto buscar_en_indice funciona, pero avisa de que los resultados son parciales.

  • cancelar_sincronizacion para tras el boletín en curso (o al instante si está en una pausa); lo ya indexado se conserva.

  • Cuida el cortafuegos del sitio, que bloquea la IP tras unas 5 respuestas de error (detalle en Seguridad y cortesía). Estas cifras, como el ritmo y el límite de arriba, son los valores por defecto: puedes cambiarlas en los ajustes de ritmo y protección:

    • No pasa de 3 respuestas de error cada 10 minutos: si llega al límite, hace una pausa preventiva (la indica mensaje), así que puede ir más lenta.

    • Tras una página de boletín rota (HTTP 500) hace una pausa de 30–60 s.

    • Un boletín cuya página respondió 500 dos veces queda como roto: las sincronizaciones normales lo saltan y estado_indice lo cuenta aparte, no como pendiente. reintentar_rotos: true los vuelve a pedir, pero cada uno cuesta un 500 que el cortafuegos cuenta: úsalo solo para comprobar si el sitio los arregló.

    • Si el sitio bloquea igualmente (403, 429 o 503, o dos peticiones seguidas sin respuesta), termina en estado bloqueado y bome-navaja no vuelve a pedirle nada durante 75 minutos (o más, si el sitio lo pide con Retry-After); reintentar_tras_segundos dice cuánto falta. Relánzala pasado ese tiempo: continúa donde quedó.

  • Si tienes dos clientes abiertos con bome-navaja (por ejemplo, Claude Desktop y Claude Code), solo uno sincroniza: el otro recibe en_curso_en_otro_proceso con el origen que ocupa el turno. Hay un solo turno por índice, sea cual sea el origen: mientras sincroniza bomemelilla.es no se puede sincronizar el portal antiguo, y al revés. El turno se considera abandonado si su dueño deja de dar señales durante 3 minutos.

Cada respuesta de buscar_en_indice trae un bloque cobertura (rango de fechas indexado, boletines indexados y pendientes, última sincronización, si hay una en curso, y lo indexado de cada origen en por_origen). Los pendientes cuentan solo desde 2018; los boletines anteriores que un índice de una versión previa tenga en su calendario sin indexar salen aparte en pendientes_anteriores_2018 (también en estado_indice). Si el índice está vacío, devuelve 0 resultados y un aviso que sugiere sincronizar o usar buscar_articulos mientras tanto.

Indexar el portal antiguo (melilla.es)

sincronizar_indice con origen="melilla.es" guarda en el mismo índice los sumarios de artículos del portal antiguo, para buscar con Y, O y «no contiene» en 1991–2017 y en varios años a la vez, cosa que la búsqueda del portal (literal, de una sola frase y sin paginar) no permite.

{"origen": "melilla.es"}
  • Qué indexa: los sumarios de la ficha de cada boletín (ficha_bome.jsp), con una petición por boletín y nunca los PDF. Por defecto, los boletines del 1 de enero de 1991 al 31 de diciembre de 2017: antes de 1991 las fichas no traen artículos (solo el PDF del boletín entero) y desde 2018 está bomemelilla.es. Admite otro desde/hasta.

  • El mismo ritmo y el mismo límite que la de bomemelilla.es: por defecto, 2 s más hasta 1 s aleatorio entre peticiones y como mucho 250 boletines por ejecución (max_boletines), unos 15–20 minutos. El rango por defecto tiene unos 2.000–2.500 boletines, así que hacen falta unas 8–10 ejecuciones, mejor espaciadas; pendientes_tras_limite dice cuántos quedan. Los ajustes de ritmo y protección (BOME_NAVAJA_SYNC_DELAY, BOME_NAVAJA_SYNC_MAX_BOLETINES y el resto) son los mismos para los dos orígenes.

  • Es reanudable y no repite trabajo: se salta los boletines ya indexados con sumarios (de cualquier origen) y los que el portal ya dio sin artículos. Reintenta los fallidos (reintentar_errores) y los roto solo con reintentar_rotos. reindexar_recientes_dias no se aplica: el portal está congelado.

  • Usa la guardia del portal antiguo (estado_sitio_melilla.json), no la de bomemelilla.es: termina bloqueado si melilla.es la bloquea, y sus errores no cuentan para el otro sitio.

  • Un solo turno por índice: mientras corre la sincronización de un origen, la del otro recibe en_curso_en_otro_proceso. cancelar_sincronizacion para la que esté en curso, sea del origen que sea.

  • Si un boletín está en los dos orígenes, gana el mejor resultado: con sumarios gana a sin sumarios, y este a un fallo; a igualdad, gana bomemelilla.es. Así los boletines de 2014–2016, que bomemelilla.es tiene sin sumarios, se rellenan con los del portal antiguo, y cada boletín sale una sola vez en buscar_en_indice.

  • Resultados: cada artículo trae origen: "melilla.es", url (la ficha del boletín en melilla.es) y pdf_url (el PDF de la página del artículo, para leer_pdf con url). Su bome_cve es el identificador del portal (antes de 2014 no es un CVE de bomemelilla.es; si se repite, lleva el dboid detrás, como BOME-BX-1986-1~280058) y su cve, una clave interna MEL-<dboid>-<número>. estado_indice cuenta cada origen en por_origen, guarda la última sincronización de cada uno en ultimas_sincronizaciones y muestra el origen de la que está en curso.

Dónde está y cómo rehacerlo

El índice es el fichero sumarios.sqlite3 dentro de la carpeta de datos; estado_servidor y estado_indice muestran su ruta. Para rehacerlo desde cero, cierra el cliente, borra sumarios.sqlite3 (y sumarios.sqlite3-wal / sumarios.sqlite3-shm si existen) y vuelve a llamar a sincronizar_indice. Un índice de una versión anterior de bome-navaja se migra solo al abrirlo, sin volver a descargar nada; los boletines que tenían anotado un HTTP 500 pasan a roto.


🏛️ Portal antiguo (melilla.es)

bomemelilla.es es una migración incompleta antes de 2018: de 2014 a 2017 le faltan 141 boletines (y ahí se concentran sus páginas rotas), y no tiene nada anterior a 2014. El portal antiguo del BOME en melilla.es, congelado desde marzo de 2021, conserva el catálogo entero: 3.260 boletines del 3 de enero de 1985 al 12 de marzo de 2021, con sumarios de artículos desde ~1991 y el PDF de cada página.

Qué quieres

Herramienta

Saber qué boletines hay en unas fechas

listar_bomes: antes del 13 de marzo de 2021 junta los dos catálogos (si un boletín está en los dos gana bomemelilla.es); los que solo tiene el portal antiguo traen origen: "melilla.es", su dboid y ver_con

Buscar artículos

buscar_bome_antiguo: búsqueda literal en el texto de los artículos (3–200 caracteres; no busca por número de boletín). El portal devuelve todo en una sola página, así que conviene usar términos concretos. Cada artículo trae boletín, fecha, número, tipo, sumario, consejería/dirección/sección y el PDF de cada página. Filtra por fechas (desde/hasta) y devuelve como mucho limite artículos (por defecto 100, máximo 500) con total y truncado

Ver un boletín

ver_bome_antiguo con cve o dboid: el PDF del boletín entero y sus artículos con sus páginas

Buscar con Y, O o «no contiene», o en varios años a la vez

buscar_en_indice, después de indexar el portal antiguo con sincronizar_indice y origen="melilla.es" (1991–2017 por defecto)

Leer o guardar un PDF

leer_pdf / descargar_pdf con url (solo las URL https://www.melilla.es/mandar.php/... que dan las dos herramientas anteriores)

Si ver_bome no encuentra un boletín anterior a 2022 en bomemelilla.es, su error sugiere ver_bome_antiguo.

Identificadores. Desde 2014 la numeración del portal antiguo coincide con los CVE de bomemelilla.es (BOME-B-2016-5302, BOME-BX-2021-16). Antes de 2014 los identificadores tienen la misma forma pero no son CVE de bomemelilla.es (cve_oficial: false) y algunos se repiten (24 casos, por ejemplo dos «Extra 1» en 1986): ver_bome_antiguo responde entonces boletin_ambiguo con los candidatos (dboid, fecha, sufijo), y basta con repetir con el dboid. Además, 14 boletines tienen una fecha distinta en cada sitio (por ejemplo BOME-B-2015-5230: 17-12-2015 en bomemelilla.es y 01-05-2015 en melilla.es); cita la fecha junto al origen.

robots.txt y política de uso. El robots.txt de melilla.es no permite a los robots las fichas de boletín (ficha_bome.jsp) ni los PDF (/mandar.php). Las herramientas solo los piden bajo demanda: cuando el modelo llama a una para responderte, una petición cada vez. Desde la versión 0.0.4 hay una excepción deliberada, porque el portal está congelado y puede desaparecer: la indexación del portal antiguo recorre las fichas en masa, pero solo cuando se pide con sincronizar_indice y origen="melilla.es" (nunca por su cuenta), despacio (por defecto, ~2–3 s entre peticiones), con un máximo de 250 boletines por ejecución (también por defecto) y bajo la guardia del portal. Los PDF nunca se recorren en masa: solo se piden bajo demanda.

Su propia guardia y su caché. El portal antiguo es otro sitio, así que tiene su propia guardia con las mismas reglas y los mismos ajustes (por defecto, como mucho 3 respuestas de error cada 10 minutos y 75 minutos sin pedirle nada si bloquea), guardada aparte en estado_sitio_melilla.json; sus errores nunca cuentan para bomemelilla.es, y estado_servidor la muestra en guardia_portal_antiguo. Sus herramientas van a su propio ritmo (~1–1,5 s entre peticiones, de una en una), que no se puede ajustar. El catálogo (~1 MB) se descarga con una sola petición la primera vez que hace falta y se guarda en catalogo_portal_antiguo.json; como el portal está congelado, se reutiliza siempre (estado_servidor lo muestra en catalogo_portal_antiguo; borrarlo fuerza una nueva descarga). Si el portal no responde, listar_bomes devuelve igualmente lo de bomemelilla.es con un aviso.


📖 Leer documentos largos

leer_articulo, leer_boletin y leer_pdf comparten el mismo cursor, así que un boletín de ~35 páginas nunca llega recortado en silencio:

Campo

Significado

max_caracteres

Presupuesto por llamada: entre 1000 y 100000 (por defecto 20000); un valor fuera de rango se ajusta al límite más cercano

paginas

Páginas enteras hasta llenar el presupuesto, siempre al menos una

siguiente

{desde_pagina, desde_caracter} para la siguiente llamada, o null si no queda nada

cortada

true si una página sola no cabía y se entregó un trozo; siguiente apunta dentro de esa página

sin_texto

true en páginas sin texto extraíble (escaneadas); viene con un aviso

completo

true solo si todo el documento cupo en una respuesta

Para seguir leyendo, pasa desde_pagina y desde_caracter tal cual vienen en siguiente.

leer_articulo acepta el CVE del artículo (BOME-A-2026-1051) o el del boletín más numero. Para los artículos de 2014–2016, que no tienen texto, responde con fuente: "ninguna" y un aviso.


💾 PDF descargados

  • descargar_pdf (y los lectores cuando hace falta) guardan cada PDF en la carpeta de PDF, por defecto pdfs/ dentro de la carpeta de datos.

  • El nombre del fichero es siempre el CVE canónico (BOME-P-2026-4784.pdf) o, para un PDF del portal antiguo, la ruta de su URL ya validada (https://www.melilla.es/mandar.php/n/9/4914/5302_73.pdf → melilla-9-4914-5302_73.pdf): nunca sale de datos del servidor ni de lo que escriba el modelo, y no hay parámetro para elegir otra ruta. Solo tú puedes moverla, con BOME_NAVAJA_PDF_DIR.

  • Del portal antiguo solo se aceptan URL https://www.melilla.es/mandar.php/n/<número>/<número>/<nombre>.pdf (sus enlaces http:// se pasan a https); cualquier otra se rechaza con url_pdf_invalida sin tocar la red.

  • Una copia válida en caché se reutiliza; refrescar: true fuerza la descarga. La escritura es atómica, y una descarga fallida conserva la copia anterior.

  • Límite: 100 MB por PDF (documento_demasiado_grande). Como referencia, un boletín ordinario ronda los 4 MB.


📂 Dónde guarda los datos

Sistema

Carpeta de datos por defecto

Windows

%LOCALAPPDATA%\bome-navaja (o ~\AppData\Local\bome-navaja si la variable no existe)

macOS

~/Library/Application Support/bome-navaja

Linux y otros

$XDG_DATA_HOME/bome-navaja o, si no está definida, ~/.local/share/bome-navaja

Dentro están el índice (sumarios.sqlite3), los PDF (pdfs/), el estado de la guardia del sitio (estado_sitio.json, y estado_sitio_melilla.json para el portal antiguo) y la caché del catálogo del portal antiguo (catalogo_portal_antiguo.json). Nada se crea hasta que hace falta.

Variable

Efecto

BOME_NAVAJA_DATA_DIR

Cambia la carpeta de datos entera (índice y, salvo otra indicación, PDF)

BOME_NAVAJA_PDF_DIR

Cambia solo la carpeta de PDF

Una ruta relativa en estas variables se resuelve contra el directorio de trabajo del proceso, y estado_servidor lo indica en el motivo de cada ruta; ~ se expande a tu carpeta de usuario. Un XDG_DATA_HOME relativo se ignora, como manda la especificación XDG. Con el paquete .mcpb, el ajuste Carpeta de datos fija BOME_NAVAJA_DATA_DIR; vacío equivale a no definirla.


🚀 Instalación

Hay tres caminos, de menos a más técnico. Todos necesitan uv salvo el paquete .mcpb, que Claude Desktop gestiona solo.

Opción A — Paquete .mcpb para Claude Desktop

  1. Consigue el paquete. Descarga bome-navaja-<versión>.mcpb desde la sección Releases del repositorio (la primera es v0.0.1). Otras opciones:

    • El artefacto bome-navaja-mcpb de una ejecución en verde del flujo CI (pestaña Actions del repositorio), para probar una versión sin publicar.

    • O constrúyelo desde un clon (necesitas uv y Node.js con npx): scripts/build_mcpb.sh en macOS/Linux o scripts\build_mcpb.ps1 en Windows PowerShell. El resultado queda en dist/bome-navaja-<versión>.mcpb (unos 70 KB).

  2. Haz doble clic en el archivo, o arrástralo a la ventana de Claude Desktop. Aparece el diálogo de instalación con las 19 herramientas.

  3. Opcional: en Carpeta de datos elige dónde guardar el índice y los PDF. Si la dejas vacía se usa la carpeta por defecto de tu sistema. Los demás ajustes (el ritmo con que se piden páginas y la protección frente al bloqueo del sitio) ya traen los valores recomendados: no los hagas más agresivos sin leer antes Ajustes de ritmo y protección.

  4. Acepta y reinicia Claude por completo si te lo pide.

La primera vez que arranca, Claude Desktop instala Python y las dependencias por su cuenta (unos segundos). Desde la versión 0.0.5 el paquete incluye uv.lock, así que instala las mismas versiones de las dependencias con las que se probó esa versión.

NOTE

El paqueteno está firmado, así que Claude Desktop puede mostrar una advertencia al instalarlo.

Requisito: uv

Para las opciones B y C, bome-navaja no necesita que instales Python: uv lo baja solo, junto con las dependencias, la primera vez. Instálalo una vez:

# macOS y Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Cierra y vuelve a abrir la terminal después de instalarlo.

Opción B — Claude Code

claude mcp add bome-navaja -- uvx --from git+https://github.com/jgarcialaneitor/bome-navaja bome-navaja-mcp
IMPORTANT

El repositorio esprivado por ahora: uvx necesita que tu git tenga acceso a él (credenciales de GitHub configuradas). Si no lo tiene, clona el repositorio y usa la variante con uv run --directory de la opción C.

Opción C — Configuración manual de Claude Desktop

  1. En Claude Desktop, ve a Settings → Developer → Edit Config para abrir claude_desktop_config.json:

    • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

    • Windows: %APPDATA%\Claude\claude_desktop_config.json

  2. Añade la entrada dentro de mcpServers:

{
  "mcpServers": {
    "bome-navaja": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/jgarcialaneitor/bome-navaja",
        "bome-navaja-mcp"
      ]
    }
  }
}

O, desde un clon local (por ejemplo, si no tienes acceso git al repositorio privado):

{
  "mcpServers": {
    "bome-navaja": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "/ruta/a/tu/clon/bome-navaja",
        "bome-navaja-mcp"
      ],
      "env": {
        "BOME_NAVAJA_DATA_DIR": "/ruta/opcional/para/los/datos"
      }
    }
  }
}

La clave env es opcional; en ella también van los ajustes de ritmo y protección.

  1. Guarda y cierra Claude por completo (no solo la ventana). Al reabrirlo deben aparecer las herramientas de bome-navaja.

Comprobar que quedó bien

Pídele al asistente:

Ejecuta estado_servidor de bome-navaja.

Debe responder con la versión, las rutas de datos, PDF e índice (y por qué se eligió cada una), si SQLite tiene FTS5 y trigram, y los ajustes en uso con sus avisos (ajustes). No toca la red ni crea el índice. Luego prueba una búsqueda real:

Busca en el BOME los artículos sobre ceses de personal eventual y cita sus CVE.

🔒 Seguridad y cortesía con el sitio

Las cifras de esta sección son los valores por defecto, que son también los recomendados; cómo cambiarlas y qué arriesgas al hacerlo está en Ajustes de ritmo y protección.

  • Pausa de cortesía entre peticiones en las herramientas (~0,5 s por defecto), con tiempos de espera acotados (30 s por defecto).

  • Un único cliente serializado para todas las herramientas: aunque el modelo lance varias a la vez, las peticiones al sitio salen de una en una.

  • La sincronización del índice va más despacio: por defecto, su propio cliente espera 2 s más una variación aleatoria de hasta 1 s entre peticiones, indexa como mucho 250 boletines por ejecución y se detiene sola (estado bloqueado) si el sitio la bloquea. La del portal antiguo va igual.

  • Guardia del sitio. El cortafuegos de bomemelilla.es bloquea la IP (en torno a una hora) tras unas 5 respuestas de error, por despacio que vayan las peticiones, y muchas son HTTP 500 de páginas de boletín rotas del propio sitio. Para no llegar a eso:

    • Entre todas las herramientas y la sincronización se admiten como mucho 3 respuestas de error (cualquier 4xx o 5xx) cada 10 minutos (valores por defecto); con el cupo lleno, la sincronización espera y las herramientas responden pausa_preventiva con reintentar_tras_segundos, sin tocar el sitio.

    • La sincronización hace una pausa de 30–60 s (por defecto) tras una página rota y no vuelve a pedir un boletín roto (su página respondió 500 dos veces) salvo con reintentar_rotos.

    • Si el sitio bloquea igualmente (403, 429 o 503, o dos peticiones seguidas sin respuesta), bome-navaja deja de tocarlo durante 75 minutos por defecto (o más, si pide Retry-After): las herramientas responden sitio_bloqueando con reintentar_tras_segundos y la sincronización termina bloqueado.

    Todos los procesos de bome-navaja comparten esta guardia y se conserva entre reinicios: vive en estado_sitio.json, en la carpeta de datos. estado_servidor la muestra en guardia_sitio. El portal antiguo de melilla.es tiene otra guardia igual pero aparte (estado_sitio_melilla.json, guardia_portal_antiguo).

  • Portal antiguo: sus PDF (que su robots.txt no permite a los robots) se piden solo bajo demanda, cuando una herramienta los necesita para responderte, nunca en masa. Sus fichas (que tampoco permite) solo se recorren en masa con la indexación del portal antiguo, que arranca solo a mano, va despacio y tiene límite por ejecución; ver Portal antiguo.

  • No recorre el sitio si no se le pide: nada al arrancar, y la sincronización solo con sincronizar_indice. Nunca corren dos sincronizaciones a la vez sobre el mismo índice, ni de dos procesos ni de dos orígenes.

  • Se identifica con un User-Agent de navegador real y no usa ni guarda credenciales.

  • El modelo no elige dónde se escribe: los PDF se nombran por su CVE canónico dentro de la carpeta configurada, y las rutas solo las cambias tú con variables de entorno.

  • stdout lleva exclusivamente JSON-RPC; los mensajes para personas van a stderr.

Ajustes de ritmo y protección

WARNING

Uso responsable. El cortafuegos de bomemelilla.es bloquea tu IP durante cerca de 1 hora tras unas 5 respuestas de error en poco tiempo, vayas al ritmo que vayas. Los valores por defecto son los recomendados y están pensados para no llegar ahí. Si pones valores más agresivos, tu IP puede acabar bloqueada y cargas más un servicio público que usa mucha gente. El servidor acepta cualquier valor válido, pero estado_servidor te lo advierte: ajustes.riesgos lista los valores más arriesgados que lo recomendado, y ajustes.avisos los que no son válidos (no son un número, son negativos, son cero donde no puede funcionar…), que se ignoran y se sustituyen por el valor por defecto.

Los nueve ajustes son los mismos para bomemelilla.es y para el portal antiguo de melilla.es (cada sitio con su propia guardia). Los cambios se aplican al reiniciar la extensión (o el servidor MCP en otros clientes): el servidor los lee una sola vez por proceso.

  • Con el paquete .mcpb: en Claude Desktop, abre la configuración de la extensión BOME Melilla — Boletín Oficial de Melilla. Cada ajuste aparece con el nombre de la tabla y una descripción con lo que hace, lo que arriesgas y el valor recomendado.

  • Con otros clientes (Claude Code, la configuración manual…): define las variables de entorno de la tabla en la configuración del servidor, por ejemplo en la clave env:

"env": {
  "BOME_NAVAJA_SYNC_DELAY": "3",
  "BOME_NAVAJA_SYNC_MAX_BOLETINES": "100"
}

Una variable vacía o sin definir usa el valor por defecto. Los decimales admiten punto o coma (0.5 o 0,5), y los recuentos, un entero escrito como 250.0. Un tiempo de más de un día (24 horas) no es válido: se usa el valor por defecto. estado_servidor muestra los valores en uso en ajustes (y el ritmo de la sincronización en cortesia_sincronizacion y cortesia_sincronizacion_portal_antiguo).

Ajuste en Claude Desktop y variable

Por defecto (recomendado)

Qué hace

Si lo haces más agresivo

Pausa entre peticiones al sincronizar (segundos)BOME_NAVAJA_SYNC_DELAY

2 (2 o más)

Segundos de espera entre cada página que pide la sincronización del índice, de los dos orígenes

Si la bajas, sincroniza antes, pero pide páginas más deprisa y el cortafuegos puede bloquear tu IP

Variación al azar de la pausa al sincronizar (segundos)BOME_NAVAJA_SYNC_JITTER

1 (1 o más)

Hasta cuántos segundos al azar se suman a cada pausa de la sincronización, para no pedir a un ritmo fijo

Si la bajas, el ritmo es más regular, más fácil de tomar por un robot y de bloquear

Máximo de boletines por sincronizaciónBOME_NAVAJA_SYNC_MAX_BOLETINES

250 (250 o menos)

Cuántos boletines procesa como mucho cada ejecución de sincronizar_indice sin max_boletines; los que falten quedan para la siguiente

Si lo subes, cada ejecución hace más peticiones seguidas y aumenta el riesgo de bloqueo

Pausa entre peticiones en las consultas (segundos)BOME_NAVAJA_QUERY_DELAY

0.5 (0,5 o más)

Segundos de espera entre peticiones de las herramientas que consultan bomemelilla.es en vivo (buscar, abrir boletines, leer artículos). Las del portal antiguo van a su propio ritmo, que no cambia

Si la bajas, las respuestas llegan antes, pero el sitio puede bloquear tu IP

Errores del sitio tolerados antes de pararBOME_NAVAJA_GUARD_MAX_ERRORS

3 (3 o menos)

Cuántas respuestas de error (4xx o 5xx) admite la guardia dentro de la ventana antes de hacer una pausa preventiva

Si lo subes, deja menos margen frente al bloqueo; con 5 o más ya no para antes de que el sitio bloquee tu IP

Ventana para contar los errores del sitio (minutos)BOME_NAVAJA_GUARD_WINDOW_MINUTES

10 (10 o más)

Minutos durante los que la guardia recuerda cada respuesta de error para contarla

Si la acortas, los errores se olvidan antes y caben más en poco tiempo, lo que acerca el bloqueo

Espera tras una señal de bloqueo (minutos)BOME_NAVAJA_GUARD_COOLDOWN_MINUTES

75 (75 o más)

Minutos sin pedir nada al sitio cuando da señales de bloqueo (403, 429 o 503, o dos peticiones seguidas sin respuesta), o más si lo pide con Retry-After

El bloqueo dura cerca de 1 hora: si esperas menos (sobre todo menos de 60), vuelves a un sitio que aún te bloquea y puedes alargar el bloqueo

Pausa tras un error del sitio al sincronizar (segundos)BOME_NAVAJA_ERROR_PAUSE_SECONDS

30 (30 o más)

Pausa mínima de la sincronización tras una página rota; la real es al azar entre este valor y el doble (30–60 s por defecto)

Si la bajas, vuelve a pedir antes, y varios errores seguidos provocan el bloqueo de tu IP

Tiempo máximo de espera de cada petición (segundos)BOME_NAVAJA_TIMEOUT

30 (30 o más)

Segundos que se espera la respuesta de cualquiera de los dos sitios antes de dar la petición por fallida

Si lo bajas, un sitio lento puede parecer bloqueado: dos peticiones seguidas sin respuesta se toman como bloqueo y se deja de pedir durante la espera tras bloqueo


🧪 Desarrollo

uv sync
uv run pytest                          # determinista, contra respuestas guardadas del sitio
BOME_NAVAJA_LIVE=1 uv run pytest       # además, los tests marcados live contra el sitio real

Los tests live consultan bomemelilla.es y se omiten salvo que definas BOME_NAVAJA_LIVE=1; la CI nunca los ejecuta.

Para construir el paquete .mcpb: scripts/build_mcpb.sh (macOS/Linux) o scripts\build_mcpb.ps1 (Windows). Ambos preparan build/mcpb con scripts/build_mcpb.py, validan el manifiesto con npx @anthropic-ai/mcpb validate y empaquetan en dist/. El manifiesto parte de mcpb/manifest.template.json.

La CI (.github/workflows/ci.yml) tiene cuatro trabajos:

Trabajo

Qué hace

test

uv run pytest en Ubuntu

test-windows

uv run pytest en Windows

bundle

Construye el .mcpb en Ubuntu y lo publica como artefacto bome-navaja-mcpb

bundle-windows

Construye el .mcpb con el script de PowerShell en Windows


🚧 Limitaciones conocidas

  • El O del sitio no funciona: su buscador trata el O como Y. buscar_bomes lo rechaza; el O solo funciona en buscar_articulos y buscar_en_indice.

  • Artículos ocultos en los extremos: los artículos que la página del boletín omite se recuperan cuando dejan un hueco en la numeración, pero no se detectan si faltan al principio o al final del boletín.

  • 2014–2016 sin texto ni PDF: solo se puede buscar en el contenido con buscar_bomes y ambito="contenido".

  • El índice solo cubre sumarios, no el texto completo de los artículos ni de los PDF. Del portal antiguo solo tiene lo que hayas indexado con sincronizar_indice y origen="melilla.es" (1991–2017 por defecto, en varias ejecuciones); los boletines anteriores a ~1991 no tienen sumarios en el portal.

  • Portal antiguo: su búsqueda es literal y sin paginar (una búsqueda muy genérica puede superar el límite de 15 MB y pide términos más concretos); los identificadores anteriores a 2014 no son CVE de bomemelilla.es y algunos se repiten; 14 boletines tienen una fecha distinta en cada sitio.

  • Claves mixtas: algunas respuestas (ver_bome, ver_sumario, listar_bomes) usan claves en inglés (number, date, sections) junto a las castellanas del resto.

  • Política de privacidad: el sitio no publica un aviso legal, así que el enlace de privacidad del paquete .mcpb apunta a su política de cookies.


📜 Licencia

MIT. Consulta LICENSE.

Available Tools

19 tools
buscar_articulosA

Búsqueda en vivo de ARTÍCULOS por su sumario: busca boletines en el sitio, abre cada uno y devuelve los artículos cuyo sumario coincide.

Misma semántica que el sitio (subcadena sin tildes ni mayúsculas; Y dentro del mismo artículo) y además admite O: terminos=[{texto, operador: "y"|"o", modo: "contiene"|"no_contiene"}]. Lenta (una petición por boletín, ~0,5 s): acotada por max_bomes (por defecto 20, máx. 100) y max_articulos (por defecto 100, máx. 500); mira 'truncado' y 'total_bomes'. Si el índice local está sincronizado, buscar_en_indice es instantánea. Recupera artículos que la página del boletín omite. Los boletines sin coincidencia local salen en 'bomes_sin_coincidencia'.

Inputs: anio, desde, hasta, texto, +8 more.

buscar_bome_antiguoA

Busca artículos en el portal antiguo del BOME (melilla.es): boletines de 1985 al 12-03-2021, con sumarios de artículos desde ~1991.

Úsalo para cualquier cosa anterior a 2018 (bomemelilla.es está incompleto ahí y no tiene nada antes de 2014). Búsqueda literal de texto en los artículos (3-200 caracteres, sin distinguir mayúsculas; no busca por número de boletín: para eso usa ver_bome_antiguo o listar_bomes). El portal devuelve TODO en una sola página, así que usa términos concretos. Cada artículo trae cve_boletin, fecha, numero, tipo, sumario, ruta (consejería, dirección, sección), paginas (número y url_pdf de cada página: léelas con leer_pdf(url=...)), dboid_boletin y url_ficha. desde/hasta (AAAA-MM-DD o DD/MM/AAAA) filtran por la fecha del boletín después de buscar. Devuelve como mucho limite artículos (por defecto 100, máx. 500) en el orden del portal; 'total' cuenta los que pasan el filtro y 'truncado' dice si hay más: acota el texto o las fechas.

Inputs: texto (required), desde, hasta, limite.

buscar_bomesA

Búsqueda en vivo en el buscador avanzado del sitio: devuelve BOLETINES (10 por página).

texto: frase literal (subcadena, sin tildes ni mayúsculas). ambito: "sumario" (sumarios de artículos, desde finales de 2016) o "contenido" (texto de las páginas, única forma de buscar en 2014-2016). terminos: más frases [{texto, modo: "contiene"|"no_contiene", ambito?}], todas con Y y en el MISMO artículo; el sitio ignora el O, así que se rechaza (usa buscar_articulos). Fechas AAAA-MM-DD o DD/MM/AAAA (por defecto 2014-01-01..hoy). Filtros por id (listar_consejerias/listar_organismos) y números exactos. Para ver qué artículos coinciden usa buscar_articulos o buscar_en_indice.

Inputs: anio, desde, hasta, texto, +9 more.

buscar_en_indiceA

Búsqueda instantánea de artículos en el índice local de sumarios (sin tocar el sitio).

Requiere haber llamado antes a sincronizar_indice; si el índice está vacío devuelve 0 resultados y un aviso (usa buscar_articulos mientras tanto). Mira 'cobertura' (rango indexado, pendientes, sincronización en curso) antes de afirmar que algo no existe. La sincronización por defecto cubre desde 2018-01-01: 'pendientes' cuenta solo boletines desde esa fecha y pendientes_anteriores_2018 los anteriores del calendario sin indexar (bomemelilla.es está incompleto antes de 2018; esos boletines se consultan mejor en el portal antiguo de melilla.es). Incluye también los boletines del portal antiguo (melilla.es, 1991-2017) una vez sincronizados con sincronizar_indice(origen="melilla.es"): cada artículo trae 'origen' ("bomemelilla.es" o "melilla.es"); en los de melilla.es, url es la ficha del boletín en el portal antiguo, pdf_url el PDF de la página del artículo (léelo con leer_pdf(url=...)), bome_cve el identificador del portal (antes de 2014 no es un CVE de bomemelilla.es) y cve una clave interna MEL--. cobertura.por_origen da lo indexado de cada origen. Un boletín que está en los dos sale una sola vez, del origen con mejor resultado (con sumarios gana; a igualdad, bomemelilla.es). coincidencia: "fragmento" (subcadena, como el sitio: "cese" encuentra "ceses" y "procese") o "palabra" (cada frase debe empezar una palabra: "cese" → cese, ceses, no procese). terminos=[{texto, operador: "y"|"o", modo: "contiene"|"no_contiene"}]; Y dentro del mismo artículo. consejeria: parte del nombre (sin tildes). orden: "fecha" o "relevancia". Pagina con limite (máx. 200) y desplazamiento ('siguiente' da el próximo). Solo cubre sumarios: de bomemelilla.es desde finales de 2016 y del portal antiguo desde ~1991.

Inputs: desde, hasta, orden, texto, +6 more.

cancelar_sincronizacionA

Pide parar la sincronización en curso de este proceso, sea cual sea su origen (bomemelilla.es o el portal antiguo melilla.es: cualquiera de las dos, solo corre una a la vez); termina tras el boletín que esté procesando (o al instante si está en una pausa: preventiva o tras una página rota del sitio).

Devuelve el estado de esa sincronización, con su 'origen'. Lo ya indexado se conserva y una nueva sincronizar_indice (con el mismo origen) continúa desde ahí.

Inputs: no named parameters.

descargar_pdfA

Descarga el PDF de cualquier CVE (o, con url, uno del portal antiguo de melilla.es) a la caché local y devuelve su ruta, tamaño, sha256 y número de páginas.

Da exactamente uno: cve, o url (solo las URL https://www.melilla.es/mandar.php/... que devuelven buscar_bome_antiguo y ver_bome_antiguo). El nombre del fichero sale solo del CVE canónico o de la ruta de esa URL (melilla-9-4914-5302_73.pdf); el directorio lo fija BOME_NAVAJA_PDF_DIR (ver estado_servidor). Reutiliza la copia en caché salvo refrescar=true. Límite: 100 MB. Los PDF de 2014-2016 no existen en bomemelilla.es (404): búscalos en el portal antiguo.

Inputs: cve, url, refrescar.

estado_indiceA

Estado del índice local de sumarios y de su sincronización (no toca el sitio).

Devuelve boletines indexados / sin sumarios / con error / rotos (páginas que el sitio respondió con error interno dos veces; no cuentan como pendientes), artículos, rango de fechas, pendientes frente al calendario, última sincronización y el progreso de la actual (hechos, total_planificado, eta_segundos). 'pendientes' cuenta solo boletines desde 2018-01-01 (el inicio por defecto de sincronizar_indice); los anteriores del calendario sin indexar (de sincronizaciones antiguas o con un 'desde' anterior) salen aparte en pendientes_anteriores_2018 y no son trabajo pendiente. Úsalo para seguir una sincronización lanzada con sincronizar_indice. Por origen: indice.por_origen cuenta boletines, artículos y fechas de cada origen ("bomemelilla.es" y "melilla.es", el portal antiguo) e indice.ultimas_sincronizaciones guarda el resumen de la última sincronización de cada uno (ultima_sincronizacion es la de bomemelilla.es). 'sincronizacion' es la de este proceso que está en curso (o la última lanzada), de cualquiera de los dos orígenes, con su 'origen'; indice.sincronizacion_en_curso dice qué origen sincroniza ahora cualquier proceso. Estados de la sincronización: en_curso, completado, cancelado, fallido y bloqueado (el sitio nos bloqueó: 403/429/503 o dos peticiones seguidas sin respuesta; lo indexado se conserva y bome-navaja no le pide nada durante reintentar_tras_segundos, ~75 min por defecto: no vuelvas a sincronizar antes; ver 'mensaje'). En 'mensaje' también aparecen las pausas preventivas (por defecto, como mucho 3 respuestas de error del sitio cada 10 minutos) y la sincronización cuenta los boletines que quedaron rotos en 'rotos'.

Inputs: no named parameters.

estado_servidorA

Configuración y estado del servidor, sin tocar la red ni crear el índice.

Versión, pid, rutas de datos, PDFs e índice (con el motivo de cada una: variable de entorno, XDG, LOCALAPPDATA...; las rutas relativas en BOME_NAVAJA_* se resuelven contra el directorio de trabajo), si existe el fichero del índice y su estado si ya está abierto, versión de SQLite con FTS5/trigram, URL base y:

  • ajustes: todos los ajustes que marcan cuánto se le pide a los sitios, con las variables de entorno aplicadas (un único juego para bomemelilla.es y el portal antiguo): pausa_sincronizacion_segundos y variacion_sincronizacion_segundos (ritmo de la sincronización), max_boletines_por_ejecucion, pausa_consultas_segundos (herramientas de bomemelilla.es), guardia_max_errores, guardia_ventana_minutos y guardia_enfriamiento_minutos (guardia del sitio), pausa_tras_error_segundos (la pausa tras una página rota va de ese valor al doble, pausa_tras_error_max_segundos), tiempo_espera_segundos; 'variables' dice qué variable BOME_NAVAJA_* fija cada uno, 'avisos' los valores no válidos (se usa el valor por defecto) y 'riesgos' los valores más arriesgados que lo recomendado (se usan igualmente; explícale al usuario el riesgo de bloqueo). Se leen al arrancar: cambiarlos exige reiniciar el servidor.

  • cortesia_segundos (pausa de las herramientas) y cortesia_sincronizacion (pausa, variación aleatoria y máximo de boletines por ejecución, con BOME_NAVAJA_SYNC_DELAY, BOME_NAVAJA_SYNC_JITTER y BOME_NAVAJA_SYNC_MAX_BOLETINES aplicadas, y sus avisos).

  • guardia_sitio: enfriamiento_hasta, segundos_restantes y motivo si el sitio nos bloqueó, durante el cual las herramientas responden sitio_bloqueando; errores HTTP en la ventana (ventana_segundos, 10 minutos por defecto) frente al máximo permitido (max_errores, 3 por defecto): con el cupo lleno las herramientas responden pausa_preventiva; y su fichero estado_sitio.json, compartido por todos los procesos de bome-navaja.

  • Del portal antiguo (melilla.es): url_portal_antiguo, su propia guardia (guardia_portal_antiguo, con su fichero estado_sitio_melilla.json) y la caché de su catálogo (catalogo_portal_antiguo: ruta, existe, fetched_at y número de boletines). La sincronización del portal antiguo (sincronizar_indice con origen="melilla.es") va al mismo ritmo y con el mismo máximo por ejecución que la de bomemelilla.es, con las mismas variables de entorno aplicadas: cortesia_sincronizacion_portal_antiguo (el portal interactivo va a ~1-1,5 s entre peticiones).

Inputs: no named parameters.

leer_articuloA

Texto completo de un artículo (anuncio), página a página.

cve: el CVE del artículo (BOME-A-2026-1051) o el del boletín (BOME-B-...) junto con numero (el número del artículo). Un artículo extraordinario (BOME-AX-...) se localiza sin el resolutor del sitio, que lo confunde con el artículo ordinario del mismo número: se usa el índice local si lo tiene y, si no, el calendario del año y las páginas de sus boletines extraordinarios (puede costar unas peticiones más). Nunca se devuelve un artículo distinto del pedido. Los artículos de 2014-2016 no tienen texto en el sitio: fuente="ninguna" y un aviso. Paginación: devuelve páginas enteras hasta max_caracteres (1000-100000, por defecto 20000), siempre al menos una; una página más larga que max_caracteres se corta ahí (cortada=true). Si 'siguiente' no es null, vuelve a llamar con desde_pagina y desde_caracter de 'siguiente' para continuar; null significa que no queda más.

Inputs: cve (required), numero, desde_pagina, desde_caracter, +1 more.

leer_boletinA

Texto completo de un boletín entero (su PDF) con los metadatos del boletín.

Un boletín ordinario tiene ~35 páginas; lee por tramos. El PDF se descarga una vez y se guarda en caché. Los boletines de 2014-2016 no tienen PDF (fuente="ninguna"): lee sus artículos con leer_articulo. Paginación: devuelve páginas enteras hasta max_caracteres (1000-100000, por defecto 20000), siempre al menos una; una página más larga que max_caracteres se corta ahí (cortada=true). Si 'siguiente' no es null, vuelve a llamar con desde_pagina y desde_caracter de 'siguiente'; null significa que no queda más.

Inputs: cve (required), desde_pagina, desde_caracter, max_caracteres.

leer_pdfA

Texto del PDF de cualquier CVE: boletín, sumario (BOME-S), artículo (BOME-A) o página (BOME-P / BOME-PX); o, con url en vez de cve, de un PDF del portal antiguo de melilla.es.

Da exactamente uno: cve, o url (solo las URL https://www.melilla.es/mandar.php/... que devuelven buscar_bome_antiguo y ver_bome_antiguo, por página o del boletín entero; se rechaza cualquier otra). Las páginas sin texto extraíble (escaneadas, frecuentes en los boletines antiguos) salen con sin_texto=true y un aviso. Paginación: devuelve páginas enteras hasta max_caracteres (1000-100000, por defecto 20000), siempre al menos una; una página más larga que max_caracteres se corta ahí (cortada=true). Si 'siguiente' no es null, vuelve a llamar con desde_pagina y desde_caracter de 'siguiente'; null significa que no queda más.

Inputs: cve, url, desde_pagina, desde_caracter, +1 more.

listar_bomesA

Lista los boletines publicados entre dos fechas (calendario de bomemelilla.es y, antes de 2021-03-13, también el catálogo del portal antiguo de melilla.es).

Fechas en AAAA-MM-DD o DD/MM/AAAA, ambas incluidas. Por defecto, los últimos 30 días hasta hoy. Devuelve como máximo 500 boletines, del más reciente al más antiguo; si hay más, 'truncado' es true y 'total' dice cuántos hay: acota el rango. Cada boletín trae cve, number, date, extraordinary (BOME-BX), title, url y origen ("bomemelilla.es" o "melilla.es"). Si el rango llega antes del 2021-03-13 se añaden los boletines que solo tiene el portal antiguo (a bomemelilla.es le faltan muchos antes de 2018 y no tiene nada antes de 2014); traen dboid y ver_con (ábrelos con ver_bome_antiguo) y 'solo_portal_antiguo' los cuenta. Si un boletín está en los dos, gana bomemelilla.es (ábrelo con ver_bome). Si el portal antiguo no responde, devuelve lo de bomemelilla.es y un 'aviso'. Antes de 2014 los identificadores no son CVE de bomemelilla.es (cve_oficial=false) y pueden repetirse: usa el dboid.

Inputs: desde, hasta.

listar_consejeriasB

Consejerías de un departamento, con su id (para filtrar buscar_bomes/buscar_articulos).

El departamento 1 es CIUDAD AUTÓNOMA DE MELILLA, el habitual.

Inputs: departamento (required).

listar_organismosA

Organismos de una consejería, con su id (filtro 'organismo' de las búsquedas en vivo).

Inputs: consejeria (required).

resolver_cveA

Devuelve la URL canónica de cualquier CVE (boletín, artículo, sumario o página).

Útil para citar o para saber a qué boletín y artículo pertenece un CVE de artículo (BOME-A-...) o de página (BOME-P-...). Comprueba que la página exista. El resolutor del sitio confunde los extraordinarios con los ordinarios: un BOME-AX se localiza sin él (índice local o calendario del año y páginas de sus boletines extraordinarios; puede costar unas peticiones más) y se comprueba el artículo; para un BOME-PX se devuelve la URL de su PDF, con un aviso. Nunca se da por buena una redirección a un boletín del otro tipo (extraordinario frente a ordinario).

Inputs: cve (required).

sincronizar_indiceA

Arranca en segundo plano la sincronización del índice local de sumarios y vuelve al instante.

origen: "bomemelilla.es" (por defecto, el sitio actual) o "melilla.es" (el portal antiguo). Solo corre una a la vez por índice, sea del origen que sea: si ya hay una sincronización en curso (de cualquiera de los dos, en este u otro proceso) devuelve su estado o en_curso_en_otro_proceso con el origen que la ocupa, sin arrancar otra.

origen="bomemelilla.es": recorre el calendario (por defecto 2018-01-01..hoy) del más reciente al más antiguo: indexa los boletines que falten, re-indexa los de los últimos reindexar_recientes_dias días y, si reintentar_errores, los que fallaron. Empieza en 2018 porque antes bomemelilla.es está incompleto e inestable (faltan boletines y sus páginas rotas responden HTTP 500, que el cortafuegos castiga) y apenas tiene texto buscable; los boletines anteriores se consultan mejor en el portal antiguo de melilla.es. Un 'desde' anterior es posible pero no recomendable. Para no saturar el sitio va despacio (~2-3 s entre peticiones) y cada ejecución indexa como mucho max_boletines boletines (por defecto 250, los más recientes; ~15-20 minutos). El rango por defecto (~1100 boletines) necesita varias ejecuciones: si el estado final trae pendientes_tras_limite > 0, vuelve a llamarla más tarde (espaciar las ejecuciones es más amable con el sitio). Es reanudable: si se corta, la siguiente llamada continúa donde quedó. Sigue el progreso con estado_indice; mientras tanto buscar_en_indice da resultados parciales. Si ya hay una en curso (en este u otro proceso) devuelve su estado sin arrancar otra. Solo sincroniza cuando se le pide. El cortafuegos del sitio bloquea la IP tras unas 5 respuestas de error, así que la sincronización admite como mucho 3 cada 10 minutos (si llega al límite hace una pausa preventiva y va más lenta) y espera 30-60 s tras una página rota (valores por defecto; los que están en uso, en estado_servidor, 'ajustes'). Si el sitio la bloquea (403/429/503 o dos peticiones seguidas sin respuesta) termina en estado "bloqueado" y bome-navaja no le pide nada durante reintentar_tras_segundos (~75 min): no la relances antes (terminaría "bloqueado" al instante). Los boletines "rotos" (su página respondió con error interno, HTTP 500, dos veces) se saltan; reintentar_rotos=True los vuelve a pedir: úsalo solo para comprobar si el sitio los arregló, porque cada uno cuesta un HTTP 500 que el cortafuegos del sitio cuenta.

origen="melilla.es" indexa los sumarios de artículos de las fichas de boletín del portal antiguo: por defecto los boletines de 1991-01-01 a 2017-12-31 (antes de 1991 las fichas no traen artículos; desde 2018 manda bomemelilla.es), del más reciente al más antiguo, y se salta los que ya están indexados con sumarios desde cualquiera de los dos orígenes. Una petición por boletín (la ficha, nunca los PDF), igual de despacio (~2-3 s entre peticiones) y con el mismo límite max_boletines (por defecto 250, ~15-20 minutos por ejecución): los ~2.000-2.500 boletines del rango necesitan varias ejecuciones espaciadas (mira pendientes_tras_limite). Es reanudable, reintenta los fallidos si reintentar_errores y los rotos solo con reintentar_rotos. reindexar_recientes_dias no se aplica (el portal está congelado). El portal antiguo tiene su propia guardia (guardia_portal_antiguo): sus errores no cuentan para bomemelilla.es. Rellena también los boletines de 2014-2016 que bomemelilla.es tiene sin sumarios.

Inputs: desde, hasta, origen, max_boletines, +3 more.

ver_bomeA

Muestra un boletín (BOME-B-AAAA-N o BOME-BX-AAAA-N) con su árbol de artículos.

Estructura: sections (departamento) → consejerias → organismos → articles, cada artículo con cve, number, sumario, url y pdf_url. Antes de finales de 2016 los artículos no tienen sumario. La página del sitio a veces omite artículos; con recuperar_ocultos=true se buscan los huecos de numeración (una petición por hueco) y se devuelven en 'articulos_ocultos'. Para el texto de un artículo usa leer_articulo.

Inputs: cve (required), recuperar_ocultos.

ver_bome_antiguoA

Ficha de un boletín del portal antiguo (melilla.es, 1985 al 12-03-2021): PDF del boletín entero y sus artículos.

Da exactamente uno: cve (BOME-B-AAAA-N o BOME-BX-AAAA-N; se busca en el catálogo del portal) o dboid (el id del portal, como lo dan listar_bomes, buscar_bome_antiguo y los errores de ambigüedad). Antes de 2014 los identificadores tienen forma de CVE pero no son CVE de bomemelilla.es y algunos se repiten: entonces responde boletin_ambiguo con los candidatos (dboid, fecha, sufijo) y hay que repetir con su dboid. Devuelve url_pdf (el boletín entero), y articulos con numero, tipo, sumario, ruta (consejería, dirección, sección) y paginas (url_pdf de cada página). Lee cualquiera de esos PDF con leer_pdf(url=...).

Inputs: cve, dboid.

ver_sumarioA

Vista web del sumario de un boletín: lista plana de artículos con su primera página.

Acepta el CVE del boletín (BOME-B/BX) o del sumario (BOME-S/SX). Aviso: en algunos boletines el sumario web es texto libre y se analiza como 0 entradas; en ese caso usa ver_bome, que es la fuente fiable de artículos y sumarios.

Inputs: cve (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    A4.2/5.0

    Scored across 19 tools

    Disambiguation4/5

    Most tools map to distinct resources and actions (view bulletin, search articles, read PDF, sync index), and the descriptions carefully separate live search from local index search and old-portal tools. A few pairs could still be confused at a glance—ver_sumario vs ver_bome and leer_pdf vs leer_boletin/leer_articulo—but the descriptions resolve most ambiguity.

    Naming Consistency4/5

    Tool names are uniformly snake_case and mostly follow a verb_noun pattern such as ver_bome, buscar_articulos, leer_pdf, and listar_bomes. Minor deviations like estado_indice/estado_servidor and buscar_en_indice break the pure verb-first pattern, but the convention remains readable and predictable.

    Tool Count4/5

    19 tools is on the high side, but the server covers two distinct portals, a local search index, and PDF/read/download workflows, so each tool has a genuine role. It is slightly above the ideal 3-15 range but not bloated or redundant.

    Completeness5/5

    The tool surface covers the full reading workflow: listing bulletins, viewing summaries and article trees, reading articles and PDFs, downloading PDFs, resolving CVEs, searching live or in the local index, and synchronizing or canceling index sync. There are no obvious dead ends for the stated archive-search purpose.

    Maintenance

    ActivitySlowing
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI agents to search Spain's consolidated legislation by title, inspect any statute's metadata and article table of contents, and read every historical version of a chosen article. Also retrieves the daily table of contents of the Spanish state gazette, grouped by section and issuing department, via the Agencia Estatal Boletín Oficial del Estado open-data API.
      270 npm
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables AI clients to query Spain's official BDNS subsidy and grant listings and BOE open-data publications live, with exact counts, computed deadlines, forecast calendars, and literal PDF text of grant bases. It also surfaces BOE oposiciones and licitaciones, flagging uncertainty instead of inventing data.
      10
      64 npm
      MIT