vlad.build

Project: Turning Claude into a stock trading agent (MCP)

Screenshot 2025-05-13 at 09

Disclaimer: None of this is financial advice. This bot was not built in order to make good financial decisions.

The project

I built a Claude agent that trades stocks with a $100,000 paper money account. Every day, Claude looks at its portfolio, reads hundreds of websites to reflect on the state of the market, analyzes recent stock performance, buys and sells stocks, and writes an investment memo explaining its decisions. You can follow its daily progress here.

My main goal was to familiarize myself with building MCP integrations, which allow LLM-powered clients to easily integrate external applications and APIs.

Building the MCP connector

The project relies on the excellent Alpaca API. You can get a paper trading account covering the entire functionality of their API, and use it for free. The API allows you to get market data (stock quotes, stock bars) and manage your account (check your assets, buy and sell positions).

I built an MCP wrapper over the Alpaca API. I didn't cover all the methods, just the ones that would allow Claude to get market data and trade stocks.

I used the FastMCP library to build the server. It was very easy to setup. Essentially you're just creating the server object and then wrapping every function in a decorator:

# Create an MCP server
mcp = FastMCP("Demo")

@mcp.tool()
def get_latest_quotes(symbols: Union[str, List[str]]) -> Dict[str, Any]:
...

You need to ensure that the function you're wrapping is only using native types as arguments, so the MCP client (e.g. Claude) will be able to call it over JSON-RPC (the data exchange format in the MCP protocol).

The Alpaca API logic and the MCP wrapping are all in this file.

Once the MCP server was done, I had to expose it to the client, in this case the Claude Desktop app. In the local claude_desktop_config.json file, I added the following configuration:

    },
    "alpaca": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "/Users/{USERNAME}/mcp/alpaca-mcp-2",
        "mcp",
        "run",
        "server.py"
      ],
      "env": {
        "ALPACA_API_KEY": "",
        "ALPACA_SECRET_KEY": ""
      }
    },

Here's how it works:

  1. Claude Desktop is the MCP client. When you start it, it runs the command from the configuration. The uv command starts the server in the background. The client and the server communicate by sending JSON-RCP messages via stdio.

  2. Claude Desktop sends a request to the server to discover tools. Remember, tools are wrappers over functions. The function docstring is very important, because it becomes the tool description. For each available tool, Claude will now see the description and available arguments.

  3. In the Claude app, the user can toggle which tools are active at any time:

Screenshot 2025-05-13 at 11

  1. Based on your requests, Claude will automatically decide when to use tools, and which arguments to provide to them. Claude is very good at this!

  2. When Claude calls a tool, it sends a request to the MCP server via stdio. The MCP server then calls the Alpaca API and returns the response. Claude reads the response and informs you of the progress.

Screenshot 2025-05-13 at 11

There are many ways to debug an MCP. My favorite one is the MCP inspector, which you can start by running:

uv run mcp dev server.py

The inspector shows you the exposed tools and allows you to call them directly.

Screenshot 2025-05-13 at 11

Building a trading agent

Next, I needed to create the trading agent. I opted for a very simple solution: using Claude Desktop.

First, I created a Claude Project for the agent. Then, I wrote a setup prompt that explains the workflow. This prompt is attached to the project via GitHub integration, so Claude will always see it.

In the same repository, I store Claude's daily investment memos (aka diary entries) which are the agent's memory. The GitHub folder for the memos is also attached to the project.

Every day, I tell Claude to run the workflow:

  1. Clade reads the main prompt and the previous diary entries.

  2. It uses the Alpaca MCP to check the state of the portfolio.

  3. It runs a Research process where it reads hundreds of websites to see the state of the market.

  4. Using the Alpaca MCP, it can place buy and sell orders for its account.

  5. It writes a diary entry detailing what it did today and why, which will go into the agent's memory. The entry needs to be pushed to GitHub, and I found a nice hack to do it: I exposed Claude Code as an MCP server. Then I taught Claude Desktop how to use it to create the markdown file in the code folder and push it to GitHub.

In summary, the agent has the following components: instruction prompts, memory in the form of Markdown files, and the MCP connector to interact with the Alpaca service.

Frontend

The frontend is a simple Streamlit app that's hosted for free on Streamlit cloud.

The dashboard is fed by a script that calls the Alpaca API to get the portfolio status and the list of orders. A GitHub workflow runs this script every 15 minutes to keep the dashboard updated. Not much else to see there.

Conclusion

This is a very simple workflow that I built in a few hours (actually, it was mostly written by Claude Code!).

The result is pretty satisfying. The agent is getting the job done, if by job we mean making weird investment decisions and underperforming the S&P 500.

The downside is that it runs inside the Claude Desktop app, and there's no way to trigger it automatically. I have to run the agent manually every day. The next step would be to fully automate it and build more complex agents (e.g. with the Agents SDK).

The MCP workflow is almost magical in its simplicity. You essentially write a few Python functions and Claude is instantly able to use them for its purposes.