Setup Guide · MCP Server v0.2

Connect your AI agent to ftInvstr

ftInvstr speaks the Model Context Protocol — Anthropic's open standard for letting AI agents discover and call tools on remote servers. Connect Claude, Cursor, Claude Code, Windsurf, VS Code, ChatGPT, or any Python agent — they all consume the same endpoint and the same 11 tools. Once connected, your AI can browse 60+ Indian equity strategies, fetch full stats, design and run real backtests end-to-end, and cancel jobs mid-flight.

endpoint: https://ftinvstr.in/mcp/

01 Get your API key

  1. Log in at ftinvstr.in (or sign up if you haven't).
  2. Go to Profile → API Keys.
  3. Click Generate Key, label it (e.g. "Claude Desktop · MacBook").
  4. Copy the plaintext key shown. Keys look like fti_aB3cD4eF5gH6iJ7…
The plaintext is shown only once. Store it somewhere safe before leaving the page. The server only keeps a hash — we cannot recover it.

02 Configure your AI client

Pick your client below — same endpoint, same Bearer header, format varies. After pasting the snippet, replace YOUR_KEY_HERE with the key from step 1.

The easiest setup — no API key, no JSON config, no Node.js. claude.ai handles the auth handshake automatically via OAuth.

Requires a paid plan (Claude Pro / Max / Team / Enterprise). Free-tier claude.ai accounts don't have the custom-connector option — fall back to Claude Desktop or the Python SDK below.
  1. Open claude.ai. Click your profile icon (top-right) → Settings.
  2. In the left sidebar, click Connectors (or Custom Integrations, depending on your account's UI version).
  3. Click Add custom connector.
  4. Fill in:
    • Name: ftInvstr
    • Remote MCP server URL: https://ftinvstr.in/mcp/
  5. Leave the OAuth Client ID and OAuth Client Secret fields empty under Advanced settings — our server uses Dynamic Client Registration, no manual provisioning.
  6. Click Add, then click Connect on the new entry.
  7. You'll be redirected to ftinvstr.in. Sign in if prompted, then click Allow access on the consent screen.
  8. claude.ai redirects you back. Open a new chat and click the 🔧 tools icon — you should see ftinvstr · 11 tools listed.

Test prompt:

"Use the ftinvstr tool — show me Indian equity strategies with Sharpe above 0.9."

To revoke access later: in claude.ai → Settings → Connectors → remove the ftInvstr entry. That deletes the connector locally; the matching token on our side will simply expire (or you can also email us to force-revoke).

Edit your Claude Desktop config file (create it if missing):

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json

Claude Desktop only speaks stdio. Use the mcp-remote bridge to reach our HTTPS endpoint. Requires Node.js (brew install node or nodejs.org).

{ "mcpServers": { "ftinvstr": { "command": "npx", "args": [ "-y", "mcp-remote", "https://ftinvstr.in/mcp/", "--header", "Authorization:Bearer YOUR_KEY_HERE" ] } } }

Fully quit Claude Desktop (Cmd+Q / right-click tray → Quit, not just close the window) and reopen. The 🔧 tools icon should now list ftinvstr with 11 tools.

Open Settings → MCP, or edit ~/.cursor/mcp.json directly:

{ "mcpServers": { "ftinvstr": { "url": "https://ftinvstr.in/mcp/", "headers": { "Authorization": "Bearer YOUR_KEY_HERE" } } } }

Cursor speaks HTTP natively for remote MCP servers, so no Node bridge needed. Restart Cursor; the tool appears in the agent's tool list.

One-shot CLI command from any terminal:

# Add the ftInvstr MCP server (user scope, available in every project) claude mcp add --transport http ftinvstr https://ftinvstr.in/mcp/ \ --header "Authorization: Bearer YOUR_KEY_HERE"

Confirm with claude mcp list. The tool becomes available immediately in the next claude session — no restart needed.

Edit ~/.codeium/windsurf/mcp_config.json:

{ "mcpServers": { "ftinvstr": { "serverUrl": "https://ftinvstr.in/mcp/", "headers": { "Authorization": "Bearer YOUR_KEY_HERE" } } } }

Restart Windsurf. The Cascade panel will list ftinvstr alongside other configured servers.

VS Code's GitHub Copilot Chat (1.96+) supports MCP via settings.json. Open Command Palette → "Preferences: Open User Settings (JSON)":

{ "github.copilot.chat.mcp.servers": { "ftinvstr": { "type": "http", "url": "https://ftinvstr.in/mcp/", "headers": { "Authorization": "Bearer YOUR_KEY_HERE" } } } }

Reload window (Cmd+Shift+P → "Developer: Reload Window"). Copilot Chat agent mode will show ftinvstr tools.

ChatGPT supports remote MCP servers via the Connectors UI (ChatGPT Pro / Enterprise).

  1. Open Settings → Connectors → Add custom connector.
  2. Set Server URL to https://ftinvstr.in/mcp/
  3. Under Authentication, choose "Bearer token" and paste your fti_… key.
  4. Save and enable the connector for the conversations where you want it.
Free-tier ChatGPT does not support remote MCP yet — use one of the other clients above.

The official mcp Python SDK works with any HTTP MCP server. Compatible with OpenAI Agents SDK, LangChain MCP adapter, and custom agents.

# pip install mcp import asyncio from mcp import ClientSession from mcp.client.streamable_http import streamablehttp_client async def main(): headers = {"Authorization": "Bearer YOUR_KEY_HERE"} async with streamablehttp_client("https://ftinvstr.in/mcp/", headers=headers) as (r, w, _): async with ClientSession(r, w) as sess: await sess.initialize() tools = await sess.list_tools() print([t.name for t in tools.tools]) result = await sess.call_tool("search_strategies", {"min_cagr": 25, "min_sharpe": 0.8}) print(result.content[0].text) asyncio.run(main())

For OpenAI Agents SDK: pass the same headers when creating the MCP server connection (see openai-agents-python).

For LangChain: use langchain-mcp-adapters with the same URL + Bearer header.

Any HTTP client speaks JSON-RPC 2.0 directly. Useful for debugging or custom integrations.

# List all available tools curl -X POST https://ftinvstr.in/mcp/ \ -H "Authorization: Bearer YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # Call a tool (search strategies with CAGR > 25%) curl -X POST https://ftinvstr.in/mcp/ \ -H "Authorization: Bearer YOUR_KEY_HERE" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"search_strategies","arguments":{"min_cagr":25}} }'

Required protocol: MCP spec 2024-11-05, Streamable HTTP transport, JSON-RPC 2.0 framing. Initial initialize handshake is required before tools/call.

03 Verify the connection

In a new chat with your AI client, ask it to list its tools or run this prompt:

"Use the ftinvstr tool to find Indian equity strategies with CAGR above 30% and Sharpe above 0.9, then show me their year-by-year returns."

The agent should make two tool calls (search_strategies then get_strategy_stats) and return a structured answer in seconds.

04 Designing & running a backtest via your agent

Backtest submissions use an async pattern — your agent submits a job, polls for status, and fetches the result when done. Typical flow:

1. // agent learns the DSL once per session get_expression_help(topic="overview") get_expression_help(topic="fields") // 276 fields get_expression_help(topic="functions") // 36 operators get_expression_help(topic="examples") 2. // build expression locally expr = "order(normalize(rank('ROCE %')), 0.7, 0.3, 1)" 3. // fast syntax / field check — no queue burn validate_expression(expr) // → {ok: true} 4. // submit. Returns immediately with a job_id. submit_backtest( expression=expr, universe="NIFTY500", // top 500 by mkt cap start="2020-01-01", end="2025-12-31", investment_mode="max_position_legacy", rebalance_frequency="monthly", max_positions=10 ) // → {job_id, status, universe, stocks_count, eta_seconds} 5. // poll every ~30s. Returns queued / running / done / failed. get_backtest_status(job_id) 6. // when done, fetch full stats + curves get_backtest_result(job_id) // same shape as get_strategy_stats // (optional) cancel mid-flight stop_backtest(job_id)
Serialized per user. You can only have one backtest in flight at a time. If you submit a second while one is running, the call is rejected with the existing job_id so your agent knows what to poll (or cancel via stop_backtest).
Want to browse the DSL yourself? The same 276 fields and 36 operators your agent reads via get_expression_help are listed (with descriptions, examples, and field categories) at /function-docs/. Useful while you're sketching an expression before letting the agent run with it.

05 The 11 tools your agent can call

Read-only catalog (Phase 1)

ToolWhat it returns
list_strategiesCatalog overview — name, badges, factor family, rebalance frequency, full stats per strategy.
get_strategy_statsOne strategy's full stats — CAGR, Sharpe, Sortino, Calmar, max DD, year-by-year + equity / drawdown curves + monthly returns.
get_holdingsActual current portfolio — ticker, company name, shares held, latest price, market value, weight %.
search_strategiesFilter the catalog by min CAGR, min Sharpe, max DD, universe.
get_rebalance_historyAggregate rebalance activity — date + buy/sell counts per rebalance, no specific tickers.

Writable backtests (Phase 2)

ToolWhat it does
get_expression_helpDSL reference — overview / fields (276 fields) / functions (36 operators) / functions:<name> (one-op detail) / examples. Same content humans browse at /function-docs/.
validate_expressionSyntax + field check before submit. Fast, no queue burn. Returns {ok: true} or specific error.
submit_backtestQueues a real full-fidelity backtest. Args: expression, universe (NIFTY50 / 100 / 200 / 500 / 1000 / 2000 / ALL), start, end, max_positions, investment_mode (7 modes), rebalance_frequency (daily/weekly/monthly), name. Returns {job_id, status, universe, stocks_count, eta_seconds}.
get_backtest_statusPoll: queued / running / done / failed. Surfaces a progress dict (description + percent) during runs.
get_backtest_resultFetch full stats when status is done. Same shape as get_strategy_stats.
stop_backtestCancel an in-flight backtest you submitted. Revokes the Celery task, drops the partial DB, removes the temp CONFIG. Idempotent.

Investment modes (passed to submit_backtest)

ModeBehaviour
max_position_legacyDefault. Long-only, equal-weight slot-based top-N with score-driven swaps. Matches what most platform strategies use.
equal_weight_top_nLong-only, strict equal weights across top-N each rebalance.
score_weighted_top_nLong-only, weights proportional to score within top-N.
daily_top_n_long_short50/50 long top-N vs short bottom-N.
beta_neutral_top_nLong-short scaled to net-zero beta vs NIFTY.
sector_neutral_top_nPaired long-short within each sector.
regime_switching_dynamicRegime-aware: long-only in bull/sideways, neutral or short in bear.

06 Limits & safety

  • 10 submit_backtest calls per day, per user. Resets at midnight UTC. Counter is per-user, shared across all your API keys.
  • One concurrent backtest per user. A second submit_backtest while one is in flight is rejected with the existing job_id. Call stop_backtest to free the slot or wait it out.
  • Expression length cap: 5000 characters.
  • Universes: seven friendly index labels — NIFTY50, NIFTY100 (default), NIFTY200, NIFTY500, NIFTY1000, NIFTY2000, NIFTYALL. Each = top-N of the broad listed pool ranked by market cap. Same expression across NIFTY50 vs NIFTY500 vs NIFTYALL gives you small-cap vs mid-cap vs full-market behaviour.
  • Date range: start_date ≥ 2018-01-01. This floor exists because fundamentals data (qr, pl, bl, cf, rto and ML predictions derived from them) is sparse before 2018. Technical / price-only strategies (Close, Volume, momentum operators, beta) work back to 2015 — let us know if you need an earlier start for a pure-technical expression.
  • Read tools are unlimited (list / get / search / help / validate / status / result). Only submit_backtest consumes the daily quota.

07 Troubleshooting

SymptomLikely cause / fix
401 UnauthorizedMissing or invalid Bearer header. Re-copy from /profile/api-keys/. Header is case-sensitive: Authorization: Bearer fti_....
Tools don't appear in Claude DesktopForgot to fully quit + reopen (Cmd+Q, not just close the window). Check ~/Library/Logs/Claude/mcp*.log on macOS.
command not found: npxNode.js not installed locally. Install from nodejs.org or brew install node on macOS.
"You already have a backtest in flight"Serialize gate — one job per user at a time. Poll get_backtest_status on the returned existing_job_id until done, or call stop_backtest.
"daily submit limit reached"Hit the 10/day cap. Resets at midnight UTC. Read tools still work.
Backtest finished with 0 tradesMost common cause: a hard binary filter inside multiply(score, gt(...)) or multiply(score, lt(...)) zeroes out every stock because the gated field is sparse. Use the field as a weighted factor (multiply(rank('field'), 0.3)) inside an add(...) instead of as a hard gate.
"unknown or expired job_id"Job records have a 7-day TTL in Redis. After that, results are only fetchable via list_strategies if the strategy was kept.
validate_expression rejects a fieldField name must match the catalog exactly. Call get_expression_help(topic="fields") or browse /function-docs/ for the full list. Field names are case-sensitive and use single quotes.
Tool returns empty listFilters too strict. Try list_strategies() with no arguments first to confirm connectivity.
"Cannot reach server"Corporate firewall blocks ftinvstr.in. Try a different network or whitelist the host.

08 Security & disclaimers

  • Treat keys like passwords. Anyone with the key can submit backtests as you and read your account.
  • Use one key per AI client / device so you can revoke selectively. The "Last used" timestamp helps you spot stale or compromised keys.
  • If a key leaks, delete it immediately from /profile/api-keys/.
  • Expressions you submit and the resulting CONFIG / strategy_name labels are tied to your user_id in Redis. Other users cannot see, status, result, or stop your jobs.
  • ftInvstr is a quantitative research tool — not investment advice. We are not SEBI-registered investment advisers.
  • All results are historical backtests on Indian equity data. Past performance does not predict future returns. The bias-safe fundamentals layer (lagged by reporting filings) is always enforced — you can't accidentally peek into the future.
Ready to connect? Generate your first key →
Go to API Keys