MCP Tool Reference
The complete surface of the Folio Lab MCP server: 43 tools and 5 resources. For each tool, this page gives the OAuth scope it checks, the MCP annotations it declares, its main arguments and what it is for. The AI assistants overview covers how to connect.
How to Read the Tables
- Scope is the OAuth scope the token must carry. The server defines six:
runs:read,runs:write,analytics:read,templates:read,catalog:readanddocs:read. - Hints are the MCP tool annotations. read-only changes nothing. destructive tells a client that the tool changes account state and should be confirmed. idempotent means a repeat call has no further effect. open world means the tool reads an outside source, such as a market data provider or the live docs site.
- Arguments list the main parameters. Every constrained parameter publishes its full list of legal values in the tool schema.
Find securities and funds
Call these before a submission. The submission tools take exact symbols and scheme codes, and an assistant should never guess one.
| Tool | Scope | Hints | Arguments | Purpose |
|---|---|---|---|---|
search_stocks | catalog:read | read-only | query, exchange, limit | Resolve a company name or partial symbol to NSE and BSE listings. |
resolve_ticker | catalog:read | read-only | name_or_symbol, exchange | The single best listing for one name, NSE preferred when both list it. Returns no match rather than a guess. |
search_us_stocks | catalog:read | read-only, open world | query | Resolve a company name or partial ticker to NYSE and NASDAQ equities. |
search_mutual_funds | catalog:read | read-only, open world | query, asset_class, limit | Find Indian mutual funds by name and return the AMFI scheme_code a fund run takes. |
import_holdings | catalog:read | read-only, open world | sheets or file_base64 (one of the two) | Read a Zerodha or Groww holdings export into two separate starting portfolios, stocks and funds, each with submit_arguments to pass to submit_optimization. Lists what it excluded and what it could not match, with their weights. The file is at most 2 MB. |
Constraints
Read config://constraint_capability before offering a constrained portfolio: not every method can enforce every family of rule.
| Tool | Scope | Hints | Arguments | Purpose |
|---|---|---|---|---|
preview_constraints | runs:write | read-only | tickers, constraints, exchange | Check rules against a universe before a run is spent: whether they can be stated, whether any portfolio satisfies all of them together, and what each group can reach under the others. Uses no run and no quota. |
list_classification_maps | runs:read | read-only | none | Every saved classification list on the account, with the map_id a constraint block's saved_classifications field takes. Reading only: a list cannot be created or edited over MCP. |
Submit and manage runs
Each submission returns an id at once and runs asynchronously. Poll the matching status tool, then read the result.
| Tool | Scope | Hints | Arguments | Purpose |
|---|---|---|---|---|
submit_optimization | runs:write | destructive | tickers or mutual_funds, methods, benchmark, benchmark_basis, exchange, rolling_backtest and its fields, constraints, mode, current_weights | Optimize Indian stocks or Indian equity mutual funds, never both in one run. Can carry an inline walk-forward backtest for the portfolio being optimized now. |
submit_us_optimization | runs:write | destructive | tickers, methods, benchmark, risk_free_tenor, rolling_backtest and its fields, constraints | Optimize NYSE and NASDAQ equities. A run cannot mix US and Indian assets. |
submit_backtest | runs:write | destructive | run_id, methods, rebalance_frequency, window_type, window_length_years | A standalone walk-forward backtest against a succeeded run, on that run's frozen inputs. Use this, not a second submit_optimization, to backtest a run that already exists. |
submit_monte_carlo | runs:write | destructive | run_id, method, horizon_years, path_count, cash flows, goal, return_process, scenarios, rebalance_mode, tax, inflation, seed and further settings | A forward Monte Carlo simulation on a succeeded run of Indian stocks. Every probability is conditional on the selected model, the frozen inputs, the configuration, the engine version and the seed. |
cancel_job | runs:write | destructive | run_id, kind | Cancel one queued or running optimization, simulation or backtest. A job that already finished returns 409. |
rename_run | runs:write | destructive, idempotent | run_id, name | Set a display name of at most 120 characters. An empty name restores the default. |
tag_run | runs:write | write, idempotent | run_id, tag_name, tag_color | Attach a tag to a run. Tagging twice has the effect of tagging once. |
untag_run | runs:write | destructive, idempotent | run_id, tag_name | Remove one tag from a run. Returns 404 when the tag was not applied. |
delete_run | runs:write | destructive | run_id | Permanently delete a run and everything attached to it: simulations, backtests, artifacts, metrics, weights, tags and comparison membership. It cannot be undone and it does not return quota. |
Status, results and history
Every run-related response carries a result_url. An assistant should show it as a link: the web page is the full interactive view.
| Tool | Scope | Hints | Arguments | Purpose |
|---|---|---|---|---|
get_job_status | runs:read | read-only | run_id | Poll an optimization run's lifecycle state. |
get_job_result | runs:read | read-only | run_id, include, methods | Weights, metrics and per-asset statistics of a succeeded run, with a compact headline block. include and methods narrow the payload. |
get_job_config | runs:read | read-only | run_id | The inputs a run was submitted with. For reading back, not for resubmitting. |
list_recent_runs | runs:read | read-only | limit, cursor, search, status, tag, market, mode, constraints | Optimization runs, newest first, cursor paginated, with facet filters. |
list_active_jobs | runs:read | read-only | none | Everything still queued or running, across all three job kinds. |
get_monte_carlo_result | runs:read | read-only | mc_run_id | Status and results of one simulation, with the interpretation lines and the assumptions block that must be presented together with any probability. |
list_monte_carlo_runs | runs:read | read-only | run_id | The simulations of one parent run, newest first. |
list_all_monte_carlo_runs | runs:read | read-only | limit (1 to 100, default 20), cursor | Every simulation on the account, with its parent run id and name. |
get_backtest_result | runs:read | read-only | backtest_run_id | Per-period weights and turnover, out-of-sample metrics and Sharpe inference of one standalone backtest. |
list_backtest_runs | runs:read | read-only | run_id | The standalone backtests of one parent run, newest first. |
list_all_backtest_runs | runs:read | read-only | limit (1 to 100, default 20), cursor | Every standalone backtest on the account, with its parent run id and name. |
list_run_tags | runs:read | read-only | none | Every tag in use on the account, with its colour and the number of runs that carry it. |
list_templates | templates:read | read-only | none | The saved optimization templates on the account. |
Compare and analyse
In-sample optimizer metrics and out-of-sample backtest metrics are different populations. These tools keep them apart through kind.
| Tool | Scope | Hints | Arguments | Purpose |
|---|---|---|---|---|
compare_runs | runs:read | read-only | run_ids, metrics, kind, page_size, cursor, detail, groups, curve_methods | Side-by-side metrics for up to 5 runs at once, or up to 100 in pages, or a run against its backtest. |
search_runs_by_metric | runs:read | read-only | metric, operator (gt, gte, lt, lte), value, limit, kind, market, mode, constraints | Runs whose metric passes a threshold. There is no equality operator: bracket a value with gte and lte. |
get_analytics_summary | analytics:read | read-only | market, mode, constraints, benchmark, basis, tag, date_from, date_to | Cross-run totals and per-method aggregates. Pass market: Indian and US runs use different currencies, benchmarks and risk-free rates. |
explain_metric | catalog:read | read-only | metric_name | A short explanation of a metric, with its docs URL and up to three related pages. Accepts keys and common names. |
Charts, reports and files
Chart tools return JSON arrays under 25 KB for the assistant to draw. The server never returns an image.
| Tool | Scope | Hints | Arguments | Purpose |
|---|---|---|---|---|
get_chart_data | runs:read | read-only, open world | run_id, chart (weights, metrics, cumulative_returns, backtest), top_n, methods, run_ids | A chart packet for an optimization run. backtest is available only for a run submitted with an inline rolling backtest. |
get_backtest_chart_data | runs:read | read-only, open world | backtest_run_id, methods | The walk-forward equity curve of one standalone backtest, one point per rebalance period, with the benchmark rebased to the start. |
get_monte_carlo_chart_data | runs:read | read-only, open world | mc_run_id, chart (eleven packets), basis, metric, view | A chart packet for a succeeded simulation: wealth_fan, goal_probability, terminal_quantiles, path_metric, drawdown_state, scenarios, metric_suite, weight_paths, goal_ladder, annualized_return or paired_comparison. |
get_run_artifacts | runs:read | read-only | run_id | Every stored artifact of a run, each with a signed download URL valid for one hour. |
request_pdf_report | runs:write | destructive | run_id, kind (optimization, monte_carlo, backtest) | Start PDF generation for one report. Idempotent: a report that exists returns ready, and a request for one that cannot exist yet has no effect. |
get_report_status | runs:read | read-only | run_id, kind | absent, queued, rendering, ready or failed. Poll this rather than requesting the report again. |
get_report_files | runs:write | write | run_id, generate_missing_pdf, kinds | One-hour download links for each report's PDF and Excel file. It can start a missing PDF, which is why it needs the write scope. |
Documentation
For a conceptual question an assistant should cite these pages rather than answer from memory.
| Tool | Scope | Hints | Arguments | Purpose |
|---|---|---|---|---|
list_docs | docs:read | read-only | section | Documentation pages with canonical URLs, optionally for one section. |
search_docs | docs:read | read-only | query, section, limit | Ranked pages for a query, with the full URL to cite. |
get_doc | docs:read | read-only, open world | path_or_url | The live content of one docs page. Refuses a URL outside the docs. |
Resources
Each resource is generated from the server-side definition it describes, so a new method or benchmark cannot be missing from it.
| URI | Contents |
|---|---|
config://methods | Every selectable optimization method, with a one-line description of each. |
config://benchmarks | Every Indian benchmark key, with its index name. |
config://us_benchmarks | The three US benchmarks: sp500, nasdaq_100 and russell_3000, each a total-return series through an exchange-traded fund. |
config://constraint_capability | For each method and each family of rule (per-name bounds, group sums, each_member): direct, or unsupported with the reason. The same table the web app and the report attestation read. |
config://fund_manager_mode | What mode="fund_manager" enforces, what it does not provide, its Enterprise entitlement and its default benchmark. Read it before offering the mode. |
Plan Gates
A plan gate applies when a tool spends something or uses a gated capability. Reading a run that already exists is never gated, even after a plan changes.
| Tool | Gate |
|---|---|
Any tool | A Pro or Enterprise plan. The connection is refused for a Free account. |
submit_optimization | The monthly optimization quota: Pro 50, Enterprise unlimited. mutual_funds needs a plan with fund runs. constraints needs Enterprise. mode="fund_manager" needs Enterprise. current_weights needs Pro or Enterprise. |
submit_us_optimization | Pro or Enterprise, and the same monthly optimization quota. constraints needs Enterprise. |
submit_backtest | The monthly backtest quota: Pro 50, Enterprise unlimited. |
submit_monte_carlo | The separate Monte Carlo quota: Pro 20 runs a month and at most 50,000 paths; Enterprise unlimited runs and at most 100,000 paths. The selectable return processes also depend on the plan. |
preview_constraints | Enterprise, the same entitlement that gates constraints at submission. |
list_classification_maps | None. A list saved while the plan allowed constraints stays readable afterwards; the gate sits on the submission. |
Errors
A tool reports a refusal as a tool error whose text reaches the assistant. Four shapes exist:
- A missing scope names the tool, the scopes it needs and the scopes the token has. Reconnect the connector and approve the scope.
- A plan refusal names the capability and the plan, for example a constraints request on a plan without the constraints entitlement.
- A refusal from the service is the HTTP status and its detail, in the form
<status>: <detail>. A 404 means the id is not on this account; a 409 fromcancel_jobmeans the job had already finished. - An unexpected failure is reported only as
Error calling tool '<name>'. The detail is withheld on purpose.
access denied: tool 'submit_backtest' requires scopes ['runs:write']; token has ['catalog:read', 'docs:read', 'runs:read'] 409: <detail naming the state the job was already in> Error calling tool 'get_job_result'
Some tools return a result object with an error field instead of a tool error, for example import_holdings when a file matches neither broker layout, and submit_optimization when a method name is not recognised, with the full list of valid names.
Links Back to the Web App
The result_url on a response opens the matching page. The page needs a sign-in to the same account that owns the run.
| Object | URL pattern |
|---|---|
| An optimization run | https://www.foliolab.ai/results/{run_id} |
| A simulation | https://www.foliolab.ai/results/{run_id}/monte-carlo?mc={mc_run_id} |
| A standalone backtest | https://www.foliolab.ai/backtests/{backtest_run_id} |
| An inline rolling backtest | https://www.foliolab.ai/results/{run_id}/rolling |
Connection and Token Lifetimes
- Discovery. A client finds the authorization server at
/.well-known/oauth-authorization-serverand the protected resource at/.well-known/oauth-protected-resource, which also answers under the resource path, for example/.well-known/oauth-protected-resource/mcp. - Client identity. A client either registers at
POST /oauth/registeror presents an HTTPS URL to a client ID metadata document as itsclient_id, which is how ChatGPT connects. - The flow. Authorization code with PKCE. Only the
S256challenge method is accepted. An authorization code is valid for 10 minutes. - Tokens. An access token is valid for 15 minutes. A refresh token is valid for 30 days and is replaced at every use.
- Plan checks. The plan is checked when you approve the connection and again at every refresh. A plan that no longer carries MCP access makes the next refresh fail.
- Revocation. Revoking a connector in account settings ends its refresh tokens at once, so the next refresh fails. An access token already issued stays valid until it expires, which is at most 15 minutes later.
What an Assistant Must Not Do
- Present a Monte Carlo probability without its
assumptionsblock. Probabilities are conditional on the selected model, the frozen optimizer-time inputs, the effective configuration, the engine version and the seed. No return generator has been validated out of sample, and none is a calibrated forecast. - Present a backtest as expected future performance, or a favourable backtest as evidence that a policy will outperform.
- Resubmit an existing portfolio through
submit_optimizationto attach a backtest. That spends a second run and refits the weights;submit_backtestholds the parent's frozen inputs.
Not investment advice. Past performance is not indicative of future results.