Ulule MCP

Creación de tu proyecto de financiación participativa

Servidor MCP alojado

npx add-mcp 'https://api.ulule.com/mcp/public'

Se instala en Claude Code, Codex, Cursor y más

Documentación

Ulule MCP

Ulule expone un servidor público MCP (Model Context Protocol). Permite que un cliente MCP — como Claude, Cursor o cualquier asistente compatible con OAuth 2.1 — actúe en nombre de un usuario de Ulule: redactar una propuesta de proyecto, editar uno de los proyectos del usuario, fijar su objetivo de financiación, añadir imágenes y recompensas, o escribir una actualización de noticias, todo desde una conversación.

El endpoint del servidor es:

post https://api.ulule.com/mcp/public

Habla MCP sobre Streamable HTTP (se aceptan tanto POST como GET) y es sin estado: cada solicitud se autentica por sí misma, por lo que no hay una sesión de larga duración que mantener. Es una superficie distinta de la API REST de Ulule: endpoint diferente, autenticación diferente y un pequeño conjunto de herramientas con ámbito de usuario en lugar del árbol completo de recursos REST.

En nombre de quién actúa

Cada herramienta actúa solo para el usuario que posee el token de acceso. La identidad siempre proviene del token — nunca se pasa un id de usuario como argumento. Como consecuencia, un id (una propuesta o un proyecto) que no pertenezca al usuario autenticado se reporta como no encontrado, nunca como prohibido, por lo que el servidor no puede usarse para sondear qué ids existen.

Cómo conectarse

  1. Apunta tu cliente MCP a https://api.ulule.com/mcp/public.
  2. El cliente descubre el servidor de autorización y recorre el flujo OAuth 2.1 — ver Conexión. La mayoría de los clientes lo hacen automáticamente; el usuario solo ve la pantalla de consentimiento de Ulule.
  3. Una vez autorizado, el cliente puede llamar a las herramientas.

Conexión

El servidor MCP está protegido por OAuth 2.1. El acceso es por usuario final: el cliente obtiene un token de acceso para la persona que lo usa, y ese token es en nombre de quien actúa cada herramienta.

A diferencia del método OAuth2 utilizado por la API REST, no necesitas una aplicación de socio pre-registrada: el servidor MCP admite registro dinámico de clientes y PKCE, que casi todos los clientes MCP realizan automáticamente. En la práctica, el usuario solo ve la pantalla de autorización de Ulule.

Descubrimiento

Una solicitud no autenticada al endpoint MCP devuelve 401 con un encabezado WWW-Authenticate que apunta al documento de metadatos del recurso protegido (RFC 9728):

get https://api.ulule.com/.well-known/oauth-protected-resource

Ese documento nombra el recurso (https://api.ulule.com/mcp/public) y el servidor de autorización, cuyos propios metadatos (RFC 8414) se sirven en:

get https://api.ulule.com/.well-known/oauth-authorization-server

Un cliente MCP lee estos dos documentos por sí mismo para encontrar los endpoints a continuación.

Endpoints

PasoEndpoint
Registrar un cliente (RFC 7591)POST https://api.ulule.com/oauth2/register/
Autorizar (pantalla de consentimiento del usuario)GET https://www.ulule.com/oauth2/authorize/
Intercambiar el código / renovar el tokenPOST https://api.ulule.com/oauth2/token/
Revocar un tokenPOST https://api.ulule.com/oauth2/revoke/

El flujo utiliza el grant authorization_code con PKCE (S256), y refresh_token para renovar un token de acceso caducado.

Uso del token

Envía el token de acceso en el encabezado Authorization, y en ningún otro lugar — un token pasado como parámetro de cadena de consulta se rechaza:

$ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" "https://api.ulule.com/mcp/public"

Límite de velocidad

Las llamadas tienen un límite de velocidad por usuario. Cuando se supera el límite, el servidor responde 429 Too Many Requests con un encabezado Retry-After; X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset se devuelven en cada respuesta para que un cliente pueda ajustar su ritmo.

Herramientas

Las herramientas que expone el servidor MCP público. Todas actúan solo para el usuario autenticado. Los campos multilingües (name, description, title, content) son objetos claveados por código de idioma, p. ej. {"fr": "Le Semainier"}, no cadenas simples.

ping

Comprueba que la conexión está autenticada y funciona. No toma argumentos y no devuelve datos sobre el usuario o sus proyectos. Útil para confirmar que un cliente está correctamente conectado antes de hacer cualquier otra cosa.

create_proposal

Envía una propuesta de proyecto de crowdfunding (en francés, proposition de collecte) en nombre del usuario. Es el primer paso para crear una campaña — no el proyecto en sí.

Solo se requieren country y description, por lo que una propuesta puede iniciarse ahora y completarse más tarde con update_proposal. Una propuesta está completa una vez que tiene país, moneda, idioma, descripción, un objetivo de financiación y recompensas; el campo submitted de la respuesta es false mientras sigue siendo un borrador incompleto y true una vez completa. Una propuesta completa se procesa automáticamente y no es revisada por un humano de inmediato. Si se acepta, se crea un proyecto a partir de ella como borrador no publicado: el propietario ya puede empezar a completarlo y ponerse en contacto con un coach, que modera el proyecto antes de que pueda publicarse. El id de ese proyecto aparece entonces como project_id en list_my_proposals — el identificador para las herramientas con ámbito de proyecto.

Llama a list_my_proposals primero: si ya hay una propuesta abierta, actualízala en lugar de crear una segunda.

ParámetroObligatorioDescripción
countryCódigo de país ISO 3166-1 alpha-2, p. ej. FR.
descriptionQué es el proyecto — lo que un coach lee primero.
nameTítulo del proyecto.
typeUno de project, presale, membership. Por defecto project.
currencyCódigo de moneda ISO 4217, p. ej. EUR.
langIdioma del proyecto, p. ej. fr.
goalObjetivo de financiación en la moneda elegida (para type=project).
goal_rangeObjetivo de financiación como horquilla {min, max} cuando no se fija una cifra exacta.
nb_products_minNúmero mínimo de unidades a vender. Obligatorio cuando type=presale.
rewardsQué reciben los mecenas, en prosa.
rewards_typeconcrete, symbolic, financial, none o undefined.
cityCiudad donde se basa el proyecto.
community_rangeAudiencia a la que ya llega el remitente, como horquilla {min, max}.
date_start_estimationCuándo planea lanzar el remitente.
legal_entity_typeForma jurídica del titular del proyecto.
structureEmpresa o asociación detrás del proyecto.
linksURLs del proyecto o de la audiencia existente del remitente.
phone_numberNúmero de teléfono de contacto (15 caracteres como máximo).
referencesCualquier otra cosa que el remitente quiera que sepan los coaches.

update_proposal

Actualiza una de las propuestas del usuario. Solo se cambian los campos que pasas; todo lo demás se deja intacto. Una vez que no falta nada, la propuesta se vuelve completa y se procesa automáticamente — no hay un paso de envío separado, y no es revisada por un humano de inmediato. Una propuesta ya aceptada ya no se puede editar: se ha convertido en un proyecto, cuyo id aparece como project_id en list_my_proposals. Una vez aceptada, el propietario puede empezar a completar ese proyecto y ponerse en contacto con un coach.

ParámetroObligatorioDescripción
proposal_idId de la propuesta a actualizar, tal como lo devuelve create_proposal o list_my_proposals.
otrosMismos campos que create_proposal (excepto city y community_range), cada uno opcional — un parche.

list_my_proposals

Lista las propuestas del usuario. No toma argumentos. Cada entrada lleva el id necesario para actualizarla, si está completa y ha sido procesada (submitted; una propuesta aún no enviada sigue siendo un borrador incompleto), y — una vez que una propuesta se acepta y se convierte en proyecto — el project_id que toman las herramientas con ámbito de proyecto.

update_project

Reescribe el título o la descripción de uno de los proyectos del usuario. Solo se cambian los campos que pasas, y ninguno puede vaciarse.

Esta herramienta no puede cambiar la imagen, el objetivo de financiación, las fechas, las recompensas o el estado. Para eso, la respuesta devuelve enlaces backoffice para enviar al usuario.

ParámetroObligatorioDescripción
project_idId del proyecto (no se acepta un slug).
nameTítulo del proyecto, claveado por código de idioma, p. ej. {"fr": "Le Semainier"}.
descriptionDescripción del proyecto (se permite HTML), claveada por código de idioma.

Debe proporcionarse al menos uno de name o description.

update_goal

Establece el tipo y el objetivo de financiación de uno de los proyectos del usuario. Solo se cambian los campos que pasas.

Cambiar el tipo solo es posible mientras el proyecto sigue siendo un borrador, y el objetivo ya no se puede cambiar una vez que la campaña está terminando. Cuando el estado del proyecto prohíbe el cambio, la herramienta responde con el motivo.

ParámetroObligatorioDescripción
project_idId del proyecto (no se acepta un slug).
typepresale (campaña de preventa) o project (recaudación todo o nada).
goalObjetivo de financiación como importe entero en la moneda del proyecto, p. ej. 5000. Debe ser positivo.

Debe proporcionarse al menos uno de type o goal.

create_project_image

Añade una imagen a uno de los proyectos del usuario. Los bytes se dan codificados en base64 (image_base64) o como una URL pública http(s) (image_url) — exactamente una de las dos. Los formatos aceptados son png, jpeg y gif, hasta 5.5 MB. Una URL obtenida debe ser públicamente accesible y no se sigue a través de redirecciones.

El type elige el rol de la imagen:

  • main — la imagen principal de la campaña, mostrada en la parte superior de la página pública del proyecto (al menos 640×360). Una por idioma.
  • background — la imagen de fondo de la página (al menos 1440×530). Una por idioma.
  • secondary — una imagen adicional guardada en la biblioteca de medios del proyecto. Se almacena pero no se muestra en la página pública por sí sola; para mostrarla, toma el url que devuelve esta herramienta e insértalo en la descripción del proyecto con update_project.

main y background pueden establecerse cada una una vez por idioma y no se pueden reemplazar aquí — hazlo desde el back office. Esta herramienta nunca cambia el objetivo, las fechas, las recompensas o el estado.

ParámetroObligatorioDescripción
project_idId del proyecto (no se acepta un slug).
typeUno de main, background, secondary.
langCódigo de idioma para el que se establece la imagen, p. ej. fr.
image_base64Los bytes de la imagen, codificados en base64. Se acepta un prefijo de URI data:. Da esto o image_url, no ambos.
image_urlURL pública http(s) para obtener la imagen. Da esto o image_base64, no ambos.

La respuesta devuelve el id, type, lang de la imagen almacenada y (excepto para un fondo) su url.

create_reward

Añade una recompensa (contrepartie) a uno de los proyectos del usuario: su título, descripción, precio y, opcionalmente, una imagen.

Una imagen es opcional. Cuando se da, se proporciona codificada en base64 (image_base64) o como una URL pública http(s) (image_url) — como máximo una de las dos — y se convierte en la imagen de la recompensa. Se acepta cualquier tamaño (png, jpeg o gif, hasta 5.5 MB); a diferencia de la imagen main o background de un proyecto, una imagen de recompensa no tiene dimensiones mínimas.

Esta herramienta no puede establecer el stock, variantes, opciones, envío o configuración de impuestos. Para eso, la respuesta devuelve un backoffice_url para enviar al usuario.

ParámetroObligatorioDescripción
project_idId del proyecto (no se acepta un slug).
titleTítulo de la recompensa, organizado por código de idioma, p. ej. {"fr": "Un tote bag"}. Debe incluir el idioma principal del proyecto.
pricePrecio que paga un patrocinador por la recompensa, en la moneda del proyecto, p. ej. 25 para 25.00. Debe ser al menos 1.
descriptionDescripción de la recompensa (se permite HTML), organizada por código de idioma.
image_base64Imagen de la recompensa, codificada en base64. Se acepta un prefijo de URI data:. Proporcione esto o image_url, no ambos.
image_urlURL pública http(s) para obtener la imagen de la recompensa. Proporcione esto o image_base64, no ambos.

create_news

Escribe una actualización de noticias en uno de los proyectos del usuario. La noticia se guarda como borrador y no se envía nada: no sale ningún correo electrónico hasta que el usuario la publique él mismo desde el back office del proyecto. Esta herramienta no puede publicar, programar ni adjuntar una imagen o un video.

ParámetroObligatorioDescripción
project_idId del proyecto en el que publicar la noticia.
titleTítulo de la noticia, organizado por código de idioma. Se requiere el idioma propio del proyecto.
contentCuerpo de la noticia (se permite HTML), organizado por código de idioma. Se requiere el idioma propio del proyecto.
audience_typePara quién es la noticia: all, supporters, fans, paying-members o tip-supporters. El valor predeterminado es all.