Skip to main content
Glama
roman-zaglauer

OctoBot MCP Server

convert_profile_to_live

Convert a specified OctoBot profile to live trading type and select it, requiring explicit confirmation before applying the change.

Instructions

Relabel a profile as OctoBot's internal ProfileType.LIVE and select it. Confirm-gated (ADR-0003).

This tool does NOT enable real-money trading -- confirmed against OctoBot source, not just suspected (resolves requirements doc open question #5). Whether OctoBot actually places real orders is governed entirely by a separate config flag, config.trader.enabled, checked by OctoBot's own is_real_trading(profile) (semantically: returns trading_util.is_trader_enabled(profile.config), itself config[CONFIG_TRADER][CONFIG_ENABLED_OPTION] -- both confirmed against source, not a verbatim one-line quote of the actual multi-statement function body). models.convert_to_live_profile and models.select_profile (the two functions this tool's route calls -- see "Spec correction #1" below) both leave config.trader/config.trader-simulator completely untouched; only profile.profile_type (a label) changes. The one HTTP-visible route this project found that DOES set config.trader.enabled (_save_distribution_user_config, reached via save_prediction_market_configuration in OctoBot's web-interface source) is registered only when the running OctoBot instance's distribution is OctoBotDistribution.PREDICTION_MARKET -- an elif branch mutually exclusive with the DEFAULT distribution this project assumes throughout (confirmed against controllers/__init__.py::register()); it has nothing to do with OctoBot's onboarding wizard (a separate, always-registered controllers/welcome.py). This route is therefore unreachable on the ordinary/default OctoBot instance this server targets, not because of this project's own "onboarding" out-of-scope exclusion (a previous version of this docstring cited that exclusion; it was the wrong reason, even though the practical conclusion below still holds). As of this writing, this server has NO tool that can actually toggle real-vs-simulated trading on a default OctoBot instance. If you need that, it currently requires editing config.trader/config.trader-simulator in the profile's own saved config file directly (outside this server) and re-importing/re-selecting the profile -- there is no safer, HTTP-API-driven path this server can offer today.

If confirm is not exactly true, no OctoBot call is made at all -- this returns require_confirmation's structured refusal (a normal return, not an error) instead.

Once confirmed, maps to GET /profiles_management/use_as_live?profile_id=<id> (confirmed against source controllers/configuration.py's "use_as_live" action).

Spec correction #1, verified against source and reproduced live: this route's one non-raising code path calls models.convert_to_live_profile(profile_id) then models.select_profile(profile_id), flashes an HTML-only session message, and returns flask.redirect(flask.url_for("profile")) -- an HTTP 302 to /profile with no informative body at all, whether or not the conversion actually took effect. This is the same uninformative-GET-response category milestone 5 already found for duplicate (also a bare success marker) and select_profile (a 200 that can silently mean "nothing changed"). Following the same pattern select_profile established, this tool never trusts the response status alone: it re-fetches via the same scrape list_profiles/ get_profile use afterward and raises ProfileConversionFailedError if profile_id isn't selected there (see spec correction #2 for why only is_selected, not profile_type, is re-checked this way).

Spec correction #2 -- a genuine terminology collision in OctoBot's own data model, found live and confirmed against source, NOT just a misreading of this milestone's own instructions: is_selected/ profile_type were expected to both be independently re-verifiable post-hoc via the same scrape list_profiles uses (mirroring select_profile's pattern). is_selected is: the profile-overview-selected CSS class this scrape already parses reliably reflects models.select_profile(profile_id)'s effect. profile_type, however, is NOT reverified here, because the scrape's profile_type field (list_profiles/get_profile's "LIVE"/ "SIMULATOR"/"UNKNOWN") and the profile.profile_type attribute models.convert_to_live_profile actually sets are two unrelated OctoBot concepts that merely share a confusingly similar name:

  • The scrape's profile_type comes from the badge-info badge text, which is the return value of get_enabled_trader(profile) (confirmed against source flask_util/context_processor.py): "Real trading" iff trading_util.is_trader_enabled(profile.config), else "Simulated trading" iff is_trader_simulator_enabled, else no badge at all -- entirely about whether a real (vs. simulated) trader is enabled in that profile's OWN trading config.

  • models.convert_to_live_profile (confirmed against source models/profiles.py) only does profile.profile_type = commons_enums.ProfileType.LIVE; profile.validate_and_save_config(). octobot_commons.enums.ProfileType (confirmed against source) has exactly two members, LIVE = "live" and BACKTESTING = "backtesting" -- there is no SIMULATOR member at all, and this attribute is never rendered anywhere in /profiles_selector's HTML (confirmed by reading components/config/profiles.html and context_processor.py: neither references profile.profile_type).

Concretely (reproduced live against a freshly-duplicated, default SIMULATOR-trader profile): after a successful convert_profile_to_live call, the scrape's profile_type for that profile is still "SIMULATOR" -- convert_to_live_profile never touches the trader-enabled config the badge reflects. Gating this tool's success on profile_type == "LIVE" (as this milestone's own instructions originally called for) would therefore make it report failure on essentially every real invocation, which is worse than not checking it at all. There is no OctoBot HTTP-visible signal (Tier A or B) this server can use to independently confirm profile.profile_type flipped -- an acknowledged, documented gap (the same category as update_profile's undeliverable config field from milestone 5), not a silently-accepted assumption. This tool's "profile_type": "LIVE" in its own output below is therefore an echo of what was requested (and, per convert_to_live_profile's unconditional, non-branching implementation, reliably applied whenever this call doesn't raise -- see spec correction #3), not an independently re-scraped fact.

Spec correction #3, on why a non-5xx response is nonetheless a reasonably strong signal for the profile_type half specifically: unlike remove_profile's check-and-return-(result, err) pattern, convert_to_live_profile's body (confirmed against source) has no conditional branch that could skip the profile.profile_type = ProfileType.LIVE assignment -- it either runs to completion (assigns, then saves) or raises (propagating to the uncaught-500 path this tool already classifies as OctoBotServerError). A non-5xx response therefore does mean that assignment executed and was saved; the remaining genuine uncertainty this tool resolves by re-checking is only whether the immediately-following models.select_profile(profile_id) call (a separate function with its own historically-silent-failure mode for unknown ids, per select_profile's docstring) actually took effect -- which is exactly what the is_selected re-check above verifies.

An exception raised inside OctoBot's own handling (e.g. an unrecognized profile_id, which makes the underlying get_profile() raise) is not caught by this route at all, so it propagates to OctoBot's global error handler as an HTTP 500 -- classified here as OctoBotServerError, with the Content-Type: application/json request-header hint (same established technique as duplicate/select_profile/export_profile) so that handler's message is readable JSON instead of an HTML page.

Output on success: {"profile_id": str, "profile_type": "LIVE", "selected": true}.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
confirmNo
profile_idYes

Schema Changelog

Changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. First observedv0.1.0

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden, and it is exceptionally transparent. It discloses the confirm-gating behavior, the underlying HTTP route, the non-informative 302 response, the post-hoc re-check via is_selected, the profile_type verification gap, the conditions under which errors are raised, and the fact that non-5xx responses are only a reasonably strong signal rather than definitive proof.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely overlong and repetitive. It includes extensive source-code archaeology, multiple 'spec correction' sections, repeated phrases like 'confirmed against source,' and lengthy tangential explanations that go far beyond what is needed for an agent to call the tool. The front-loaded purpose is good, but almost every sentence after the first few could be substantially condensed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite its excessive length, the description is highly complete: it covers the tool's exact behavior, confirmation requirements, HTTP mapping, response limitations, error classification, verification strategy, known gaps, and success output shape. An agent has enough context to call the tool correctly and to understand the limits of what the result means.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains that profile_id is used in the underlying route and re-check, and it explains that confirm must be exactly true and that anything else produces a structured refusal. It does not provide a full formal parameter reference, but it gives enough operational meaning for both parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states exactly what the tool does: 'Relabel a profile as OctoBot's internal ProfileType.LIVE and select it.' It is a specific verb+resource statement that clearly differentiates this tool from siblings like select_profile, and the bold warning that it does NOT enable real-money trading removes a likely source of confusion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly explains when confirm is required, what happens if confirm is not exactly true, and explicitly warns that no server tool can toggle real-vs-simulated trading on a default OctoBot instance. It could be slightly stronger by explicitly naming select_profile as the alternative when only selection is needed, but the guidance is otherwise clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.