MCP for AI Agents

MCP Server for Stock Data

The same free EOD stock data API — 15 years of daily OHLCV bars across U.S.-listed tickers — exposed as a Model Context Protocol (MCP) server, so Claude, OpenAI, ChatGPT, or any other MCP-capable agent can pull it directly.

* No credit card, ever — the free key is throttled under a fair-use policy of 300 requests/hour, 800/day, and 4,000/week, shared with the REST endpoint.

Step 1 — Get a free API key

Sign up, then go to Profile → Developer API and click "Get free key". It works for both the REST endpoint and the MCP server below — same key, same rate-limit bucket.

Step 2 — Connect your AI tool

The endpoint speaks Streamable HTTP (stateless, JSON responses, no SSE). Pick whichever client you use below — same key, same rate-limit bucket, in every case.

Claude Code & Claude Desktop

Both accept a url plus custom headers in their MCP server config — Claude Code's .mcp.json, Claude Desktop's remote-server settings:

{
  "mcpServers": {
    "stashgamma": {
      "url": "https://www.stashgamma.com/api/dataapi/mcp",
      "headers": {
        "X-Api-Key": "YOUR_API_KEY"
      }
    }
  }
}

Ready-to-drop files: claude_code_mcp.json, claude_desktop_config.json. Restart the client after saving, then ask it about a symbol.

OpenAI (Responses API)

The Responses API supports remote MCP servers as a built-in tool type — pass the same URL and header, no separate integration to write:

from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-4.1",
    tools=[{
        "type": "mcp",
        "server_label": "stashgamma",
        "server_url": "https://www.stashgamma.com/api/dataapi/mcp",
        "headers": {"X-Api-Key": "YOUR_API_KEY"},
        "require_approval": "never",
    }],
    input="Get QQQ's daily EOD bars for the last month.",
)

Full runnable script: responses_mcp_example.py.

Assistants that only ask for a server URL

Many hosted AI assistants have an "add connector" or "add MCP server" form with a single URL field and no place for a header. Put your key in the URL and, if the form asks, choose "no authentication":

https://www.stashgamma.com/api/dataapi/mcp/YOUR_API_KEY

Click-by-click steps for the Claude and ChatGPT apps, with your own key filled in: Claude & ChatGPT setup guide.

?key=YOUR_API_KEY on the plain endpoint works the same way. Treat the full URL as a secret — if it leaks, rotate the key from Profile → Developer API and the old URL stops working.

ChatGPT (Custom GPT Actions)

A Custom GPT calls tools via an OpenAPI schema instead of MCP (a REST call, not the MCP endpoint above). Paste this schema into GPT Builder → Configure → Actions:

  1. Download stashgamma-eod.openapi.yaml and paste its contents into a new Action.
  2. Set Authentication to API Key, Auth Type Custom, header name X-Api-Key, value = your key.
  3. Save — your GPT can now pull EOD bars for any U.S.-listed symbol.

Step 3 — Ask for data

Three read-only tools are exposed. Ask your agent about a symbol in plain language and it calls one of these underneath:

ToolArgumentsReturns
get_eod_datasymbol (required), from/to (optional, YYYY-MM-DD)Same OHLCV bar shape as the REST API
get_latest_quotesymbol (required)Most recent daily bar plus change vs the previous close
get_api_usagenonePlan and remaining requests per hour/day/week — free, doesn't count against your quota

Rate-limit and auth errors come back as a tool result with isError: true (e.g. "retry in Ns") instead of an opaque protocol error, so the agent can see and react to the reason directly.

Building your own agent? Call it programmatically

No chat client involved — use an MCP SDK directly from a script or your own agent framework. Same endpoint, same tool, same key.

Python (official mcp SDK)

# pip install mcp
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async def get_eod_data(symbol, api_key):
    async with streamablehttp_client(
        "https://www.stashgamma.com/api/dataapi/mcp",
        headers={"X-Api-Key": api_key},
    ) as (read, write, _get_session_id):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("get_eod_data", {"symbol": symbol})
            if result.isError:
                raise RuntimeError(result.content[0].text)
            return result.content[0].text  # JSON string, same shape as the REST response

Node.js (@modelcontextprotocol/sdk)

// npm install @modelcontextprotocol/sdk
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://www.stashgamma.com/api/dataapi/mcp"),
  { requestInit: { headers: { "X-Api-Key": apiKey } } }
);
const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(transport);

const result = await client.callTool({
  name: "get_eod_data",
  arguments: { symbol: "QQQ" },
});

Full runnable versions of both (plus ready-to-drop claude_desktop_config.json / .mcp.json snippets) — python_client.py, node_client.mjs.

Why MCP instead of REST?

No glue code

The agent discovers and calls the tool directly — no hand-written fetch/parse wrapper to write or maintain.

Same data, same quota

It's the identical dataset and rate limit as the REST endpoint — switch between them, or use both, without a second key.

Full protocol-level reference (headers, error shapes, transport details) is in the API documentation's MCP section.

Ready to wire your agent in?

Free forever, no credit card — get a key and connect Claude or your own MCP client.

Get Started Free