Content
# mcp-linkedin
**Servidor MCP que expone una colección de Firestore como herramientas para asistentes de IA.**
Permite a Claude (o cualquier cliente compatible con [Model Context Protocol](https://modelcontextprotocol.io/)) leer y escribir propuestas de posts de LinkedIn directamente sobre Firestore: listar, buscar, crear en lote, editar y eliminar — sin salir de la conversación.
Lo construí para el CRM que desarrollo, donde el flujo de contenido vivía entre la app web y un chat. Ahora el asistente propone los posts y quedan guardados en el mismo lugar donde el equipo los revisa.
```
Claude ──stdio──► Servidor MCP ──Admin SDK──► Firestore
(6 tools) posts_linkedin
```
---
## Tools disponibles
### Lectura
| Tool | Qué hace |
|---|---|
| `listar_posts_linkedin` | Lista posts con filtro por estado y búsqueda de texto en el copy o la descripción. Ordena por fecha de publicación y limita resultados. |
| `get_post_linkedin` | Detalle completo de un post por su ID de documento. |
### Escritura
| Tool | Qué hace |
|---|---|
| `crear_post_linkedin` | Crea una propuesta. Nace como `borrador` salvo que se indique otro estado. |
| `proponer_posts_linkedin` | Crea varias propuestas en una sola llamada, para generar lotes de contenido. |
| `actualizar_post_linkedin` | Edita un post existente. Solo modifica los campos enviados; el resto queda intacto. |
| `eliminar_post_linkedin` | Elimina un post. Requiere `confirmar: true` como salvaguarda explícita. |
Cada post admite un **guion de slides**: un brief visual, lámina por lámina, que se entrega a diseño. El servidor normaliza el guion recibido — descarta láminas sin descripción, recorta strings y renumera el orden — para que el asistente no tenga que preocuparse del formato.
---
## Decisiones de diseño
**Las tools de escritura no tocan el contenido visual.** Un post creado por el asistente nace sin adjuntos; las imágenes se suben después desde la aplicación web. En lectura se devuelven las **URLs** del contenido visual como texto, sin descargar binarios. Mantiene las respuestas livianas y evita meter archivos en un canal pensado para texto.
**El orden de las slides lo asigna el servidor, no el input.** Se deriva de la posición en el arreglo. Un parámetro menos que el modelo puede equivocar, y el guion queda siempre consistente.
**`eliminar` exige confirmación explícita.** Un borrado accidental disparado por una instrucción ambigua es un riesgo real cuando quien llama la herramienta es un modelo. El parámetro `confirmar` obliga a un paso deliberado.
**Esquemas Zod con `.describe()` en cada campo.** Esas descripciones son lo que el modelo lee para decidir cómo llamar la herramienta. Un esquema mal documentado produce llamadas mal formadas: el `.describe()` no es comentario, es interfaz.
**Los timestamps de Firestore se serializan a ISO 8601** antes de salir. El objeto `Timestamp` no es JSON válido y el modelo no sabe interpretarlo.
---
## Requisitos
- Node.js 18 o superior
- Un proyecto de Firebase con Firestore
- Una service account con permisos sobre Firestore
## Instalación
```bash
git clone https://github.com/mau-f/mcp-linkedin.git
cd mcp-linkedin
npm install
```
### Credenciales
1. Firebase Console → **Configuración del proyecto** → **Cuentas de servicio** → *Generar nueva clave privada*
2. Guarda el archivo como `serviceAccountKey.json` en la raíz del proyecto
> ⚠️ Ese archivo da acceso administrativo completo a tu proyecto de Firebase. Está en el `.gitignore` — **no lo subas nunca a un repositorio.**
Alternativamente, apunta la variable `SERVICE_ACCOUNT_PATH` a la ruta donde la tengas.
### Configuración
| Variable | Por defecto | Descripción |
|---|---|---|
| `SERVICE_ACCOUNT_PATH` | `./serviceAccountKey.json` | Ruta al JSON de la service account |
| `FIRESTORE_COLLECTION` | `posts_linkedin` | Colección de Firestore a exponer |
---
## Conectarlo a Claude
Agrega esto a la configuración de MCP de tu cliente (en Claude Desktop, `claude_desktop_config.json`):
```json
{
"mcpServers": {
"linkedin-posts": {
"command": "node",
"args": ["/ruta/absoluta/a/mcp-linkedin/index.js"],
"env": {
"SERVICE_ACCOUNT_PATH": "/ruta/absoluta/a/serviceAccountKey.json",
"FIRESTORE_COLLECTION": "posts_linkedin"
}
}
}
}
```
Reinicia el cliente. Las seis tools deberían aparecer disponibles.
---
## Estructura del documento
```js
{
copy: string, // el texto del post
descripcion: string, // descripción interna
guion_slides: [ // brief visual para diseño
{ orden: number, titulo: string | null, descripcion: string }
],
contenido_visual: [ // se llena desde la app web
{ nombre: string, tipo: string, url: string }
],
estado: 'borrador' | 'programado' | 'publicado',
fecha_publicacion: string | null, // yyyy-mm-dd
url_publicado: string | null,
notas: string | null,
creado_en: Timestamp,
actualizado_en: Timestamp
}
```
---
## Stack
`Node.js` · `@modelcontextprotocol/sdk` · `firebase-admin` · `zod`
## Licencia
MIT
---
**Mauricio Flores Correa** · [LinkedIn](https://linkedin.com/in/mau-f) · mauricioignacio.1@gmail.com