@qubaomingg/stock-mcp
by qubaomingg
Verified
- 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'; // 修改扩展名为 .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();