Transkribus MCP Server

Servidor MCP para a API REST do Transkribus — gerencie coleções, documentos, reconhecimento HTR/OCR, modelos e muito mais. 290 ferramentas em 22 domínios de recursos.

Documentação

transkribus-mcp-server

Tests

Servidor MCP para a API REST do Transkribus. Gerencie coleções, documentos, reconhecimento HTR/OCR, modelos e muito mais através do Model Context Protocol.

304 ferramentas em 23 domínios de recursos, com 9 pontos de entrada para que você possa escolher o servidor certo para o limite de ferramentas do seu cliente MCP.

Escopo da API: Este servidor cobre duas APIs do Transkribus:

  • a API REST legada do TrpServer (https://transkribus.eu/TrpServer/rest), baseada em sessão — 300 ferramentas;
  • a API de Processamento Metagrapho (https://transkribus.eu/processing/v1), autenticação OIDC bearer via account.readcoop.eu — as 4 ferramentas transkribus_processing_*.

Atenção à versão. Alguns materiais do Transkribus ainda mostram /processing/v2 e um campo config.modelId. Esse caminho retorna 404; o serviço ativo é /processing/v1 e aceita config.textRecognition.htrId.

Instalação

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

Ou execute diretamente:

npx @lazyants/transkribus-mcp-server

Configuração

O Transkribus usa autenticação baseada em sessão. As credenciais são resolvidas nesta ordem, por valor:

  1. Chaveiro do sistema operacional (recomendado — nada é gravado em um arquivo de configuração em texto claro)
  2. Variável de ambiente (TRANSKRIBUS_USER + TRANSKRIBUS_PASSWORD, ou TRANSKRIBUS_SESSION_ID)

Ou um nome de usuário e senha (o servidor faz login e gerencia a sessão) ou um ID de sessão que você já possui. Um ID de sessão tem precedência quando ambos estão disponíveis; ele expira, então um nome de usuário e senha é a melhor escolha para uma configuração de longo prazo — e é o que permite que o servidor reautentique após um 401.

O chaveiro nunca é obrigatório: se ele estiver indisponível — uma máquina Linux sem serviço Secret Service, uma plataforma não suportada, uma instalação com --omit=optional — ou se ele não responder dentro de 5 segundos, o servidor recorre ao ambiente.

Armazenar as credenciais no chaveiro do sistema operacional

Três entradas sob um único nome de serviço, transkribus-mcp por padrão: user, password e session-id (armazene apenas o que você usa).

[!IMPORTANT] Os comandos abaixo leem o valor de um prompt interativo em vez de recebê-lo como argumento, para que ele nunca apareça no histórico do shell, em uma linha de comando ou no ambiente de inicialização de outro processo. Evite colar uma senha diretamente na linha de comando.

macOS

Omitir o valor após -w faz o security solicitar:

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

[!NOTE] Um item do chaveiro de login pertence ao programa que o criou. Na primeira vez que o servidor ler um item criado por security, o macOS mostra um diálogo "…quer usar suas informações confidenciais armazenadas em transkribus-mcp" — escolha Sempre Permitir e ele não perguntará novamente. Até que isso seja concedido, a leitura não pode ser concluída: o servidor espera 5 segundos e então recorre às variáveis de ambiente, então um servidor iniciado onde ninguém pode responder ao diálogo se comporta como se o chaveiro estivesse vazio, em vez de travar.

Para evitar o diálogo completamente, escreva a entrada a partir do mesmo runtime Node.js que a lerá. O valor é enviado pela entrada padrão, então ele aparece nem em uma linha de comando nem em um ambiente de processo (ps -E mostra esses). O prompt abaixo é POSIX simples, então ele se comporta da mesma forma em zsh e bash:

npm install -g @lazyants/transkribus-mcp-server   # o módulo do chaveiro acompanha
cd "$(npm root -g)/@lazyants/transkribus-mcp-server"
printf 'Senha do 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("armazenado");
  });
'
unset TK_SECRET

Repita com "user" no lugar de "password". Uma instalação diferente do Node.js posteriormente (uma troca de nvm, por exemplo) é um programa diferente para o chaveiro, então o diálogo pode aparecer mais uma vez para ela.

Windows (PowerShell)

cmdkey só pode receber o valor como argumento de linha de comando, o que o expõe na lista de processos. Leia-o de um prompt oculto e escreva-o diretamente no Gerenciador de Credenciais do Windows via CredWrite. O nome do alvo da credencial é <account>.<service> — user.transkribus-mcp e password.transkribus-mcp para o serviço padrão — que é exatamente o que o servidor lê de volta:

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'

Usando um TRANSKRIBUS_KEYRING_SERVICE personalizado (por exemplo, acme)? Defina TargetName para user.acme / password.acme para corresponder — o servidor procura cada valor sob <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)

Uma vez armazenado, os arquivos de configuração MCP não precisam de credenciais.

Usar variáveis de ambiente em vez disso

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

Ou, com uma sessão que você já possui:

export TRANSKRIBUS_SESSION_ID=your-session-id

Variáveis de ambiente

VariávelPadrãoDescrição
TRANSKRIBUS_USER—E-mail da conta; usado quando o chaveiro não tem entrada user para o serviço configurado
TRANSKRIBUS_PASSWORD—Senha da conta; usada quando o chaveiro não tem entrada password
TRANSKRIBUS_SESSION_ID—Um ID de sessão existente; usado quando o chaveiro não tem entrada session-id
TRANSKRIBUS_KEYRING_SERVICEtranskribus-mcpNome do serviço do chaveiro. Substitua para conectar-se a várias contas do Transkribus ao mesmo tempo — execute uma instância do servidor por conta, cada uma com seu próprio nome de serviço

Credenciais da API de Processamento

As ferramentas transkribus_processing_* falam com um serviço diferente com um esquema de autenticação diferente, mas não precisam de configuração extra: os mesmos TRANSKRIBUS_USER + TRANSKRIBUS_PASSWORD são trocados por um token bearer OIDC (concessão de senha SSO READCOOP, cliente processing-api-client) e atualizados automaticamente. TRANSKRIBUS_SESSION_ID não se aplica a eles.

Duas substituições opcionais:

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

Pontos de Entrada

ComandoDomíniosFerramentas
transkribus-mcp-serverTodos os 23 domínios304
transkribus-mcp-collectionsAuth, Coleções (core/docs/pages/users/crowd/editdecl/credits/stats/labels/activity/tags)131
transkribus-mcp-adminAuth, Admin, Créditos, Uploads, Rótulos, Arquivos, Sistema, Raiz62
transkribus-mcp-transcriptionAuth, Reconhecimento, Análise de Layout, PyLaia, P2PaLA, DU47
transkribus-mcp-usersAuth, Usuários, Crowdsourcing, eLearning29
transkribus-mcp-modelsAuth, Modelos26
transkribus-mcp-jobsAuth, Trabalhos, Ações19
transkribus-mcp-searchAuth, Busca, KWS16
transkribus-mcp-processingProcessamento (Metagrapho) — sem ferramentas de autenticação legadas4

Use servidores divididos para reduzir o tamanho do contexto — escolha apenas as divisões que você precisa.

Enviando um documento

Para ingerir um documento, use este fluxo de três etapas:

  1. transkribus_upload_create_structure — forneça collId, um title e um array pages de { fileName, pageNr } (uma entrada por imagem de página que você está prestes a enviar). Retorna um upload com um uploadId.
  2. transkribus_upload_page — chame uma vez por página com o uploadId e o imagePath (um caminho para um arquivo de imagem local), opcionalmente pageXmlPath para uma transcrição PAGE XML existente.
  3. transkribus_upload_get_status — consulte com o uploadId até que o documento apareça na coleção.

Essas ferramentas de upload vêm no transkribus-mcp-server completo e na divisão transkribus-mcp-admin — não no transkribus-mcp-collections. A ingestão de PDF não é suportada; converta o PDF em imagens de página primeiro e use o fluxo acima.

Claude Code

Adicione ao ~/.claude/settings.json. Com as credenciais no chaveiro do sistema operacional sob o nome de serviço padrão (recomendado), nenhuma chave env é necessária:

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

Ou use servidores divididos (escolha as divisões que você precisa):

{
  "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"]
    }
  }
}

Duas contas do Transkribus ao mesmo tempo — uma instância por conta, cada uma apontada para seu próprio nome de serviço do chaveiro:

{
  "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" }
    }
  }
}

Sem um chaveiro, passe as credenciais em env em vez disso:

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

Claude Desktop

Adicione ao claude_desktop_config.json. Com as credenciais no chaveiro do sistema operacional (recomendado — assume o nome de serviço padrão transkribus-mcp):

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

Sem um chaveiro:

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

Segurança

  • Use o chaveiro do sistema operacional para manter sua senha fora de arquivos de configuração e do histórico do shell completamente (veja Configuração)
  • Nunca envie suas credenciais para o controle de versão
  • IDs de sessão expiram — prefira um nome de usuário e senha para configurações de longo prazo; um ID de sessão sozinho não pode ser renovado após um 401

Aviso Legal

Este é um servidor MCP não oficial para o Transkribus. Os autores não são afiliados à READ-COOP SCE. Use por sua conta e risco.

Lançamento

Os lançamentos são enviados via evento GitHub Release. Fluxo do mantenedor:

  1. Aumente a versão em package.json, package-lock.json e server.json (npm version <x.y.z> --no-git-tag-version atualiza os dois primeiros juntos). npm run check-versions falha de forma rígida a menos que package.json#/version e server.json#/packages[0].version concordem. server.json#/version é verificado de forma flexível: deve estar presente e só falha quando regride abaixo de packages[0].version — um valor deixado no lançamento anterior passa com uma linha WARN: e saída 0. O script não olha para package-lock.json ou CHANGELOG.md de forma alguma, então leia sua saída em vez de confiar no código de saída.

  2. Atualize CHANGELOG.md.

  3. Faça o commit e mescle o aumento de versão em main antes de criar o lançamento. Então crie a tag você mesmo, em um SHA que você verificou, e só então crie o lançamento a partir dela:

    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"
    

    A falha que isso evita: sem uma tag existente, gh release create vX.Y.Z coloca uma na ponta do branch padrão. Execute-o enquanto o aumento ainda está em um branch de lançamento e ele marca o commit do lançamento anterior; o fluxo de trabalho então publica qualquer versão que encontrar no package.json desse commit, produzindo um GitHub Release vX.Y.Z que silenciosamente republica a versão antiga. O fluxo de trabalho de publicação agora se recusa a continuar quando GITHUB_REF_NAME não é v<package.json version>, então esse cenário exato falha antes de npm publish em vez de republicar silenciosamente. A sequência acima ainda é necessária e protege um caso que o fluxo de trabalho não pode: a proteção do fluxo de trabalho só é executada quando um lançamento já existe, e passa para qualquer commit que carregue a versão correta — então ela detecta um lançamento com tag incorreta, não o commit errado sendo marcado.

    Cada elemento é essencial:

  • gh pr view … .mergeCommit.oid nomeia o commit de squash do próprio PR de lançamento. Não substitua por git rev-parse origin/main: isso é meramente o que estiver em main no momento em que você olha, então um merge não relacionado que chegar nesse intervalo será marcado e publicado em seu lugar. gh sai com código 0 e não imprime nada para um PR não mesclado, daí o test -n explícito.

    • A cadeia && para na primeira falha em vez de cair na etapa irreversível. Ambas as chamadas git show são atribuídas a uma variável em vez de serem canalizadas diretamente, então seu status de saída é realmente verificado — um pipeline reporta apenas o status do último comando, a menos que pipefail esteja definido, o que não é assumido aqui.
    • git merge-base --is-ancestor prova que o commit é alcançável a partir de main. A mera existência não é suficiente: um commit pode estar presente localmente porque outro branch foi buscado, e se seus arquivos de versão coincidirem, ele passaria em todas as verificações restantes.
    • O teste de versão lê package.json do commit alvo, não da árvore de trabalho — que ainda mostraria a versão correta enquanto $SHA apontasse para outro lugar.
    • O awk extrai a seção dessa versão do CHANGELOG.md do commit para --notes-file. Sem ele, o corpo do lançamento é o que --notes-from-tag encontrar na anotação — aqui a string literal vX.Y.Z, uma nota de lançamento ruim para qualquer versão e enganosa para um lançamento com mudança que quebra compatibilidade. Ele para no próximo cabeçalho ## [ ou na primeira definição de referência de link, porque a entrada mais antiga não tem cabeçalho depois dela e, de outra forma, engoliria todo o bloco de referências de link. grep -q em vez de test -s protege o resultado: uma seção vazia exceto por sua linha em branco ainda produz um arquivo de um byte, que test -s aceita.
    • --verify-tag faz gh abortar em vez de inventar uma tag se o push não ocorreu — a proteção contra o fallback de ponta do branch padrão descrito acima.

    Se gh release create falhar depois que a tag já foi enviada, não execute novamente o bloco inteiro; ele parará em git tag, o que está correto. Execute novamente apenas o comando final.

  1. O workflow Publish to npm + MCP Registry roda automaticamente: ele npm publish com proveniência, consulta o registro até o tarball estar disponível, então envia a server.json correspondente para o MCP Registry via mcp-publisher.

O workflow pula npm publish limpo se a versão já estiver no npm (proteção de transição para lançamentos parcialmente publicados manualmente).

Autenticação npm

A publicação usa npm Trusted Publishing: o token OIDC do GitHub do workflow (id-token: write) é trocado por um token de publicação de uso único em tempo de execução. Nenhum segredo NPM_TOKEN precisa existir no repositório.

A vinculação é configurada na interface web do npm (pacote → Trusted Publishers): provedor GitHub Actions, organização lazyants, repositório transkribus-mcp-server, workflow publish-registry.yml.

Licença

FSL-1.1-MIT — veja LICENSE para os termos completos. Versões 1.x permanecem licenciadas sob MIT.