Layven

Unidad compartida para tus agentes y compañeros de equipo.

Documentación

Servidor MCP de Layven

Layven es un disco compartido que tus agentes montan sobre MCP. Cada escritura tiene versión, cada acción se atribuye al agente que la realizó, y cualquier cosa se puede revertir.

Un bloque de configuración, sin cambios en el código del agente. Alojado en https://api.layven.io/mcp.

Documenta el servidor MCP de Layven 1.0.2.


Inicio rápido

claude mcp add --transport http layven https://api.layven.io/mcp --header "Authorization: Bearer agd_your_agent_token"
  1. Obtén un token en layven.io: abre la consola, ve a Agents, crea uno. El secreto se muestra una sola vez.
  2. Reinicia tu cliente.
  3. Pregunta a tu agente: "lista mis espacios de trabajo de Layven".

El punto del producto se muestra en la segunda conexión. Crea un segundo token, conecta una herramienta diferente con él, y haz que esa herramienta lea el archivo que el primero acaba de escribir. Ambos agentes ven el mismo disco, y el feed de actividad dice quién hizo qué. Tutorial: examples/two-agent-handoff.md.


Conecta tu cliente

Claude Code

claude mcp add --transport http layven https://api.layven.io/mcp --header "Authorization: Bearer agd_your_agent_token"

Conector personalizado de Claude.ai

Pega https://api.layven.io/mcp y autentícate con OAuth. Esa interfaz no tiene campo de encabezado personalizado, por eso existe OAuth.

ChatGPT

Igual que Claude.ai: pega https://api.layven.io/mcp y autentícate con OAuth.

Cursor (~/.cursor/mcp.json)

{
  "mcpServers": {
    "layven": {
      "url": "https://api.layven.io/mcp",
      "headers": {
        "Authorization": "Bearer agd_your_agent_token"
      }
    }
  }
}

Codex (~/.codex/config.toml)

[mcp_servers.layven]
url = "https://api.layven.io/mcp"
http_headers = { "Authorization" = "Bearer agd_your_agent_token" }

Gemini (~/.gemini/settings.json)

Mismo JSON que Cursor, pero la clave es httpUrl en lugar de url, porque Gemini lee url como un endpoint SSE.

{
  "mcpServers": {
    "layven": {
      "httpUrl": "https://api.layven.io/mcp",
      "headers": {
        "Authorization": "Bearer agd_your_agent_token"
      }
    }
  }
}

JSON MCP genérico

{
  "mcpServers": {
    "layven": {
      "url": "https://api.layven.io/mcp",
      "headers": {
        "Authorization": "Bearer agd_your_agent_token"
      }
    }
  }
}

Autenticación

Hay dos formas de entrar, y ambas resuelven al mismo registro de token, por lo que los permisos, la revocación y el rastro de auditoría son idénticos en ambos casos.

Token estático de portador. Envía Authorization: Bearer agd_... en cada solicitud. Créalo en la consola; el secreto se muestra una sola vez.

OAuth 2.1, para clientes cuya interfaz no tiene campo de encabezado personalizado:

Servidor de autorizaciónhttps://api.layven.io
Metadatos del recurso protegidohttps://api.layven.io/.well-known/oauth-protected-resource/mcp
Recursohttps://api.layven.io/mcp
Registro dinámico de clientesCompatible
Caducidad del secreto de clienteNo caduca

El consentimiento acuña un token ordinario, que puedes ver y revocar en la consola como cualquier otro.


Transporte

  • POST https://api.layven.io/mcp, Streamable HTTP, sin estado.
  • Cada POST es totalmente independiente. Sin id de sesión, sin reanudación de sesión, sin endpoint SSE separado, sin stdio.
  • GET y DELETE devuelven HTTP 405 con exactamente este cuerpo:
    {"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed (stateless)"},"id":null}
    
  • Encabezados de solicitud requeridos: Content-Type: application/json y Accept: application/json, text/event-stream. Ambos tipos de medio deben estar presentes en Accept o el servidor devuelve 406.
  • Las respuestas vuelven como Content-Type: text/event-stream.
  • MCP-Protocol-Version es opcional. Si está presente, debe ser uno de 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07, de lo contrario el servidor devuelve HTTP 400.
  • Capacidades: solo tools. Sin recursos, sin prompts.
  • Identidad del servidor en initialize: nombre Layven, versión 1.0.2, sitio web https://layven.io.

Herramientas

Cada herramienta acepta un workspace opcional, el slug del espacio de trabajo. Un token con exactamente un espacio de trabajo puede omitirlo. list sin workspace se distribuye a todos los espacios de trabajo que el token puede alcanzar.

HerramientaAccesoHaceArgumentos clave
listroLista una carpeta, o encuentra archivos por subcadena de rutapath, recursive, q, limit
readroLee un archivo en la versión actual o una anteriorpath, version
greproBusca contenido de archivos con un patrón RE2pattern, prefix, context_lines, max_matches
historyroLista las versiones de un archivo, de la más reciente a la más antiguapath, limit, cursor
activityroLista qué cambió y qué agente lo cambiósince, path_prefix, limit
writerwCrea o reemplaza un archivo con contenido en líneapath, content, encoding, expected_version
editrwAplica reemplazos de cadenas a un archivo de texto existentepath, edits, expected_version
moverwMueve o renombra un archivofrom, to, overwrite
deleterwMarca un archivo como eliminado, recuperable con restorepath, expected_version
restorerwRestaura un archivo a una versión, o una carpeta a una marca de tiempopath + to_version, o prefix + at
lockrwToma un bloqueo de asesoramiento de 5 minutos en una rutapath
unlockrwLibera un bloqueo que este token mantienepath
request_uploadrwInicia una carga de archivo grande, devuelve una URL PUT prefirmadapath, size, expected_version
finalize_uploadrwConfirma un archivo subido como una nueva versiónupload_id

Solo delete está anotado como destructivo, y escribe una versión de eliminación que restore recupera. write, delete, lock y unlock están anotados como idempotentes; edit, move, restore, request_upload y finalize_upload no lo están. Ninguna herramienta alcanza fuera de Layven.

NOT_FOUND (espacio de trabajo no resoluble), PERMISSION_DENIED, RATE_LIMITED y INTERNAL pueden volver de cualquier herramienta, por lo que la línea Errors debajo de cada herramienta nombra lo específico de esa herramienta.

list

Lista una carpeta, o busca en todos los espacios de trabajo concedidos rutas que coincidan con una subcadena.

Argumentos

workspace?        string    workspace slug; omit to fan out over every granted workspace
path              string    default "" (workspace root)
recursive         boolean   default false
include_deleted   boolean   default false
limit             integer   1..1000, default 500, applied per workspace
cursor?           string    opaque; requires an explicit workspace
q?                string    1..1024 chars, case-insensitive substring of the full path; implies recursive

Devuelve

{
  "results": [
    {
      "workspace": { "id": "...", "slug": "research" },
      "entries": [
        {
          "path": "notes/todo.md",
          "type": "file",
          "size": 1284,
          "version": 7,
          "modified_at": "2026-08-05T09:12:44Z",
          "modified_by_label": "research-agent",
          "by_actor": "agent",
          "deleted": true
        }
      ],
      "next_cursor": "..."
    }
  ]
}

type es "file" o "folder". size, version, modified_at, modified_by_label, by_actor y deleted son opcionales por entrada.

Errores: INVALID_PATH.

Notas

  • results es siempre un array de bloques por espacio de trabajo, incluso cuando el token tiene exactamente un espacio de trabajo. No escribas un cliente que espere un array entries desnudo.
  • Pasar cursor mientras se distribuye devuelve INVALID_PATH con reason: "cursor_requires_workspace". Fija el espacio de trabajo antes de paginar.
  • Las carpetas se sintetizan a partir de prefijos de ruta. No hay registros de carpetas para crear o eliminar.

read

Lee un archivo, ya sea la versión actual o una anterior.

Argumentos

workspace?   string
path         string
version?     integer   defaults to the current version

Devuelve, en línea, cuando el tamaño bruto es de 262144 bytes o menos y el tipo mime es texto:

{
  "path": "notes/todo.md",
  "version": 7,
  "size": 1284,
  "mime_type": "text/markdown",
  "encoding": "utf8",
  "content": "..."
}

Devuelve, para cualquier cosa más grande o binaria:

{
  "path": "datasets/corpus.tar.gz",
  "version": 3,
  "size": 431912448,
  "mime_type": "application/gzip",
  "download_url": "https://...",
  "url_expires_at": "2026-08-05T09:27:00Z"
}

Errores: NOT_FOUND (con deleted: true y last_version cuando la ruta está marcada como eliminada), INVALID_PATH.

Notas

  • La forma de la respuesta cambia según el tamaño y el tipo mime, no según una bandera que pases. Por encima de 256 KiB, o para cualquier archivo no textual, obtienes un download_url válido por 15 minutos en lugar de contenido en línea. Maneja ambas formas.

grep

Busca contenido de archivos con una expresión regular.

Argumentos

workspace?       string
path?            string    search a single file
prefix?          string    search one folder; omit both path and prefix to search the whole workspace
pattern          string    min 1 char, RE2 syntax
case_sensitive   boolean   default false
context_lines    integer   0..10, default 2
max_matches      integer   1..200, default 50

Devuelve

{
  "matches": [
    {
      "path": "notes/todo.md",
      "line": 42,
      "text": "TODO: rotate the staging token",
      "before": ["..."],
      "after": ["..."]
    }
  ],
  "files_scanned": 128,
  "files_skipped_binary": 3,
  "files_skipped_too_large": 0,
  "truncated": false
}

Errores: INVALID_PATTERN, INVALID_PATH.

Notas

  • Los patrones son RE2, por lo que no hay referencias inversas ni lookaround. Un patrón inválido devuelve INVALID_PATTERN.
  • Las coincidencias se encuentran solo dentro de líneas individuales. Un patrón que abarca un salto de línea nunca coincidirá.
  • Una entrada por línea coincidente, como grep -n, sin importar cuántas ocurrencias tenga esa línea.
  • truncated: true significa que el escaneo alcanzó su presupuesto y los resultados son parciales. Reduce el prefix o ajusta el patrón.
  • Los números de línea son solo para mostrar. Nunca pegues uno en el old_str de edit.

history

Lista las versiones de un archivo, de la más reciente a la más antigua.

Argumentos

workspace?   string
path         string
limit        integer   1..1000, default 50
cursor?      string    digits only

Devuelve

{
  "versions": [
    {
      "version": 7,
      "op": "write",
      "size": 1284,
      "content_hash": "...",
      "created_at": "2026-08-05T09:12:44Z",
      "by_label": "research-agent",
      "by_actor": "agent",
      "moved_from": "drafts/todo.md",
      "purged": false,
      "restorable_until": "2027-08-05T09:12:44Z"
    }
  ],
  "next_cursor": "182734"
}

op es uno de write, edit, move, delete, restore. moved_from, by_actor y restorable_until son opcionales.

Errores: NOT_FOUND, INVALID_PATH.

Notas

  • De la más reciente a la más antigua, por lo que limit: 1 es la forma más barata de confirmar que una escritura llegó.
  • next_cursor es una cadena opaca, nunca un número. Está ausente en la última página, así es como sabes que debes detenerte.
  • purged: true significa que la retención liberó el contenido de esa versión. La fila permanece para el rastro de auditoría, pero restore a ella devuelve NOT_FOUND con reason: "version_purged".

activity

Lista qué cambió en un espacio de trabajo y qué agente lo cambió.

Argumentos

workspace?    string
since?        string    RFC 3339 timestamp
path_prefix?  string
limit         integer   1..1000, default 100
cursor?       string

Devuelve

{
  "events": [
    {
      "at": "2026-08-05T09:12:44Z",
      "actor": "agent",
      "by_label": "research-agent",
      "by_actor": "agent",
      "op": "write",
      "path": "notes/todo.md",
      "old_path": "drafts/todo.md",
      "version": 7
    }
  ],
  "next_cursor": "9014522"
}

actor es uno de agent, user, system. De la más reciente a la más antigua.

op es write, edit, move, delete, restore, purge, lock, unlock o grep. Los barridos del sistema también registran purge_retention y purge_workspace_delete, ambos sin ruta. Solo write, edit, move, delete y un restore de un solo archivo llevan un version; en el resto es nulo. Ten en cuenta que purge lleva una ruta real o un prefijo de carpeta, por lo que coincide con un filtro path_prefix: si estás auditando una carpeta desde este feed, una purga aparece junto a las escrituras.

Errores: INVALID_PATH.

Notas

  • next_cursor es una cadena opaca, nunca un número. Está ausente en la última página, así es como sabes que debes detenerte.
  • Esto es un sondeo. No hay webhooks, ni disparadores, ni push. Los agentes se coordinan llamando a activity en un intervalo, lo que cabe cómodamente dentro del límite de tasa a una cadencia de segundos a minutos.
  • since es una marca de tiempo, no un cursor, y dos eventos pueden compartir una. Espera re-entrega ocasional y haz el trabajo idempotente. Ver examples/two-agent-handoff.md.

write

Crea o reemplaza un archivo con contenido en línea.

Argumentos

workspace?         string
path               string
content            string
encoding           "utf8" | "base64"   default "utf8"
mime_type?         string
expected_version?  integer   fail instead of overwriting a concurrent change
override_lock      boolean   default false

Límite en línea: 1 MiB decodificado. Cualquier cosa más grande pasa por request_upload.

Devuelve

{
  "path": "notes/todo.md",
  "version": 8,
  "size": 1301,
  "content_hash": "...",
  "deduplicated": false,
  "unchanged": true
}

unchanged está presente solo cuando corresponde.

Errores: INVALID_PATH, VERSION_CONFLICT, LOCKED, QUOTA_EXCEEDED, TOO_LARGE.

Notas

  • Escribir contenido byte-idéntico a la versión actual es un no-op: devuelve unchanged: true y no crea una nueva versión. Para un trabajo programado, vale la pena registrarlo en voz alta, porque generalmente significa que el generador no se ejecutó.
  • El contenido idéntico a una versión anterior sí crea una nueva versión.
  • Escribir en una ruta marcada como eliminada la resucita.

edit

Aplica reemplazos de cadenas a un archivo de texto existente sin reenviar todo el cuerpo.

Argumentos

workspace?         string
path               string
edits              array of 1..20 objects:
                     old_str      string    min 1 char
                     new_str      string
                     replace_all  boolean   default false
expected_version?  integer
override_lock      boolean   default false

Archivos de texto de hasta 16 MiB.

Devuelve

{
  "path": "notes/todo.md",
  "version": 9,
  "edits_applied": 2,
  "replacements": [1, 3],
  "size_before": 1301,
  "size_after": 1288,
  "context": "..."
}

unchanged está presente solo cuando corresponde.

Errores: STRING_NOT_FOUND, STRING_NOT_UNIQUE, NOT_EDITABLE, TOO_LARGE_FOR_EDIT, VERSION_CONFLICT, LOCKED, QUOTA_EXCEEDED, NOT_FOUND.

Notas

  • Las ediciones se aplican en orden y se confirman atómicamente como una nueva versión, por lo que una llamada con 20 ediciones es una entrada en history, no veinte. Si alguna edición falla, ninguna se aplica.
  • Cada old_str debe coincidir exactamente una vez; de lo contrario, obtienes STRING_NOT_FOUND o STRING_NOT_UNIQUE. Establece replace_all cuando quieras que coincida en cada ocurrencia.
  • Como las ediciones se aplican en orden, un old_str posterior debe coincidir con el texto tal como lo dejaron las ediciones anteriores.

move

Mueve o renombra un archivo.

Argumentos

workspace?         string
from               string
to                 string
expected_version?  integer
overwrite          boolean   default false
override_lock      boolean   default false

Devuelve

{ "from": "drafts/todo.md", "to": "notes/todo.md", "version": 1 }

version es la nueva versión en el destino.

Errores: NOT_FOUND, INVALID_PATH, VERSION_CONFLICT (con reason: "destination_exists"), LOCKED.

Notas

  • El token necesita acceso de escritura a ambas rutas. Una regla de prefijo que cubre el origen pero no el destino falla con PERMISSION_DENIED.
  • Un destino activo con overwrite: false devuelve VERSION_CONFLICT con reason: "destination_exists". Ese fallo es útil: dos trabajadores compitiendo por reclamar el mismo elemento pueden move, y el perdedor recibe un error limpio en lugar de trabajo duplicado.

delete

Marca un archivo como eliminado (tombstone).

Argumentos

workspace?         string
path               string
expected_version?  integer
override_lock      boolean   default false

Devuelve

{ "path": "notes/todo.md", "version": 10, "unchanged": true }

unchanged está presente solo cuando corresponde.

Errores: NOT_FOUND, INVALID_PATH, VERSION_CONFLICT, LOCKED.

Notas

  • Esto escribe una versión de eliminación, no borra el contenido. El archivo sigue siendo recuperable con restore durante el tiempo que permita la ventana de historial de versiones de tu plan.
  • Escribir en la misma ruta más tarde lo resucita como una nueva versión en el mismo historial.
  • list oculta las rutas eliminadas a menos que pases include_deleted: true.

restore

Restaura un archivo a una versión anterior, o una carpeta completa a un punto en el tiempo.

Argumentos, forma de archivo:

workspace?      string
path            string
to_version      integer
override_lock   boolean   default false

Argumentos, forma de carpeta:

workspace?      string
prefix          string
at              string    RFC 3339 timestamp in UTC, e.g. 2026-08-05T14:04:55Z
override_lock   boolean   default false

Devuelve, forma de archivo:

{ "path": "notes/todo.md", "version": 11 }

Devuelve, forma de carpeta:

{
  "restored": 42,
  "deleted": 3,
  "affected_paths": ["content/pricing.md", "content/index.md"],
  "total": 45
}

affected_paths es una muestra limitada; total es el recuento real.

Errores: NOT_FOUND (con reason: "version_purged" cuando la retención ya liberó la versión objetivo), INVALID_PATH, LOCKED.

Notas

  • at debe ser UTC, terminando en Z, con milisegundos opcionales. Un desplazamiento UTC como +02:00 se rechaza aunque sea RFC 3339 válido, así que convierte antes de llamar.
  • La restauración agrega nuevas versiones y nunca reescribe el historial. Las versiones malas permanecen en history, por lo que restaurar a una marca de tiempo incorrecta es en sí mismo restaurable, y restaurar dos veces es seguro.
  • En la forma de carpeta, los archivos que no existían en at reciben eliminaciones (tombstones), contadas por deleted. No se borran y una escritura posterior los trae de vuelta.
  • No hay simulación (dry run). Dimensiona la operación con list y confirma un solo archivo con history primero. Recorrido: examples/folder-restore-after-bad-run.md.

lock

Toma un bloqueo de asesoramiento sobre una ruta.

Argumentos

workspace?   string
path         string

Devuelve

{ "path": "notes/todo.md", "expires_at": "2026-08-05T09:17:44Z" }

Errores: LOCKED, INVALID_PATH.

Notas

  • De asesoramiento y 5 minutos. Llama a lock de nuevo con el mismo token para renovarlo.
  • Los bloqueos nunca bloquean lecturas. Un bloqueo válido ajeno hace que las escrituras devuelvan LOCKED con locked_by_label y expires_at, a menos que el llamador pase override_lock: true, lo cual se registra en el feed de actividad.
  • El archivo no necesita existir, así que puedes bloquear una ruta que estás a punto de crear.
  • Para trabajo que pueda hacerse idempotente, prefiere una reclamación con move sobre un bloqueo: sobrevive a un fallo, y un TTL de 5 minutos no.

unlock

Libera un bloqueo que este token mantiene.

Argumentos

workspace?   string
path         string

Devuelve

{ "path": "notes/todo.md", "released": true }

Errores: PERMISSION_DENIED (el bloqueo pertenece a otro token), INVALID_PATH.

Notas

  • Desbloquear una ruta sin bloqueo devuelve released: true, no NOT_FOUND. La llamada no dice nada sobre si existía un bloqueo, así que no es una forma de preguntar quién lo tiene.

request_upload

Inicia una subida para contenido demasiado grande para write en línea. Primero de dos pasos; ver Large file uploads.

Argumentos

workspace?         string
path               string
size               integer   positive, the exact byte count of the file
mime_type?         string
expected_version?  integer
override_lock      boolean   default false

Devuelve

{
  "upload_id": "...",
  "put_url": "https://...",
  "url_expires_at": "2026-08-05T09:27:00Z",
  "max_size": 1073741824
}

Errores: TOO_LARGE, QUOTA_EXCEEDED, VERSION_CONFLICT, LOCKED, INVALID_PATH.

Notas

  • La URL PUT prefirmada es válida por 15 minutos y el registro de subida por 1 hora. No hay subida reanudable ni multiparte: si el PUT falla, comienza de nuevo desde request_upload.
  • size debe ser el recuento exacto de bytes. Se vuelve a verificar en finalize_upload.

finalize_upload

Confirma un archivo subido como una nueva versión. Segundo de dos pasos.

Argumentos

workspace?   string
upload_id    string

Devuelve

{
  "path": "datasets/corpus.tar.gz",
  "size": 431912448,
  "version": 3,
  "content_hash": "..."
}

Errores: UPLOAD_EXPIRED, VERSION_CONFLICT, QUOTA_EXCEEDED, TOO_LARGE.

Notas

  • El tamaño y expected_version se vuelven a verificar aquí, así que un VERSION_CONFLICT puede aparecer en la finalización aunque request_upload haya tenido éxito. Alguien escribió la ruta mientras subías; comienza de nuevo desde request_upload.
  • Llamar a finalizar una segunda vez devuelve UPLOAD_EXPIRED.

Errores

Los fallos de dominio vuelven como un resultado de herramienta normal que lleva isError: true, cuyo contenido de texto es JSON:

{ "code": "VERSION_CONFLICT", "message": "...", "current_version": 9 }

Nunca son errores de protocolo JSON-RPC. Los agentes y clientes deben ramificar según code.

La validación de argumentos falla de la misma manera, pero el texto no es JSON. Pasar un argumento del tipo incorrecto devuelve isError: true con una cadena en inglés simple como MCP error -32602: Input validation error: Invalid arguments for tool activity: ..., producida por la capa MCP antes de que la solicitud llegue a Layven. Así que analiza de forma defensiva: un resultado isError cuyo texto no se analice como JSON es un error en tu llamada, no un error de dominio de Layven. upload/layven-upload.mjs hace exactamente esto, recurriendo a code: "UNKNOWN" con el texto crudo como mensaje.

CódigoSignificadoExtras
NOT_FOUNDRuta, versión o espacio de trabajo ausenteworkspaces (los slugs del token) cuando un slug de espacio de trabajo no se resuelve; deleted: true y last_version en una ruta eliminada; reason: "version_purged" en una versión purgada
PERMISSION_DENIEDEl token carece del nivel de acceso, o una regla de prefijo bloquea la rutarequired
INVALID_PATHLa ruta falla la normalizaciónreason
VERSION_CONFLICTexpected_version no coincidió, o el destino existecurrent_version, a veces reason (por ejemplo destination_exists)
LOCKEDOtro token mantiene un bloqueo válidolocked_by_label, expires_at
QUOTA_EXCEEDEDLa organización superó su cuota de almacenamientolimit_bytes, used_bytes
TOO_LARGEContenido en línea sobre el límite, o archivo sobre 1 GiBmax_bytes
UPLOAD_EXPIREDFinalizar llamado en una subida expirada o ya consumida
RATE_LIMITEDLímite de tasa del token o la organización alcanzadoretry_after_ms
INTERNALFallo inesperado del servidorrequest_id
STRING_NOT_FOUNDedit: old_str no está presente en el archivopista
STRING_NOT_UNIQUEedit: old_str coincidió más de una vez y replace_all no se estableció
NOT_EDITABLEedit: el archivo no es texto
TOO_LARGE_FOR_EDITedit: archivo sobre 16 MiB
INVALID_PATTERNgrep: el patrón no es RE2 válido

RATE_LIMITED es el único código que vale la pena reintentar automáticamente: duerme retry_after_ms, luego intenta de nuevo.


Límites

LímiteValor
Escritura en línea1 MiB decodificado; contenido más grande va a través de request_upload
Lectura en línea256 KiB y un tipo MIME de texto, de lo contrario una URL de descarga
EdiciónArchivos de texto hasta 16 MiB, hasta 20 ediciones por llamada
Grep8 MiB por archivo escaneado, 500 archivos candidatos por llamada, resultados parciales más allá del presupuesto de tiempo
Tamaño máximo de archivo1 GiB
URL PUT prefirmada15 minutos
Registro de subida1 hora
URL de descarga15 minutos
Longitud de ruta1024 bytes
TTL de bloqueo5 minutos, renovable
Límite de tasa600 solicitudes por minuto por token, 3000 por minuto por organización

Exceder un límite de tasa devuelve RATE_LIMITED con retry_after_ms.


Rutas y versionado

Las rutas son UTF-8, separadas por / y sensibles a mayúsculas. Se normalizan en la entrada:

  • sin barra inicial: /a/b se convierte en a/b
  • sin barras duplicadas
  • sin segmentos . o .., y sin segmentos vacíos
  • sin barra final en un archivo
  • sin caracteres de control
  • máximo 1024 bytes

Cualquier otra cosa devuelve INVALID_PATH con un reason. Los directorios son implícitos: no hay registros de carpetas, y list sintetiza carpetas a partir de prefijos de ruta.

Versionado. Cada mutación crea una nueva versión, numerada por archivo. delete escribe una versión de eliminación. move crea una versión en el destino y elimina el origen. restore agrega una nueva versión que reproduce un estado anterior. El historial es de solo agregar y nunca se reescribe, por eso una restauración mala es en sí misma restaurable.

Concurrencia optimista. El valor predeterminado es último-escritura-gana, lo cual es seguro porque nada se pierde. Cuando quieras que una escritura falle en lugar de sobrescribir un cambio concurrente, pasa expected_version con la versión que leíste. Una discrepancia devuelve VERSION_CONFLICT con current_version en la carga útil, para que el llamador pueda volver a leer y decidir.

Bloqueos. lock toma un bloqueo de asesoramiento de 5 minutos, renovado llamando a lock de nuevo con el mismo token. Un bloqueo válido ajeno hace que las escrituras devuelvan LOCKED con locked_by_label y expires_at; override_lock: true continúa de todos modos y se registra en el feed de actividad. Los bloqueos nunca bloquean lecturas.


Permisos

A cada token se le otorga acceso a espacios de trabajo específicos en uno de tres niveles:

NivelHerramientas
rolist, read, grep, history, activity
rwtodo en ro, más write, edit, move, delete, restore, lock, unlock, request_upload, finalize_upload
adminreservado para futura gestión de espacios de trabajo

Una concesión puede llevar reglas de prefijo opcionales que restringen un token a carpetas particulares, expresadas como listas allow o deny. Denegar supera a permitir. move requiere permiso tanto en la ruta de origen como en la de destino.

Dale a cada agente su propio token. Eso es lo que hace que by_label en list, history y activity sea legible, y es lo que te permite revocar un agente sin tocar a los demás.


Subidas de archivos grandes

write en línea tiene un límite de 1 MiB. Por encima de eso, sube en tres pasos.

1. Pide una URL. Llama a request_upload con el recuento exacto de bytes:

{ "path": "datasets/corpus.tar.gz", "size": 431912448, "mime_type": "application/gzip" }
{
  "upload_id": "...",
  "put_url": "https://...",
  "url_expires_at": "2026-08-05T09:27:00Z",
  "max_size": 1073741824
}

2. Haz PUT de los bytes a put_url. Esto es un PUT HTTP simple del archivo crudo, no una llamada MCP. La URL es válida por 15 minutos.

3. Confírmalo. Llama a finalize_upload:

{ "upload_id": "..." }
{
  "path": "datasets/corpus.tar.gz",
  "size": 431912448,
  "version": 3,
  "content_hash": "..."
}

Por qué no hay SDK

No hay una biblioteca cliente de Layven y no la habrá. Layven es un servidor MCP alojado: apuntas tu cliente a una URL y tu agente obtiene 14 herramientas, sin código que escribir y nada que mantener actualizado. Esta es la única excepción. El flujo de subida tiene un paso intermedio que es un PUT HTTP crudo, y un cliente MCP no puede emitir uno, así que enviamos un único script sin dependencias para ello. Cópialo, léelo, cámbialo. Es MIT.

upload/layven-upload.mjs

Node 18 o más reciente. Sin dependencias, sin instalación.

LAYVEN_TOKEN=agd_your_agent_token \
node upload/layven-upload.mjs ./corpus.tar.gz datasets/corpus.tar.gz \
  [--workspace slug] [--mime type] [--expected-version N] [--override-lock] \
  [--url https://api.layven.io/mcp]

LAYVEN_TOKEN es obligatorio. --url por defecto es https://api.layven.io/mcp.

Ejecuta sus pruebas desde la raíz del repositorio con:

node --test

Ejemplos


Planes

FreePro $19/moScale $49/moEnterprise
Almacenamiento5 GB100 GB500 GBPersonalizado
Historial de versiones30 días1 añoIlimitadoIlimitado
Registro de actividad30 días1 año1 añoIlimitado
Espacios de trabajo1525Ilimitado
Tokens225100Ilimitado
Usuarios1310Ilimitado
Tamaño máximo de archivo1 GiB1 GiB1 GiB1 GiB
Límite de peticiones600 req/min/token600 req/min/token600 req/min/token600 req/min/token

Precio fijo. Sin medidores, sin créditos.


Residencia de datos

Tus archivos se almacenan en OVHcloud en Gravelines, Francia, y están cifrados en reposo. Ninguna IA de terceros ni API de modelos toca tu contenido. Puedes exportar todo como archivos planos, y la eliminación es una eliminación real.


Control de versiones

La versión en server.json y en el changelog coincide con la versión que el servidor informa en initialize, para que siempre puedas comprobar con qué estás hablando. Los cambios de documentación que no siguen un cambio de servidor no incrementan la versión.

Consulta CHANGELOG.md.


Soporte

Errores en estos documentos, los ejemplos o el asistente de carga: abre un issue. Preguntas sobre cuenta, facturación o datos: info@layven.io.


Licencia

MIT cubre este repositorio: la documentación, los ejemplos y el asistente de carga. El servicio Layven en sí es de código cerrado.