Conectando Asistentes de IA con Bases de Datos Empresariales
"Haciendo accesibles las capacidades de PeopleWorks GPT a cualquier asistente de IA compatible con MCP"
Imagina que estás charlando con Claude Desktop y quieres preguntar: "Muéstrame las 10 propiedades principales por ingresos de este mes". Sin el Servidor MCP, Claude educadamente diría que no puede acceder a tu base de datos. Pero con el Servidor MCP de PeopleWorks GPT, Claude puede autenticarse, conectarse a tu base de datos SQL Server, generar la consulta SQL óptima usando IA, ejecutarla y devolver resultados hermosos - todo en un solo intercambio conversacional.
El Model Context Protocol (MCP) es el estándar revolucionario de Anthropic que permite a asistentes de IA como Claude conectarse de forma segura a fuentes de datos externas y herramientas. Piénsalo como un adaptador universal que permite a cualquier asistente de IA hablar con cualquier fuente de datos o servicio: bases de datos, APIs, sistemas de archivos y más.
| ¿Qué es MCP? Una Analogía Sencilla | ||
|---|---|---|
| 🔌 | Antes de MCPComo tener diferentes cargadores para cada dispositivo - iPhone usa Lightning, Android usa USB-C, laptops usan cargadores propietarios | Fragmentado |
| ⚡ | Con MCPComo USB-C volviéndose universal - un protocolo que funciona con cada asistente de IA y cada fuente de datos | Unificado |
| 🌐 | El ResultadoCualquier IA compatible con MCP (Claude, ChatGPT, agentes personalizados) puede conectarse instantáneamente a cualquier servidor MCP (bases de datos, CRMs, ERPs, APIs) | Interoperable |
PeopleWorks ya tiene un potente motor DatabaseGPT que convierte lenguaje natural a SQL. El Servidor MCP expone esta capacidad a Claude Desktop y otros clientes MCP sin reescribir una sola línea de lógica central.
Autenticación multiusuario con claves API, tokens de sesión JWT, permisos granulares de base de datos y registro de auditoría completo - todas las características de seguridad que las empresas demandan.
Funciona con SQL Server, PostgreSQL, MySQL, Oracle y más. La capa de abstracción maneja automáticamente las diferencias de dialecto.
Las pistas de base de datos y prompts personalizados enseñan a la IA sobre tu dominio de negocio, resultando en consultas más precisas y conscientes del contexto.
No solo sentencias SELECT - el servidor soporta plantillas de análisis, desgloses, comparaciones, auditorías de calidad de datos y consultas complejas de inteligencia de negocios.
Una vez construido, cualquier cliente compatible con MCP (Claude Desktop, futuras versiones de ChatGPT, agentes de IA personalizados, STRPlatform) puede usarlo inmediatamente.
Los servidores MCP exponen tres tipos de capacidades: Herramientas (acciones ejecutables), Prompts (plantillas reutilizables) y Recursos (datos estructurados). Exploremos cada uno en detalle.
| Herramienta | Propósito | Parámetros Clave | Devuelve |
|---|---|---|---|
| AuthenticateAsync | Autenticación de usuario y creación de sesión | username, apiKey |
Token de sesión JWT (expiración 60 min) |
| ListConnectionsAsync | Descubrir bases de datos disponibles | sessionToken |
Lista de conexiones de base de datos accesibles |
| ExecuteQueryAsync | Ejecutar consulta en lenguaje natural | sessionToken, connectionId, query, includeHints |
SQL generado + conjunto de resultados + métricas de ejecución |
| GetSchemaAsync | Recuperar esquema de base de datos | sessionToken, connectionId, specificTables |
Tablas, columnas, tipos, restricciones en markdown |
| ListHintsAsync | Ver pistas de base de datos activas | sessionToken, connectionId |
Reglas de negocio, prompts personalizados, contexto |
| UpdateHintsAsync | Modificar pistas de base de datos | sessionToken, connectionId, hintsContent |
Confirmación de éxito |
| GetSuggestedQuestionsAsync | Consultas sugeridas generadas por IA | sessionToken, connectionId, category |
Lista de preguntas relevantes que el usuario puede hacer |
| ExplainQueryAsync | Explicar proceso de generación SQL | sessionToken, connectionId, query |
Explicación paso a paso de la generación SQL |
Los prompts son plantillas preconfiguradas que guían a la IA en la generación de consultas analíticas complejas. Codifican las mejores prácticas para escenarios comunes de BI.
| Plantilla de Prompt | Caso de Uso | Ejemplo |
|---|---|---|
| Consulta de Análisis | Métricas de negocio con agregaciones | "Ingresos totales por tipo de propiedad para el último trimestre con rankings" |
| Exploración de Datos | Patrones de descubrimiento estadístico | "Encontrar patrones inusuales en duraciones de reserva por temporada" |
| Desglose | Análisis jerárquico | "Desglosar ingresos totales por región → ciudad → propiedad" |
| Comparación A/B | Métricas lado a lado | "Comparar Q1 2024 vs Q1 2025: ingresos, reservas, ocupación" |
| Calidad de Datos | Auditoría y validación | "Verificar tabla Properties para NULLs, duplicados, valores atípicos en precio" |
Esquema completo de base de datos: tablas, columnas, tipos de datos, relaciones, índices. Devuelto en JSON estructurado para análisis eficiente.
Scripts CREATE TABLE con DDL completo, restricciones, valores predeterminados y columnas calculadas para comprensión profunda del esquema.
Primeras 5 filas de cualquier tabla para entender patrones de datos, formatos y valores reales - crucial para consultas conscientes del contexto.
Reglas de negocio, prompts personalizados, contexto multi-tenant y conocimiento de dominio que mejoran la precisión de generación de consultas.
using Infrastructure.Persistence.Contexts;
using Microsoft.EntityFrameworkCore;
using ModelContextProtocol.Server;
using PeopleworksGPT.MCP.Server.Services;
using System.ComponentModel;
using System.Text.Json;
namespace PeopleworksGPT.MCP.Server.Tools
{
[McpServerToolType]
public sealed class AuthenticationTool
{
private readonly ApplicationDbContext _context;
private readonly SessionManager _sessionManager;
public AuthenticationTool(ApplicationDbContext context, SessionManager sessionManager)
{
_context = context;
_sessionManager = sessionManager;
}
[McpServerTool(Name = "AuthenticateAsync")]
[Description("Authenticate user and receive session token for subsequent requests")]
public async Task<string> AuthenticateAsync(
[Description("Username")] string username,
[Description("API key for authentication")] string apiKey)
{
try
{
// Find user by username and API key
var user = await _context.ApplicationUsers
.FirstOrDefaultAsync(u => u.UserName == username
&& u.ApiKey == apiKey
&& u.IsActive
&& !u.Deleted);
if (user == null)
{
return JsonSerializer.Serialize(new
{
success = false,
error = "Invalid credentials"
});
}
// Update last login timestamp
user.UpdatedDate = DateTime.Now;
await _context.SaveChangesAsync();
// Generate JWT token with 60-minute expiration
var sessionToken = _sessionManager.GenerateJwtToken(user.Id, user.UserName!);
return JsonSerializer.Serialize(new
{
success = true,
session_token = sessionToken,
user_id = user.Id,
username = user.UserName,
expires_at = DateTime.UtcNow.AddMinutes(60).ToString("O")
});
}
catch (Exception ex)
{
return JsonSerializer.Serialize(new
{
success = false,
error = $"Authentication failed: {ex.Message}"
});
}
}
}
}
[McpServerToolType] - Marca la clase como contenedora de herramientas MCP[McpServerTool] - Expone el método como una herramienta MCP[Description] - Proporciona documentación legible por IA[McpServerTool(Name = "ExecuteQueryAsync")]
[Description("Execute a natural language query against a specific database connection")]
public async Task<string> ExecuteQueryAsync(
[Description("Session token from authenticate()")] string sessionToken,
[Description("Database connection ID from list_connections()")] long connectionId,
[Description("Natural language query")] string query,
[Description("Include database hints (default: true)")] bool includeHints = true,
[Description("Additional context for filtering")] string? additionalContext = null,
[Description("Security filter for multi-tenant isolation (JSON)")] string? securityFilter = null)
{
var stopwatch = Stopwatch.StartNew();
try
{
// 1. Validate JWT session token
var (isValid, userId, username) = _sessionManager.ValidateToken(sessionToken);
if (!isValid)
{
return JsonSerializer.Serialize(new {
success = false,
error = "Invalid or expired session token"
});
}
// 2. Verify user has access to this connection
var connection = await _context.DatabaseConnectionSettings
.FirstOrDefaultAsync(c =>
c.Id == connectionId &&
c.AvailableForUsers.Any(u => u.Id == userId) &&
!c.Deleted &&
!c.Disabled);
if (connection == null)
{
return JsonSerializer.Serialize(new {
success = false,
error = "Connection not found or access denied"
});
}
// 3. Execute query through DatabaseGPT engine
var (sql, results) = await _queryExecutionService.ExecuteNaturalLanguageQueryAsync(
connection,
query,
includeHints,
additionalContext,
securityFilter);
stopwatch.Stop();
// 4. Log to audit trail
await _auditLogger.LogQueryAsync(
userId,
connectionId,
query,
sql,
(int)stopwatch.ElapsedMilliseconds,
results.Count,
success: true);
// 5. Return structured results
return JsonSerializer.Serialize(new
{
success = true,
query_id = Guid.NewGuid().ToString(),
original_query = query,
generated_sql = sql,
results,
row_count = results.Count,
execution_time_ms = stopwatch.ElapsedMilliseconds,
connection_name = connection.DbName
});
}
catch (Exception ex)
{
stopwatch.Stop();
// Log failure to audit
await _auditLogger.LogQueryAsync(
userId, connectionId, query, null,
(int)stopwatch.ElapsedMilliseconds, 0,
success: false, errorMessage: ex.Message);
return JsonSerializer.Serialize(new
{
success = false,
error = $"Query execution failed: {ex.Message}"
});
}
}
public class SessionManager
{
private readonly IConfiguration _configuration;
public string GenerateJwtToken(long userId, string username)
{
var secretKey = _configuration["JWT:SecretKey"]
?? throw new InvalidOperationException("JWT SecretKey not configured");
var securityKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(secretKey));
var credentials = new SigningCredentials(
securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
new Claim(ClaimTypes.Name, username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var token = new JwtSecurityToken(
issuer: _configuration["JWT:Issuer"],
audience: _configuration["JWT:Audience"],
claims: claims,
expires: DateTime.UtcNow.AddMinutes(60),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public (bool IsValid, long UserId, string Username) ValidateToken(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = _configuration["JWT:Issuer"],
ValidAudience = _configuration["JWT:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_configuration["JWT:SecretKey"]!))
};
var principal = tokenHandler.ValidateToken(token, validationParameters, out _);
var userId = long.Parse(principal.FindFirst(ClaimTypes.NameIdentifier)!.Value);
var username = principal.FindFirst(ClaimTypes.Name)!.Value;
return (true, userId, username);
}
catch
{
return (false, 0, string.Empty);
}
}
}
| Característica | Transporte STDIO (Desarrollo) |
Transporte HTTP (Producción) |
|---|---|---|
| Cómo Funciona | Claude ejecuta dotnet run cada vez |
El servidor corre permanentemente, Claude conecta vía HTTP |
| Complejidad de Configuración | ✓ Copiar archivo de configuración, reiniciar Claude | ✗ Publicar, desplegar, configurar IIS/Docker |
| Código Fuente Requerido | ✗ Sí, en máquina cliente | ✓ No, solo binario compilado |
| Soporte Multi-Cliente | ✗ Solo un usuario | ✓ Usuarios concurrentes ilimitados |
| Cambios de Código | ✓ Efecto inmediato | ✗ Requiere redespliegue |
| Acceso Remoto | ✗ Solo local | ✓ Nube, red corporativa, cualquier lugar |
| Mejor Para | Desarrolladores, pruebas rápidas, experimentación local | Producción, equipos, integración STRPlatform, empresas |
{
"mcpServers": {
"peopleworksgpt": {
"command": "dotnet",
"args": [
"run",
"--project",
"C:\\Proyecto\\AI\\PeopleworksGPT\\PeopleworksGPT.MCP.Server\\PeopleworksGPT.MCP.Server.csproj"
],
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Windows: %APPDATA%\Claude\claude_desktop_config.json
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"peopleworksgpt": {
"url": "https://mcp.peopleworks.com/mcp",
"transport": "http",
"headers": {
"MCP-Protocol-Version": "2025-06-18"
}
}
}
}
# Publish the application
dotnet publish -c Release -o C:\inetpub\PeopleworksGPT-MCP
# Create IIS Application Pool
New-WebAppPool -Name "PeopleworksGPT-MCP" -Force
Set-ItemProperty IIS:\AppPools\PeopleworksGPT-MCP `
-Name managedRuntimeVersion -Value ""
# Create IIS Website
New-WebSite -Name "PeopleworksGPT-MCP" `
-Port 5000 `
-PhysicalPath "C:\inetpub\PeopleworksGPT-MCP" `
-ApplicationPool "PeopleworksGPT-MCP" `
-Force
# Configure web.config for InProcess hosting
$webConfig = @"
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*"
modules="AspNetCoreModuleV2"
resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet"
arguments=".\PeopleworksGPT.MCP.Server.dll"
stdoutLogEnabled="true"
stdoutLogFile=".\logs\stdout"
hostingModel="InProcess" />
</system.webServer>
</configuration>
"@
Set-Content -Path "C:\inetpub\PeopleworksGPT-MCP\web.config" -Value $webConfig
Write-Host "Deployment complete! Server available at http://localhost:5000" -ForegroundColor Green
El usuario proporciona nombre de usuario y clave API. El servidor valida las credenciales y genera un token de sesión JWT válido por 60 minutos.
Usuario: "Auténticame con usuario 'admin' y apiKey 'pk_admin_1'"
Claude: [Llama a la herramienta AuthenticateAsync]
Respuesta: ✅ ¡Autenticado! Token de sesión: eyJ0eXAiOiJKV1Q...
El usuario solicita las conexiones de base de datos disponibles. El servidor devuelve solo las conexiones a las que el usuario autenticado tiene permiso de acceso.
Usuario: "Muéstrame mis conexiones de base de datos"
Claude: [Llama a la herramienta ListConnectionsAsync]
Respuesta: 📊 Tienes acceso a:
1. MonetSTR-Production (SQL Server 2022)
2. Analytics-Warehouse (PostgreSQL 15)
El usuario examina la estructura de la base de datos. El servidor proporciona definiciones de tablas, relaciones y datos de muestra.
Usuario: "¿Qué tablas hay en MonetSTR-Production?"
Claude: [Llama a la herramienta GetSchemaAsync]
Respuesta: 📋 Esquema de Base de Datos:
• Properties (15 columnas)
• Bookings (22 columnas)
• Customers (18 columnas)
• Payments (12 columnas)
El usuario hace una pregunta de negocio. El servidor la convierte a SQL optimizado, la ejecuta y devuelve resultados formateados.
Usuario: "Muéstrame las 10 propiedades principales por ingresos para noviembre 2024"
Claude: [Llama a la herramienta ExecuteQueryAsync]
SQL Generado:
SELECT TOP 10
PropertyName,
SUM(TotalAmount) AS TotalRevenue
FROM Bookings
WHERE BookingDate >= '2024-11-01' AND BookingDate < '2024-12-01'
GROUP BY PropertyName
ORDER BY TotalRevenue DESC
Resultados:
1. Beach Villa Sunset - $125,450
2. Downtown Loft 42 - $98,320
...
El usuario hace preguntas de seguimiento. Claude mantiene el contexto y refina consultas basándose en el historial de conversación.
Usuario: "Ahora muéstrame lo mismo para diciembre"
Claude: [Modifica consulta, llama a ExecuteQueryAsync]
Usuario: "¿Qué tal una comparación año a año?"
Claude: [Usa plantilla de Comparación, genera SQL complejo con CTEs]
Inyecta conocimiento de dominio: "PropertyStatus 1=Activo, 2=Inactivo" o "Los ingresos se calculan como TotalAmount - Discounts". La IA usa estas pistas para generar consultas más precisas.
Define plantillas específicas de negocio: "Para la industria hotelera, siempre calcula la tasa de ocupación como (noches_reservadas / noches_disponibles) * 100"
Filtrado automático: "ClientId = @CurrentUserClientId" inyectado en todas las consultas para asegurar aislamiento de datos en sistemas multi-tenant.
Cada consulta registrada: usuario, timestamp, entrada en lenguaje natural, SQL generado, tiempo de ejecución, filas devueltas, éxito/fallo.
Pregunta "Explica cómo generaste ese SQL" - obtén un desglose paso a paso del proceso de razonamiento de la IA.
La IA analiza tu esquema y sugiere preguntas relevantes: "¿Cuál es la duración promedio de reserva?", "¿Qué propiedades tienen la mayor ocupación?"
| Escenario | Enfoque Tradicional | Con Servidor MCP |
|---|---|---|
| Dashboard Ejecutivo | Contratar equipo BI → Construir reportes → Esperar semanas → Flexibilidad limitada | Preguntar a Claude: "Muéstrame KPIs para todas las propiedades este trimestre" → Resultados instantáneos → Desglose conversacional |
| Auditoría de Calidad de Datos | Escribir scripts SQL → Pruebas manuales → Documentar hallazgos | Preguntar: "Verificar todas las tablas para valores NULL, duplicados y valores atípicos" → Reporte completo en segundos |
| Soporte al Cliente | Agente de soporte → Escalar a equipo dev → Esperar consulta → Respuesta manual | Soporte pregunta a Claude: "Encontrar reservas para el cliente Juan Pérez en últimos 6 meses" → Respuesta inmediata |
| Análisis de Negocio | Definir requisitos → Solicitar reporte → Esperar desarrollador → Iterar | Analista chatea con Claude: "Comparar ingresos Q1 vs Q2 por región con análisis de varianza" → Hecho |
| Validación de Migración de Datos | Escribir scripts de validación → Ejecutar manualmente → Comparar resultados → Reportar | Preguntar: "Comparar conteos de filas y totales de sumas entre origen y destino para todas las tablas" → Validación instantánea |
var builder = WebApplication.CreateBuilder(args);
// Configure Serilog for structured logging
builder.Host.UseSerilog();
// Add database context with SQL Server
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
var connectionString = builder.Configuration.GetConnectionString("PeopleworksGPT");
options.UseSqlServer(connectionString);
});
// Add Identity for user management
builder.Services.AddIdentity<ApplicationUser, IdentityRole<long>>()
.AddEntityFrameworkStores<ApplicationDbContext>();
// Add CORS for HTTP transport
builder.Services.AddCors(options =>
{
options.AddPolicy("MCPClients", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
// Add PeopleWorks services (reuse existing infrastructure!)
builder.Services.AddScoped<ISettingService, SettingService>();
builder.Services.AddScoped<IPromptProvider, PromptProvider>();
builder.Services.AddScoped<IOpenAiCompatiblePwDatabaseGptClient, OpenAiCompatiblePwDatabaseGptClient>();
// Add MCP-specific services
builder.Services.AddScoped<SessionManager>();
builder.Services.AddScoped<AuditLogger>();
builder.Services.AddScoped<QueryExecutionService>();
// Add MCP Server with automatic tool discovery
builder.Services.AddMcpServer(options =>
{
options.ServerInfo = new Implementation
{
Name = "PeopleWorksGPT",
Version = "1.0.0"
};
})
.WithHttpTransport(httpOptions =>
{
httpOptions.Stateless = true; // No session state required
})
.WithToolsFromAssembly(); // Auto-discover all [McpServerTool] methods
var app = builder.Build();
// Enable CORS
app.UseCors("MCPClients");
// Map MCP endpoints
app.MapMcp();
await app.RunAsync();
WithToolsFromAssembly() encuentra todas las herramientas automáticamente| Métrica | Valor | Optimización |
|---|---|---|
| Latencia de Autenticación | < 100ms | Búsquedas indexadas en base de datos, generación eficiente de JWT |
| Tiempo de Generación de Consulta | 1-3 segundos | Depende de la latencia del proveedor de IA (OpenAI/Azure) |
| Ejecución de Consulta | Varía según complejidad | Generación SQL optimizada, sugerencias de indexación apropiadas |
| Usuarios Concurrentes | Limitado por conexiones de base de datos | Pooling de conexiones, async/await en todo el código |
| Caché de Esquema | Planificado para v2.0 | Caché en memoria para esquemas accedidos frecuentemente |
Actual: Texto plano en base de datos
Recomendado: Encriptado usando AES-256, política de rotación de claves, integración con Azure Key Vault
Actual: Expiración de 60 minutos
Mejora: Tokens de actualización, lista de revocación de tokens, expiración más corta con auto-renovación
Requerido: HTTPS/TLS para producción
Mejor: mTLS para autenticación de cliente, lista blanca de IP, acceso VPN
Incorporado: Solo consultas parametrizadas
Adicional: Validación de consultas, análisis SQL, detección de palabras clave peligrosas
Actual: Auditoría de consultas en base de datos
Mejorado: Integración SIEM, detección de anomalías, reportes de cumplimiento (GDPR, HIPAA)
Planificado: Límites de consultas por usuario
Recomendación: 100 consultas/hora, protección contra ráfagas, controles de costo para uso de API de IA
🎯 La Innovación Central: El Servidor MCP de PeopleWorks GPT transforma cómo las empresas interactúan con sus datos. En lugar de contratar equipos de BI, construir dashboards o escribir SQL, los usuarios simplemente pueden hacer preguntas en lenguaje natural.
🔄 La Victoria de Reutilización: Al implementar el protocolo MCP, hemos hecho accesibles las poderosas capacidades de IA-a-SQL de DatabaseGPT a cualquier cliente compatible con MCP - Claude Desktop hoy, ChatGPT mañana, agentes personalizados la próxima semana.
🏢 El Valor Empresarial: Autenticación multiusuario, permisos granulares, registros de auditoría, soporte multi-base de datos e inyección de conocimiento de dominio hacen de esta una solución lista para producción para negocios reales.
🚀 El Camino Futuro: Esto es solo el comienzo. Con integración de STRPlatform, plantillas de análisis avanzadas y soporte multi-proveedor de IA en la hoja de ruta, la plataforma se volverá aún más poderosa.
"El Model Context Protocol es el USB-C de la IA - y PeopleWorks GPT está listo para conectarse."
Comienza a usar el Servidor MCP de PeopleWorks GPT hoy