Servidor MCP
@rebasepro/mcp es un servidor del Model Context Protocol
que proporciona a un asistente de IA herramientas reales sobre un proyecto de Rebase:
leer y escribir filas, gestionar usuarios, ejecutar migraciones, invocar funciones y
controlar el servidor de desarrollo.
Se comunica mediante MCP únicamente a través de stdio. No hay puerto ni listener; el proceso es tan confiable como lo que lo haya generado, y no hay ningún emisor remoto que autenticar. Esa es la parte segura. Las preguntas interesantes tratan sobre lo que hace una vez que se está ejecutando, y esta página las responde antes de mostrarte el bloque de configuración.
Un backend desplegado también puede servir MCP por sí mismo, a través de HTTP, para las personas que usan tu aplicación. Eso es algo diferente con un modelo de credenciales distinto: consulta El endpoint remoto.
Conectar un cliente
Sección titulada «Conectar un cliente»El servidor se ejecuta desde tu proyecto: @rebasepro/mcp es una devDependency que
cada scaffold de rebase init fija con la CLI, y cada bloque a continuación — la
integración completa — arranca esa copia (pnpm exec rebase-mcp, o npx --no rebase-mcp
en un proyecto npm), nunca una más reciente desde npm. Un proyecto más antiguo la añade
una vez, con rebase skills install --mcp o pnpm add -D @rebasepro/mcp.
rebase init escribe el bloque para cada agente que elijas cuando
configura tus agentes de programación con IA, manteniendo
cualquier otro servidor que ya esté en el archivo. rebase init --agent cursor,codex hace
lo mismo sin preguntar.
Claude Code — .mcp.json en la raíz de tu proyecto. rebase init escribe este
archivo por ti:
{ "mcpServers": { "rebase": { "command": "pnpm", "args": ["exec", "rebase-mcp"], "env": { "REBASE_PROJECT_DIR": "." } } }}Cursor — la misma estructura, en .cursor/mcp.json. Cursor expande
${workspaceFolder} a la raíz del proyecto:
{ "mcpServers": { "rebase": { "command": "pnpm", "args": ["exec", "rebase-mcp"], "env": { "REBASE_PROJECT_DIR": "${workspaceFolder}" } } }}Gemini CLI — .gemini/settings.json, bajo la misma clave:
{ "mcpServers": { "rebase": { "command": "pnpm", "args": ["exec", "rebase-mcp"], "env": { "REBASE_PROJECT_DIR": "." } } }}Codex CLI — TOML en lugar de JSON, en el .codex/config.toml del proyecto.
Codex lee la configuración de un proyecto solo una vez que hayas confiado en él:
[mcp_servers.rebase]command = "pnpm"args = ["exec", "rebase-mcp"]
[mcp_servers.rebase.env]REBASE_PROJECT_DIR = "."Kiro — .kiro/settings/mcp.json:
{ "mcpServers": { "rebase": { "command": "pnpm", "args": ["exec", "rebase-mcp"], "env": { "REBASE_PROJECT_DIR": "." } } }}GitHub Copilot en VS Code — .vscode/mcp.json, bajo servers y con
un transporte explícito:
{ "servers": { "rebase": { "type": "stdio", "command": "pnpm", "args": ["exec", "rebase-mcp"], "env": { "REBASE_PROJECT_DIR": "${workspaceFolder}" } } }}Windsurf lee los servidores MCP únicamente desde su configuración a nivel de usuario,
por lo que no hay ningún archivo de proyecto que escribir. Añade el servidor en su
configuración de MCP como "command": "pnpm", "args": ["--dir", "/absolute/path/to/your/project", "exec", "rebase-mcp"],
con esa misma ruta en REBASE_PROJECT_DIR.
Cualquier cliente MCP que pueda iniciar un servidor stdio funcionará; la estructura es la misma.
Sobre qué directorio actúa
Sección titulada «Sobre qué directorio actúa»REBASE_PROJECT_DIR es el directorio que contiene rebase.json. Hay una
precedencia y es la misma en todos los clientes:
- El bloque de entorno —
REBASE_PROJECT_DIR,REBASE_BASE_URL,REBASE_API_TOKEN. Si cualquiera de ellos está definido, el proyectodefaultse reconstruye a partir de ellos en cada inicio. - El directorio de trabajo del servidor, cuando contiene un
rebase.json. Un proyecto en el que te encuentras tiene prioridad sobre cualquier cosa guardada en~/.rebase/projects.json. - El
defaultpersistido en~/.rebase/projects.json, cuando ninguno de los dos primeros indica nada.
El autodescubrimiento desde .rebase/state.json llena vacíos en los tres casos y nunca
anula un valor proporcionado por alguno de ellos.
Los bloques a nivel de proyecto definen el proyecto (".", el directorio de trabajo del
cliente o el ${workspaceFolder} del editor) porque la regla 3 lee un archivo compartido
por todos los proyectos del equipo. Una configuración a nivel de usuario, como la de Windsurf,
especifica una ruta absoluta en su lugar.
A qué puede acceder el servidor
Sección titulada «A qué puede acceder el servidor»Esta es la sección que debes leer antes de apuntar un asistente a una base de datos que te importe.
El servidor cuenta con una única credencial ambiental para todo el proceso. No hay identidad por herramienta ni modo de solo lectura; cada herramienta utiliza el mismo token, y la única opción disponible en el paquete sirve para habilitar más alcance en lugar de reducirlo.
Qué credencial es esa, en orden de prioridad:
REBASE_API_TOKEN/REBASE_TOKENdel entornoREBASE_SERVICE_KEYleída desde el.envdel proyecto- La clave de servicio descubierta automáticamente desde
.rebase/state.jsonmientrasrebase devestá en ejecución
Un token que registres para un proyecto prevalece sobre el autodescubrimiento. El descubrimiento solo llena vacíos.
Proporcionar una credencial restringida en su lugar
Sección titulada «Proporcionar una credencial restringida en su lugar»Registra una clave de API con alcance restringido y el modelo de dos
barreras se aplicará de verdad. Una clave de servicio se ejecuta con los roles
["service"], los cuales las políticas de administración inyectadas no nombran; por lo tanto,
RLS no le otorga nada a menos que una de tus propias políticas indique lo contrario, y sus
alcances la restringen aún más:
rebase api-keys create -n "claude-code" \ --scopes data:read:articles \ --expires-in 30Luego, entrega la clave rk_live_… resultante al servidor en lugar de dejar que descubra
una clave de servicio:
{ "mcpServers": { "rebase": { "command": "pnpm", "args": ["exec", "rebase-mcp"], "env": { "REBASE_PROJECT_DIR": "/absolute/path/to/your/project", "REBASE_API_TOKEN": "rk_live_..." } } }}Dos cosas que esto no hace, ambas importantes antes de depender de ello:
- No restringe las herramientas de CLI.
rebase_db_push,rebase_db_migrate,rebase_doctory las herramientas de ramas inician la CLI de Rebase, la cual se conecta conDATABASE_URLy nunca ve tu token. La barrera de loopback que se describe a continuación es lo único que se interpone frente a ellas. - Una clave llega a una herramienta de administración solo con el alcance de esa herramienta.
list_usersylist_rolesnecesitanusers:read;create_user,update_user,delete_useryrebase_auth_reset_passwordnecesitanusers:write; las herramientas de almacenamiento y de cron necesitan el alcancestorage:*ocron:*correspondiente;invoke_functionnecesitafunctions:invoke. Sin él, la llamada responde403 SCOPE_MISSING. Incluso conusers:write, una clave no puede cambiar la cuenta de un administrador: un administrador tienekeys:readykeys:write, que ninguna clave puede tener, y nadie puede gestionar una cuenta que tenga más que él.
Una clave creada con --roles admin es un asunto diferente: cuenta con los roles
["service", "admin"], lo que cumple las mismas políticas de administración predeterminadas
que la clave de servicio. Si además le das --full-access, su alcance es el de la clave de
servicio, menos la gestión de claves. La diferencia es que es revocable, puede expirar y
cuenta con límites de tasa por clave, características que no aplican a la clave de servicio;
rotar esa última requiere editar .env y reiniciar el servidor.
Consulta Agentes y servidores MCP para ver la guía completa sobre el alcance de claves.
Dejar una colección completamente fuera de alcance
Sección titulada «Dejar una colección completamente fuera de alcance»La razón por la que una credencial de administrador lee todo es la política base que Rebase
inyecta en cada colección, otorgando el contexto de servidor de confianza y el rol admin.
Una colección puede optar por no aplicar esa base y asumir la responsabilidad total de su propia RLS:
import { defineCollection } from "@rebasepro/cms-types";
export const medicalRecordsCollection = defineCollection({ slug: "medical_records", name: "Medical records", table: "medical_records", properties: { patient_id: { name: "Patient", type: "string" }, notes: { name: "Notes", type: "string" } }, // Remove the injected admin/server baseline — nothing is readable // except what the rules below allow. disableDefaultPolicies: true, securityRules: [ { operations: ["select", "update"], ownerField: "patient_id" } ]});Ahora la única forma de acceder es coincidir con patient_id. El uid de la clave de servicio
es la cadena literal service, por lo que una regla de propietario nunca coincidirá con ella:
las lecturas devolverán cero filas y las escrituras serán rechazadas por Postgres. Este es el
único control que restringe la credencial predeterminada del servidor MCP en lugar de darla
por supuesta.
Recuerda que este es un cambio real de RLS, no documental: surte efecto únicamente una vez
que rebase schema generate y una migración hayan aplicado las políticas. Consulta
Reglas de seguridad (RLS).
La barrera de loopback
Sección titulada «La barrera de loopback»rebase_project_add acepta cualquier baseUrl, y las herramientas de CLI se conectan con
cualquier DATABASE_URL que declare el proyecto. Por lo tanto, la misma lista de herramientas
que edita una base de datos de prueba en tu ordenador puede eliminar filas de producción, sin
nada de por medio excepto el criterio del asistente sobre qué proyecto está activo.
Cualquier herramienta que modifique el entorno de destino es rechazada a menos que ese destino esté en la interfaz de loopback. La barrera está estructurada como una lista de lo que no está restringido, de modo que una herramienta agregada más tarde llega protegida de forma predeterminada.
- Sin restricción — lecturas:
rebase_schema_plan,rebase_doctor,rebase_db_branch_list,rebase_db_branch_info,list_documents,get_document,list_users,list_roles,storage_list_objects,storage_get_download_url,cron_list_jobs,cron_get_job,cron_get_job_logs,rebase_dev_logs. - Sin restricción — solo locales:
rebase_schema_introspect,rebase_schema_generate,rebase_db_generate,rebase_generate_sdk, las herramientas del servidor de desarrollo y las herramientas del registro de proyectos. Estas escriben archivos locales o estado local y no tienen un destino remoto que verificar. - Restringidas contra
DATABASE_URL: las herramientas de CLI restantes —rebase_db_push,rebase_db_migrate,rebase_db_branch_create,rebase_db_branch_delete. - Restringidas contra la
baseUrldel proyecto: las herramientas del SDK restantes —create_document,update_document,delete_document,create_user,update_user,delete_user,rebase_auth_reset_password,storage_delete_object,cron_trigger_job,cron_toggle_job,invoke_function.
Los dos destinos no son intercambiables. Las herramientas de CLI nunca ven baseUrl, por lo
que un backend en localhost situado junto a una DATABASE_URL de producción se comprueba
contra la base de datos, no contra el backend.
Un rechazo tiene este aspecto:
Error: Refusing to run "delete_document": project "default" points athttps://api.example.com/, which is not local. Set REBASE_MCP_ALLOW_REMOTE_WRITES=trueto allow destructive tools against remote environments.Si no se puede resolver ninguna cadena de conexión, las herramientas de base de datos con barrera son rechazadas.
Sin DATABASE_URL, la CLI usa la base de datos de desarrollo gestionada, que es la
predeterminada en un proyecto nuevo, y la barrera rechaza allí sus cuatro herramientas de
base de datos. El rechazo explica por qué y nombra lo que sí funciona. No sugiere la
desactivación de la barrera:
Error: Refusing to run "rebase_db_push": project "default" sets no DATABASE_URL, so theCLI would use the managed development database (PGlite, started by `rebase dev`). Youmost likely do not need this tool: the dev server applies the collections to thatdatabase at boot, additively. After changing a collection, restart it withrebase_dev_stop and rebase_dev_start. …Desde 0.25 Desde una terminal,
rebase db push y rebase db migrate sí se ejecutan en esa base de datos; solo se
rechazan las herramientas de MCP. En la 0.24 la CLI también las rechaza allí.
Solo loopback cuenta como local: localhost, *.localhost, 127.0.0.0/8, ::1.
Los rangos privados como 10.x y 192.168.x no lo hacen; es tan probable que sean
un clúster de staging compartido como un ordenador portátil, y tratarlos como locales
permitiría exactamente el accidente que la barrera existe para evitar.
Establece REBASE_MCP_ALLOW_REMOTE_WRITES=true para desactivar esta protección. Establecerlo
globalmente en la configuración de tu cliente MCP elimina la barrera para todos los proyectos
a los que el servidor pueda acceder, no solo para aquel en el que estabas pensando.
Marcado de datos no confiables
Sección titulada «Marcado de datos no confiables»Las filas, los registros de usuario, las listas de almacenamiento, las tareas cron, las respuestas de funciones y la salida de CLI se devuelven envueltos en un contenedor explícito:
<<<UNTRUSTED_DATA source="list_documents" id="9b2f4c1e-…">>>[ … rows … ]<<<END_UNTRUSTED_DATA id="9b2f4c1e-…">>>Cualquier cosa almacenada en tu base de datos fue escrita por alguien, y llega por el mismo canal que el contrato de herramientas que sigue el asistente. El contenedor le indica al modelo que lo trate como contenido inerte y no como instrucciones.
El id se genera de forma nueva para cada respuesta, después de que los datos fueron escritos,
y solo el marcador final que lo contiene cierra el bloque. El texto dentro de los datos que
tenga forma de marcador se divide con un espacio de ancho cero, por lo que una fila que imprima
<<<END_UNTRUSTED_DATA>>> no puede cerrar el contenedor antes de tiempo ni dejar fuera lo que sigue.
El endpoint remoto marca los resultados de sus herramientas de la misma
forma y se lo indica al cliente; su structuredContent transporta el resultado sin marcar.
Desde 0.25 list_collections y
describe_collection son las excepciones: solo un modelo las lee, así que se envían
una sola vez, en el texto. Antes de la 0.24 el listado llevaba además una copia en
structuredContent.
Es un marcador, no un entorno aislado (sandbox). Un asistente que disponga de estas herramientas es tan seguro como el contenido que le permitas leer.
Múltiples proyectos
Sección titulada «Múltiples proyectos»Las configuraciones de proyectos se almacenan en ~/.rebase/projects.json, y el servidor puede
albergar varias a la vez, lo cual resulta útil cuando trabajas entre entornos locales y remotos.
Mientras rebase dev está en ejecución, el servidor lee el puerto activo y la clave de servicio
desde .rebase/state.json en el directorio del proyecto, que es lo que hace que el caso local
funcione sin configuración previa.
Los tokens se almacenan en ese registro en texto plano. Es un archivo en tu directorio de inicio que contiene credenciales de administrador para cada proyecto que hayas registrado; trátalo en consecuencia.
Referencia de herramientas
Sección titulada «Referencia de herramientas»42 herramientas, en nueve grupos: esquema y base de datos, planificación de esquema, documentos, usuarios y roles, almacenamiento, cron, funciones, el servidor de desarrollo y el registro de proyectos. Cada una, con lo que necesita y si la barrera la rechaza frente a un destino no local, está en la referencia de herramientas MCP.
Recursos
Sección titulada «Recursos»Más allá de las herramientas, el servidor expone recursos MCP para que un cliente pueda extraer el contexto del proyecto sin gastar una llamada a herramienta:
| URI | Descripción |
|---|---|
rebase://collections/{name} |
Código fuente en TypeScript de una definición de colección |
rebase://schema |
El esquema generado de Drizzle (schema.generated.ts) |
Las colecciones se descubren a partir de app/config/collections/, config/collections/
o collections/ bajo el directorio del proyecto activo, cualquiera que exista.
rebase://schema se lista solo si el esquema generado existe. findBackendDir busca
backend/ y luego app/backend/ bajo el directorio del proyecto activo, y lee
src/schema.generated.ts de donde lo encuentre; por lo que tanto la estructura inicial
como la de este monorepositorio funcionan, y un proyecto estructurado de una tercera forma,
o uno que aún no haya ejecutado rebase schema generate, simplemente no verá ofrecido el recurso.
El endpoint remoto
Sección titulada «El endpoint remoto»Todo lo anterior es una herramienta para desarrolladores: se ejecuta en tu máquina y utiliza
una clave de servicio o una clave de API. Un backend desplegado también puede servir MCP por
sí mismo, en /mcp, para las personas que usan tu aplicación. Un asistente que alguno de ellos
conecte lee y escribe en el proyecto como esa persona, y cada llamada se ejecuta bajo su
propia seguridad a nivel de fila (RLS).
Está desactivado a menos que lo actives, y ambas variables son obligatorias:
REBASE_MCP_ENABLED=trueREBASE_PUBLIC_URL=https://app.example.com # this deployment's real originSin REBASE_PUBLIC_URL, un secreto JWT o un controlador de datos que pueda restringir una
consulta a un usuario, el endpoint se niega a montarse y explica el motivo en el registro
de inicio. Ningún REBASE_ROLE lo activa.
- OAuth, con pantalla de consentimiento. Un cliente encuentra el servidor de autorización
a través de
/.well-known/oauth-protected-resource, se registra (el registro dinámico está activado por defecto;REBASE_MCP_OPEN_REGISTRATION=falselo limita a los clientes que registres) y envía a la persona a una pantalla de consentimiento que inicia su sesión a través de tu/auth/loginexistente. - Ocho herramientas, tres alcances. Los mismos alcances
que usa toda credencial.
data:readofrecelist_collections,describe_collection,query_collection,count_documentsyget_document;data:writeañadecreate_documentyupdate_document;data:deleteañadedelete_document. Un cliente que no pide nada recibedata:read. Cada uno se restringe a una colección:data:read:postslista, describe y leepostsy nada más. Un alcance decide qué herramientas se ofrecen y a qué colecciones llegan, no qué filas: una lista vacía puede ser resultado del funcionamiento de RLS, ydata:writesigue sin poder escribir una fila que la persona no podría. - Las concesiones anteriores a 0.24 conservan su alcance.
mcp:readse lee comodata:read, ymcp:writecomodata:write data:delete, en las concesiones guardadas y en los tokens ya emitidos. - También funciona una clave de API.
/mcpacepta ademásAuthorization: Bearer rk_…, para un cliente configurado con una cabecera en lugar de un flujo OAuth. La clave llega a las herramientas que cubren sus alcancesdata:*, como quien sea que represente: una clave personal como su propietario, una clave de servicio comoapi-key:<id>. - El vocabulario del SDK, las respuestas de REST. Las herramientas toman lo mismo que el
SDK —
where({"status": ["==", "paid"]}),orderBy(["created_at", "desc"]o"created_at:desc"),limit,offset,searchStringydatapara una escritura — y leen a través de la ruta deGET /api/data/<collection>, por lo que una fila llega tal como la sirve REST (fechas ISO, unabelongsTocomo su clave foránea, p. ej.authorId) y puede reenviarse sin cambios en una actualización.query_collectionresponde{ data, meta }conmeta.totalymeta.hasMore,count_documents{ count }. Igual que en REST, se rechazan unlimitsuperior a 1000, un argumento no declarado y una edición o eliminación de una fila en la papelera (404); poner el campo de borrado suave anullla restaura. - Desde 0.25 El listado nombra las colecciones;
describe_collectionda el esquema de una.list_collectionsresponde elname, eltitley ladescriptionde cada colección, ydescribe_collection { collection }el esquema OpenAPIrowycreatede esa colección, además desoftDeleteFieldcuando las filas van a una papelera. Las descripciones de las herramientas indican al modelo que describa una colección antes de escribir en ella. El listado de un proyecto de 200 colecciones ocupa unos 5k tokens, y cada descripción menos de 1k; con todos los esquemas en el listado eran unos 150k. - Un token solo para este endpoint. Un token de acceso MCP es rechazado por
/api/data,/api/adminy el WebSocket, por lo que conectar un asistente no le otorga una sesión.
Una limitación. Desconectar un cliente (DELETE /api/oauth/grants/:clientId, con la propia
sesión de la persona) revoca sus tokens de actualización de inmediato, pero un token de
acceso ya emitido sigue funcionando hasta que expire, dentro de una hora. Esa misma hora
delimita todo lo demás: cada actualización vuelve a leer los roles de la persona y rechaza
una cuenta que haya sido eliminada o una concesión anterior a su último “cerrar sesión en
todas partes” o cambio de contraseña. De este modo, una degradación de rol o un cierre de
sesión llega a un cliente conectado en el plazo de vida útil de un token de acceso. Una
sesión de invitado no puede otorgar consentimiento en absoluto.
Las rutas se encuentran en Endpoints y las variables en Configuración.
Configuración recomendada
Sección titulada «Configuración recomendada»- Apunta el servidor a un proyecto local y deja
REBASE_MCP_ALLOW_REMOTE_WRITESsin definir. La barrera es lo más valioso del paquete. - Para cualquier entorno remoto, registra una clave de API
rk_con alcance restringido en lugar de permitir que el descubrimiento entregue una clave de servicio. - Comprueba
rebase_project_currentcuando la salida parezca incorrecta. El proyecto activo es persistente y reside fuera de tu repositorio. - Trata
~/.rebase/projects.jsoncomo un archivo de secretos.