Version 2.0.1.0 Released
Date: 3rd May 2026
Major Feature Release: Remote MCP — Self-Hosted OAuth 2.1 + MCP HTTP/SSE Server for ChatGPT, Claude.ai, and Claude Mobile, Plus Per-Purpose 2FA Enforcement, Symbol Search Expansion, Admin Diagnostics, and Zerodha NCO/GLOBAL_INDEX Support
This is the biggest release in the 2.0.x line, covering 20+ commits since v2.0.0.9. The headline change is Remote MCP — a self-hosted OAuth 2.1 + Model Context Protocol HTTP/SSE transport that lets hosted AI clients (ChatGPT.com, Claude.ai, Claude iOS / Android) connect to your OpenAlgo install over HTTPS with the same 40 tools the local stdio MCP already exposes. The local stdio MCP (Claude Desktop, Cursor, Windsurf) is untouched — Remote MCP is a parallel, opt-in transport, off by default, that ships behind two enabler scripts (one for native Ubuntu, one for Docker) and a full admin operations console at /admin/remote-mcp. Alongside Remote MCP, this release lands per-purpose TOTP enforcement (login / MCP / password reset), a multi-exchange Symbol Search expansion (issue #1326), an admin Diagnostics page with downloadable system reports, and Zerodha NCO + GLOBAL_INDEX exchange support.
Highlights
- Remote MCP — Hosted AI Clients via OAuth — Brand-new
/mcpHTTP/SSE transport with full OAuth 2.1 + PKCE, Dynamic Client Registration (DCR), JWKS-published RS256 JWTs, refresh-token rotation with reuse-detection family revocation, and per-token-per-scope rate limits. ChatGPT-compatible discovery (/.well-known/oauth-authorization-server,/.well-known/oauth-protected-resource), claude.ai-compatible scope flow. Off by default; turned on byinstall/enable-remote-mcp.sh(native) orinstall/enable-remote-mcp-docker.sh(Docker). - Per-purpose 2FA enforcement — TOTP can now be required independently for dashboard login, MCP authorization (
write:ordersconsent), and password reset — set the master switch in Profile → TOTP, then pick which purposes apply. Saving requires a fresh TOTP code in the same request to prove authenticator access for both enabling and disabling. - Admin → Remote MCP operations console — Approve / revoke DCR clients, browse the full MCP tool-call audit log (
log/mcp.jsonl) by tool / scope / outcome, and a one-click Kill switch that atomically revokes every refresh token across every approved client. - Symbol Search rewrite (#1326) — Multi-exchange + multi-instrumenttype filtering, CSV download, AmiBroker / TradingView / Python / Excel copy formats, lifted the 500-row hard cap, exchange-only browse mode, and per-user search history.
- Admin Diagnostics page —
/admin/diagnosticsshows live system info (Python / Flask versions, DB sizes, broker session state), a paginated error browser overlog/errors.jsonl, and a one-click downloadable diagnostic bundle (env-redacted) for support tickets. - Zerodha NCO + GLOBAL_INDEX exchanges — NCO (NSE Commodities) and GLOBAL_INDEX (US30 / JAPAN225 / HANGSENG, plus GIFTNIFTY from NSE IFSC) now route correctly through the master contract download and quote endpoints. Quote-only on GLOBAL_INDEX (no orders by exchange convention).
- "Virtual / Paper" → "Sandbox" rename — All in-product copy, docs, and SDK examples now uniformly say Sandbox (the database, blueprint, and API endpoint names were already
sandbox— only display strings were inconsistent). - Platform version bump —
2.0.0.9→2.0.1.0..sample.envENV_CONFIG_VERSION1.0.6→1.0.7. SDK pin (openalgo==1.0.49) unchanged.
Remote MCP — feature deep dive
Remote MCP brings the OpenAlgo MCP toolset to hosted AI clients over the public internet. Same 40 tools as the local stdio integration, exposed at https://yourdomain.com/mcp with full OAuth 2.1.
Architecture in one sentence: the hosted client (ChatGPT / Claude.ai) only ever holds an OAuth Bearer JWT signed by your server's RS256 keypair; tool dispatch on the server side reuses your existing /api/v1/* API key (looked up server-side at boot) over loopback. The hosted client never sees your API key or your broker tokens.
OAuth foundation (Phase 2a + 2c + 2d) — e86cf450f, 0f4f71f0-derived family, cb9350f27:
- RS256 keypair generated and rotated via
utils/oauth_keys.py; public set published at/oauth/jwks.json - Dynamic Client Registration at
/oauth/register(RFC 7591) — clients land in a pending bucket, gated behind admin approval (defaultMCP_OAUTH_REQUIRE_APPROVAL=True) - Authorization Code + PKCE-S256 only —
plainis not advertised;alg=noneandalg=HS256JWTs are rejected by the verifier - Refresh-token rotation with family revocation (RFC 6749 §10.4): single-use, atomic
UPDATE ... WHERE revoked_at IS NULL, replay of a revoked token revokes the entire family /oauth/revokefor explicit token retirement,/oauth/tokenfor code-exchange and refresh- Argon2 hashing with
API_KEY_PEPPERfor client_secret + refresh-token storage indatabase/oauth_db.py
Per-purpose 2FA (Phase 2b + Phase 2 UI) — dbc595e88, ff44adf46:
- Four new boolean columns on
users:totp_enabled+totp_required_for_login+totp_required_for_mcp+totp_required_for_password_reset is_totp_required_for(purpose)helper centralizes the gating decision- Login flow: POST
/auth/login→ on TOTP requirement, returnstotp_requiredflag + temp ticket → POST/auth/login/totpwith code - Configure flow at
/auth/2fa/configurerequires a fresh TOTP in the same request (proves authenticator access for both enabling and disabling — closes the "stolen session can disable 2FA" hole) - React UI:
TwoFactorEnforcement.tsxprofile-page toggle,Login.tsxTOTP step,ResetPassword.tsxTOTP path
HTTP transport (Phase 3) — 7d805af15:
- JSON-RPC 2.0 dispatcher at
/mcp(POST) + Server-Sent Events transport for streaming - Per-token-per-scope sliding-window rate limits (
MCP_RATE_LIMIT_READ/MCP_RATE_LIMIT_WRITE) - CORS allowlist (default:
https://claude.ai,https://chatgpt.com) withWWW-Authenticateexposed viaAccess-Control-Expose-Headersso browsers can read the realm hint on 401 - Audit log writes to
log/mcp.jsonl— every tool call with timestamp, JTI, scope, outcome, latency,params_hash(raw params are deliberately not logged) - Tool registry (
utils/mcp_tool_registry.py) maps all 40 tools to scopes (read:market/read:account/write:orders) and exposes FastMCP-generated JSON schemas in thetools/listresponse - Pre-flight refusal: server refuses to boot with
MCP_HTTP_ENABLED=TrueandFLASK_DEBUG=Truetogether (debug tracebacks would leak bearer tokens)
Install integration (Phase 4) — b36637b5e, 90897a550:
install/enable-remote-mcp.sh— native Ubuntu enabler. Detects allopenalgo-*systemd services, refuses ifFLASK_DEBUG=True, backs up.env, sets the four MCP keys, runsupgrade/migrate_all.py, restarts the service, and probes the discovery / JWKS //mcp/healthzendpoints to confirm boot.install/enable-remote-mcp-docker.sh— Docker enabler. Walks/opt/openalgo/*/docker-compose.yaml, picks a stack, backs up the bind-mounted.env, updates keys, restarts the container (whosestart.shruns migrations automatically), and runs the same smoke probe.install/Remote-MCP-readme.md— operator-focused install guide with same-domain Mode 1 (automated) and subdomain Mode 2 (manual nginx + certbot recipe), threat model, and disabling instructions.- New
docs/userguide/remote-mcp.md— end-user guide for connecting ChatGPT (Settings → Apps → New App BETA → Advanced OAuth → DCR) and Claude.ai (Settings → Connectors → + → Add custom connector).
Admin operations (Phase 5) — 8be942a7c:
/admin/remote-mcpReact page with three tables (Pending / Approved / Revoked) + audit viewer + kill switchGET /admin/api/oauth/clientslists clients by status; approve/revoke endpoints require typed-string confirmation for destructive actionsGET /admin/api/mcp/audit— paginated audit log overlog/mcp.jsonlwith whitelisted query keysPOST /admin/api/mcp/kill-switch— typed-string confirm, atomically revokes every refresh token across every approved client (read-only access tokens still expire on their existing 15-minute TTL)
Security audit fixes + ChatGPT compatibility — 926a597bf:
- Migrated from deprecated
authlib.jose→joserfcwith explicitalgorithms=["RS256"]pinning MCP_PUBLIC_URLis a hard requirement whenMCP_HTTP_ENABLED=True— collapsing it to empty would let JWTs minted on instance A be replayed against instance B's loopbackerror_detailin MCP responses replaced with generic "Tool execution failed" — the full detail is in the audit log only, so SQL errors / stack traces don't leak to the model- Added path-relative discovery alias
/mcp/.well-known/oauth-protected-resourcebecause ChatGPT fetches it that way (RFC 9728 says root-relative is canonical, but ChatGPT does both) - Default
MCP_RATE_LIMIT_WRITEraised from 5/min → 50/min based on real ChatGPT/Claude usage patterns - Removed the vestigial
MCP_OAUTH_LOGIN_AUTH_LEVELenv var (replaced by the per-purpose 2FA flags)
CSP and consent screen fixes — 52c96a11a, 5f60b4817, 3175a4104:
- Per-page CSP on the consent screen sets
form-actionto allow exactly the registered redirect_uri's origin — fixes the form-submit block when the global CSP middleware would otherwise refuse the cross-origin POST - Global CSP middleware (
csp.py) now respects view-set CSP headers (won't overwrite if a header is already set) tools/listresponse now includes the real Pydantic-generated JSON schemas (reach into FastMCP's_tool_manager._tools) so ChatGPT stops hallucinating parameter names likeproduct_typeinstead ofproduct- Removed Jinja-time
csrf_token()dependency on the consent template — render the token via_csrf_token_value()helper inside the view so timing-of-globals isn't an issue
Three new admin endpoints + four new database models:
| New | Purpose |
|---|---|
database/oauth_db.py
| OAuthClient, OAuthRefreshToken (with family_id / parent_id), OAuthSigningKey
|
database/user_db.py
| 4 boolean columns + find_user_by_exact_username()
|
utils/oauth_keys.py
| RS256 keypair generation + rotation + public_jwks()
|
utils/oauth_tokens.py
| issue_access_token, rotate_refresh_token, verify_access_token
|
Default security posture:
| Setting | Default | Why |
|---|---|---|
MCP_HTTP_ENABLED
| False
| Off until you opt in |
MCP_OAUTH_REQUIRE_APPROVAL
| True
| DCR clients land pending until admin approves |
MCP_OAUTH_WRITE_SCOPE_ENABLED
| False
| Order placement unreachable until you flip the switch |
MCP_RATE_LIMIT_READ
| 60/min
| Per-token sliding window |
MCP_RATE_LIMIT_WRITE
| 50/min
| Per-token sliding window |
MCP_MAX_ORDER_QTY
| 0 (no cap)
| Recommend setting a sane cap |
Symbol Search expansion (#1326)
232c637fb—feat(search): lift 500 cap, allow exchange-only browse, add search historyf0c03eede—feat(search): multi-exchange/instrumenttype, CSV download, copy formats
The Symbol Search page now supports filtering across multiple exchanges and multiple instrument types in a single query, browsing an entire exchange without entering a search term, downloading the result set as CSV, and copying selections in AmiBroker / TradingView / Python / Excel formats. The previous 500-row hard cap is gone — large result sets stream incrementally. Per-user search history is preserved across sessions.
Admin / Operations
566113d49—feat(admin): add Diagnostics page with system info, error browser, and downloadable report
/admin/diagnostics consolidates the moving parts of "what's going on with this install" into a single React page: Python / Flask / SQLAlchemy versions, database sizes for all six SQLite/DuckDB databases, broker session state, configured env vars (with secrets redacted), a paginated browser over log/errors.jsonl with stack traces and Flask request context, and a one-click Download diagnostic bundle that produces an env-redacted ZIP suitable for attaching to a support ticket.
Brokers
Zerodha
6bc37381e—feat(zerodha): support NCO and GLOBAL_INDEX exchanges
Adds two Zerodha-only exchange codes:
- NCO — NSE Commodities (Zerodha's symbol format differs from NCDEX; this fix routes correctly through the master contract download)
- GLOBAL_INDEX — US30, JAPAN225, HANGSENG, plus
GIFTNIFTYfrom NSE IFSC. Quote-only by exchange convention; orders are not supported on GLOBAL_INDEX.
Documentation
199c544d1—docs: rename "virtual/paper trading" to "sandbox trading" terminology6efaf1655—docs: rename remaining "virtual" trading terms to "sandbox" equivalents500e27cbb—docs: add Remote MCP user guide for ChatGPT and Claude.ai- New
install/Remote-MCP-readme.md— operator-focused install + threat model - New
docs/prd/remote-mcp.md— full product requirements doc with architecture, MUST/SHOULD/COULD security controls
The "virtual / paper trading" rename only touched display strings — the database (db/sandbox.db), blueprint (blueprints/sandbox.py), and API endpoints (/api/v1/sandbox/*) were already named sandbox. The rename closes a long-standing inconsistency between in-product copy and the underlying schema.
Configuration changes
.sample.env:
ENV_CONFIG_VERSION1.0.6→1.0.7- New section:
MCP_HTTP_ENABLED,MCP_PUBLIC_URL,MCP_OAUTH_REQUIRE_APPROVAL,MCP_OAUTH_WRITE_SCOPE_ENABLED,MCP_HTTP_CORS_ORIGINS,MCP_HTTP_IP_ALLOWLIST,MCP_OAUTH_ACCESS_TTL,MCP_OAUTH_REFRESH_TTL,MCP_OAUTH_CODE_TTL,MCP_RATE_LIMIT_READ,MCP_RATE_LIMIT_WRITE,MCP_MAX_ORDER_QTY - Removed:
MCP_OAUTH_LOGIN_AUTH_LEVEL(vestigial — replaced by per-purpose 2FA flags)
pyproject.toml:
version = "2.0.1.0"- SDK pin (
openalgo==1.0.49) unchanged
utils/version.py:
VERSION = "2.0.1.0"
Upgrade procedure
For existing installs (Native Ubuntu):
cd /var/python/openalgo-flask/<deploy-name>/openalgo
sudo ./install/update.sh
# update.sh runs migrate_all.py — schema changes for the OAuth + 2FA columns
# are applied automatically. Remote MCP stays disabled by default.For existing installs (Docker):
cd /opt/openalgo/<domain>
sudo docker compose pull
sudo docker compose up -d
# The container's start.sh runs migrate_all.py before gunicorn boots.
# Remote MCP stays disabled by default.To enable Remote MCP (after upgrading):
# Native Ubuntu
sudo ./install/enable-remote-mcp.sh
# Docker
sudo ./install/enable-remote-mcp-docker.shBoth enabler scripts are idempotent and back up .env before any change. They print a one-liner rollback command if the smoke probe fails.
For local developers (uv):
git pull origin main
uv sync
cd frontend && npm install && npm run build
uv run app.pyContributors
- @marketcalls (Rajandran) — release management, Remote MCP architecture and full OAuth 2.1 implementation (5 phases — scaffold → OAuth foundation → 2FA wiring → discovery + JWKS + DCR → /authorize + /token + /revoke → Phase 2 UI → HTTP/SSE transport → install integration → admin UI), security audit + joserfc migration, CSP fixes for the consent flow, ChatGPT-compatibility hardening (path-relative discovery, real tool schemas, generic error_detail), Docker enabler, install integration, comprehensive PRD + operator docs + end-user docs, Symbol Search rewrite (#1326), Admin Diagnostics page, Zerodha NCO + GLOBAL_INDEX support, and the "virtual → sandbox" terminology cleanup.
Links
- Repository: https://github.com/marketcalls/openalgo
- Documentation: https://docs.openalgo.in
- Remote MCP guide: https://docs.openalgo.in/mcp/remote-mcp
- Discord: https://www.openalgo.in/discord
- YouTube: https://www.youtube.com/@openalgo
- Issue tracker: https://github.com/marketcalls/openalgo/issues