# Shorted MCP Server

> Served at `/docs/mcp.md`. This file is `public/docs/mcp-markdown.md` — a
> public file at `public/docs/mcp.md` would collide with the route and make
> Next.js refuse to build ("A conflicting public file and page file was found").
> Same arrangement as `/docs/api.md`.

Shorted exposes its data to MCP-capable clients — Claude, ChatGPT, Cursor, and
anything else speaking the Model Context Protocol — over streamable HTTP.

```
https://api.shorted.com.au/mcp
```

Protocol version **2026-07-28**, negotiating back through `2025-11-25`,
`2025-06-18`, `2025-03-26` and `2024-11-05`. No install step, no account, no
token — and if your client supports OAuth, adding the URL is the whole setup:
it will discover the flow, open a browser once, and come back authorised.

## What it covers

Twenty-four read-only tools across four domains:

- **Market and stocks** — ASIC short positions for ASX-listed securities,
  rankings, industry treemaps, squeeze candidates, price and short-interest
  history, director trades, peer comparison, search, a screener, per-stock news,
  and published weekly/monthly/yearly reports.
- **Housing** — official ABS/RBA house-price series, per-suburb profiles with
  Census and electoral overlays, and derived price-drop aggregates.
- **Economy** — the ABS/RBA economic-series layer (CPI, labour, trade, state
  final demand, approvals, retail, population) and company-to-state exposure.
- **Politicians** — the federal Registers of Members' and Senators' Interests.

Three **resources** carry the context the tools cannot: how to read a short
interest figure, what each domain covers and what is deliberately excluded, and
how access and limits work. Three **prompts** compose the tools into briefings:
`short_interest_briefing`, `suburb_housing_brief`, `market_wrap`.

The live catalog — every tool, its description, its domain, its JSON input
schema — is at
[`https://api.shorted.com.au/mcp/catalog.json`](https://api.shorted.com.au/mcp/catalog.json),
and is rendered at the end of this page. It is generated from the server's own
tool registry, so it cannot drift from what the server actually serves.

## Connecting

### Claude Code

```bash
claude mcp add --transport http shorted https://api.shorted.com.au/mcp
```

### Claude Desktop

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "shorted": {
      "type": "http",
      "url": "https://api.shorted.com.au/mcp"
    }
  }
}
```

### ChatGPT

In a Developer-mode connector, add a custom MCP server with the URL
`https://api.shorted.com.au/mcp`. Authentication **None** works; **OAuth** also
works and needs nothing configured — no client id, no secret, no URLs. The
connector registers itself.

### Any other client

Point it at `https://api.shorted.com.au/mcp` as a **streamable HTTP** (not SSE,
not stdio) MCP server. Authentication is optional. The endpoint is stateless: it
does not issue session IDs, so a client that load-balances requests across
connections works without affinity.

### Checking it by hand

The catalog is a plain GET and needs no MCP client:

```bash
curl -s https://api.shorted.com.au/mcp/catalog.json | head -40
```

The MCP endpoint itself is JSON-RPC over POST and answers in
`text/event-stream`, so pipe it to a reader that tolerates SSE rather than to a
JSON parser.

## Signing in (optional)

OAuth 2.1 **identifies you**, and raises your limits wherever per-caller quotas
are applied (see below — they are not, today). It does not unlock tools: all
twenty-four work anonymously, and none is reserved for a paid plan. There is
nothing to configure — point a client at the URL and it does the rest:

1. It calls a tool, gets `401` with
   `WWW-Authenticate: Bearer resource_metadata="…"`, or reads the server card.
2. It fetches
   [`/.well-known/oauth-protected-resource/mcp`](https://api.shorted.com.au/.well-known/oauth-protected-resource/mcp)
   and then
   [`/.well-known/oauth-authorization-server`](https://api.shorted.com.au/.well-known/oauth-authorization-server).
3. It registers itself — either by RFC 7591 dynamic registration at
   `/oauth/register`, or by handing us its Client ID Metadata Document URL.
4. It opens `https://shorted.com.au/oauth/authorize` in a browser. You sign in
   and see which client is asking, where it will receive access, and what it
   will be able to read. Nothing is issued until you approve.
5. It exchanges the code at `/oauth/token` with PKCE (S256 only).

Scopes, all read-only: `shorts:read`, `housing:read`, `economy:read`,
`politics:read`. Access tokens last an hour; refresh tokens rotate on every use,
and reusing a rotated one revokes the whole family.

## Access, limits and caveats

**Anonymous works.** No token is required.

**The limit in force today is at the edge.** The endpoint sits behind
Cloudflare, which applies a tier-blind per-IP ceiling — **60 requests per 10
seconds and 300 per minute** for anonymous MCP callers, counted per HTTP request
rather than per tool call. A normal agent turn is comfortably inside it; a tight
loop is not. On HTTP 429, honour `Retry-After`.

**Per-caller tier quotas are not currently applied.** When they are, they will
be the [API tier](https://shorted.com.au/pricing) numbers, counted **per tool
call** — the handshake, `tools/list`, `resources/list` and `prompts/list` free,
and a JSON-RPC batch charged for each call it carries:

| | Per minute | Per month |
|---|---|---|
| Anonymous (by IP) | 30 | 500 |
| Signed in, free | 60 | 1,000 |
| Signed in, paid | 120 | 10,000 |

`GET /mcp/catalog.json` reports which of these is true for the deployment you
are talking to (`authentication.rateLimits.enforced`); it is read from the
server's own configuration, so it cannot be stale. When a per-caller limit does
fire, the rejection is a JSON-RPC error whose `data` says which limit fired, its
ceiling, when it resets and where to raise it — the same facts are on the
response headers (`X-RateLimit-Detail`, `Retry-After`).

**Everything is read-only.** There are no write or mutating tools, and none are
planned.

**Short-interest data is T+4.** ASIC publishes with a four trading-day delay, so
the most recent figure any tool returns is already several days old. It is also
short *interest* — positioning — not short-sale flow.

**Some things are permanently absent.** Individual property listings, addresses
and agents are never republished (the crawl licence permits derived aggregates
only); the register of politicians' interests carries no amounts, quantities or
values; and parliamentary prose is reproduced verbatim or not at all, because
the source is CC BY-NC-ND. Read the `shorted://catalog/coverage` resource before
concluding a gap is a bug.

**Nothing here is financial advice.**

## Related

- [MCP server card (SEP-1649)](https://shorted.com.au/.well-known/mcp/server-card.json)
- [Tool catalog](https://api.shorted.com.au/mcp/catalog.json)
- [HTTP API reference](https://shorted.com.au/docs/api.md) — the same data,
  uncapped, for non-MCP clients
- [OpenAPI 3.1 description](https://shorted.com.au/openapi.json)
- [Site overview for agents](https://shorted.com.au/llms.txt)
- [Glossary](https://shorted.com.au/glossary)

Questions: support@shorted.com.au

## Tool catalog

24 tools, live from [`/mcp/catalog.json`](https://api.shorted.com.au/mcp/catalog.json).

### Market

- **`list_top_shorts`** — List the most shorted ASX-listed stocks, ranked by latest reported short interest (percent of total product in issue held short, 0-100), highest first.
- **`get_industry_treemap`** — Break ASX short interest down by industry: returns the list of industries and, within each, its constituent stocks with their latest reported short position as a percentage of shares on issue (0-100).
- **`get_market_snapshot`** — Get every reported ASX short position as at one specific trading date — a point-in-time snapshot rather than the latest figures.
- **`list_squeeze_candidates`** — Rank ASX stocks by short-squeeze risk or by bull-versus-bear divergence.

### Stock

- **`get_stock`** — Look up a single ASX-listed stock by ticker code and return its latest reported short position: percent of total product in issue held short (0-100), the raw number of shares shorted, total shares on issue, and the company name and industry.
- **`get_stock_history`** — Get the time series of a single ASX stock's reported short position over a lookback window (1D, 1W, 1M, 3M, 6M, 1Y, 2Y, 5Y, 10Y or MAX; default 1M).
- **`get_stock_details`** — Get the company profile behind an ASX ticker: registered name, industry, website, address, a description of what the company does, background, stated competitive advantages, recent developments, risk factors and key people.
- **`get_director_trades`** — List disclosed director (insider) trades for one ASX-listed company: date, director name, whether it was a buy, a sell or an option exercise, the number of shares, price per share and total value in AUD, plus a link to the source ASX announcement.
- **`get_peer_comparison`** — Compare one ASX stock against other companies in the same industry, on short interest (percent of shares on issue), market capitalisation in AUD, P/E ratio, trailing dividend yield and one-month price change.

### Discovery

- **`search_stocks`** — Find ASX-listed stocks by company name or ticker code when you do not already know the code.
- **`screen_stocks`** — Filter ASX-listed stocks by CRITERIA and return the matches, sorted.

### News

- **`get_stock_news`** — List recent news and ASX announcements matched to one ASX-listed company: headline, publisher, publication date, a link to the original article, a short summary where one exists, and whether the ASX flagged the announcement price-sensitive.

### Reports

- **`list_reports`** — List published Shorted short-selling reports, most recent first, with each one's slug, headline, standfirst, period end date and headline statistics (the most shorted stock and its percentage, how many stocks were shorted, the top five tickers).
- **`get_report`** — Read one published Shorted short-selling report: its narrative sections, market-wide statistics, the period's most shorted stocks, the biggest risers and fallers in short interest, a breakdown by industry, and the sources the narrative cites.

### Housing

- **`get_housing_overview`** — Latest Australian house-price headline metrics: mean and median dwelling price (AUD), a price index, and household debt-to-income, for the nation, each state and territory, and the greater capital cities, with quarter-on-quarter and year-on-year change.
- **`get_house_price_series`** — One Australian house-price time series for a region and measure — the history behind a get_housing_overview row, oldest first, with its source and licence.
- **`get_suburb_profile`** — Profile of one Australian suburb by ABS SAL code: Valuer-General median house price, ABS Census 2021 demographics, SEIFA decile, federal and state representation, council, state and national median comparisons, and crime percentiles.
- **`list_suburb_price_drops`** — Australian suburbs ranked by recent asking-price reductions on residential for-sale listings.

### Economy

- **`list_economic_series`** — Catalogue of the Australian economic series held here — the discovery step for get_economic_series, which needs an exact series_key that cannot be guessed.
- **`get_economic_series`** — Observations for up to 3 named Australian economic series, oldest first, in the publisher's own units — no rebasing, indexing or cross-series comparison is done, and series whose `adjustment` differs are not comparable with each other.
- **`get_state_company_aggregates`** — ASX-listed company activity by Australian state and territory: how many listed companies have material operations in each, their exposure-weighted market capitalisation in AUD, and their exposure-weighted short interest as a percent of shares on issue.

### Politicians

- **`search_politicians`** — Find Australian federal parliamentarians in the Registers of Members' and Senators' Interests, by name substring, chamber, state or party.
- **`get_politician`** — One Australian federal parliamentarian's declared interests, from the APH Registers of Members' and Senators' Interests: each declaration's register item, whose interest it is (member, spouse or partner, or dependent children), the member's own words VERBATIM, any ASX code or ABS suburb it resolved to, whether it is still declared, and the aph.gov.au source document.
- **`list_stock_politicians`** — Which Australian federal parliamentarians declare an interest in one ASX-listed company, from the APH Registers of Members' and Senators' Interests: who they are, whose interest it is (member, spouse or partner, or dependent children), their own words VERBATIM, whether it is still declared, and the aph.gov.au source document, plus a count of distinct declaring members by party.

### Resources

- **`shorted://guide/reading-the-data`** — How to interpret short-interest figures from this server: net vs gross, the T+4 publication delay, the 0.01% reporting threshold, days to cover, and the readings that are routinely misread.
- **`shorted://catalog/coverage`** — What each domain (market, housing, economy, politicians) actually contains, how fresh it is, and the licence-driven exclusions that will never be filled — no individual property listings, no declared-interest amounts, no rewritten parliamentary prose.
- **`shorted://guide/access`** — This endpoint is anonymous and unmetered, but sits behind a per-IP abuse ceiling.

### Prompts

- **`short_interest_briefing(ticker, period?)`** — Produce a briefing on one ASX-listed company's short interest: where it stands now, how it has moved, how it compares with peers, and what news and director trading sit alongside it.
- **`suburb_housing_brief(state, suburb)`** — Produce a brief on one Australian suburb: prices and how they have moved, the demographic and socio-economic profile, and current discounting activity — from official sources and derived aggregates only.
- **`market_wrap(period?)`** — Produce a market-wide wrap of ASX short selling: what is most shorted, which sectors are carrying the positioning, and where squeeze risk is concentrated.
