# ST Market API MCP Setup

The mounted server exposes 36 registered names: **25 canonical tools and 11
deprecated aliases**. Configure new clients to use the canonical inventory.

## Choose the transport

Use the environment-specific mounted endpoint for remote Market Data and
backtest tasks:

```text
https://YOUR_TOOLS_HOST/mcp-server/mcp
```

Both OAuth/OIDC Bearer and Basic Auth resolve to the same local principal,
permissions, quotas, and task ownership. For a remote client, use OAuth first
and keep Basic Auth only as a compatibility fallback.

## Account access

The local account must have the shared Tool API/MCP master permission. An
operator may explicitly grant it with one enabled `tool_api` row for
early-access or tools-only accounts. While
`TOOL_API_SUBSCRIPTION_ENFORCE=false`, all legacy Data API subscribers,
including Light Data and RGNCM, retain their old access. Once Recurly
synchronization is confirmed, enabling the switch leaves only `data` and
`premium-data-yearly` eligible by inheritance. Per-app rows can further
restrict an eligible account.

## Recommended: OAuth/OIDC

Configure the remote MCP URL without a static `Authorization` header, then let
an OAuth-capable client open its browser sign-in flow. Do not ask a user to
paste a password, token, client secret, or generated header into chat.

Discover OAuth from the protected-resource metadata for the exact deployed MCP
endpoint; do not hard-code an issuer, authorization URL, or token URL:

```text
https://YOUR_TOOLS_HOST/.well-known/oauth-protected-resource/mcp-server/mcp
```

A `200` response identifies the external authorization server and required
scopes (`market.read backtest.run`). Fetch that issuer's
`/.well-known/oauth-authorization-server` metadata before authorizing. The
client should complete authorization-code + PKCE and refresh-token rotation
itself. Do not enter a client secret for a public/CIMD client, and do not reuse
another application's client ID.

The API does not provide login, authorization, token, refresh-token, or client
registration endpoints. Let the OAuth-capable MCP client complete the flow with
the external IdP. The IdP identity must already be mapped to a local account by
its exact `(issuer, subject)` pair. The token must target this API's configured
audience and be identifiable as an access token (`token_use=access` or
`typ=at+jwt`). Never use an ID token.

## Fallback: Basic Auth

Use Basic Auth only when protected-resource metadata is unavailable (for
example, a `404` means OAuth is disabled on that deployment) or when the MCP
client cannot complete the OAuth flow. Store the account email and password in
the client's protected credential store; never generate or paste a Basic header
in an agent chat, command line, shared shell history, or repository.

The mounted endpoint accepts per-request Basic Auth:

```text
https://YOUR_TOOLS_HOST/mcp-server/mcp
```

If a client cannot keep the header in protected storage, use a supported
OAuth-capable client instead or ask the client administrator for a supported
setup.

## Local-only transports

Local stdio and standalone SSE use `MCP_AUTH_EMAIL` and `MCP_AUTH_PASSWORD`.
Standalone SSE omits caller-sensitive Market Data and backtest task tools.

Verify either credential type using the MCP client's built-in connection check,
then run one read-only discovery tool. Do not put an Authorization header into a
terminal command. The deployed endpoint is stateless, so the client must supply
its protected authentication on every request. Operators running the
repository's staging-only test IdP should follow `docs/oauth-oidc.md`; regular
MCP users do not need that helper.

## Canonical inventory

| Domain | Tools |
|---|---|
| Discovery | `list_pattern_templates`, `list_seasonality_events`, `list_scanner_signals`, `search_market_data`, `get_indicator_workbench`, `open_indicator_workbench` |
| Analysis | `find_similar_patterns`, `analyze_market_relationships`, `analyze_seasonality`, `get_scanner_picks` |
| Specialized backtests | `cpm`, `scanner_trader` |
| Backtest jobs | `validate_backtest`, `run_backtest`, `submit_backtest`, `list_backtests`, `get_backtest` |
| Reports | `get_predefined_report_types`, `get_reports` |
| Market Data | `get_market_history`, `get_market_snapshot`, `get_recent_market_data`, `get_intraday_history`, `list_custom_indicators`, `get_custom_indicator_data` |

The 11 deprecated aliases are `asset_corr`, `symbol_corr`, `pattern_corr`,
`symbol_beta`, `seasonality`, `smart_scanner`,
`smart_scanner_latest_day_all`, `get_price_history`,
`get_indicator_history`, `get_pair_data`, and `poll_backtest_status`. Do not
use them in new prompts or examples.

## Quick verification

After registration, restart or reload the client and confirm the server is
connected. Then try one small read-only workflow from each enabled domain:

- Discover a pattern, event, or scanner signal before using its analysis tool.
- Call `analyze_market_relationships` with one relationship kind.
- Call `search_market_data` before requesting a market-data series.
- Call `validate_backtest` before `submit_backtest`.
- Use `get_backtest` for a known task and `list_backtests` to recover tasks.

## Optional local Data API Dashboard

The official SentimenTrader Data API Dashboard, shown to users as **My Data API
Dashboard**, is an optional read-only
dashboard on the user's own machine. Its list is the MCP permission-filtered
entitled catalog, not the user's website favorites and not their account-owned
custom indicators. Every MCP tool works without it.

### Open My Data API Dashboard through an agent

The primary always-open link is:
[Open My Data API Dashboard](https://st-tools.sentimentrader.com/indicator-workbench).
It opens immediately and offers the guided setup; return it first. The default
local dashboard URL is:

[Open the local Data API Dashboard](http://127.0.0.1:4174/)

An agent that connects the MCP server only mentions the dashboard, with the
hosted link marked optional; connecting does not install it
([CONNECT.md](CONNECT.md)). Prefer the request **“Open my SentimenTrader Data
API Dashboard.”** Continue to recognize “Indicator Workbench,” dashboard
wording, and `/indicator-workbench` for compatibility. The agent calls
`get_indicator_workbench`, which
returns this workflow, instead of looking for other copies on disk. That
request is one-time authorization for the following automatic, local-only
workflow. `ensure` also keeps the dashboard current: it compares the
installed runtime with the published version and, when a newer one exists,
replaces it and restarts a running dashboard.

The normal path needs no preinstalled Python. The first-stage native installer
provisions a private, checksum-verified CPython 3.14 runtime under the
dashboard's own data directory without installing or modifying system Python.
An existing CPython 3.11–3.14 remains the preflight fallback only when the
installer cannot run. Follow the canonical launch and recovery guide at
https://st-tools.sentimentrader.com/skills/mcp-server/WORKBENCH.md.

1. If the private interpreter and installed launcher exist, run
   `<private interpreter> -I workbench-bootstrap.py ensure --json`, wait for
   its ready result, and return the actual loopback URL rather than guessing a
   port. Always run it, even when the dashboard is already open, because it
   updates the runtime when a newer one is published. If the result has no
   `version` field, that launcher predates automatic updates: run the official
   launcher from step 2 once. If it has `update_pending: true`, an older build
   is still running; the update applies once it exits or the computer restarts.
2. When the private interpreter or installed launcher is missing, automatically
   download the fixed native installer and its `.sha256` into a new temporary
   directory, verify the checksum, and run it (`workbench-install.sh` for
   macOS/Linux, `workbench-install.ps1` for Windows). It provisions the private
   runtime, then downloads the fixed official bootstrap launcher into a new
   temporary directory and runs `workbench-bootstrap.py ensure --json`. The
   launcher downloads the fixed runtime bundle and matching `.sha256`, will
   verify its checksum before extraction, rejects unsafe archive entries, and
   installs it. Do not manually extract the ZIP or ask a second confirmation.
3. If the native installer cannot run (`unsupported_platform`,
   `download_tool_missing`, or a company/network block), perform the CPython
   3.11–3.14 preflight, download the official launcher, verify its `.sha256`,
   and run `workbench-bootstrap.py ensure --json` with that interpreter.
4. If the launcher cannot run, probe `http://127.0.0.1:4174/_health` and require
   exactly `{"service":"sentiment-workbench","status":"ok"}`. Return the default link only after the default local
   service is confirmed running.

The fixed official bundle is:

```text
https://st-tools.sentimentrader.com/skills/mcp-server/templates/sentiment-workbench.zip
```

The first-use launcher is:

```text
https://st-tools.sentimentrader.com/skills/mcp-server/templates/workbench-bootstrap.py
```

The companion checksum is a transfer-integrity check for the bundle fetched
from that fixed official HTTPS endpoint; the HTTPS endpoint is the source of
trust, not a detached package signature.

The bootstrap uses a private virtual environment rather than global pip,
installs into one dedicated per-user application directory, replaces the runtime
only with a newer verified bundle (keeping its local cache and the saved
sign-in), starts OAuth mode on `127.0.0.1:4174` (or another free
loopback port when 4174 is busy), and waits for `/_health`. The agent returns
the dashboard URL it reports; on the first visit the page asks the user to sign
in, and the browser callback returns to the dashboard. The user completes the
browser login; the agent does not log in for them.

For the installed-runtime check, use only these fixed paths; do not search
elsewhere on disk:

- Linux: `${XDG_DATA_HOME}/sentimentrader/indicator-workbench/runtime/` when
  `XDG_DATA_HOME` is absolute, otherwise
  `~/.local/share/sentimentrader/indicator-workbench/runtime/`.
- macOS: `~/Library/Application Support/sentimentrader/indicator-workbench/runtime/`.
- Windows: `%LOCALAPPDATA%\sentimentrader\indicator-workbench\runtime\`,
  falling back to `%APPDATA%` and then the user's local AppData directory.

The automatic `ensure` launcher binds only to loopback and always starts
browser OAuth; it does not read a Basic configuration. A manually started
`server.py` without `--oauth` can reuse a locally readable Basic Authorization
header from `~/.codex/config.toml`; the MCP entry name can be arbitrary. For a
readable JSON MCP config, or a TOML config at another location, add
`--config /absolute/path/to/config` only when the user has supplied that
location. Its public client metadata is:

```text
https://st-tools.sentimentrader.com/skills/mcp-server/sentiment-workbench-oauth-client.json
```

Only the dashboard process may store its rotating refresh token and opaque
cache partition in the operating-system credential store; it remembers that
session on later launches. A remembered dashboard OAuth session takes priority
over a readable Basic configuration, so the account cannot silently change on
restart. Access tokens remain in memory and renew before expiry. Never copy an
Authorization value or token into a command or template file. To remove its
saved OAuth session and its matching local cache partition, even while offline, run
`python3 server.py --logout` from the installed runtime.

Never place credentials in a download command, browser, project file, or chat;
never inspect a credential store. The agent must not copy an Authorization
value or invoke an OAuth login page itself.

`submit_backtest` returns a task ID immediately. Call `get_backtest` about every
15 seconds for no more than five minutes. `SUCCESS` is the canonical successful
terminal status; `COMPLETED` is a legacy list-filter alias.

## Local stdio

Provide local credentials through environment variables:

```json
{
  "mcpServers": {
    "st-market-api": {
      "command": "/home/ubuntu/anaconda3/envs/st_market_api_py313/bin/python",
      "args": ["/path/to/st_market_api/mcp_server.py"],
      "env": {
        "MCP_AUTH_EMAIL": "${MCP_AUTH_EMAIL}",
        "MCP_AUTH_PASSWORD": "${MCP_AUTH_PASSWORD}"
      }
    }
  }
}
```

## Troubleshooting

| Symptom | Meaning or action |
|---|---|
| `401` with only `Basic` challenge | OAuth is disabled; correct Basic credentials |
| `401 invalid_token` | Refresh the access token; check issuer, audience, expiry, signature, and token type |
| `403 Access denied` | Ask the operator to verify the external-identity mapping |
| `403 insufficient_scope` | Ask the IdP/client administrator for the required resource scopes |
| Other `403` | Ask an administrator to verify subscription and app/resource grants |
| `503 Authentication service unavailable` | Retry later or ask the operator to inspect JWKS, users DB, and Redis health |
| Tools missing | Reload the client and verify the configured endpoint/transport |
| Invalid backtest | Inspect `validate_backtest` output and the strategy schema |
| Job still running | Report its state after the bounded five-minute retry window |

Never persist passwords, access tokens, client secrets, or generated
Authorization headers in the repository or in this skill. The dashboard alone
may keep its rotating refresh token in an approved operating-system credential
store; never put it in a config file, browser storage, shell command, or chat.
