Skip to main content
Glama

Alpaca MCP Server

by cesarvarela
index.js4.95 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import dotenv from "dotenv"; import { z } from "zod"; import fetch from "node-fetch"; import Debug from "debug"; dotenv.config(); const debug = Debug("alpaca-mcp"); async function request({ base = process.env.ALPACA_ENDPOINT, path, method = "GET", params = {} }) { if (!process.env.ALPACA_API_KEY || !process.env.ALPACA_SECRET_KEY) { throw new Error("Alpaca credentials not configured. Set ALPACA_API_KEY and ALPACA_SECRET_KEY."); } const qs = new URLSearchParams(params).toString(); const url = `${base}${path}${qs ? `?${qs}` : ""}`; const res = await fetch(url, { method, headers: { "APCA-API-KEY-ID": process.env.ALPACA_API_KEY, "APCA-API-SECRET-KEY": process.env.ALPACA_SECRET_KEY, }, }); if (!res.ok) { const err = await res.json(); throw new Error(`${res.status} ${res.statusText} - ${JSON.stringify(err)}`); } return (await res.json()); } function getBatches(arr, size) { const batches = []; for (let i = 0; i < arr.length; i += size) batches.push(arr.slice(i, i + size)); return batches; } export { request, getBatches }; export async function getAssets({ assetClass = 'us_equity' }) { try { const data = await request({ base: process.env.ALPACA_BROKER_ENDPOINT, path: "/v1/assets", params: { status: "active", asset_class: assetClass }, }); const assets = data.filter((a) => a.tradable); return { content: [{ type: "text", text: JSON.stringify(assets) }] }; } catch (err) { debug("get-assets error", err); return { content: [{ type: "text", text: `Error fetching assets: ${err.message}` }], isError: true }; } } export async function getStockBars({ symbols, start, end, timeframe }) { try { const result = { bars: {} }; for (const batch of getBatches(symbols, 2000)) { let pageToken; do { const params = { timeframe, limit: 10000, start, end, symbols: batch.join(",") }; if (pageToken) params.page_token = pageToken; const resp = await request({ base: process.env.ALPACA_ENDPOINT, path: "/v2/stocks/bars", params, }); Object.assign(result.bars, resp.bars); pageToken = resp.next_page_token; } while (pageToken); } return { content: [{ type: "text", text: JSON.stringify(result) }] }; } catch (err) { debug("get-stock-bars error", err); return { content: [{ type: "text", text: `Error fetching stock bars: ${err.message}` }], isError: true }; } } export async function getMarketDays({ start, end }) { try { const days = await request({ base: process.env.ALPACA_ENDPOINT, path: "/v2/calendar", params: { start, end }, }); return { content: [{ type: "text", text: JSON.stringify(days) }] }; } catch (err) { debug("get-market-days error", err); return { content: [{ type: "text", text: `Error fetching market days: ${err.message}` }], isError: true }; } } export async function getNews({ start, end, symbols }) { try { const all = []; let pageToken; do { const params = pageToken ? { page_token: pageToken } : { sort: "desc", start, end, symbols: symbols.join(","), include_content: true }; const resp = await request({ base: process.env.ALPACA_ENDPOINT, path: "/v1beta1/news", params, }); all.push(...resp.news); pageToken = resp.next_page_token; } while (pageToken); return { content: [{ type: "text", text: JSON.stringify(all) }] }; } catch (err) { debug("get-news error", err); return { content: [{ type: "text", text: `Error fetching news: ${err.message}` }], isError: true }; } } const server = new McpServer({ name: "Alpaca MCP Server", version: "1.0.0", description: "Expose Alpaca API via MCP", }); server.tool("get-assets", { assetClass: z.enum(["us_equity", "crypto"]).optional().default("us_equity") }, getAssets); server.tool("get-stock-bars", { symbols: z.array(z.string()), start: z.string(), end: z.string(), timeframe: z.string(), }, getStockBars); server.tool("get-market-days", { start: z.string(), end: z.string() }, getMarketDays); server.tool("get-news", { start: z.string(), end: z.string(), symbols: z.array(z.string()) }, getNews); const transport = new StdioServerTransport(); await server.connect(transport);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cesarvarela/alpaca-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server