248
src/examples.ts
Archivo normal
248
src/examples.ts
Archivo normal
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* Ejemplos de uso del MCP INE Server
|
||||
* Ejecutar con: node dist/examples.js
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
const MCP_ENDPOINT = 'http://localhost:3000/mcp/v1';
|
||||
|
||||
/**
|
||||
* Función helper para llamar al servidor MCP
|
||||
*/
|
||||
async function callMCPTool(toolName: string, args: any = {}) {
|
||||
try {
|
||||
const response = await axios.post(MCP_ENDPOINT, {
|
||||
jsonrpc: '2.0',
|
||||
method: 'tools/call',
|
||||
params: {
|
||||
name: toolName,
|
||||
arguments: args
|
||||
},
|
||||
id: Date.now()
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
console.error(`Error llamando a ${toolName}:`, error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejemplo 1: Obtener últimos datos del IPC
|
||||
*/
|
||||
async function ejemplo1_datosIPC() {
|
||||
console.log('\n📊 Ejemplo 1: Últimos datos del IPC\n');
|
||||
|
||||
const result = await callMCPTool('ine_datos_serie', {
|
||||
idSerie: 'IPC251856',
|
||||
nult: 12,
|
||||
tip: 'A',
|
||||
idioma: 'ES'
|
||||
});
|
||||
|
||||
if (result?.result?.content?.[0]?.text) {
|
||||
console.log(JSON.parse(result.result.content[0].text));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejemplo 2: Listar operaciones disponibles
|
||||
*/
|
||||
async function ejemplo2_operaciones() {
|
||||
console.log('\n📋 Ejemplo 2: Operaciones Disponibles\n');
|
||||
|
||||
const result = await callMCPTool('ine_operaciones_disponibles', {
|
||||
idioma: 'ES',
|
||||
geo: 0,
|
||||
det: 1
|
||||
});
|
||||
|
||||
if (result?.result?.content?.[0]?.text) {
|
||||
const data = JSON.parse(result.result.content[0].text);
|
||||
console.log(`Total de operaciones: ${data.data?.length || 0}`);
|
||||
console.log('Primeras 5 operaciones:');
|
||||
data.data?.slice(0, 5).forEach((op: any) => {
|
||||
console.log(`- ${op.Nombre} (${op.Id})`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejemplo 3: Obtener variables de la operación IPC
|
||||
*/
|
||||
async function ejemplo3_variablesIPC() {
|
||||
console.log('\n🏷️ Ejemplo 3: Variables de la Operación IPC\n');
|
||||
|
||||
const result = await callMCPTool('ine_variables_operacion', {
|
||||
idOperacion: 'IPC',
|
||||
idioma: 'ES'
|
||||
});
|
||||
|
||||
if (result?.result?.content?.[0]?.text) {
|
||||
const data = JSON.parse(result.result.content[0].text);
|
||||
console.log('Variables del IPC:');
|
||||
data.data?.slice(0, 10).forEach((variable: any) => {
|
||||
console.log(`- ${variable.Nombre} (ID: ${variable.Id})`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejemplo 4: Obtener datos de una tabla
|
||||
*/
|
||||
async function ejemplo4_datosTabla() {
|
||||
console.log('\n📈 Ejemplo 4: Datos de Tabla 50902\n');
|
||||
|
||||
const result = await callMCPTool('ine_datos_tabla', {
|
||||
idTabla: '50902',
|
||||
nult: 3,
|
||||
tip: 'A',
|
||||
idioma: 'ES'
|
||||
});
|
||||
|
||||
if (result?.result?.content?.[0]?.text) {
|
||||
const data = JSON.parse(result.result.content[0].text);
|
||||
console.log('Últimos 3 períodos de la tabla 50902:');
|
||||
console.log(JSON.stringify(data, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejemplo 5: Obtener información de una operación
|
||||
*/
|
||||
async function ejemplo5_infoOperacion() {
|
||||
console.log('\n📖 Ejemplo 5: Información de la Operación IPC\n');
|
||||
|
||||
const result = await callMCPTool('ine_operacion', {
|
||||
idOperacion: 'IPC',
|
||||
det: 2,
|
||||
idioma: 'ES'
|
||||
});
|
||||
|
||||
if (result?.result?.content?.[0]?.text) {
|
||||
const data = JSON.parse(result.result.content[0].text);
|
||||
console.log('Información del IPC:');
|
||||
console.log(JSON.stringify(data, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejemplo 6: Buscar series con filtros
|
||||
*/
|
||||
async function ejemplo6_seriesConFiltros() {
|
||||
console.log('\n🔍 Ejemplo 6: Series del IPC con Filtros\n');
|
||||
|
||||
const result = await callMCPTool('ine_datos_metadata_operacion', {
|
||||
idOperacion: 'IPC',
|
||||
p: 1, // Periodicidad mensual
|
||||
nult: 1,
|
||||
g1: '115:29', // Madrid
|
||||
g2: '3:84', // Variación mensual
|
||||
tip: 'A',
|
||||
idioma: 'ES'
|
||||
});
|
||||
|
||||
if (result?.result?.content?.[0]?.text) {
|
||||
const data = JSON.parse(result.result.content[0].text);
|
||||
console.log('Datos del IPC para Madrid:');
|
||||
console.log(JSON.stringify(data, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejemplo 7: Listar herramientas disponibles
|
||||
*/
|
||||
async function ejemplo7_listarHerramientas() {
|
||||
console.log('\n🛠️ Ejemplo 7: Herramientas MCP Disponibles\n');
|
||||
|
||||
try {
|
||||
const response = await axios.post(MCP_ENDPOINT, {
|
||||
jsonrpc: '2.0',
|
||||
method: 'tools/list',
|
||||
params: {},
|
||||
id: 1
|
||||
});
|
||||
|
||||
const tools = response.data.result.tools;
|
||||
console.log(`Total de herramientas: ${tools.length}\n`);
|
||||
|
||||
tools.forEach((tool: any) => {
|
||||
console.log(`- ${tool.name}`);
|
||||
console.log(` ${tool.description}`);
|
||||
console.log('');
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('Error listando herramientas:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejemplo 8: Obtener periodicidades
|
||||
*/
|
||||
async function ejemplo8_periodicidades() {
|
||||
console.log('\n⏰ Ejemplo 8: Periodicidades Disponibles\n');
|
||||
|
||||
const result = await callMCPTool('ine_periodicidades', {
|
||||
idioma: 'ES'
|
||||
});
|
||||
|
||||
if (result?.result?.content?.[0]?.text) {
|
||||
const data = JSON.parse(result.result.content[0].text);
|
||||
console.log('Periodicidades:');
|
||||
data.data?.forEach((per: any) => {
|
||||
console.log(`- ${per.Nombre} (ID: ${per.Id})`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ejecutar todos los ejemplos
|
||||
*/
|
||||
async function ejecutarTodos() {
|
||||
console.log('='.repeat(60));
|
||||
console.log(' EJEMPLOS DE USO DEL MCP INE SERVER');
|
||||
console.log('='.repeat(60));
|
||||
console.log('\n⚠️ Asegúrate de que el servidor esté corriendo en el puerto 3000');
|
||||
console.log(' Comando: npm start\n');
|
||||
|
||||
// Verificar que el servidor esté activo
|
||||
try {
|
||||
await axios.get('http://localhost:3000/health');
|
||||
console.log('✅ Servidor MCP INE activo\n');
|
||||
} catch (error) {
|
||||
console.error('❌ Error: El servidor no está activo. Inicia el servidor con: npm start');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await ejemplo7_listarHerramientas();
|
||||
await ejemplo1_datosIPC();
|
||||
await ejemplo2_operaciones();
|
||||
await ejemplo3_variablesIPC();
|
||||
await ejemplo4_datosTabla();
|
||||
await ejemplo5_infoOperacion();
|
||||
await ejemplo8_periodicidades();
|
||||
await ejemplo6_seriesConFiltros();
|
||||
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log(' FIN DE LOS EJEMPLOS');
|
||||
console.log('='.repeat(60));
|
||||
}
|
||||
|
||||
// Ejecutar si se llama directamente
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
ejecutarTodos().catch(console.error);
|
||||
}
|
||||
|
||||
export {
|
||||
callMCPTool,
|
||||
ejemplo1_datosIPC,
|
||||
ejemplo2_operaciones,
|
||||
ejemplo3_variablesIPC,
|
||||
ejemplo4_datosTabla,
|
||||
ejemplo5_infoOperacion,
|
||||
ejemplo6_seriesConFiltros,
|
||||
ejemplo7_listarHerramientas,
|
||||
ejemplo8_periodicidades
|
||||
};
|
||||
611
src/index.ts
Archivo normal
611
src/index.ts
Archivo normal
@@ -0,0 +1,611 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
import cors from 'cors';
|
||||
import swaggerUi from 'swagger-ui-express';
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
Tool
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
import { ineClient } from './services/ine-client.js';
|
||||
import { swaggerSpec } from './swagger.js';
|
||||
import type { Idioma } from './types/ine.types.js';
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
const app = express();
|
||||
|
||||
// Middleware
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Swagger Documentation
|
||||
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
|
||||
|
||||
// Health check
|
||||
app.get('/health', (req: Request, res: Response) => {
|
||||
res.json({
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
service: 'MCP INE Server'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Definición de herramientas MCP para la API del INE
|
||||
*/
|
||||
const tools: Tool[] = [
|
||||
{
|
||||
name: 'ine_datos_tabla',
|
||||
description: 'Obtiene datos de una tabla específica del INE. Permite filtrar por periodos, nivel de detalle y variables.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idTabla: { type: 'string', description: 'ID de la tabla (ej: 50902)' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES', description: 'Idioma' },
|
||||
nult: { type: 'number', description: 'Número de últimos periodos' },
|
||||
det: { type: 'number', enum: [0, 1, 2], description: 'Nivel de detalle' },
|
||||
tip: { type: 'string', enum: ['A', 'M', 'AM'], description: 'Tipo: A=amigable, M=metadatos, AM=ambos' },
|
||||
tv: { type: 'string', description: 'Filtro de variables (formato: id_variable:id_valor)' },
|
||||
date: { type: 'string', description: 'Rango de fechas (formato: aaaammdd:aaaammdd)' }
|
||||
},
|
||||
required: ['idTabla']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_datos_serie',
|
||||
description: 'Obtiene datos de una serie temporal específica del INE.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idSerie: { type: 'string', description: 'Código de la serie (ej: IPC251856)' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
nult: { type: 'number', description: 'Número de últimos periodos' },
|
||||
det: { type: 'number', enum: [0, 1, 2], description: 'Nivel de detalle' },
|
||||
tip: { type: 'string', enum: ['A', 'M', 'AM'], description: 'Tipo de respuesta' },
|
||||
date: { type: 'string', description: 'Rango de fechas' }
|
||||
},
|
||||
required: ['idSerie']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_datos_metadata_operacion',
|
||||
description: 'Obtiene datos de series usando filtros de metadata de una operación.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idOperacion: { type: 'string', description: 'Código de operación (ej: IPC)' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
p: { type: 'number', description: 'Periodicidad (1=mensual, 3=trimestral, 12=anual)' },
|
||||
nult: { type: 'number', description: 'Número de últimos periodos' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A', 'M', 'AM'] },
|
||||
g1: { type: 'string', description: 'Filtro 1 (formato: id_variable:id_valor)' },
|
||||
g2: { type: 'string', description: 'Filtro 2' },
|
||||
g3: { type: 'string', description: 'Filtro 3' },
|
||||
g4: { type: 'string', description: 'Filtro 4' },
|
||||
g5: { type: 'string', description: 'Filtro 5' }
|
||||
},
|
||||
required: ['idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_operaciones_disponibles',
|
||||
description: 'Lista todas las operaciones estadísticas disponibles en el INE.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
geo: { type: 'number', enum: [0, 1], description: '0=nacional, 1=geográfico' },
|
||||
page: { type: 'number', description: 'Página (500 elementos por página)' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_operacion',
|
||||
description: 'Obtiene información detallada de una operación estadística.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idOperacion: { type: 'string', description: 'Código de operación' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] }
|
||||
},
|
||||
required: ['idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_variables',
|
||||
description: 'Lista todas las variables estadísticas disponibles.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
page: { type: 'number' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_variables_operacion',
|
||||
description: 'Obtiene las variables utilizadas en una operación específica.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idOperacion: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
page: { type: 'number' }
|
||||
},
|
||||
required: ['idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_valores_variable',
|
||||
description: 'Obtiene todos los valores posibles de una variable.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idVariable: { type: 'string', description: 'ID de la variable' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
clasif: { type: 'number', description: 'ID de clasificación' }
|
||||
},
|
||||
required: ['idVariable']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_valores_variable_operacion',
|
||||
description: 'Obtiene valores de una variable en el contexto de una operación.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idVariable: { type: 'string' },
|
||||
idOperacion: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] }
|
||||
},
|
||||
required: ['idVariable', 'idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_tablas_operacion',
|
||||
description: 'Lista todas las tablas de una operación estadística.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idOperacion: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
geo: { type: 'number', enum: [0, 1] },
|
||||
tip: { type: 'string', enum: ['A'] }
|
||||
},
|
||||
required: ['idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_grupos_tabla',
|
||||
description: 'Obtiene los grupos de selección que definen una tabla.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idTabla: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
},
|
||||
required: ['idTabla']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_valores_grupos_tabla',
|
||||
description: 'Obtiene los valores de un grupo específico de una tabla.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idTabla: { type: 'string' },
|
||||
idGrupo: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] }
|
||||
},
|
||||
required: ['idTabla', 'idGrupo']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_serie',
|
||||
description: 'Obtiene información completa de una serie temporal.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idSerie: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A', 'M', 'AM'] }
|
||||
},
|
||||
required: ['idSerie']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_series_operacion',
|
||||
description: 'Lista todas las series de una operación.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idOperacion: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A', 'M', 'AM'] },
|
||||
page: { type: 'number' }
|
||||
},
|
||||
required: ['idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_valores_serie',
|
||||
description: 'Obtiene las variables y valores que definen una serie.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idSerie: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] }
|
||||
},
|
||||
required: ['idSerie']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_series_tabla',
|
||||
description: 'Obtiene todas las series de una tabla específica.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idTabla: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A', 'M', 'AM'] },
|
||||
tv: { type: 'string', description: 'Filtro de variables' }
|
||||
},
|
||||
required: ['idTabla']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_serie_metadata_operacion',
|
||||
description: 'Busca series usando filtros de metadata en una operación.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idOperacion: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
p: { type: 'number', description: 'Periodicidad' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A', 'M', 'AM'] },
|
||||
g1: { type: 'string' },
|
||||
g2: { type: 'string' },
|
||||
g3: { type: 'string' },
|
||||
g4: { type: 'string' },
|
||||
g5: { type: 'string' }
|
||||
},
|
||||
required: ['idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_periodicidades',
|
||||
description: 'Lista todas las periodicidades disponibles (mensual, trimestral, etc.).',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_publicaciones',
|
||||
description: 'Lista todas las publicaciones estadísticas disponibles.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A'] }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_publicaciones_operacion',
|
||||
description: 'Obtiene las publicaciones de una operación específica.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idOperacion: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A'] }
|
||||
},
|
||||
required: ['idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_publicacion_fecha_publicacion',
|
||||
description: 'Obtiene las fechas de publicación para una publicación dada.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idPublicacion: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A'] }
|
||||
},
|
||||
required: ['idPublicacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_clasificaciones',
|
||||
description: 'Lista todas las clasificaciones estadísticas disponibles.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_clasificaciones_operacion',
|
||||
description: 'Obtiene las clasificaciones utilizadas en una operación.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idOperacion: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
},
|
||||
required: ['idOperacion']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_valores_hijos',
|
||||
description: 'Obtiene valores hijos en una estructura jerárquica (ej: provincias de una comunidad).',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idVariable: { type: 'string', description: 'ID de la variable' },
|
||||
idValor: { type: 'string', description: 'ID del valor padre' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
det: { type: 'number', enum: [0, 1, 2] }
|
||||
},
|
||||
required: ['idVariable', 'idValor']
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Maneja las llamadas a las herramientas MCP
|
||||
*/
|
||||
async function handleToolCall(name: string, args: any): Promise<any> {
|
||||
const idioma = (args.idioma || 'ES') as Idioma;
|
||||
|
||||
switch (name) {
|
||||
case 'ine_datos_tabla':
|
||||
return await ineClient.getDatosTabla(args.idTabla, args, idioma);
|
||||
|
||||
case 'ine_datos_serie':
|
||||
return await ineClient.getDatosSerie(args.idSerie, args, idioma);
|
||||
|
||||
case 'ine_datos_metadata_operacion':
|
||||
return await ineClient.getDatosMetadataOperacion(args.idOperacion, args, idioma);
|
||||
|
||||
case 'ine_operaciones_disponibles':
|
||||
return await ineClient.getOperacionesDisponibles(args, idioma);
|
||||
|
||||
case 'ine_operacion':
|
||||
return await ineClient.getOperacion(args.idOperacion, args, idioma);
|
||||
|
||||
case 'ine_variables':
|
||||
return await ineClient.getVariables(args, idioma);
|
||||
|
||||
case 'ine_variables_operacion':
|
||||
return await ineClient.getVariablesOperacion(args.idOperacion, args, idioma);
|
||||
|
||||
case 'ine_valores_variable':
|
||||
return await ineClient.getValoresVariable(args.idVariable, args, idioma);
|
||||
|
||||
case 'ine_valores_variable_operacion':
|
||||
return await ineClient.getValoresVariableOperacion(args.idVariable, args.idOperacion, args, idioma);
|
||||
|
||||
case 'ine_tablas_operacion':
|
||||
return await ineClient.getTablasOperacion(args.idOperacion, args, idioma);
|
||||
|
||||
case 'ine_grupos_tabla':
|
||||
return await ineClient.getGruposTabla(args.idTabla, idioma);
|
||||
|
||||
case 'ine_valores_grupos_tabla':
|
||||
return await ineClient.getValoresGruposTabla(args.idTabla, args.idGrupo, args, idioma);
|
||||
|
||||
case 'ine_serie':
|
||||
return await ineClient.getSerie(args.idSerie, args, idioma);
|
||||
|
||||
case 'ine_series_operacion':
|
||||
return await ineClient.getSeriesOperacion(args.idOperacion, args, idioma);
|
||||
|
||||
case 'ine_valores_serie':
|
||||
return await ineClient.getValoresSerie(args.idSerie, args, idioma);
|
||||
|
||||
case 'ine_series_tabla':
|
||||
return await ineClient.getSeriesTabla(args.idTabla, args, idioma);
|
||||
|
||||
case 'ine_serie_metadata_operacion':
|
||||
return await ineClient.getSerieMetadataOperacion(args.idOperacion, args, idioma);
|
||||
|
||||
case 'ine_periodicidades':
|
||||
return await ineClient.getPeriodicidades(idioma);
|
||||
|
||||
case 'ine_publicaciones':
|
||||
return await ineClient.getPublicaciones(args, idioma);
|
||||
|
||||
case 'ine_publicaciones_operacion':
|
||||
return await ineClient.getPublicacionesOperacion(args.idOperacion, args, idioma);
|
||||
|
||||
case 'ine_publicacion_fecha_publicacion':
|
||||
return await ineClient.getPublicacionFechaPublicacion(args.idPublicacion, args, idioma);
|
||||
|
||||
case 'ine_clasificaciones':
|
||||
return await ineClient.getClasificaciones(idioma);
|
||||
|
||||
case 'ine_clasificaciones_operacion':
|
||||
return await ineClient.getClasificacionesOperacion(args.idOperacion, idioma);
|
||||
|
||||
case 'ine_valores_hijos':
|
||||
return await ineClient.getValoresHijos(args.idVariable, args.idValor, args, idioma);
|
||||
|
||||
default:
|
||||
throw new Error(`Herramienta desconocida: ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint JSON-RPC para MCP
|
||||
*/
|
||||
app.post('/mcp/v1', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { jsonrpc, method, params, id } = req.body;
|
||||
|
||||
if (jsonrpc !== '2.0') {
|
||||
return res.status(400).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32600, message: 'Invalid Request' },
|
||||
id: null
|
||||
});
|
||||
}
|
||||
|
||||
// Listar herramientas
|
||||
if (method === 'tools/list') {
|
||||
return res.json({
|
||||
jsonrpc: '2.0',
|
||||
result: { tools },
|
||||
id
|
||||
});
|
||||
}
|
||||
|
||||
// Llamar a una herramienta
|
||||
if (method === 'tools/call') {
|
||||
const { name, arguments: args } = params;
|
||||
const result = await handleToolCall(name, args || {});
|
||||
|
||||
return res.json({
|
||||
jsonrpc: '2.0',
|
||||
result: {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(result, null, 2)
|
||||
}
|
||||
]
|
||||
},
|
||||
id
|
||||
});
|
||||
}
|
||||
|
||||
// Método no soportado
|
||||
return res.status(404).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32601, message: 'Method not found' },
|
||||
id
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('Error en MCP:', error);
|
||||
return res.status(500).json({
|
||||
jsonrpc: '2.0',
|
||||
error: { code: -32603, message: error.message || 'Internal error' },
|
||||
id: req.body.id || null
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// API REST endpoints (adicionales para compatibilidad)
|
||||
app.get('/api/datos-tabla/:idTabla', async (req, res) => {
|
||||
const result = await ineClient.getDatosTabla(req.params.idTabla, req.query as any);
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
app.get('/api/datos-serie/:idSerie', async (req, res) => {
|
||||
const result = await ineClient.getDatosSerie(req.params.idSerie, req.query as any);
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
app.get('/api/operaciones-disponibles', async (req, res) => {
|
||||
const result = await ineClient.getOperacionesDisponibles(req.query as any);
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
app.get('/api/operacion/:idOperacion', async (req, res) => {
|
||||
const result = await ineClient.getOperacion(req.params.idOperacion, req.query as any);
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
app.get('/api/variables', async (req, res) => {
|
||||
const result = await ineClient.getVariables(req.query as any);
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
app.get('/api/variables-operacion/:idOperacion', async (req, res) => {
|
||||
const result = await ineClient.getVariablesOperacion(req.params.idOperacion, req.query as any);
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
app.get('/api/series-operacion/:idOperacion', async (req, res) => {
|
||||
const result = await ineClient.getSeriesOperacion(req.params.idOperacion, req.query as any);
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
app.get('/api/tablas-operacion/:idOperacion', async (req, res) => {
|
||||
const result = await ineClient.getTablasOperacion(req.params.idOperacion, req.query as any);
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
// Iniciar servidor HTTP
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🚀 MCP INE Server ejecutándose en http://localhost:${PORT}`);
|
||||
console.log(`📚 Documentación Swagger: http://localhost:${PORT}/api-docs`);
|
||||
console.log(`🔧 Endpoint MCP JSON-RPC: http://localhost:${PORT}/mcp/v1`);
|
||||
console.log(`💚 Health check: http://localhost:${PORT}/health`);
|
||||
});
|
||||
|
||||
// Para uso con stdio (AI Toolkit)
|
||||
export async function runStdioServer() {
|
||||
const server = new Server(
|
||||
{
|
||||
name: 'ine-mcp-server',
|
||||
version: '1.0.0',
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Registrar handlers
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||
tools
|
||||
}));
|
||||
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
const result = await handleToolCall(name, args || {});
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(result, null, 2)
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
|
||||
console.error('MCP INE Server iniciado en modo stdio');
|
||||
}
|
||||
|
||||
// Si se ejecuta directamente con --stdio
|
||||
if (process.argv.includes('--stdio')) {
|
||||
runStdioServer().catch(console.error);
|
||||
}
|
||||
215
src/server-sse.ts
Archivo normal
215
src/server-sse.ts
Archivo normal
@@ -0,0 +1,215 @@
|
||||
import express, { Request, Response } from 'express';
|
||||
import cors from 'cors';
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
import { ineClient } from './services/ine-client.js';
|
||||
import type { Idioma } from './types/ine.types.js';
|
||||
|
||||
const PORT = process.env.PORT || 3001;
|
||||
const app = express();
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Almacenamiento de sesiones SSE
|
||||
const sessions = new Map<string, { server: Server; transport: SSEServerTransport }>();
|
||||
|
||||
/**
|
||||
* Maneja las llamadas a las herramientas MCP
|
||||
*/
|
||||
async function handleToolCall(name: string, args: any): Promise<any> {
|
||||
const idioma = (args.idioma || 'ES') as Idioma;
|
||||
|
||||
switch (name) {
|
||||
case 'ine_datos_tabla':
|
||||
return await ineClient.getDatosTabla(args.idTabla, args, idioma);
|
||||
case 'ine_datos_serie':
|
||||
return await ineClient.getDatosSerie(args.idSerie, args, idioma);
|
||||
case 'ine_datos_metadata_operacion':
|
||||
return await ineClient.getDatosMetadataOperacion(args.idOperacion, args, idioma);
|
||||
case 'ine_operaciones_disponibles':
|
||||
return await ineClient.getOperacionesDisponibles(args, idioma);
|
||||
case 'ine_operacion':
|
||||
return await ineClient.getOperacion(args.idOperacion, args, idioma);
|
||||
case 'ine_variables':
|
||||
return await ineClient.getVariables(args, idioma);
|
||||
case 'ine_variables_operacion':
|
||||
return await ineClient.getVariablesOperacion(args.idOperacion, args, idioma);
|
||||
case 'ine_valores_variable':
|
||||
return await ineClient.getValoresVariable(args.idVariable, args, idioma);
|
||||
case 'ine_valores_variable_operacion':
|
||||
return await ineClient.getValoresVariableOperacion(args.idVariable, args.idOperacion, args, idioma);
|
||||
case 'ine_tablas_operacion':
|
||||
return await ineClient.getTablasOperacion(args.idOperacion, args, idioma);
|
||||
case 'ine_grupos_tabla':
|
||||
return await ineClient.getGruposTabla(args.idTabla, idioma);
|
||||
case 'ine_valores_grupos_tabla':
|
||||
return await ineClient.getValoresGruposTabla(args.idTabla, args.idGrupo, args, idioma);
|
||||
case 'ine_serie':
|
||||
return await ineClient.getSerie(args.idSerie, args, idioma);
|
||||
case 'ine_series_operacion':
|
||||
return await ineClient.getSeriesOperacion(args.idOperacion, args, idioma);
|
||||
case 'ine_valores_serie':
|
||||
return await ineClient.getValoresSerie(args.idSerie, args, idioma);
|
||||
case 'ine_series_tabla':
|
||||
return await ineClient.getSeriesTabla(args.idTabla, args, idioma);
|
||||
case 'ine_serie_metadata_operacion':
|
||||
return await ineClient.getSerieMetadataOperacion(args.idOperacion, args, idioma);
|
||||
case 'ine_periodicidades':
|
||||
return await ineClient.getPeriodicidades(idioma);
|
||||
case 'ine_publicaciones':
|
||||
return await ineClient.getPublicaciones(args, idioma);
|
||||
case 'ine_publicaciones_operacion':
|
||||
return await ineClient.getPublicacionesOperacion(args.idOperacion, args, idioma);
|
||||
case 'ine_publicacion_fecha_publicacion':
|
||||
return await ineClient.getPublicacionFechaPublicacion(args.idPublicacion, args, idioma);
|
||||
case 'ine_clasificaciones':
|
||||
return await ineClient.getClasificaciones(idioma);
|
||||
case 'ine_clasificaciones_operacion':
|
||||
return await ineClient.getClasificacionesOperacion(args.idOperacion, idioma);
|
||||
case 'ine_valores_hijos':
|
||||
return await ineClient.getValoresHijos(args.idVariable, args.idValor, args, idioma);
|
||||
default:
|
||||
throw new Error(`Herramienta desconocida: ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Definición de herramientas (mismo que en index.ts)
|
||||
const tools = [
|
||||
{
|
||||
name: 'ine_datos_tabla',
|
||||
description: 'Obtiene datos de una tabla específica del INE',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idTabla: { type: 'string', description: 'ID de la tabla' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
nult: { type: 'number' },
|
||||
det: { type: 'number', enum: [0, 1, 2] },
|
||||
tip: { type: 'string', enum: ['A', 'M', 'AM'] }
|
||||
},
|
||||
required: ['idTabla']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_datos_serie',
|
||||
description: 'Obtiene datos de una serie temporal',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idSerie: { type: 'string' },
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
nult: { type: 'number' },
|
||||
det: { type: 'number', enum: [0, 1, 2] }
|
||||
},
|
||||
required: ['idSerie']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ine_operaciones_disponibles',
|
||||
description: 'Lista todas las operaciones estadísticas',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
idioma: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
geo: { type: 'number', enum: [0, 1] },
|
||||
page: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
// Agregar el resto de herramientas según sea necesario
|
||||
];
|
||||
|
||||
/**
|
||||
* Endpoint SSE para conexión MCP
|
||||
*/
|
||||
app.get('/sse', async (req: Request, res: Response) => {
|
||||
const sessionId = Math.random().toString(36).substring(7);
|
||||
|
||||
// Configurar SSE
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive'
|
||||
});
|
||||
|
||||
// Crear servidor MCP
|
||||
const server = new Server(
|
||||
{
|
||||
name: 'ine-mcp-server-sse',
|
||||
version: '1.0.0',
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Registrar handlers
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
||||
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
const result = await handleToolCall(name, args || {});
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(result, null, 2)
|
||||
}
|
||||
]
|
||||
};
|
||||
});
|
||||
|
||||
// Crear transporte SSE
|
||||
const transport = new SSEServerTransport('/messages', res);
|
||||
await server.connect(transport);
|
||||
|
||||
sessions.set(sessionId, { server, transport });
|
||||
|
||||
// Limpiar al cerrar conexión
|
||||
req.on('close', () => {
|
||||
sessions.delete(sessionId);
|
||||
console.log(`Sesión SSE cerrada: ${sessionId}`);
|
||||
});
|
||||
|
||||
console.log(`Nueva sesión SSE iniciada: ${sessionId}`);
|
||||
});
|
||||
|
||||
/**
|
||||
* Endpoint para enviar mensajes (POST)
|
||||
*/
|
||||
app.post('/messages', async (req: Request, res: Response) => {
|
||||
try {
|
||||
// Este endpoint procesa mensajes enviados por el cliente
|
||||
const message = req.body;
|
||||
console.log('Mensaje recibido:', message);
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error: any) {
|
||||
console.error('Error procesando mensaje:', error);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Health check
|
||||
app.get('/health', (req: Request, res: Response) => {
|
||||
res.json({
|
||||
status: 'ok',
|
||||
transport: 'SSE',
|
||||
sessions: sessions.size,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`🚀 MCP INE Server (SSE) ejecutándose en http://localhost:${PORT}`);
|
||||
console.log(`📡 Endpoint SSE: http://localhost:${PORT}/sse`);
|
||||
console.log(`💚 Health check: http://localhost:${PORT}/health`);
|
||||
});
|
||||
283
src/services/ine-client.ts
Archivo normal
283
src/services/ine-client.ts
Archivo normal
@@ -0,0 +1,283 @@
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import type {
|
||||
Idioma,
|
||||
DatosTablaParams,
|
||||
DatosSerieParams,
|
||||
DatosMetadataOperacionParams,
|
||||
OperacionesDisponiblesParams,
|
||||
OperacionParams,
|
||||
VariablesParams,
|
||||
VariablesOperacionParams,
|
||||
ValoresVariableParams,
|
||||
ValoresVariableOperacionParams,
|
||||
TablasOperacionParams,
|
||||
ValoresGruposTablaParams,
|
||||
SerieParams,
|
||||
SeriesOperacionParams,
|
||||
ValoresSerieParams,
|
||||
SeriesTablaParams,
|
||||
SerieMetadataOperacionParams,
|
||||
PublicacionesParams,
|
||||
PublicacionesOperacionParams,
|
||||
PublicacionFechaPublicacionParams,
|
||||
ValoresHijosParams,
|
||||
INEResponse
|
||||
} from '../types/ine.types.js';
|
||||
|
||||
/**
|
||||
* Cliente para la API del INE
|
||||
*/
|
||||
export class INEClient {
|
||||
private readonly baseURL = 'https://servicios.ine.es/wstempus/js';
|
||||
private readonly client: AxiosInstance;
|
||||
|
||||
constructor() {
|
||||
this.client = axios.create({
|
||||
baseURL: this.baseURL,
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': 'MCP-INE-Server/1.0'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Construye la URL con parámetros
|
||||
*/
|
||||
private buildURL(idioma: Idioma, funcion: string, input?: string, params?: Record<string, any>): string {
|
||||
let url = `/${idioma}/${funcion}`;
|
||||
if (input) {
|
||||
url += `/${input}`;
|
||||
}
|
||||
|
||||
if (params && Object.keys(params).length > 0) {
|
||||
const queryParams = new URLSearchParams();
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null) {
|
||||
queryParams.append(key, String(value));
|
||||
}
|
||||
});
|
||||
const queryString = queryParams.toString();
|
||||
if (queryString) {
|
||||
url += `?${queryString}`;
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Realiza una petición GET a la API
|
||||
*/
|
||||
private async get<T>(url: string): Promise<INEResponse<T>> {
|
||||
try {
|
||||
const response = await this.client.get<T>(url);
|
||||
return {
|
||||
data: response.data,
|
||||
success: true
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
data: null as any,
|
||||
success: false,
|
||||
error: error.message || 'Error desconocido'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DATOS_TABLA - Obtener datos para una tabla específica
|
||||
*/
|
||||
async getDatosTabla(idTabla: string, params?: DatosTablaParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'DATOS_TABLA', idTabla, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* DATOS_SERIE - Obtener datos para una serie específica
|
||||
*/
|
||||
async getDatosSerie(idSerie: string, params?: DatosSerieParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'DATOS_SERIE', idSerie, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* DATOS_METADATAOPERACION - Obtener datos de series usando filtros
|
||||
*/
|
||||
async getDatosMetadataOperacion(idOperacion: string, params?: DatosMetadataOperacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'DATOS_METADATAOPERACION', idOperacion, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* OPERACIONES_DISPONIBLES - Obtener todas las operaciones disponibles
|
||||
*/
|
||||
async getOperacionesDisponibles(params?: OperacionesDisponiblesParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'OPERACIONES_DISPONIBLES', undefined, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* OPERACION - Obtener una operación específica
|
||||
*/
|
||||
async getOperacion(idOperacion: string, params?: OperacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'OPERACION', idOperacion, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* VARIABLES - Obtener todas las variables disponibles
|
||||
*/
|
||||
async getVariables(params?: VariablesParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'VARIABLES', undefined, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* VARIABLES_OPERACION - Obtener variables de una operación
|
||||
*/
|
||||
async getVariablesOperacion(idOperacion: string, params?: VariablesOperacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'VARIABLES_OPERACION', idOperacion, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* VALORES_VARIABLE - Obtener valores de una variable
|
||||
*/
|
||||
async getValoresVariable(idVariable: string, params?: ValoresVariableParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'VALORES_VARIABLE', idVariable, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* VALORES_VARIABLEOPERACION - Obtener valores de una variable en una operación
|
||||
*/
|
||||
async getValoresVariableOperacion(idVariable: string, idOperacion: string, params?: ValoresVariableOperacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'VALORES_VARIABLEOPERACION', `${idVariable}/${idOperacion}`, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* TABLAS_OPERACION - Obtener tablas de una operación
|
||||
*/
|
||||
async getTablasOperacion(idOperacion: string, params?: TablasOperacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'TABLAS_OPERACION', idOperacion, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* GRUPOS_TABLA - Obtener grupos de una tabla
|
||||
*/
|
||||
async getGruposTabla(idTabla: string, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'GRUPOS_TABLA', idTabla);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* VALORES_GRUPOSTABLA - Obtener valores de un grupo de tabla
|
||||
*/
|
||||
async getValoresGruposTabla(idTabla: string, idGrupo: string, params?: ValoresGruposTablaParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'VALORES_GRUPOSTABLA', `${idTabla}/${idGrupo}`, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* SERIE - Obtener información de una serie
|
||||
*/
|
||||
async getSerie(idSerie: string, params?: SerieParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'SERIE', idSerie, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* SERIES_OPERACION - Obtener series de una operación
|
||||
*/
|
||||
async getSeriesOperacion(idOperacion: string, params?: SeriesOperacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'SERIES_OPERACION', idOperacion, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* VALORES_SERIE - Obtener valores y variables que definen una serie
|
||||
*/
|
||||
async getValoresSerie(idSerie: string, params?: ValoresSerieParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'VALORES_SERIE', idSerie, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* SERIES_TABLA - Obtener series de una tabla
|
||||
*/
|
||||
async getSeriesTabla(idTabla: string, params?: SeriesTablaParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'SERIES_TABLA', idTabla, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* SERIE_METADATAOPERACION - Obtener series con filtros de metadata
|
||||
*/
|
||||
async getSerieMetadataOperacion(idOperacion: string, params?: SerieMetadataOperacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'SERIE_METADATAOPERACION', idOperacion, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* PERIODICIDADES - Obtener periodicidades disponibles
|
||||
*/
|
||||
async getPeriodicidades(idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'PERIODICIDADES');
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUBLICACIONES - Obtener publicaciones disponibles
|
||||
*/
|
||||
async getPublicaciones(params?: PublicacionesParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'PUBLICACIONES', undefined, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUBLICACIONES_OPERACION - Obtener publicaciones de una operación
|
||||
*/
|
||||
async getPublicacionesOperacion(idOperacion: string, params?: PublicacionesOperacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'PUBLICACIONES_OPERACION', idOperacion, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUBLICACIONFECHA_PUBLICACION - Obtener fechas de publicación
|
||||
*/
|
||||
async getPublicacionFechaPublicacion(idPublicacion: string, params?: PublicacionFechaPublicacionParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'PUBLICACIONFECHA_PUBLICACION', idPublicacion, params);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* CLASIFICACIONES - Obtener clasificaciones disponibles
|
||||
*/
|
||||
async getClasificaciones(idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'CLASIFICACIONES');
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* CLASIFICACIONES_OPERACION - Obtener clasificaciones de una operación
|
||||
*/
|
||||
async getClasificacionesOperacion(idOperacion: string, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'CLASIFICACIONES_OPERACION', idOperacion);
|
||||
return this.get(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* VALORES_HIJOS - Obtener valores hijos en estructura jerárquica
|
||||
*/
|
||||
async getValoresHijos(idVariable: string, idValor: string, params?: ValoresHijosParams, idioma: Idioma = 'ES') {
|
||||
const url = this.buildURL(idioma, 'VALORES_HIJOS', `${idVariable}/${idValor}`, params);
|
||||
return this.get(url);
|
||||
}
|
||||
}
|
||||
|
||||
// Exportar instancia singleton
|
||||
export const ineClient = new INEClient();
|
||||
346
src/swagger.ts
Archivo normal
346
src/swagger.ts
Archivo normal
@@ -0,0 +1,346 @@
|
||||
/**
|
||||
* Especificación OpenAPI para la API del INE MCP Server
|
||||
*/
|
||||
|
||||
export const swaggerSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'INE MCP Server API',
|
||||
version: '1.0.0',
|
||||
description: 'Servidor MCP para consultar la API del Instituto Nacional de Estadística (INE) de España',
|
||||
contact: {
|
||||
name: 'API Support',
|
||||
url: 'https://github.com/your-repo/mcp-ine-server'
|
||||
},
|
||||
license: {
|
||||
name: 'MIT',
|
||||
url: 'https://opensource.org/licenses/MIT'
|
||||
}
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
url: 'http://localhost:3000',
|
||||
description: 'Servidor de desarrollo'
|
||||
}
|
||||
],
|
||||
tags: [
|
||||
{ name: 'MCP', description: 'Endpoints del protocolo MCP' },
|
||||
{ name: 'Datos', description: 'Consulta de datos estadísticos' },
|
||||
{ name: 'Operaciones', description: 'Gestión de operaciones estadísticas' },
|
||||
{ name: 'Variables', description: 'Gestión de variables' },
|
||||
{ name: 'Series', description: 'Gestión de series temporales' },
|
||||
{ name: 'Tablas', description: 'Gestión de tablas estadísticas' },
|
||||
{ name: 'Metadatos', description: 'Información de metadatos' }
|
||||
],
|
||||
paths: {
|
||||
'/mcp/v1': {
|
||||
post: {
|
||||
tags: ['MCP'],
|
||||
summary: 'Endpoint JSON-RPC del protocolo MCP',
|
||||
description: 'Endpoint principal para comunicación JSON-RPC con el servidor MCP',
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
jsonrpc: { type: 'string', example: '2.0' },
|
||||
method: { type: 'string', example: 'tools/call' },
|
||||
params: { type: 'object' },
|
||||
id: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Respuesta exitosa',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
jsonrpc: { type: 'string' },
|
||||
result: { type: 'object' },
|
||||
id: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/datos-tabla/{idTabla}': {
|
||||
get: {
|
||||
tags: ['Datos'],
|
||||
summary: 'Obtener datos de una tabla',
|
||||
description: 'Devuelve los datos de una tabla específica del INE',
|
||||
parameters: [
|
||||
{
|
||||
name: 'idTabla',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
description: 'ID de la tabla',
|
||||
example: '50902'
|
||||
},
|
||||
{
|
||||
name: 'idioma',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['ES', 'EN'], default: 'ES' },
|
||||
description: 'Idioma de la respuesta'
|
||||
},
|
||||
{
|
||||
name: 'nult',
|
||||
in: 'query',
|
||||
schema: { type: 'integer' },
|
||||
description: 'Número de últimos periodos'
|
||||
},
|
||||
{
|
||||
name: 'det',
|
||||
in: 'query',
|
||||
schema: { type: 'integer', enum: [0, 1, 2] },
|
||||
description: 'Nivel de detalle'
|
||||
},
|
||||
{
|
||||
name: 'tip',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['A', 'M', 'AM'] },
|
||||
description: 'Tipo de respuesta (A=amigable, M=metadatos, AM=ambos)'
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Datos de la tabla',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
data: { type: 'object' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/datos-serie/{idSerie}': {
|
||||
get: {
|
||||
tags: ['Datos'],
|
||||
summary: 'Obtener datos de una serie',
|
||||
description: 'Devuelve los datos de una serie específica del INE',
|
||||
parameters: [
|
||||
{
|
||||
name: 'idSerie',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
description: 'ID de la serie',
|
||||
example: 'IPC251856'
|
||||
},
|
||||
{
|
||||
name: 'idioma',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
},
|
||||
{
|
||||
name: 'nult',
|
||||
in: 'query',
|
||||
schema: { type: 'integer' }
|
||||
},
|
||||
{
|
||||
name: 'det',
|
||||
in: 'query',
|
||||
schema: { type: 'integer', enum: [0, 1, 2] }
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
'200': { description: 'Datos de la serie' }
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/operaciones-disponibles': {
|
||||
get: {
|
||||
tags: ['Operaciones'],
|
||||
summary: 'Listar operaciones disponibles',
|
||||
description: 'Obtiene todas las operaciones estadísticas disponibles en el INE',
|
||||
parameters: [
|
||||
{
|
||||
name: 'idioma',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
},
|
||||
{
|
||||
name: 'geo',
|
||||
in: 'query',
|
||||
schema: { type: 'integer', enum: [0, 1] },
|
||||
description: '0=nacional, 1=geográfico'
|
||||
},
|
||||
{
|
||||
name: 'page',
|
||||
in: 'query',
|
||||
schema: { type: 'integer' }
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
'200': { description: 'Lista de operaciones' }
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/operacion/{idOperacion}': {
|
||||
get: {
|
||||
tags: ['Operaciones'],
|
||||
summary: 'Obtener información de una operación',
|
||||
parameters: [
|
||||
{
|
||||
name: 'idOperacion',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: { type: 'string' },
|
||||
example: 'IPC'
|
||||
},
|
||||
{
|
||||
name: 'idioma',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
'200': { description: 'Información de la operación' }
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/variables': {
|
||||
get: {
|
||||
tags: ['Variables'],
|
||||
summary: 'Listar todas las variables',
|
||||
parameters: [
|
||||
{
|
||||
name: 'idioma',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
},
|
||||
{
|
||||
name: 'page',
|
||||
in: 'query',
|
||||
schema: { type: 'integer' }
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
'200': { description: 'Lista de variables' }
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/variables-operacion/{idOperacion}': {
|
||||
get: {
|
||||
tags: ['Variables'],
|
||||
summary: 'Variables de una operación',
|
||||
parameters: [
|
||||
{
|
||||
name: 'idOperacion',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: { type: 'string' }
|
||||
},
|
||||
{
|
||||
name: 'idioma',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
'200': { description: 'Variables de la operación' }
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/series-operacion/{idOperacion}': {
|
||||
get: {
|
||||
tags: ['Series'],
|
||||
summary: 'Series de una operación',
|
||||
parameters: [
|
||||
{
|
||||
name: 'idOperacion',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: { type: 'string' }
|
||||
},
|
||||
{
|
||||
name: 'idioma',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
},
|
||||
{
|
||||
name: 'page',
|
||||
in: 'query',
|
||||
schema: { type: 'integer' }
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
'200': { description: 'Series de la operación' }
|
||||
}
|
||||
}
|
||||
},
|
||||
'/api/tablas-operacion/{idOperacion}': {
|
||||
get: {
|
||||
tags: ['Tablas'],
|
||||
summary: 'Tablas de una operación',
|
||||
parameters: [
|
||||
{
|
||||
name: 'idOperacion',
|
||||
in: 'path',
|
||||
required: true,
|
||||
schema: { type: 'string' }
|
||||
},
|
||||
{
|
||||
name: 'idioma',
|
||||
in: 'query',
|
||||
schema: { type: 'string', enum: ['ES', 'EN'], default: 'ES' }
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
'200': { description: 'Tablas de la operación' }
|
||||
}
|
||||
}
|
||||
},
|
||||
'/health': {
|
||||
get: {
|
||||
tags: ['MCP'],
|
||||
summary: 'Health check',
|
||||
description: 'Verifica el estado del servidor',
|
||||
responses: {
|
||||
'200': {
|
||||
description: 'Servidor funcionando',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
status: { type: 'string', example: 'ok' },
|
||||
timestamp: { type: 'string', format: 'date-time' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
schemas: {
|
||||
Error: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean', example: false },
|
||||
error: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
174
src/types/ine.types.ts
Archivo normal
174
src/types/ine.types.ts
Archivo normal
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Tipos para la API del INE
|
||||
*/
|
||||
|
||||
export type Idioma = 'ES' | 'EN';
|
||||
|
||||
export interface INEBaseParams {
|
||||
det?: 0 | 1 | 2;
|
||||
tip?: 'A' | 'M' | 'AM';
|
||||
}
|
||||
|
||||
export interface DatosTablaParams extends INEBaseParams {
|
||||
nult?: number;
|
||||
tv?: string;
|
||||
date?: string;
|
||||
}
|
||||
|
||||
export interface DatosSerieParams extends INEBaseParams {
|
||||
nult?: number;
|
||||
date?: string;
|
||||
}
|
||||
|
||||
export interface DatosMetadataOperacionParams extends INEBaseParams {
|
||||
p?: number;
|
||||
nult?: number;
|
||||
g1?: string;
|
||||
g2?: string;
|
||||
g3?: string;
|
||||
g4?: string;
|
||||
g5?: string;
|
||||
}
|
||||
|
||||
export interface OperacionesDisponiblesParams extends INEBaseParams {
|
||||
geo?: 0 | 1;
|
||||
page?: number;
|
||||
}
|
||||
|
||||
export interface OperacionParams extends INEBaseParams {}
|
||||
|
||||
export interface VariablesParams {
|
||||
page?: number;
|
||||
}
|
||||
|
||||
export interface VariablesOperacionParams {
|
||||
page?: number;
|
||||
}
|
||||
|
||||
export interface ValoresVariableParams extends INEBaseParams {
|
||||
clasif?: number;
|
||||
}
|
||||
|
||||
export interface ValoresVariableOperacionParams extends INEBaseParams {}
|
||||
|
||||
export interface TablasOperacionParams extends INEBaseParams {
|
||||
geo?: 0 | 1;
|
||||
tip?: 'A';
|
||||
}
|
||||
|
||||
export interface ValoresGruposTablaParams extends INEBaseParams {}
|
||||
|
||||
export interface SerieParams extends INEBaseParams {
|
||||
tip?: 'A' | 'M' | 'AM';
|
||||
}
|
||||
|
||||
export interface SeriesOperacionParams extends INEBaseParams {
|
||||
tip?: 'A' | 'M' | 'AM';
|
||||
page?: number;
|
||||
}
|
||||
|
||||
export interface ValoresSerieParams extends INEBaseParams {}
|
||||
|
||||
export interface SeriesTablaParams extends INEBaseParams {
|
||||
tip?: 'A' | 'M' | 'AM';
|
||||
tv?: string;
|
||||
}
|
||||
|
||||
export interface SerieMetadataOperacionParams extends INEBaseParams {
|
||||
p?: number;
|
||||
tip?: 'A' | 'M' | 'AM';
|
||||
g1?: string;
|
||||
g2?: string;
|
||||
g3?: string;
|
||||
g4?: string;
|
||||
g5?: string;
|
||||
}
|
||||
|
||||
export interface PublicacionesParams extends INEBaseParams {
|
||||
tip?: 'A';
|
||||
}
|
||||
|
||||
export interface PublicacionesOperacionParams extends INEBaseParams {
|
||||
tip?: 'A';
|
||||
}
|
||||
|
||||
export interface PublicacionFechaPublicacionParams extends INEBaseParams {
|
||||
tip?: 'A';
|
||||
}
|
||||
|
||||
export interface ValoresHijosParams extends INEBaseParams {}
|
||||
|
||||
// Respuestas de la API
|
||||
export interface INEResponse<T = any> {
|
||||
data: T;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface Operacion {
|
||||
Id: number;
|
||||
Codigo: string;
|
||||
Nombre: string;
|
||||
COD_IOE?: string;
|
||||
}
|
||||
|
||||
export interface Variable {
|
||||
Id: number;
|
||||
Nombre: string;
|
||||
Codigo?: string;
|
||||
}
|
||||
|
||||
export interface Valor {
|
||||
Id: number;
|
||||
Nombre: string;
|
||||
Codigo?: string;
|
||||
Fk_Variable?: number;
|
||||
}
|
||||
|
||||
export interface Serie {
|
||||
COD: string;
|
||||
Nombre: string;
|
||||
FK_Operacion?: number;
|
||||
FK_Periodicidad?: number;
|
||||
FK_Publicacion?: number;
|
||||
FK_Unidad?: number;
|
||||
FK_Escala?: number;
|
||||
}
|
||||
|
||||
export interface Tabla {
|
||||
Id: number;
|
||||
Nombre: string;
|
||||
Codigo?: string;
|
||||
FK_Operacion?: number;
|
||||
FK_Periodicidad?: number;
|
||||
}
|
||||
|
||||
export interface Dato {
|
||||
Fecha: string;
|
||||
Valor: number | string;
|
||||
Anyo?: number;
|
||||
NombrePeriodo?: string;
|
||||
}
|
||||
|
||||
export interface Periodicidad {
|
||||
Id: number;
|
||||
Nombre: string;
|
||||
Codigo?: string;
|
||||
}
|
||||
|
||||
export interface Publicacion {
|
||||
Id: number;
|
||||
Nombre: string;
|
||||
FK_Periodicidad?: number;
|
||||
}
|
||||
|
||||
export interface Clasificacion {
|
||||
Id: number;
|
||||
Nombre: string;
|
||||
Fecha?: string;
|
||||
}
|
||||
|
||||
export interface Grupo {
|
||||
Id: number;
|
||||
Nombre: string;
|
||||
}
|
||||
Referencia en una nueva incidencia
Block a user