//d638q5pr01qnpqg08690d638q5pr01qnpqg0869g
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
require('dotenv').config();
// Initialize Server
const server = new Server(
{ name: "stock-news", version: "2.0.0" },
{ capabilities: { tools: {} } }
);
const FINNHUB_API_KEY = process.env.FINNHUB_API_KEY;
// 3. (Optional but Recommended) Add a safety check
if (!FINNHUB_API_KEY) {
console.error("ERROR: FINNHUB_API_KEY is not defined in .env file");
process.exit(1);
}
// 1. List the Tool
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [{
name: "get_market_news",
description: "Fetches live US market headlines from Finnhub",
inputSchema: { type: "object", properties: {} }
},
{
name: "get_stock_price",
description: "Get real-time price quote for a specific stock symbol (e.g. AAPL, NVDA)",
inputSchema: {
type: "object",
properties: {
symbol: {
type: "string",
description: "The stock ticker symbol (e.g., TSLA)"
}
},
required: ["symbol"]
}
}]
}));
// 2. Handle the Tool Call
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_market_news") {
try {
const response = await fetch(
`https://finnhub.io/api/v1/news?category=general&token=${FINNHUB_API_KEY}`
);
if (!response.ok) {
throw new Error(`Finnhub API error: ${response.statusText}`);
}
const data = await response.json();
// Format the top 3 headlines
const news = data.slice(0, 3)
.map(n => `- [${n.source}] ${n.headline}`)
.join("\n");
return {
content: [{ type: "text", text: `LATEST HEADLINES:\n${news || "No news found."}` }]
};
} catch (error) {
return {
content: [{ type: "text", text: `Error fetching news: ${error.message}` }],
isError: true
};
}
} else if (name === "get_stock_price") {
const symbol = args?.symbol?.toUpperCase();
if (!symbol) {
return {
content: [{ type: "text", text: "Error: No stock symbol provided." }],
isError: true
};
}
try {
// Calling the official Finnhub Quote endpoint
const response = await fetch(
`https://finnhub.io/api/v1/quote?symbol=${symbol}&token=${FINNHUB_API_KEY}`
);
if (!response.ok) throw new Error(`Finnhub error: ${response.statusText}`);
const data = await response.json();
/* Finnhub Data Map:
c: Current Price, d: Change, dp: % Change,
h: High, l: Low, pc: Prev Close
*/
const priceInfo = [
`Current: $${data.c}`,
`Change: $${data.d} (${data.dp}%)`,
`Day Range: $${data.l} - $${data.h}`,
`Previous Close: $${data.pc}`
].join("\n");
return {
content: [{ type: "text", text: `${symbol} Price Data:\n${priceInfo}` }]
};
} catch (error) {
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
}
}
throw new Error("Tool not found");
});
// 3. Start Stdio Transport
const transport = new StdioServerTransport();
await server.connect(transport);