Valyu MCP Server

  • src
// src/index.ts import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { ListToolsRequestSchema, CallToolRequestSchema, Tool } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; // Validation schemas for the API endpoints const KnowledgeRequestSchema = z.object({ query: z.string(), search_type: z.enum(["proprietary", "web", "all"]), max_price: z.number(), data_sources: z.array(z.string()).optional(), max_num_results: z.number().int().positive().default(10), similarity_threshold: z.number().min(0).max(1).default(0.4), query_rewrite: z.boolean().default(true) }); const FeedbackRequestSchema = z.object({ tx_id: z.string(), feedback: z.string(), sentiment: z.enum(["very good", "good", "bad", "very bad"]) }); // Define request types based on schemas type KnowledgeRequest = z.infer<typeof KnowledgeRequestSchema>; type FeedbackRequest = z.infer<typeof FeedbackRequestSchema>; // API client class to handle requests class ValyuAPI { private baseUrl = 'https://api.valyu.network'; private apiKey: string; constructor() { const apiKey = process.env.VALYU_API_KEY; if (!apiKey) { throw new Error('VALYU_API_KEY environment variable is required'); } this.apiKey = apiKey; } private async makeRequest(endpoint: string, method: 'GET' | 'POST', data?: unknown) { const headers = { 'x-api-key': this.apiKey, 'Content-Type': 'application/json' }; const options: RequestInit = { method, headers, body: JSON.stringify(data) }; let url = this.baseUrl + endpoint; const response = await fetch(url, options); if (!response.ok) { throw new Error(`API request failed: ${response.statusText}`); } return response.json(); } async knowledge(params: KnowledgeRequest) { return this.makeRequest('/v1/knowledge', 'POST', params); } async feedback(params: FeedbackRequest) { return this.makeRequest('/v1/feedback', 'POST', params); } } // Define tools const TOOLS: Record<string, Tool> = { knowledge: { name: "knowledge", description: "Search proprietary and/or web sources for information based on the supplied query.", inputSchema: { type: "object", properties: { query: { type: "string" }, search_type: { type: "string", enum: ["proprietary", "web", "all"] }, max_price: { type: "number" }, data_sources: { type: "array", items: { type: "string" } }, max_num_results: { type: "integer", default: 10 }, similarity_threshold: { type: "number", default: 0.4 }, query_rewrite: { type: "boolean", default: true } }, required: ["query", "search_type", "max_price"] }, }, feedback: { name: "feedback", description: "Submit user feedback and sentiment for a transaction.", inputSchema: { type: "object", properties: { tx_id: { type: "string" }, feedback: { type: "string" }, sentiment: { type: "string", enum: ["very good", "good", "bad", "very bad"] } }, required: ["tx_id", "feedback", "sentiment"] }, } }; // Create and configure the MCP server async function main() { const api = new ValyuAPI(); const server = new Server( { name: "valyu-mcp-server", version: "1.0.0", }, { capabilities: { tools: {}, }, } ); // Register tool list handler server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: Object.values(TOOLS), })); // Register tool call handler server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const args = request.params.arguments as Record<string, unknown>; switch (request.params.name) { case "knowledge": { const validatedArgs = KnowledgeRequestSchema.parse(args); const result = await api.knowledge(validatedArgs); return { content: [{ type: "text", text: JSON.stringify(result) }] }; } case "feedback": { const validatedArgs = FeedbackRequestSchema.parse(args); const result = await api.feedback(validatedArgs); return { content: [{ type: "text", text: JSON.stringify(result) }] }; } default: return { content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }], isError: true }; } } catch (error) { return { content: [{ type: "text", text: `API error: ${error instanceof Error ? error.message : 'Unknown error'}` }], isError: true }; } }); // Start the server const transport = new StdioServerTransport(); try { await server.connect(transport); } catch (error) { if (error instanceof Error) { console.error("Failed to start server:", error.message); } else { console.error("Failed to start server with unknown error"); } process.exit(1); } } main();