API e integraciones
Conecta CVforge a Claude Desktop, n8n, Cursor y tus automatizaciones a través de la API MCP. Subida de CVs, recuperación de las optimizaciones, gestión de tu perfil — todo es accesible de forma programática.
Endpoint
api.cvforge.co/mcp
Protocolo
MCP · JSON-RPC 2.0
Transporte
HTTP POST
Auth
PAT u OAuth2
1. Requisitos previos
El acceso a la API MCP está incluido en el pack Expert.
- Tener una cuenta CVforge activa con una suscripción Expert en curso.
- Crear un Personal Access Token (PAT) desde la página Ajustes → API e integraciones.
2. Autenticación
CVforge admite dos métodos de autenticación. Para la mayoría de las integraciones personales (n8n, scripts, Claude Desktop), usa un PAT. Para aplicaciones de terceros, usa el flujo OAuth 2.0 Authorization Code + PKCE.
2.1 Personal Access Token (PAT)
Un PAT es un token opaco con el prefijo mcp_pat_. Se muestra una sola vez al crearlo — guárdalo en un lugar seguro.
Uso en cada petición:
Authorization: Bearer mcp_pat_XXXXXXXXXXXXXXXXXXXX2.2 OAuth 2.0 (Authorization Code + PKCE)
Para las aplicaciones que gestionan varias cuentas de usuario, usa el flujo OAuth 2.0 estándar.
| Endpoint | URL |
|---|---|
| Discovery | https://api.cvforge.co/.well-known/oauth-authorization-server |
| Authorization | https://api.cvforge.co/oauth/authorize |
| Token exchange | https://api.cvforge.co/oauth/token |
| Revocación | https://api.cvforge.co/oauth/revoke |
2.3 Scopes
| Scope | Descripción |
|---|---|
| read:profile | Leer el perfil, el plan y el saldo de créditos |
| read:cv | Listar, consultar y descargar CVs y generaciones |
| write:cv | Subir CVs, enviar ofertas de empleo y lanzar optimizaciones |
3. Hacer una llamada MCP
La API MCP utiliza el protocolo JSON-RPC 2.0 sobre HTTP. Cada petición es un POST a https://api.cvforge.co/mcp.
Formato de una petición
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXXXXXXXXXXXXXXXXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "<nom_de_l_outil>",
"arguments": { /* paramètres de l'outil */ }
}
}Formato de una respuesta (éxito)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "{ ...données... }"
}
]
}
}Formato de una respuesta (error)
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32001,
"message": "Token invalide ou révoqué",
"data": { "error_code": "MCP_TOKEN_INVALID" }
}
}4. Herramientas disponibles
La API expone 10 herramientas. Las herramientas de lectura requieren read:profile o read:cv. La subida, el envío de ofertas y las optimizaciones requieren write:cv.
get_profileread:profileDevuelve la información de la cuenta: nombre, email, plan de suscripción.
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "get_profile", "arguments": {} }
}Respuesta (extracto)
{
"id": "uuid",
"email": "alice@example.com",
"full_name": "Alice Martin",
"subscription_plan": "Expert",
"subscription_status": "active"
}get_creditsread:profileDevuelve el saldo de créditos detallado (suscripción, pagado, gratuito).
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "get_credits", "arguments": {} }
}Respuesta (extracto)
{
"total": 7,
"subscription_credits": 5,
"paid_credits": 2,
"free_credits": 0
}list_cvsread:cvLista los perfiles de CV subidos (sin el contenido).
Parámetros
| Nombre | Tipo | Descripción |
|---|---|---|
| limit | integer? | Número máx. (por defecto: 20, máx.: 50) |
| offset | integer? | Paginación (por defecto: 0) |
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "list_cvs", "arguments": { "limit": 10, "offset": 0 } }
}Respuesta (extracto)
{
"cvs": [
{
"id": "uuid",
"original_filename": "CV_Alice_2026.pdf",
"created_at": "2026-04-10T14:30:00Z",
"generation_count": 3
}
],
"total": 1
}get_cvread:cvDevuelve el contenido completo (texto extraído) de un CV.
Parámetros
| Nombre | Tipo | Descripción |
|---|---|---|
| cv_id | string | UUID del perfil de CV |
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "get_cv", "arguments": { "cv_id": "uuid" } }
}Respuesta (extracto)
{
"id": "uuid",
"original_filename": "CV_Alice_2026.pdf",
"extracted_text": "Alice Martin — Product Manager...",
"created_at": "2026-04-10T14:30:00Z"
}upload_cvwrite:cvSube un CV en base64. Formatos aceptados: PDF, DOCX (máx. 10 MB). Devuelve el cv_profile_id que se debe usar con optimize_cv.
Parámetros
| Nombre | Tipo | Descripción |
|---|---|---|
| filename | string | Nombre del archivo (con extensión) |
| file_base64 | string | Contenido del archivo codificado en base64 |
| mime_type | string | application/pdf | application/vnd.openxmlformats-officedocument.wordprocessingml.document |
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "upload_cv", "arguments": {
"filename": "mon_cv.pdf",
"file_base64": "JVBERi0xLjQ...",
"mime_type": "application/pdf"
} }
}Respuesta (extracto)
{
"cv_profile_id": "uuid",
"message": "CV uploaded and parsed successfully."
}submit_offerwrite:cvEnvía la URL de una oferta de empleo (LinkedIn, Indeed, WTTJ, etc.) para su scraping y almacenamiento. Devuelve el offer_id que se debe usar con optimize_cv. Límite: 5 llamadas/min. Sitios compatibles: LinkedIn, Indeed, WTTJ, France Travail, HelloWork, APEC, Cadremploi, Glassdoor, Meteojob, LeBonCoin, JobTeaser, Collective Work.
Parámetros
| Nombre | Tipo | Descripción |
|---|---|---|
| offer_url | string | URL completa de la oferta de empleo |
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "submit_offer", "arguments": {
"offer_url": "https://www.linkedin.com/jobs/view/1234567890/"
} }
}Respuesta (extracto)
{
"offer_id": "uuid",
"offer_url": "https://www.linkedin.com/jobs/view/1234567890/",
"job_title": "Product Manager Senior",
"company_name": "Acme Corp"
}optimize_cvwrite:cvLanza la optimización con IA de un CV para una oferta de empleo. Consume 1 crédito. La operación es asíncrona: usa get_generation para seguir el progreso (pending → processing → completed/failed).
Parámetros
| Nombre | Tipo | Descripción |
|---|---|---|
| cv_profile_id | string | UUID del perfil de CV (obtenido mediante upload_cv o list_cvs) |
| offer_id | string | UUID de la oferta de empleo (obtenido mediante submit_offer) |
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "optimize_cv", "arguments": {
"cv_profile_id": "uuid-du-cv",
"offer_id": "uuid-de-l-offre"
} }
}Respuesta (extracto)
{
"generation_id": "uuid",
"status": "processing",
"message": "CV optimization started"
}list_generationsread:cvLista los CVs optimizados generados, con su estado y las puntuaciones ATS.
Parámetros
| Nombre | Tipo | Descripción |
|---|---|---|
| limit | integer? | Número máx. (por defecto: 20, máx.: 100) |
| offset | integer? | Paginación (por defecto: 0) |
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "list_generations", "arguments": { "limit": 5 } }
}Respuesta (extracto)
{
"generations": [
{
"id": "uuid",
"cv_id": "uuid",
"job_title": "Product Manager Senior",
"ats_score": 87,
"status": "completed",
"created_at": "2026-04-11T09:00:00Z"
}
],
"total": 1
}get_generationread:cvDevuelve el detalle de una generación: análisis, texto optimizado, puntuación.
Parámetros
| Nombre | Tipo | Descripción |
|---|---|---|
| generation_id | string | UUID de la generación |
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "get_generation", "arguments": { "generation_id": "uuid" } }
}Respuesta (extracto)
{
"id": "uuid",
"job_title": "Product Manager Senior",
"ats_score": 87,
"optimized_text": "Alice Martin — Product Manager Senior...",
"analysis": { "missing_keywords": ["OKR", "roadmap"], "strengths": [...] },
"status": "completed",
"created_at": "2026-04-11T09:00:00Z"
}download_generationread:cvDescarga el PDF final de una generación en base64.
Parámetros
| Nombre | Tipo | Descripción |
|---|---|---|
| generation_id | string | UUID de la generación |
Ejemplo de llamada
POST https://api.cvforge.co/mcp
Content-Type: application/json
Authorization: Bearer mcp_pat_XXXX
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "download_generation", "arguments": { "generation_id": "uuid" } }
}Respuesta (extracto)
{
"filename": "CV_Alice_PM_Senior.pdf",
"content_b64": "JVBERi0xLjQ...",
"mime_type": "application/pdf",
"size_bytes": 124580
}5. Ejemplos de integración
5.1 Flujo completo: subida → oferta → optimización → descarga
Ejemplo en Python que ilustra el recorrido completo en 4 pasos.
import requests, base64, time, json, os
PAT = os.environ["CVFORGE_PAT"]
MCP = "https://api.cvforge.co/mcp"
HEADERS = {"Content-Type": "application/json", "Authorization": f"Bearer {PAT}"}
def mcp(tool: str, args: dict = {}):
r = requests.post(MCP, json={
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {"name": tool, "arguments": args}
}, headers=HEADERS, timeout=60)
r.raise_for_status()
data = r.json()
if "error" in data:
raise RuntimeError(data["error"]["message"])
return json.loads(data["result"]["content"][0]["text"])
# Étape 1 — Upload du CV
with open("mon_cv.pdf", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
cv = mcp("upload_cv", {
"filename": "mon_cv.pdf",
"file_base64": b64,
"mime_type": "application/pdf",
})
cv_id = cv["cv_profile_id"]
print(f"CV uploadé : {cv_id}")
# Étape 2 — Soumission de l'offre
offer = mcp("submit_offer", {
"offer_url": "https://www.linkedin.com/jobs/view/1234567890/"
})
offer_id = offer["offer_id"]
print(f"Offre : {offer['job_title']} @ {offer['company_name']} ({offer_id})")
# Étape 3 — Lancement de l'optimisation (1 crédit consommé)
gen = mcp("optimize_cv", {"cv_profile_id": cv_id, "offer_id": offer_id})
gen_id = gen["generation_id"]
print(f"Génération démarrée : {gen_id}")
# Étape 4 — Attente + téléchargement
for _ in range(20):
time.sleep(5)
details = mcp("get_generation", {"generation_id": gen_id})
print(f" statut : {details['status']}")
if details["status"] == "completed":
dl = mcp("download_generation", {"generation_id": gen_id})
print(f"Téléchargement : {dl['download_url']} (valide 15 min)")
break
if details["status"] == "failed":
raise RuntimeError("Optimisation échouée")5.2 curl
# Remplacez YOUR_PAT par votre Personal Access Token
export PAT="mcp_pat_XXXXXXXXXXXXXXXXXXXX"
# Récupérer le profil
curl -X POST https://api.cvforge.co/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $PAT" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_profile","arguments":{}}}'
# Vérifier le solde de crédits
curl -X POST https://api.cvforge.co/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $PAT" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_credits","arguments":{}}}'5.3 Claude Desktop / Claude.ai
Añade el siguiente bloque en tu archivo de configuración de Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json en macOS).
{
"mcpServers": {
"cvforge": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.cvforge.co/mcp",
"--header",
"Authorization: Bearer mcp_pat_XXXXXXXXXXXXXXXXXXXX"
]
}
}
}Tras reiniciar, Claude tendrá acceso a las herramientas de CVforge directamente en la conversación. Di por ejemplo: "Lista mis CVs en CVforge" o "Sube el archivo MiCV.pdf a CVforge".
5.4 n8n — nodo HTTP Request
En n8n, crea un nodo HTTP Request con los siguientes parámetros:
| Method | POST |
| URL | https://api.cvforge.co/mcp |
| Authentication | Header Auth · Name: Authorization · Value: Bearer mcp_pat_XXX |
| Content-Type | application/json |
| Body (JSON) | { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "list_cvs", "arguments": {} } } |
El resultado JSON está disponible en el nodo siguiente a través de {{ $json.result.content[0].text }}. Parséalo con un nodo Set o Function para extraer los campos.
5.5 Cursor / Windsurf
En .cursor/mcp.json (o el equivalente para Windsurf):
{
"mcpServers": {
"cvforge": {
"url": "https://api.cvforge.co/mcp",
"headers": {
"Authorization": "Bearer mcp_pat_XXXXXXXXXXXXXXXXXXXX"
}
}
}
}6. Códigos de error
| error_code | código JSON-RPC | Descripción |
|---|---|---|
| MCP_TOKEN_INVALID | -32001 | Token ausente, malformado o revocado |
| MCP_TOKEN_EXPIRED | -32001 | Token caducado — regenera uno en los Ajustes |
| MCP_SUBSCRIPTION_REQUIRED | -32003 | Se requiere el plan Expert — ver /pricing |
| MCP_SCOPE_INSUFFICIENT | -32004 | El token no posee el scope necesario |
| MCP_TOOL_NOT_FOUND | -32601 | Herramienta desconocida |
| MCP_INVALID_PARAMS | -32602 | Parámetros inválidos o ausentes |
| MCP_INTERNAL_ERROR | -32603 | Error interno — reintenta o contacta con el soporte |
| PARSE_ERROR | -32700 | JSON inválido en la petición |
| INVALID_REQUEST | -32600 | Estructura JSON-RPC inválida |
7. Límites y buenas prácticas
Rate limiting
| Límite | Valor |
|---|---|
| Peticiones por minuto (por IP) | 60 req/min |
| submit_offer (por usuario) | 5 req/min |
| Tamaño máx. de un archivo subido | 10 MB |
| Formatos de CV aceptados | PDF, DOCX |
| Tokens PAT activos simultáneamente | 10 por cuenta |
En caso de superar el límite, la API devuelve un HTTP 429 con la cabecera Retry-After. Implementa un backoff exponencial en tus automatizaciones.
Buenas prácticas
- Crea un token por integración (uno para n8n, uno para Claude Desktop…) — así facilitas la revocación individual sin afectar a las demás.
- Concede únicamente los scopes necesarios a cada token.
- Guarda los tokens en variables de entorno o en un gestor de secretos, nunca en el código en claro.
- Revoca inmediatamente cualquier token comprometido desde la página Ajustes.
- El endpoint MCP admite CORS abierto — acuérdate de validar el origen en el lado servidor en tus propias integraciones.
Descubribilidad
CVforge publica un manifiesto MCP legible por los LLMs y los motores de búsqueda:
- /.well-known/mcp.json — manifiesto MCP
- /.well-known/oauth-authorization-server — descubrimiento OAuth2 (RFC 8414)
- /llms.txt — contexto MCP para los LLMs
¿Listo para integrar CVforge?
Crea tu primer token en 30 segundos desde los Ajustes.