Transkribus MCP Server

Servidor MCP para la API REST de Transkribus: gestiona colecciones, documentos, reconocimiento HTR/OCR, modelos y más. 290 herramientas en 22 dominios de recursos.

Documentación

transkribus-mcp-server

Tests

Servidor MCP para la API REST de Transkribus. Gestiona colecciones, documentos, reconocimiento HTR/OCR, modelos y más a través del Protocolo de Contexto de Modelos.

304 herramientas en 23 dominios de recursos, con 9 puntos de entrada para que puedas elegir el servidor adecuado según el límite de herramientas de tu cliente MCP.

Alcance de la API: Este servidor cubre dos APIs de Transkribus:

  • la API REST heredada de TrpServer (https://transkribus.eu/TrpServer/rest), basada en sesiones — 300 herramientas;
  • la API de Procesamiento Metagrapho (https://transkribus.eu/processing/v1), autenticación OIDC bearer mediante account.readcoop.eu — las 4 herramientas transkribus_processing_*.

Ten en cuenta la versión. Parte del material de Transkribus aún muestra /processing/v2 y un campo config.modelId. Esa ruta devuelve 404; el servicio activo es /processing/v1 y acepta config.textRecognition.htrId.

Instalación

npm install -g @lazyants/transkribus-mcp-server

O ejecuta directamente:

npx @lazyants/transkribus-mcp-server

Configuración

Transkribus utiliza autenticación basada en sesiones. Las credenciales se resuelven en este orden, por valor:

  1. Llavero del sistema operativo (recomendado — no se escribe nada en un archivo de configuración en texto claro)
  2. Variable de entorno (TRANSKRIBUS_USER + TRANSKRIBUS_PASSWORD, o TRANSKRIBUS_SESSION_ID)

Ya sea un nombre de usuario y contraseña (el servidor inicia sesión y gestiona la sesión) o un ID de sesión que ya poseas. Un ID de sesión tiene prioridad cuando ambos están disponibles; caduca, por lo que un nombre de usuario y contraseña es la mejor opción para una configuración de larga duración — y es lo que permite al servidor reautenticarse después de un 401.

El llavero nunca es obligatorio: si no está disponible — una máquina Linux sin servicio Secret Service, una plataforma no compatible, una instalación con --omit=optional — o si no responde en 5 segundos, el servidor recurre al entorno.

Almacenar las credenciales en el llavero del sistema operativo

Tres entradas bajo un único nombre de servicio, transkribus-mcp por defecto: user, password y session-id (almacena solo lo que uses).

[!IMPORTANTE] Los comandos siguientes leen el valor desde un prompt interactivo en lugar de tomarlo como argumento, para que nunca termine en el historial de tu shell, en una línea de comandos, o en el entorno de lanzamiento de otro proceso. Evita pegar una contraseña directamente en la línea de comandos.

macOS

Omitir el valor después de -w hace que security lo solicite:

security add-generic-password -s "transkribus-mcp" -a "user" -w
security add-generic-password -s "transkribus-mcp" -a "password" -w

[!NOTA] Un elemento del llavero de inicio de sesión pertenece al programa que lo creó. La primera vez que el servidor lee un elemento creado por security, macOS muestra un diálogo "…quiere usar tu información confidencial almacenada en transkribus-mcp" — elige Permitir siempre y no volverá a preguntar. Hasta que se conceda, la lectura no puede completarse: el servidor espera 5 segundos y luego recurre a las variables de entorno, por lo que un servidor iniciado donde nadie puede responder al diálogo se comporta como si el llavero estuviera vacío en lugar de bloquearse.

Para evitar el diálogo por completo, escribe la entrada desde el mismo runtime de Node.js que la leerá. El valor se introduce por la entrada estándar, por lo que aparece ni en una línea de comandos ni en un entorno de proceso (ps -E los muestra). El prompt siguiente es POSIX estándar, por lo que se comporta igual en zsh y bash:

npm install -g @lazyants/transkribus-mcp-server   # el módulo del llavero se incluye
cd "$(npm root -g)/@lazyants/transkribus-mcp-server"
printf 'Contraseña de Transkribus: ' >&2; stty -echo; IFS= read -r TK_SECRET; stty echo; printf '\n' >&2
printf '%s' "$TK_SECRET" | node -e '
  const { Entry } = require("@napi-rs/keyring");
  let value = "";
  process.stdin.setEncoding("utf8");
  process.stdin.on("data", (chunk) => { value += chunk; });
  process.stdin.on("end", () => {
    new Entry("transkribus-mcp", "password").setPassword(value);
    console.log("almacenado");
  });
'
unset TK_SECRET

Repite con "user" en lugar de "password". Una instalación diferente de Node.js más adelante (un cambio de nvm, por ejemplo) es un programa diferente para el llavero, por lo que el diálogo puede aparecer una vez más para ella.

Windows (PowerShell)

cmdkey solo puede tomar el valor como argumento de línea de comandos, lo que lo expone en la lista de procesos. Léelo desde un prompt oculto en su lugar y escríbelo directamente en el Administrador de Credenciales de Windows mediante CredWrite. El nombre de destino de la credencial es <account>.<service> — user.transkribus-mcp y password.transkribus-mcp para el servicio predeterminado — que es exactamente lo que el servidor lee:

Add-Type -Namespace TranskribusKeyring -Name Native -MemberDefinition @'
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CREDENTIAL {
    public uint Flags;
    public uint Type;
    [MarshalAs(UnmanagedType.LPWStr)] public string TargetName;
    [MarshalAs(UnmanagedType.LPWStr)] public string Comment;
    public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
    public uint CredentialBlobSize;
    public IntPtr CredentialBlob;
    public uint Persist;
    public uint AttributeCount;
    public IntPtr Attributes;
    [MarshalAs(UnmanagedType.LPWStr)] public string TargetAlias;
    [MarshalAs(UnmanagedType.LPWStr)] public string UserName;
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CredWriteW(ref CREDENTIAL credential, uint flags);
'@

function Set-TranskribusCredential {
    param([Parameter(Mandatory)][string]$Account, [Parameter(Mandatory)][string]$Prompt)
    $secure = Read-Host -AsSecureString $Prompt
    $blob = [Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($secure)
    try {
        $cred = New-Object TranskribusKeyring.Native+CREDENTIAL
        $cred.Type = 1                                  # CRED_TYPE_GENERIC
        $cred.Persist = 2                               # CRED_PERSIST_LOCAL_MACHINE
        $cred.TargetName = "$Account.transkribus-mcp"   # "<account>.<service>"
        $cred.UserName = $Account
        $cred.CredentialBlob = $blob
        $cred.CredentialBlobSize = $secure.Length * 2   # UTF-16 bytes, no terminator
        if (-not [TranskribusKeyring.Native]::CredWriteW([ref]$cred, 0)) {
            throw "CredWrite failed (Win32 error $([Runtime.InteropServices.Marshal]::GetLastWin32Error()))"
        }
        Write-Host "Stored '$Account' in Windows Credential Manager."
    } finally {
        [Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($blob)
        $secure.Dispose()
        Remove-Variable secure, blob
    }
}

Set-TranskribusCredential -Account 'user' -Prompt 'Transkribus user (e-mail)'
Set-TranskribusCredential -Account 'password' -Prompt 'Transkribus password'

¿Usas un TRANSKRIBUS_KEYRING_SERVICE personalizado (p. ej. acme)? Establece TargetName a user.acme / password.acme para que coincida — el servidor busca cada valor bajo <account>.<service>.

Linux

secret-tool store --label="Transkribus user" service transkribus-mcp username user
secret-tool store --label="Transkribus password" service transkribus-mcp username password
# (each prompts for the value)

Una vez almacenadas, los archivos de configuración de MCP no necesitan credenciales en absoluto.

Usar variables de entorno en su lugar

export TRANSKRIBUS_USER=your-email@example.com
export TRANSKRIBUS_PASSWORD=your-password

O, con una sesión que ya poseas:

export TRANSKRIBUS_SESSION_ID=your-session-id

Variables de entorno

VariablePredeterminadoDescripción
TRANSKRIBUS_USER—Correo de la cuenta; se usa cuando el llavero no tiene una entrada user para el servicio configurado
TRANSKRIBUS_PASSWORD—Contraseña de la cuenta; se usa cuando el llavero no tiene una entrada password
TRANSKRIBUS_SESSION_ID—Un ID de sesión existente; se usa cuando el llavero no tiene una entrada session-id
TRANSKRIBUS_KEYRING_SERVICEtranskribus-mcpNombre del servicio del llavero. Sobrescríbelo para conectarte a varias cuentas de Transkribus a la vez — ejecuta una instancia del servidor por cuenta, cada una con su propio nombre de servicio

Credenciales de la API de Procesamiento

Las herramientas transkribus_processing_* hablan con un servicio diferente con un esquema de autenticación diferente, pero no necesitan configuración adicional: el mismo TRANSKRIBUS_USER + TRANSKRIBUS_PASSWORD se intercambian por un token bearer OIDC (concesión de contraseña SSO de READCOOP, cliente processing-api-client) y se renuevan automáticamente. TRANSKRIBUS_SESSION_ID no se aplica a ellas.

Dos sobrescrituras opcionales:

export TRANSKRIBUS_ACCESS_TOKEN=your-bearer-token       # skip the token exchange entirely
export TRANSKRIBUS_PROCESSING_CLIENT_ID=custom-client   # non-default OIDC client

Puntos de entrada

ComandoDominiosHerramientas
transkribus-mcp-serverLos 23 dominios304
transkribus-mcp-collectionsAuth, Colecciones (core/docs/pages/users/crowd/editdecl/credits/stats/labels/activity/tags)131
transkribus-mcp-adminAuth, Admin, Créditos, Subidas, Etiquetas, Archivos, Sistema, Raíz62
transkribus-mcp-transcriptionAuth, Reconocimiento, Análisis de diseño, PyLaia, P2PaLA, DU47
transkribus-mcp-usersAuth, Usuarios, Crowdsourcing, eLearning29
transkribus-mcp-modelsAuth, Modelos26
transkribus-mcp-jobsAuth, Trabajos, Acciones19
transkribus-mcp-searchAuth, Búsqueda, KWS16
transkribus-mcp-processingProcesamiento (Metagrapho) — sin herramientas de autenticación heredadas4

Usa servidores divididos para reducir el tamaño del contexto — elige solo las divisiones que necesites.

Subir un documento

Para ingerir un documento, usa este flujo de tres pasos:

  1. transkribus_upload_create_structure — proporciónale collId, un title y un array pages de { fileName, pageNr } (una entrada por imagen de página que estés a punto de enviar). Devuelve una subida con un uploadId.
  2. transkribus_upload_page — llama una vez por página con el uploadId y el imagePath (una ruta a un archivo de imagen local), opcionalmente pageXmlPath para una transcripción PAGE XML existente.
  3. transkribus_upload_get_status — consulta con el uploadId hasta que el documento aparezca en la colección.

Estas herramientas de subida se incluyen en el transkribus-mcp-server completo y en la división transkribus-mcp-admin — no en transkribus-mcp-collections. La ingesta de PDF no es compatible; convierte el PDF a imágenes de página primero y usa el flujo anterior.

Claude Code

Añade a ~/.claude/settings.json. Con las credenciales en el llavero del sistema operativo bajo el nombre de servicio predeterminado (recomendado), no se necesita ninguna clave env:

{
  "mcpServers": {
    "transkribus": {
      "command": "npx",
      "args": ["-y", "@lazyants/transkribus-mcp-server"]
    }
  }
}

O usa servidores divididos (elige las divisiones que necesites):

{
  "mcpServers": {
    "transkribus-collections": {
      "command": "npx",
      "args": ["-y", "-p", "@lazyants/transkribus-mcp-server", "transkribus-mcp-collections"]
    },
    "transkribus-transcription": {
      "command": "npx",
      "args": ["-y", "-p", "@lazyants/transkribus-mcp-server", "transkribus-mcp-transcription"]
    }
  }
}

Dos cuentas de Transkribus a la vez — una instancia por cuenta, cada una apuntando a su propio nombre de servicio del llavero:

{
  "mcpServers": {
    "transkribus-team-a": {
      "command": "npx",
      "args": ["-y", "@lazyants/transkribus-mcp-server"],
      "env": { "TRANSKRIBUS_KEYRING_SERVICE": "transkribus-team-a" }
    },
    "transkribus-team-b": {
      "command": "npx",
      "args": ["-y", "@lazyants/transkribus-mcp-server"],
      "env": { "TRANSKRIBUS_KEYRING_SERVICE": "transkribus-team-b" }
    }
  }
}

Sin llavero, pasa las credenciales en env en su lugar:

{
  "mcpServers": {
    "transkribus": {
      "command": "npx",
      "args": ["-y", "@lazyants/transkribus-mcp-server"],
      "env": {
        "TRANSKRIBUS_USER": "your-email@example.com",
        "TRANSKRIBUS_PASSWORD": "your-password"
      }
    }
  }
}

Claude Desktop

Añade a claude_desktop_config.json. Con las credenciales en el llavero del sistema operativo (recomendado — asume el nombre de servicio predeterminado transkribus-mcp):

{
  "mcpServers": {
    "transkribus": {
      "command": "npx",
      "args": ["-y", "@lazyants/transkribus-mcp-server"]
    }
  }
}

Sin llavero:

{
  "mcpServers": {
    "transkribus": {
      "command": "npx",
      "args": ["-y", "@lazyants/transkribus-mcp-server"],
      "env": {
        "TRANSKRIBUS_USER": "your-email@example.com",
        "TRANSKRIBUS_PASSWORD": "your-password"
      }
    }
  }
}

Seguridad

  • Usa el llavero del sistema operativo para mantener tu contraseña fuera de los archivos de configuración y del historial del shell por completo (consulta Configuración)
  • Nunca confirmes tus credenciales en el control de versiones
  • Los ID de sesión caducan — prefiere un nombre de usuario y contraseña para configuraciones de larga duración; un ID de sesión solo no puede renovarse después de un 401

Aviso legal

Este es un servidor MCP no oficial para Transkribus. Los autores no están afiliados a READ-COOP SCE. Úsalo bajo tu propio riesgo.

Publicación

Las versiones se publican mediante el evento de Release de GitHub. Flujo del mantenedor:

  1. Incrementa la versión en package.json, package-lock.json y server.json (npm version <x.y.z> --no-git-tag-version actualiza los dos primeros juntos). npm run check-versions falla de forma estricta a menos que package.json#/version y server.json#/packages[0].version coincidan. server.json#/version se comprueba de forma flexible: debe estar presente, y solo falla cuando retrocede por debajo de packages[0].version — un valor dejado en la versión anterior pasa con una línea WARN: y código de salida 0. El script no mira package-lock.json ni CHANGELOG.md en absoluto, así que lee su salida en lugar de confiar en su código de salida.

  2. Actualiza CHANGELOG.md.

  3. Confirma y fusiona el incremento de versión a main antes de crear la release. Luego crea la etiqueta tú mismo, en un SHA que hayas verificado, y solo entonces crea la release a partir de ella:

    V=X.Y.Z && PR=<release-pr-number> &&
      SHA="$(gh pr view "$PR" --json mergeCommit -q .mergeCommit.oid)" && test -n "$SHA" &&
      git fetch origin main && git merge-base --is-ancestor "$SHA" origin/main &&
      PKG="$(git show "$SHA:package.json")" &&
      test "$(printf '%s' "$PKG" | node -pe 'JSON.parse(require("fs").readFileSync(0,"utf8")).version')" = "$V" &&
      CL="$(git show "$SHA:CHANGELOG.md")" &&
      printf '%s\n' "$CL" | awk -v v="$V" 'index($0,"## ["v"]")==1{f=1;next} /^## \[/{f=0} /^\[[0-9]+\.[0-9]+\.[0-9]+\]:/{f=0} f' > "/tmp/notes-v$V.md" &&
      grep -q '[^[:space:]]' "/tmp/notes-v$V.md" &&
      git tag -a "v$V" "$SHA" -m "v$V" &&
      git push origin "v$V" &&
      gh release create "v$V" --verify-tag --notes-file "/tmp/notes-v$V.md"
    

    El fallo que esto previene: sin una etiqueta existente, gh release create vX.Y.Z coloca una en la punta de la rama predeterminada. Ejecútalo mientras el incremento aún está en una rama de release y etiquetará el commit de la versión anterior; el flujo de trabajo entonces publica cualquier versión que encuentre en el package.json de ese commit, produciendo una Release de GitHub vX.Y.Z que republica silenciosamente la versión anterior. El flujo de trabajo de publicación ahora se niega a continuar cuando GITHUB_REF_NAME no es v<package.json version>, por lo que ese escenario exacto falla antes de npm publish en lugar de republicar silenciosamente. La secuencia anterior sigue siendo necesaria y protege un caso que el flujo de trabajo no puede: la protección del flujo de trabajo solo se ejecuta una vez que ya existe una release, y pasa para cualquier commit que lleve la versión correcta — por lo que detecta una release mal etiquetada, no el commit incorrecto siendo etiquetado.

    Cada elemento es esencial:

  • gh pr view … .mergeCommit.oid nombra el commit de squash propio del PR de lanzamiento. No sustituyas git rev-parse origin/main: eso es meramente lo que esté en main en el momento en que mires, por lo que una fusión no relacionada que llegue en el intervalo se etiquetaría y publicaría en su lugar. gh sale con 0 y no imprime nada para un PR sin fusionar, de ahí el test -n explícito.

    • La cadena && se detiene en el primer fallo en lugar de pasar al paso irreversible. Ambas llamadas a git show se asignan a una variable en lugar de canalizarse directamente, por lo que su estado de salida se comprueba de hecho — una canalización informa solo del estado de su último comando a menos que pipefail esté configurado, lo cual no se asume aquí.
    • git merge-base --is-ancestor demuestra que el commit es alcanzable desde main. La mera existencia no es suficiente: un commit puede estar presente localmente porque se obtuvo otra rama, y si sus archivos de versión coinciden, de otro modo pasaría todas las comprobaciones restantes.
    • La prueba de versión lee package.json del commit objetivo, no del árbol de trabajo — que aún mostraría la versión correcta mientras $SHA apuntara a otro lugar.
    • El awk extrae la sección de esa versión del CHANGELOG.md del commit para --notes-file. Sin él, el cuerpo del lanzamiento es lo que --notes-from-tag encuentre en la anotación — aquí la cadena literal vX.Y.Z, una nota de lanzamiento pobre para cualquier versión y engañosa para un lanzamiento que lleva un cambio disruptivo. Se detiene en el siguiente encabezado ## [ o en la primera definición de referencia de enlace, porque la entrada más antigua no tiene encabezado después y de otro modo se tragaría todo el bloque de referencias de enlace. grep -q en lugar de test -s protege el resultado: una sección vacía aparte de su línea en blanco aún produce un archivo de un byte, que test -s acepta.
    • --verify-tag hace que gh se interrumpa en lugar de inventar una etiqueta si el push no se realizó — la protección contra la alternativa de la punta de la rama predeterminada descrita anteriormente.

    Si gh release create falla después de que la etiqueta ya se haya enviado, no vuelvas a ejecutar todo el bloque; se detendrá en git tag, lo cual es correcto. Vuelve a ejecutar solo el comando final.

  1. El flujo de trabajo Publish to npm + MCP Registry se ejecuta automáticamente: npm publish con procedencia, consulta el registro hasta que el tarball esté disponible, luego envía el server.json correspondiente al Registro MCP mediante mcp-publisher.

El flujo de trabajo omite npm publish limpiamente si la versión ya está en npm (protección de transición para lanzamientos que se publicaron parcialmente de forma manual).

Autenticación de npm

La publicación utiliza npm Trusted Publishing: el token OIDC de GitHub del flujo de trabajo (id-token: write) se intercambia por un token de publicación de un solo uso en tiempo de ejecución. No es necesario que exista ningún secreto NPM_TOKEN en el repositorio.

El enlace se configura en la interfaz web de npm (paquete → Trusted Publishers): proveedor GitHub Actions, organización lazyants, repositorio transkribus-mcp-server, flujo de trabajo publish-registry.yml.

Licencia

FSL-1.1-MIT — consulta LICENSE para los términos completos. Las versiones 1.x permanecen con licencia MIT.