investment-scanner-agent
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Pass
- Code scan — Scanned 6 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
An educational example agent built with LangChain, LangGraph, a local Ollama model, and one MCP tool. It scans news and price data for a narrow scope: equities (stocks) and ETFs only. It is a news/trend summarizer, not a financial advisor -- it never recommends buying or selling anything.
investment-scanner-agent
An educational example agent built with LangChain, LangGraph, a local
Ollama model, and one MCP tool. It scans news and price data for a narrow
scope: equities (stocks) and ETFs only. It is a news/trend summarizer,
not a financial advisor -- it never recommends buying or selling anything.
I have created a YouTube video to walk you through the AI Agent concepts, install the dependencies, run the Agent and a working demo of this project. Here's the link to the video: https://youtu.be/TIokisGB8h0?si=upERnunB-HhpJvgS
Project structure
investment-scanner-agent/
├── README.md
├── NOTES.md
├── LICENSE
├── .gitignore
├── requirements.txt
├── config.ini # runtime settings (model, cache path/freshness)
├── run.py # entry point / demo script (hardcoded questions)
├── app.py # Streamlit UI (question box -> answer box)
├── market_log.md # generated on first run -- the news cache (gitignored)
└── investment_scanner/ # the package
├── __init__.py # exposes build_agent(), ask()
├── agent.py # the agent: tools, system prompt, create_agent
│ # (LangGraph rebuild commented at the bottom)
├── config.py # loads config.ini, with built-in defaults
└── mcp_server.py # standalone MCP server (equity/ETF price tool)
investment_scanner/agent.py-- the agent, built with LangChain'screate_agent()on top of a local Ollama model. A commented-out
LangGraph version of the exact same agent is at the bottom of the file --
uncomment it once you're ready to move pastcreate_agentand control
the graph yourself.investment_scanner/config.py-- readsconfig.inifrom the repo root
(ollama_model,log_path,freshness_hours) and exposes it asOLLAMA_MODEL,LOG_PATH,CACHE_FRESHNESS_HOURS. Falls back to the
project's built-in defaults if the file, or a given key in it, is
missing, so the project still runs out of the box with noconfig.ini
at all.investment_scanner/mcp_server.py-- your MCP use case: a standalone
server exposing one tool,get_stock_snapshot, backed by free Yahoo
Finance data viayfinance. The agent talks to this as a separate
process over stdio, the same way it would talk to any third-party MCP
server.config.ini-- edit this to change the Ollama model or cache behavior
without touching code (see "Configuration" below).run.py-- the script you actually run; imports the package and asks it
a couple of demo questions.app.py-- a one-page Streamlit UI: type a question in a text box, hit
Ask, see the agent's answer in a text box below it. Uses the samebuild_agent()/ask()API asrun.py.
Why everything here is free
- Ollama runs the model locally on your own machine -- no API key, no
per-token billing. The only cost is your own hardware/electricity. - ddgs (DuckDuckGo search) is a keyless, free news search library.
- yfinance pulls from Yahoo Finance's public endpoints for free, no
account needed.
Hardware
- RAM: the default model,
llama3.1(8B), needs roughly 8 GB RAM to
run at all; 16 GB is a more comfortable baseline if you're also running
a browser, IDE, or Streamlit alongside it. Skip the 70B/405Bllama3.1
variants unless you have serious hardware (64GB+ RAM or a strong GPU) --
this project assumes the 8B default. - GPU: not required. Ollama runs 8B models fine on CPU, just slower
per response; Apple Silicon Macs get solid performance automatically via
Metal, and an NVIDIA/CUDA GPU helps on other machines but isn't needed. - Disk: a few GB free for the model pull, plus normal space for the
Python venv and dependencies. - Network: needed for setup (
pip install,ollama pull) and at
runtime for the two live-data tools --scan_market_news(DuckDuckGo)
andget_stock_snapshot(Yahoo Finance) -- unless a cached hit avoids
it. Model inference itself is fully offline once the model is pulled.
One-time setup
- Install Python 3.10+ if you don't already have it -- download from
python.org, or on a Mac:
Check what you have withbrew install pythonpython3 --version. - Install Ollama if you haven't already -- download from
ollama.com, or on a Mac:
Make sure it's actually running afterward (the Ollama app, orbrew install ollamaollama servein a terminal). - Pull a tool-calling-capable model (required -- not every Ollama model
supports tool calls):
This downloads several GB, so it'll take a few minutes depending onollama pull llama3.1
your connection.qwen2.5andmistral-nemoare alternatives that
also support tool calling, if you want to compare. - Open a terminal in the project folder and set up Python:
cd ~/projects/investment-scanner-agent python3 -m venv .venv source .venv/bin/activate # on Windows: .venv\Scripts\activate pip install -r requirements.txt
Run it
python run.py
This runs two example questions -- a news scan and a price snapshot -- and
prints the agent's answers to the terminal. Edit the questions list inrun.py to try your own.
Or run the UI
streamlit run app.py
This opens a one-page app in your browser with a question box and an
answer box -- type any question and click Ask. The agent is built once
(the first click will be slower while Ollama and the MCP server start up)
and reused for the rest of the session, with each question/answer sharing
the same conversation memory.
Configuration
config.ini (repo root) controls runtime settings without touching code:
[agent]
ollama_model = llama3.1
[cache]
log_path = market_log.md
freshness_hours = 4
ollama_model-- which pulled Ollama model the agent uses. Must be
tool-calling-capable (see "One-time setup" above).log_path-- where the news cache file lives, relative to the repo root.freshness_hours-- how long a cachedscan_market_newsresult stays
fresh before it's treated as stale and re-searched live.
investment_scanner/config.py reads this file and falls back to the
defaults above for the file itself, or any individual key, if missing --
so the project runs fine with no config.ini at all.
How the pieces fit together
build_agent()(ininvestment_scanner/agent.py) starts aChatOllama
model pointed at your local model.- It launches
investment_scanner/mcp_server.pyas a subprocess viaMultiServerMCPClientand pulls its tool(s) in withget_tools(). - Those MCP tools are combined with the locally-defined
scan_market_news
tool into one list and handed tocreate_agent()along with a system
prompt that scopes the agent to equities/ETFs and bans investment
advice. create_agent()builds a LangGraph graph behind the scenes (a loop of
model -> tool call -> tool -> model, repeating until a final answer),
though you never touch that graph directly in this version.MemorySavergives the agent per-thread_idmemory, so callingask()
twice with the samethread_idlets it recall the earlier turn.
The news cache: market_log.md
scan_market_news checks market_log.md (created at the repo root on
first run) before searching. If it finds an entry for the same query
newer than CACHE_FRESHNESS_HOURS (4 hours by default, set inconfig.ini -- see "Configuration" above), it returns that instead of
making a new network call;
otherwise it searches live and appends the result as a new dated entry.
This is deliberately separate from MemorySaver: MemorySaver remembers
a conversation in RAM for as long as the process is running;market_log.md remembers search results on disk, across separate runs,
until they go stale. get_stock_snapshot is intentionally NOT cached the
same way -- a 4-hour-old price is just wrong, unlike a 4-hour-old
headline. The file is gitignored by default since it's generated runtime
state, not source -- remove that line from .gitignore if you'd rather
keep a version-controlled history of what the agent has searched.
Moving to LangGraph
The bottom of investment_scanner/agent.py has a fully commented-out
LangGraph rebuild of the same agent (build_langgraph_agent, usingStateGraph, ToolNode, and tools_condition directly). It's commented
out so you have a working create_agent copy first. When you're ready to
add things create_agent doesn't support out of the box -- custom routing
between specialized sub-agents, a human-approval step before certain tool
calls, deterministic non-LLM steps mixed into the flow -- uncomment that
section (and stop calling build_agent) and build from there.
Known rough edges (this is a teaching example, not production code)
- No retry logic if Ollama, DuckDuckGo, or Yahoo Finance are briefly
unreachable. yfinancescrapes public Yahoo Finance endpoints, which occasionally
change shape or rate-limit -- ifget_stock_snapshotstarts failing,
that's the most likely cause, not a bug in the MCP wiring.- No evaluation harness, logging, or alerting.
- Not every Ollama model supports tool calling; if the agent seems to
ignore your tools entirely, double checkOLLAMA_MODELinagent.pyis
set to one that does. - The
market_log.mdcache matches queries by exact normalized text
(case/whitespace-insensitive only) -- asking the same thing in
differently-worded ways still counts as separate cache entries and
triggers separate searches. It also only grows; nothing prunes old
entries from the file over time.
License
MIT -- see LICENSE. Change the copyright holder there if you'd like.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found