APIs·
advanced
·14 min read·Jul 9, 2026·Updated Oct 10, 2026
By Rad Tome·Lead AI Systems Architect·How we verify this

Alpaca Finance API MCP Server Guide

Connect Alpaca Finance API to Model Context Protocol: Stream real-time market data, execute paper trades safely, and enforce autonomous budget guardrails.

financealpacatradingmarket-datamcpautomationpaper-tradingapi-integration
Interactive Tool
1-Click Export

Generate & Validate Multi-Client MCP Config

One-click export with environment variables & path locators for Claude Desktop, Cursor, Windsurf, and OpenAI Codex CLI.

Open in Generator

Alpaca Finance API MCP Server Guide

Connecting real-time financial market data and trading APIs to the Model Context Protocol (MCP) allows engineering teams to construct intelligent financial research assistants, automated portfolio monitors, and quantitative strategy backtesters. Rather than switching between web portals and custom terminal scripts, developers can prompt AI agents in Claude Desktop, Cursor, or OpenAI Codex CLI to query real-time stock quotes, evaluate historical price action, and execute simulated paper trades.

However, financial execution environments introduce severe operational risks. If an autonomous agent enters an unconstrained retry loop or misinterprets an order volume parameter, it can rapidly deplete available capital. Operating a financial MCP server in production requires strict paper trading boundaries, hard budget caps, and multi-factor confirmation gates.

This guide provides an architectural blueprint, multi-client configuration blocks, a production TypeScript MCP implementation, and risk controls for integrating Alpaca Finance with the Model Context Protocol.


1. Architecture and Operational Safety Boundaries

An Alpaca MCP server functions as an isolated execution bridge between the reasoning LLM host and Alpaca brokerage infrastructure. The server enforces safety invariants before any order reaches Alpaca REST or WebSocket endpoints.

diagram

Guardrail Verification

No

Yes

No

Yes

Pass

AI Agent: tools/call place_paper_order

Alpaca Finance MCP Server

Paper Trading Active?

Reject: Live Trading Prohibited

Order Value <= $500?

Reject: Exceeds Max Dollar Limit

Under Rate Limit?

Alpaca Paper API: /v2/orders

Alpaca Brokerage Engine

Safety Principles for Financial MCP Servers

  1. ▸Strict Paper Trading Isolation: Development and agent testing must exclusively target the Alpaca Paper Trading environment (https://paper-api.alpaca.markets). Never configure production live trading keys in interactive AI agent settings.
  2. ▸Hard Dollar Ceilings: Enforce maximum order size limits directly inside the MCP server tool logic. If an agent attempts to submit an order exceeding your preset safety threshold (such as $500), the server immediately rejects the request prior to network transmission.
  3. ▸Structured Quote Truncation: Financial data feeds emit voluminous historical bar arrays. The MCP server aggregates and filters tick records into token-efficient summaries to protect the agent context window.

2. Environment Prerequisites and Credentials Matrix

To deploy the Alpaca MCP server, verify your system meets the required environment dependencies:

ComponentMinimum VersionDescription
Node.js>= 20.0.0JavaScript runtime environment
npm>= 10.0.0Package manager
@alpacahq/alpaca-trade-api>= 3.1.0Official Alpaca Node.js REST and WebSocket client
@modelcontextprotocol/sdk>= 1.2.0Core Model Context Protocol TypeScript framework

Obtain your paper trading API credentials from the Alpaca Developer Portal (opens in a new tab). Set the required environment variables:

bash
export APCA_API_KEY_ID="PKYOURPAPERKEYID"
export APCA_API_SECRET_KEY="your-paper-secret-key"
export APCA_PAPER="true"
export MAX_ORDER_DOLLAR_LIMIT="500"

3. Multi-Host Configuration Snippets

Configure your MCP hosts to launch the Alpaca server over standard input and output (stdio). Ensure paper trading flags are explicitly asserted in each client definition.

Claude Desktop Configuration

Add the server definition to claude_desktop_config.json:

json
{
  "mcpServers": {
    "alpaca-finance": {
      "command": "node",
      "args": ["/opt/mcp-servers/alpaca/dist/index.js"],
      "env": {
        "APCA_API_KEY_ID": "PKYOURPAPERKEYID",
        "APCA_API_SECRET_KEY": "your-paper-secret-key",
        "APCA_PAPER": "true",
        "MAX_ORDER_DOLLAR_LIMIT": "500"
      }
    }
  }
}

Cursor IDE Configuration

Place this definition inside .cursor/mcp.json:

json
{
  "mcpServers": {
    "alpaca-finance": {
      "command": "node",
      "args": ["./dist/index.js"],
      "env": {
        "APCA_API_KEY_ID": "PKYOURPAPERKEYID",
        "APCA_API_SECRET_KEY": "your-paper-secret-key",
        "APCA_PAPER": "true"
      }
    }
  }
}

OpenAI Codex CLI Configuration

In ~/.codex/config.toml, configure the server entry:

toml
[mcp_servers.alpaca_finance]
command = "node"
args = ["/opt/mcp-servers/alpaca/dist/index.js"]

[mcp_servers.alpaca_finance.env]
APCA_API_KEY_ID = "PKYOURPAPERKEYID"
APCA_API_SECRET_KEY = "your-paper-secret-key"
APCA_PAPER = "true"

4. Production TypeScript MCP Server Implementation

The following implementation provides three essential financial tools: get_stock_quote, get_account_balance, and a strictly guarded place_paper_order tool. Save this as src/index.ts:

typescript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import Alpaca from '@alpacahq/alpaca-trade-api';

const isPaper = process.env.APCA_PAPER === 'true';
const maxOrderLimit = parseFloat(process.env.MAX_ORDER_DOLLAR_LIMIT || '500');

if (!isPaper) {
  process.stderr.write("FATAL ERROR: Alpaca MCP Server must run with APCA_PAPER='true'\n");
  process.exit(1);
}

const alpaca = new Alpaca({
  keyId: process.env.APCA_API_KEY_ID,
  secretKey: process.env.APCA_API_SECRET_KEY,
  paper: true
});

const server = new Server(
  { name: 'alpaca-finance-mcp', version: '1.0.0' },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: 'get_stock_quote',
        description: 'Fetch latest bid, ask, and last trade price for a US equity ticker.',
        inputSchema: {
          type: 'object',
          properties: {
            symbol: { type: 'string', description: 'Stock ticker symbol (e.g. AAPL, MSFT)' }
          },
          required: ['symbol']
        }
      },
      {
        name: 'get_account_balance',
        description: 'Retrieve current paper trading cash balance, buying power, and portfolio equity.',
        inputSchema: {
          type: 'object',
          properties: {}
        }
      },
      {
        name: 'place_paper_order',
        description: 'Submit a simulated paper equity order with strict dollar value limits.',
        inputSchema: {
          type: 'object',
          properties: {
            symbol: { type: 'string', description: 'Stock ticker symbol' },
            qty: { type: 'number', description: 'Number of whole shares to purchase' },
            side: { type: 'string', enum: ['buy', 'sell'], description: 'Order direction' },
            order_type: { type: 'string', enum: ['market', 'limit'], default: 'market' },
            limit_price: { type: 'number', description: 'Mandatory limit price if order_type is limit' }
          },
          required: ['symbol', 'qty', 'side']
        }
      }
    ]
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    if (name === 'get_stock_quote') {
      const symbol = (args?.symbol as string).toUpperCase();
      const quote = await alpaca.getLatestQuote(symbol);
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              symbol,
              ask_price: quote.AskPrice,
              ask_size: quote.AskSize,
              bid_price: quote.BidPrice,
              bid_size: quote.BidSize,
              timestamp: quote.Timestamp
            }, null, 2)
          }
        ]
      };
    }

    if (name === 'get_account_balance') {
      const account = await alpaca.getAccount();
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              status: account.status,
              currency: account.currency,
              buying_power: account.buying_power,
              cash: account.cash,
              portfolio_value: account.portfolio_value
            }, null, 2)
          }
        ]
      };
    }

    if (name === 'place_paper_order') {
      const symbol = (args?.symbol as string).toUpperCase();
      const qty = Number(args?.qty);
      const side = args?.side as 'buy' | 'sell';
      const orderType = (args?.order_type as 'market' | 'limit') || 'market';

      const quote = await alpaca.getLatestQuote(symbol);
      const estimatedCost = qty * quote.AskPrice;

      if (estimatedCost > maxOrderLimit) {
        return {
          isError: true,
          content: [
            {
              type: 'text',
              text: `Order rejected: Estimated cost (${estimatedCost.toFixed(2)}) exceeds maximum dollar limit (${maxOrderLimit.toFixed(2)}).`
            }
          ]
        };
      }

      const orderPayload: any = {
        symbol,
        qty,
        side,
        type: orderType,
        time_in_force: 'day'
      };

      if (orderType === 'limit') {
        if (!args?.limit_price) {
          throw new Error('Limit orders require a limit_price argument.');
        }
        orderPayload.limit_price = Number(args.limit_price);
      }

      const order = await alpaca.createOrder(orderPayload);

      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              status: 'submitted',
              order_id: order.id,
              symbol: order.symbol,
              qty: order.qty,
              side: order.side,
              type: order.type
            }, null, 2)
          }
        ]
      };
    }

    throw new Error(`Tool ${name} is not recognized.`);
  } catch (err: any) {
    return {
      isError: true,
      content: [{ type: 'text', text: `Alpaca API Error: ${err.message}` }]
    };
  }
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch((err) => {
  process.stderr.write(`Fatal error: ${err.message}\n`);
  process.exit(1);
});

5. JSON-RPC 2.0 Wire Payloads

Inspecting the underlying JSON-RPC protocol messages facilitates auditing and integration testing.

Tool Invocation Request (tools/call)

json
{
  "jsonrpc": "2.0",
  "id": "alpaca-quote-42",
  "method": "tools/call",
  "params": {
    "name": "get_stock_quote",
    "arguments": {
      "symbol": "AAPL"
    }
  }
}

Result Payload

json
{
  "jsonrpc": "2.0",
  "id": "alpaca-quote-42",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\n  \"symbol\": \"AAPL\",\n  \"ask_price\": 224.50,\n  \"ask_size\": 100,\n  \"bid_price\": 224.48,\n  \"bid_size\": 200,\n  \"timestamp\": \"2026-10-09T20:30:00Z\"\n}"
      }
    ]
  }
}

6. Common Errors and Production Troubleshooting

When connecting agents to financial market feeds, handle these operational error states:

Error: 403 Forbidden: invalid key or paper/live mismatch

  • ▸Root Cause: Attempting to query paper trading endpoints using live account keys, or vice versa. Alpaca paper keys start with the prefix PK and are invalid on live endpoints (api.alpaca.markets).
  • ▸Resolution: Ensure both APCA_PAPER="true" is set and your API key starts with PK.

Error: insufficient buying power

  • ▸Root Cause: The paper account cash balance has been exhausted by earlier automated tests.
  • ▸Resolution: Reset your paper portfolio balance directly from the Alpaca developer dashboard under Paper Account Settings.

Error: order rejected: outside market hours

  • ▸Root Cause: Submitting market orders outside standard US trading sessions (9:30 AM to 4:00 PM Eastern Time).
  • ▸Resolution: Configure extended_hours: true if your account supports pre-market/after-hours trading, or submit limit orders for execution at next market open.

7. External Citations and Security Guardrails

Financial agent integrations must adhere to rigorous security and compliance boundaries:

Technical Changelog

Weekly Protocol Diffs & Verified Drops

New server guides, benchmarks, and security audits. No spam. Unsubscribe anytime.

Zero marketing spam. 1-click unsubscribe anytime.

Ready to Deploy?

Build your full agent toolstack in the Visual Generator

Combine Alpaca Finance API with databases, search APIs, and memory graphs in a single configuration file.

Customize in Generator
Developer Verification & Feedback
0 reports

Did this setup guide work with your AI host?

Help test this configuration across Claude, Cursor, and Codex CLI. Be the first to report:

Alpaca Finance API MCP Server Guide FAQ

What is the Alpaca Finance API MCP Server Guide?

Connect Alpaca Finance API to Model Context Protocol: Stream real-time market data, execute paper trades safely, and enforce autonomous budget guardrails.

How do I configure Alpaca Finance API MCP Server Guide in Claude Desktop or Cursor?

You can copy the configuration JSON from our guide or launch the interactive MCP Codex Config Generator at https://mcp-codex.com/generator to export valid configs in 1 click.

Can I use Alpaca Finance API MCP Server Guide with the OpenAI Codex CLI?

Yes, OpenAI Codex CLI supports Model Context Protocol. You can add it directly to ~/.codex/config.toml or pass arguments to codex mcp add.

RT

Written by Rad Tome

Lead AI Systems Architect & Maintainer, MCP Codex

@RadTome

Specializing in Model Context Protocol (MCP) integrations, autonomous AI agent orchestration, and distributed developer toolchains. Researches and benchmarks production MCP client-server architectures across OpenAI Codex, Claude, and Cursor.

Editorial Integrity: Package names are checked against the npm registry and repositories against the GitHub API. Where a package could not be verified, the guide says so instead of giving you a command to run.

Related Guides