pse-edge-mcp
Provides unofficial access to Philippine Stock Exchange data including quotes, price history, disclosures, financial reports, and market data via MCP.
README
pse-edge-mcp
An MCP server exposing Philippine Stock Exchange data from the PSE Edge portal — quotes, price history, disclosures, financial reports, and market data — to Claude and any other MCP client.
Unofficial. PSE Edge has no public API; this project speaks to the same endpoints the portal's own pages use. It is not affiliated with or endorsed by the PSE. Data is provided as-is for personal/research use, with no warranty.
Design: end-of-day by intention
To avoid loading PSE Edge during trading hours, this server is deliberately an EOD data service (the market-boundary freeze policy):
- Cached data is frozen between market session boundaries (Asia/Manila).
- The first query after the 15:00 close fetches that day's final numbers; everything until the next boundary is served from cache — shared across all users.
- Zero upstream requests while the market is open. Uncached queries during a session return
MARKET_OPEN_NO_CACHEwith aretry_aftertimestamp. - Every result carries
meta.as_of,meta.valid_until, andmeta.staleso clients always know exactly how fresh the data is.
Install (Claude Desktop / Claude Code, stdio)
uvx pse-edge-mcp
Claude Desktop config:
{
"mcpServers": {
"pse-edge": { "command": "uvx", "args": ["pse-edge-mcp"] }
}
}
Run with Docker Compose (HTTP + Postgres)
cp .env.example .env # set POSTGRES_PASSWORD
docker compose up --build
Serves streamable HTTP on :8000, with Postgres 18 as shared cache and archive. A one-shot
migrate service applies the Alembic schema before the app starts.
HTTP mode is stateless with plain JSON responses by default. This server is read-only tools over data the freeze policy holds still, and it uses none of the features MCP sessions exist to enable — no notifications, no resource subscriptions, no sampling, no elicitation, no progress — so every request is self-contained. That means any replica can serve any request behind plain round-robin: no sticky routing, no per-session memory, no event store. Without SSE, idle clients hold no connection either, so N users stop meaning N concurrent connections. Combined with all shared state living in Postgres, that is the whole of "any replica, any request".
Use --stateful if you need MCP sessions (resumability or server-initiated messages) and
--sse for event-stream framing; they are independent flags. Note --stateful requires
clients to complete the initialize handshake and forces sticky routing behind a balancer.
Postgres is optional. Without DATABASE_URL the server uses an in-memory cache and keeps
no archive — the zero-config path for local stdio use, and it needs neither the postgres
extra nor a database. With DATABASE_URL set you get two things: replicas share one cache,
so the market-boundary freeze still means one upstream fetch per boundary however many
processes run; and every read accumulates into an EOD archive (daily bars and disclosures)
that deepens over time at zero extra cost to PSE Edge, which serves only limited history
itself. Nothing crawls — the archive fills solely from fetches you already made.
# applying the schema by hand, outside compose
DATABASE_URL=postgresql+asyncpg://user:pass@host/db uv run alembic upgrade head
Tools
| Tool | Description |
|---|---|
search_companies(query) |
Find PSE-listed companies by name or ticker |
get_stock_quote(symbol) |
Latest EOD quote: price, change, 52-wk range, market cap, full field set |
get_price_history(symbol, start_date?, end_date?) |
Daily OHLC series from Edge's chart endpoint |
search_disclosures(symbol?, start_date?, end_date?, template?, page?) |
Disclosure metadata, market-wide or per company; 50/page with exact totals |
search_disclosure_fulltext(keyword, ...) |
Search the text inside disclosure attachments, with snippets |
get_disclosure(edge_no) |
One disclosure's details plus attachment and body-HTML links |
get_company_profile(symbol) |
Sector, incorporation, auditor, transfer agent, contacts |
get_financial_highlights(symbol) |
Annual + quarterly balance sheet and income statement |
get_dividends_and_rights(symbol) |
Declared dividends and stock rights, linked to their disclosures |
get_indices() |
PSEi and the 7 sector indices, with signed daily change |
get_market_summary() |
Index levels plus PSE Edge's homepage disclosure feeds |
Disclosure tools return metadata and links only — this server never downloads or parses
attachments, so your MCP client can fetch the returned URLs itself if it needs the files.
Note that Edge's own full-text index is partial (roughly 2023–2025 at last check), so
search_disclosure_fulltext is not a substitute for search_disclosures; it reports this
limit in its results.
Financial figures are returned exactly as PSE Edge prints them and are never rescaled —
Edge's own units labels are inconsistent between its annual and quarterly sections, so each
period reports its currency_units for you to check. Index changes are signed here even
though Edge prints them unsigned (it shows direction only as a colour and an arrow).
Roadmap (see docs/plan.md): OAuth 2.1 accounts with passkeys, per-user quotas, production deployment.
Container image
Every merge to main publishes an image:
docker pull ghcr.io/phdwight/pse-edge-mcp:latest # or :<version>, :sha-<sha>
# multi-arch: linux/amd64 and linux/arm64
docker run --rm -p 8000:8000 ghcr.io/phdwight/pse-edge-mcp:latest # streamable HTTP
docker run --rm -i --entrypoint pse-edge-mcp ghcr.io/phdwight/pse-edge-mcp:latest # stdio
Both architectures are gated before publishing, on native runners. The rule is necessity, not size: the image must contain exactly the resolved runtime dependency closure and nothing else — no build toolchain, no package manager, no dev dependencies, no bytecode caches, no source tree — plus a secret scan and a smoke test that the server starts and registers its tools. A stray dependency fails the build; a large but genuinely required one does not. Image size is reported for information and never gated.
Development
uv sync --all-extras
uv run pytest
uv run ruff check .
Tests run entirely against recorded fixtures — CI never touches PSE Edge.
Work lands on develop and reaches main by pull request; main is protected and
requires all three CI checks (test, image (amd64), image (arm64)). Bumping version in pyproject.toml makes the next merge cut
a GitHub Release with a matching immutable image tag.
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.