Alpha Vantage Stock MCP Server

  • src
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import dotenv from "dotenv"; import { getStockData, getStockAlerts } from "./alphaVantage.js"; // Load environment variables dotenv.config(); // Create an MCP server const server = new McpServer({ name: "alpha-vantage-stock-data", version: "1.0.0" }); // Add a resource for stock data server.resource( "stock-data", new ResourceTemplate("stock://{symbol}/{interval}", { list: undefined }), async (uri, { symbol, interval = "daily" }) => { try { // Ensure interval is a string, not an array const intervalStr = Array.isArray(interval) ? interval[0] : interval; const data = await getStockData(symbol, intervalStr === "daily" ? "daily" : intervalStr, "compact"); return { contents: [{ uri: uri.href, text: data, mimeType: "text/plain" }] }; } catch (error) { throw new Error(`Failed to fetch stock data: ${error instanceof Error ? error.message : String(error)}`); } } ); // Add a tool to get stock data server.tool( "get-stock-data", { symbol: z.string().describe("Stock symbol (e.g., IBM, AAPL)"), interval: z.enum(["1min", "5min", "15min", "30min", "60min"]).optional().describe("Time interval between data points (default: 5min)"), outputsize: z.enum(["compact", "full"]).optional().describe("Amount of data to return (compact: latest 100 data points, full: up to 20 years of data)") }, async ({ symbol, interval = "5min", outputsize = "compact" }) => { try { const data = await getStockData(symbol, interval, outputsize); return { content: [{ type: "text", text: data }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching stock data: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Add a tool to get stock alerts based on price movements server.tool( "get-stock-alerts", { symbol: z.string().describe("Stock symbol (e.g., IBM, AAPL)"), threshold: z.number().optional().describe("Percentage threshold for price movement alerts (default: 5)") }, async ({ symbol, threshold = 5 }) => { try { const alerts = await getStockAlerts(symbol, threshold); return { content: [{ type: "text", text: alerts }] }; } catch (error) { return { content: [{ type: "text", text: `Error generating stock alerts: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Add a tool to get daily stock data server.tool( "get-daily-stock-data", { symbol: z.string().describe("Stock symbol (e.g., IBM, AAPL)"), outputsize: z.enum(["compact", "full"]).optional().describe("Amount of data to return (compact: latest 100 data points, full: up to 20 years of data)") }, async ({ symbol, outputsize = "compact" }) => { try { const data = await getStockData(symbol, "daily", outputsize); return { content: [{ type: "text", text: data }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching daily stock data: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); async function main() { try { // Create a transport for stdio communication const transport = new StdioServerTransport(); // Connect the server to the transport await server.connect(transport); console.error("Alpha Vantage Stock MCP Server running on stdio"); } catch (error) { console.error("Error starting server:", error); process.exit(1); } } main();