tripadvisor-mcp-node
Version:
MCP server for TripAdvisor restaurant search
156 lines (155 loc) • 6.42 kB
JavaScript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
const TRIPADVISOR_API_KEY = process.env.TRIPADVISOR_API_KEY || '';
const BASE_URL = 'https://api.content.tripadvisor.com/api/v1';
const REFERER = process.env.TRIPADVISOR_REFERER || '';
const ORIGIN = process.env.TRIPADVISOR_ORIGIN || '';
async function makeApiRequest(endpoint, params = {}) {
if (!TRIPADVISOR_API_KEY) {
throw new Error('Tripadvisor API key is missing. Please set TRIPADVISOR_API_KEY environment variable.');
}
const url = new URL(`${BASE_URL}/${endpoint}`);
params.key = TRIPADVISOR_API_KEY;
Object.entries(params).forEach(([k, v]) => {
if (v !== undefined && v !== null)
url.searchParams.append(k, String(v));
});
const res = await fetch(url.toString(), {
headers: { accept: 'application/json', referer: REFERER, origin: ORIGIN }
});
if (!res.ok)
throw new Error(await res.text());
return res.json();
}
// 创建 MCP server
const server = new Server({
name: 'Tripadvisor Content API MCP',
version: '1.0.0'
}, {
capabilities: {
tools: {}
}
});
// 定义搜索地点的参数schema
const searchLocationsSchema = z.object({
searchQuery: z.string(),
language: z.string().default('en'),
category: z.string().optional(),
phone: z.string().optional(),
address: z.string().optional(),
latLong: z.string().optional()
});
// 定义搜索附近地点的参数schema
const searchNearbyLocationsSchema = z.object({
latitude: z.number(),
longitude: z.number(),
language: z.string().default('en'),
category: z.string().optional()
});
// 定义地点详情的参数schema
const locationDetailsSchema = z.object({
locationId: z.union([z.string(), z.number()]),
language: z.string().default('en')
});
// 监听工具列表请求
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'search_locations',
description: 'Search for locations on TripAdvisor',
inputSchema: zodToJsonSchema(searchLocationsSchema)
},
{
name: 'search_nearby_locations',
description: 'Search for nearby locations on TripAdvisor',
inputSchema: zodToJsonSchema(searchNearbyLocationsSchema)
},
{
name: 'get_location_details',
description: 'Get detailed information about a specific location',
inputSchema: zodToJsonSchema(locationDetailsSchema)
},
{
name: 'get_location_reviews',
description: 'Get reviews for a specific location',
inputSchema: zodToJsonSchema(locationDetailsSchema)
},
{
name: 'get_location_photos',
description: 'Get photos for a specific location',
inputSchema: zodToJsonSchema(locationDetailsSchema)
}
]
};
});
// 监听工具调用请求
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'search_locations': {
const { searchQuery, language, category, phone, address, latLong } = searchLocationsSchema.parse(args);
const params = { searchQuery, language };
if (category)
params.category = category;
if (phone)
params.phone = phone;
if (address)
params.address = address;
if (latLong)
params.latLong = latLong;
const data = await makeApiRequest('location/search', params);
return { content: [{ type: 'json', json: data }] };
}
case 'search_nearby_locations': {
const { latitude, longitude, language, category } = searchNearbyLocationsSchema.parse(args);
const params = {
latLong: `${latitude},${longitude}`,
language
};
if (category)
params.category = category;
const data = await makeApiRequest('location/search', params);
return { content: [{ type: 'json', json: data }] };
}
case 'get_location_details': {
const { locationId, language } = locationDetailsSchema.parse(args);
const params = { language };
const location_id_str = String(locationId);
const data = await makeApiRequest(`location/${location_id_str}/details`, params);
return { content: [{ type: 'json', json: data }] };
}
case 'get_location_reviews': {
const { locationId, language } = locationDetailsSchema.parse(args);
const params = { language };
const location_id_str = String(locationId);
const data = await makeApiRequest(`location/${location_id_str}/reviews`, params);
return { content: [{ type: 'json', json: data }] };
}
case 'get_location_photos': {
const { locationId, language } = locationDetailsSchema.parse(args);
const params = { language };
const location_id_str = String(locationId);
const data = await makeApiRequest(`location/${location_id_str}/photos`, params);
return { content: [{ type: 'json', json: data }] };
}
default:
throw new Error(`Unknown tool: ${name}`);
}
}
catch (error) {
throw new Error(`Error calling tool ${name}: ${error instanceof Error ? error.message : String(error)}`);
}
});
// 启动 MCP server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Tripadvisor MCP Server running on stdio');
}
main().catch(console.error);