index.ts•5.84 kB
#!/usr/bin/env node
/**
* Superprecio MCP Server
*
* A Model Context Protocol server that provides access to Superprecio's
* price comparison functionality for Argentina supermarkets (expanding to Latin America).
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
ListPromptsRequestSchema,
GetPromptRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
// Import client
import { createApiClient } from './client/superPrecioApi.js';
// Import tools
import { searchProductsTool, executeSearchProducts } from './tools/searchProducts.js';
import { searchByCodeTool, executeSearchByCode } from './tools/searchByCode.js';
import { comparePriceTool, executeComparePrice } from './tools/comparePrice.js';
import { getBestDealsTool, executeGetBestDeals } from './tools/getBestDeals.js';
import { sendNotificationTool, executeSendNotification } from './tools/sendNotification.js';
import { subscribeDeviceTool, executeSubscribeDevice } from './tools/subscribeDevice.js';
// Import resources
import { supermarketResources, getSupermarketList, getSupermarketInfo } from './resources/supermarkets.js';
// Import prompts
import { priceExpertPrompt, getPriceExpertPrompt } from './prompts/priceExpert.js';
/**
* Create and configure the MCP server
*/
async function main() {
// Initialize API client
const apiClient = createApiClient();
// Verify connection to Superprecio API
const isHealthy = await apiClient.healthCheck();
if (!isHealthy) {
console.error('⚠️ Warning: Could not connect to Superprecio API');
console.error(` Check that the API is running at: ${process.env.SUPERPRECIO_API_URL || 'http://localhost:3000'}`);
} else {
console.error('✓ Connected to Superprecio API');
}
// Create MCP server
const server = new Server(
{
name: 'superprecio-mcp',
version: '1.0.0',
},
{
capabilities: {
tools: {},
resources: {},
prompts: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
searchProductsTool,
searchByCodeTool,
comparePriceTool,
getBestDealsTool,
sendNotificationTool,
subscribeDeviceTool,
],
};
});
// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'search_products':
return await executeSearchProducts(apiClient, args as any);
case 'search_by_code':
return await executeSearchByCode(apiClient, args as any);
case 'compare_prices':
return await executeComparePrice(apiClient, args as any);
case 'get_best_deals':
return await executeGetBestDeals(apiClient, args as any);
case 'send_notification':
return await executeSendNotification(apiClient, args as any);
case 'subscribe_device':
return await executeSubscribeDevice(apiClient, args as any);
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error: any) {
return {
content: [
{
type: 'text',
text: `Error executing tool ${name}: ${error.message}`,
},
],
isError: true,
};
}
});
// List available resources
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: supermarketResources.list.uri,
name: supermarketResources.list.name,
description: supermarketResources.list.description,
mimeType: supermarketResources.list.mimeType,
},
],
};
});
// Handle resource reading
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
try {
if (uri === 'supermarket://list') {
return await getSupermarketList(apiClient);
}
// Handle specific supermarket info: supermarket://[id]/info
const match = uri.match(/^supermarket:\/\/(\d+)\/info$/);
if (match) {
const marketId = match[1];
return await getSupermarketInfo(apiClient, marketId);
}
throw new Error(`Unknown resource: ${uri}`);
} catch (error: any) {
throw new Error(`Error reading resource ${uri}: ${error.message}`);
}
});
// List available prompts
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
{
name: priceExpertPrompt.name,
description: priceExpertPrompt.description,
arguments: priceExpertPrompt.arguments,
},
],
};
});
// Handle prompt requests
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name !== 'price_expert') {
throw new Error(`Unknown prompt: ${name}`);
}
const promptText = getPriceExpertPrompt(args as any);
return {
messages: [
{
role: 'user',
content: {
type: 'text',
text: promptText,
},
},
],
};
});
// Start server with stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Superprecio MCP Server running on stdio');
}
// Run the server
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});