Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/qualtrics/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Eder Vázquez Vázquez

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
89 changes: 89 additions & 0 deletions src/qualtrics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Qualtrics MCP Server

Un servidor Model Context Protocol (MCP) para integración con la API de Qualtrics, permitiendo a los modelos de IA como Claude interactuar con encuestas, librerías, mensajes y distribuciones SMS de Qualtrics.

## Características

- **6 Herramientas MCP** para gestionar Qualtrics:
1. `configurar_credenciales` - Configurar API token y data center
2. `obtener_librerias` - Listar librerías disponibles
3. `obtener_mensajes_libreria` - Listar mensajes de una librería
4. `obtener_detalle_mensaje` - Obtener detalles de mensaje específico
5. `obtener_encuestas` - Listar encuestas con estadísticas
6. `obtener_distribuciones_sms` - Listar distribuciones SMS por encuesta

- Cliente HTTP asíncrono con paginación automática
- Manejo robusto de errores
- Type hints completos
- Arquitectura modular

## Instalación

### Opción 1: Desde el código fuente

```bash
git clone https://github.com/EderBuug/qualtrics-mcp.git
cd qualtrics-mcp
uv sync
```

### Opción 2: Desde PyPI (próximamente)

```bash
pip install qualtrics-mcp
```

## Configuración

### 1. Obtener credenciales de Qualtrics

1. Inicia sesión en Qualtrics
2. Ve a **Account Settings** → **Qualtrics IDs**
3. Genera un **API Token**
4. Identifica tu **Data Center** (ej: `ca1`, `sjc1`, `fra1`)

### 2. Configurar Claude Desktop

Edita `claude_desktop_config.json`:

```json
{
"mcpServers": {
"qualtrics": {
"command": "uv",
"args": [
"--directory",
"/path/to/qualtrics-mcp",
"run",
"python",
"main.py"
],
"env": {
"QUALTRICS_API_TOKEN": "your_token_here",
"QUALTRICS_DATA_CENTER": "ca1"
}
}
}
}
```

## Uso

Una vez configurado en Claude Desktop, podrás:

- Gestionar librerías y mensajes de Qualtrics
- Listar y analizar encuestas
- Consultar distribuciones SMS
- Todo con procesamiento inteligente de datos

## Repositorio

**Código fuente completo:** https://github.com/EderBuug/qualtrics-mcp

## Licencia

MIT License - ver LICENSE para más detalles

## Autor

Eder Vázquez Vázquez (@EderBuug)
11 changes: 11 additions & 0 deletions src/qualtrics/env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Configuración de ejemplo para el MCP de Qualtrics
# Copia este archivo como .env y configura tus valores

# Qualtrics API Configuration
QUALTRICS_API_TOKEN=your_api_token_here
QUALTRICS_DATA_CENTER=your_data_center_here
QUALTRICS_BASE_URL=https://your-datacenter.qualtrics.com

# MCP Server Configuration
MCP_SERVER_NAME=qualtrics-mcp
MCP_SERVER_VERSION=0.1.0
7 changes: 7 additions & 0 deletions src/qualtrics/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env python3
"""Punto de entrada principal para el MCP de Qualtrics."""

from src.qualtrics_mcp.server import main

if __name__ == "__main__":
main()
41 changes: 41 additions & 0 deletions src/qualtrics/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[project]
name = "qualtrics-mcp"
version = "0.1.0"
description = "Model Context Protocol (MCP) Server para integración con Qualtrics API"
readme = "README.md"
requires-python = ">=3.13"
license = {text = "MIT"}
authors = [
{name = "Eder Vázquez Vázquez", email = "eder2v@hotmail.com"},
]
keywords = ["mcp", "qualtrics", "api", "surveys", "model-context-protocol", "fastmcp", "claude"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Communications",
]
dependencies = [
"fastmcp>=2.12.4",
"httpx>=0.27.0",
"pydantic>=2.0.0",
"python-dotenv>=1.0.0",
"polars>=1.0.0",
]

[project.urls]
Homepage = "https://github.com/EderBuug/qualtrics-mcp"
Repository = "https://github.com/EderBuug/qualtrics-mcp"
Issues = "https://github.com/EderBuug/qualtrics-mcp/issues"
Documentation = "https://github.com/EderBuug/qualtrics-mcp/blob/main/README.md"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/qualtrics_mcp"]
6 changes: 6 additions & 0 deletions src/qualtrics/src/qualtrics_mcp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""Qualtrics MCP Server - Model Context Protocol para integración con Qualtrics API."""

__version__ = "0.1.0"
__author__ = "Eder Vázquez Vázquez - EderBuug"
__description__ = "MCP Server para integración con Qualtrics API"
__all__ = ["__version__", "__author__", "__description__"]
5 changes: 5 additions & 0 deletions src/qualtrics/src/qualtrics_mcp/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Módulo de API para Qualtrics."""

from .client import QualtricsClient

__all__ = ["QualtricsClient"]
76 changes: 76 additions & 0 deletions src/qualtrics/src/qualtrics_mcp/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""Configuración del servidor MCP de Qualtrics."""

import os

from dotenv import load_dotenv

# Cargar variables de entorno
load_dotenv()


class QualtricsConfig:
"""Configuración para la API de Qualtrics."""

def __init__(self, api_token: str, data_center: str):
"""
Inicializa la configuración de Qualtrics.

Args:
api_token: Token de API de Qualtrics
data_center: Centro de datos (ej: 'ca1', 'sjc1', 'fra1', etc.)
"""
self.api_token = api_token
self.data_center = data_center
self.base_url = f"https://{data_center}.qualtrics.com/API/v3"
self.headers = {"X-API-TOKEN": api_token, "Content-Type": "application/json"}

def __repr__(self) -> str:
"""Representación segura de la configuración (sin exponer el token)."""
return f"QualtricsConfig(data_center='{self.data_center}')"


# Variable global para almacenar la configuración
_qualtrics_config: QualtricsConfig | None = None


def get_config() -> QualtricsConfig | None:
"""
Obtiene la configuración global de Qualtrics.

Si no está configurada, intenta cargarla desde las variables de entorno.

Returns:
Configuración de Qualtrics o None si no está disponible
"""
global _qualtrics_config

if _qualtrics_config is None:
api_token = os.getenv("QUALTRICS_API_TOKEN")
data_center = os.getenv("QUALTRICS_DATA_CENTER")

if api_token and data_center:
_qualtrics_config = QualtricsConfig(api_token, data_center)

return _qualtrics_config


def set_config(api_token: str, data_center: str) -> QualtricsConfig:
"""
Establece la configuración global de Qualtrics.

Args:
api_token: Token de API de Qualtrics
data_center: Centro de datos de Qualtrics

Returns:
Nueva configuración establecida
"""
global _qualtrics_config
_qualtrics_config = QualtricsConfig(api_token, data_center)
return _qualtrics_config


def clear_config() -> None:
"""Limpia la configuración global."""
global _qualtrics_config
_qualtrics_config = None
106 changes: 106 additions & 0 deletions src/qualtrics/src/qualtrics_mcp/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""Servidor MCP principal para Qualtrics."""

import sys
from datetime import datetime
from typing import Any

from fastmcp import FastMCP

from .api.client import QualtricsClient
from .config import set_config
from .tools.distributions import listar_distribuciones_sms
from .tools.libraries import (
listar_librerias,
listar_mensajes_libreria,
obtener_mensaje_libreria,
)
from .tools.surveys import listar_encuestas

# Crear instancia del servidor MCP
mcp = FastMCP("qualtrics-mcp")


@mcp.tool()
def configurar_credenciales(api_token: str, data_center: str) -> dict[str, Any]:
"""Configura las credenciales para la API de Qualtrics."""
try:
config = set_config(api_token, data_center)
try:
with QualtricsClient(config) as client:
user_info = client.test_connection()
return {
"estado": "configurado",
"data_center": data_center,
"conexion_probada": True,
"usuario": user_info.get("result", {}).get("userId", "desconocido"),
"mensaje": "Credenciales configuradas y probadas correctamente",
"timestamp": datetime.now().isoformat(),
}
except Exception as e:
from .config import clear_config
clear_config()
return {
"estado": "error",
"mensaje": f"Error al probar conexión: {str(e)}",
"timestamp": datetime.now().isoformat(),
}
except Exception as e:
return {
"estado": "error",
"mensaje": f"Error al configurar credenciales: {str(e)}",
"timestamp": datetime.now().isoformat(),
}


@mcp.tool()
def obtener_librerias() -> dict[str, Any]:
"""Obtiene la lista completa de librerías disponibles en Qualtrics."""
return listar_librerias()


@mcp.tool()
def obtener_mensajes_libreria(library_id: str) -> dict[str, Any]:
"""Obtiene todos los mensajes de una librería específica de Qualtrics."""
return listar_mensajes_libreria(library_id)


@mcp.tool()
def obtener_detalle_mensaje(library_id: str, message_id: str) -> dict[str, Any]:
"""Obtiene la información detallada de un mensaje específico de una librería."""
return obtener_mensaje_libreria(library_id, message_id)


@mcp.tool()
def obtener_encuestas() -> dict[str, Any]:
"""Obtiene la lista completa de encuestas disponibles en Qualtrics."""
return listar_encuestas()


@mcp.tool()
def obtener_distribuciones_sms(survey_id: str) -> dict[str, Any]:
"""Obtiene la lista de todas las distribuciones SMS para una encuesta específica."""
return listar_distribuciones_sms(survey_id)


def main() -> None:
"""Función principal para ejecutar el servidor MCP."""
print("🚀 Iniciando servidor MCP Qualtrics...", file=sys.stderr)
print("", file=sys.stderr)
print("📡 Herramientas disponibles:", file=sys.stderr)
print(" 1. configurar_credenciales - Configurar API token y data center", file=sys.stderr)
print(" 2. obtener_librerias - Listar todas las librerías disponibles", file=sys.stderr)
print(" 3. obtener_mensajes_libreria - Listar mensajes de una librería", file=sys.stderr)
print(" 4. obtener_detalle_mensaje - Obtener detalles de un mensaje específico", file=sys.stderr)
print(" 5. obtener_encuestas - Listar todas las encuestas con estadísticas", file=sys.stderr)
print(" 6. obtener_distribuciones_sms - Listar distribuciones SMS por encuesta", file=sys.stderr)
print("", file=sys.stderr)
print("⏳ Esperando conexiones de clientes MCP...", file=sys.stderr)
try:
mcp.run()
except Exception as e:
print(f"💥 Error en servidor: {e}", file=sys.stderr)
raise


if __name__ == "__main__":
main()
Loading