AI DC BOM Stock Screener MCP
Pricing
Pay per event + usage
AI DC BOM Stock Screener MCP
MCP server that scans undervalued U.S. AI data-center bill-of-materials (BOM) stocks and ranks them by a 7-signal composite. Pay-per-event, no monthly fee.
AI DC BOM Stock Screener MCP
Pricing
Pay per event + usage
MCP server that scans undervalued U.S. AI data-center bill-of-materials (BOM) stocks and ranks them by a 7-signal composite. Pay-per-event, no monthly fee.
Initial release.
Keyless live data - the offline demo is gone. The server no longer needs an API key. Five of the seven composite signals are measured live from free, public sources:
data.sec.gov/api/xbrl/companyfacts - audited 10-K/10-Q XBRL
for PE (with filed quarterly EPS) and both 36-month growth figuresapi.nasdaq.com/api/analyst/... - real buy/hold/sell counts and
next-fiscal-year consensus EPSquery1.finance.yahoo.com/v8/... - last traded priceForward revenue growth has no free equivalent and is deliberately left
undefined rather than estimated: the engine imputes it, penalises it and flags
MISSING_FWDREVENUEGROWTH12M, and caps the composite at 60 when two or more
quantitative signals are missing. Every row carries its own provenance
(price used, PE basis, estimate count, live signal count) so two rows are
never silently scored on different denominators. FMP_API_KEY, when present,
still takes precedence and measures all seven.
Four defects found and fixed while building this, each caught by checking a result against a known figure rather than by the code running clean:
durationSeries read only units.USD, but per-share facts live under
units["USD/shares"], so every PE came back undefined with no error raised.handle() dispatched tools/call without await, so the reply was written
after the function returned. The hosted handler reads the output stream the
moment dispatch resolves and answered "No response produced" for every tool
that touched the network. Tools answering from local memory had hidden it.Foreign private issuers file 20-F under ifrs-full, leaving us-gaap empty for
TSM, so tag aliases now cover the IFRS spellings. Upstream failures are
counted and published as sourceHealth on the snapshot rather than swallowed,
because the first cloud run degraded to demo data with an empty failure list
and no log line - the one condition this module exists to prevent was the one
thing it could not report.
SCAN_OFFLINE=1 pins the bundled baseline for tests and smokes.
Hosted (Apify Standby) hardening — all verified by scripts/http-smoke.mjs (37 assertions):
node:http server that reuses the existing hand-written JSON-RPC dispatcher, replacing the MCP SDK + Express + Apify SDK handler. Removes three runtime dependencies, the cloud npm install step and any lockfile / peer-dependency drift from the build.x-apify-container-server-readiness-probe response. Without it a standby container never reports ready and every caller sees a timeout.Actor.charge equivalent; it no longer depends on an SDK import succeeding, and a failed charge is logged loudly instead of swallowed.APIFY_META_ORIGIN, which is what standby actually injects — checking only APIFY_TOKEN silently disabled billing in the exact mode being sold.GET /mcp → 405, DELETE /mcp → 204, missing text/event-stream in Accept → 406, malformed body → 400, notifications → 202.pricingInfos record with all four billable events. Apify activates only the most recently appended record, so events split across records are served free.$0 events (mcp-initialize, mcp-list-tools); a zero-price event is rejected by the API and discovery must never be billable. get_methodology is likewise free.actor.json: version corrected to MAJOR.MINOR (a three-segment version fails schema validation on push), conflicting webServerMcpPath removed so the process owns its own listener, and the input schema required before publishing added.scan / get_list now print an explicit *** OFFLINE DEMO DATA — NOT LIVE MARKET DATA *** banner, and get_methodology returns a dataSource.warning. Every row already carried OFFLINE_DEMO, but a paying caller could still read a stale ranking as current.handleMessageAsync so the hosted path can await a tool result; the stdio path stays fire-and-forget.Core:
sunday_scan prompt.FMP_API_KEY).actor.json, pay_per_event.json, Dockerfile).preflight (tests + smoke + P0 check) and refresh (Sunday scan → GitHub Pages).