MCP service operations
This page is for the team operating ForwardFlow. Invited users connect to the existing hosted service using ChatGPT setup, Claude Code setup or the general connection guide.
Production service
The live MCP endpoint is https://btcnow-forwardflow.fly.dev/mcp. The research website is ff.btcnow.com; its API proxy does not serve MCP. Keep clients connected directly to the engine endpoint.
The hosted configuration in backend/fly.toml sets FF_MCP_ACCESS=keys. The server refuses to start if FF_API_KEYS is empty. Preserve this setting when deploying. The website’s own key belongs to the server and must not be distributed to invited parties.
Operator configuration and verification
Invite a small group
Access requests go to info@btcnow.com. Issue one named key per invited person or organisation and deliver it privately. The user guides call this an access token; it is the existing API key, not a new account or login system.
Start the pilot with two or three invited parties. Keep a private record of each key’s name, recipient and status; store its value in the secret manager. Do not publish a list of tokens or hand several parties the same key. Separate keys allow individual revocation and separate request allowances. Retain the website’s own key separately.
Issue, replace or revoke a token
- Generate a different random key for each party using a password manager or
openssl rand -hex 32on the operator’s machine. Keep the key in a secret manager; do not commit it or paste it into a conversation. Key names use letters, digits,-,_or., with at most 64 characters; keys must contain at least 24 characters. - Set
FF_API_KEYSin the engine’s deployment secrets to the complete list of named keys. For example, placeholders only:web:REPLACE_ME_web_key_0000000001,party-alpha:REPLACE_ME_alpha_key_00000002,party-beta:REPLACE_ME_beta_key_000000003. Preserve the cockpit’s key and all other active entries when adding a party. KeepFF_MCP_ACCESS=keys. - Give the party the HTTPS endpoint and only its own key through a private channel. The party configures its client’s credential settings once. The engine logs the key’s name, never its value. A key grants the existing model operations; there are no per-tool permission tiers or saved private records in this release.
- To rotate a key, replace that party’s secret and update its client. To revoke it, remove that named entry while retaining the others. Apply the new secrets and restart or roll every engine instance; new requests use the new key set after each instance restarts. Already running work is not retroactively cancelled. Existing cockpit websocket tokens have their own short expiry; MCP access keys are issued by the operator and remain valid until removed or replaced.
Shared capacity
The service accepts multiple users. Each request supplies its scenario; there is no single-user model session or shared editable scenario on the engine. Separate keys do not create separate machines.
The shared compute gate allows up to three active heavy calculations and eight waiting requests per process, subject to the shared memory budget. Each named key also has 120 requests per rolling minute and four concurrent heavy-route requests, shared across REST and MCP; every MCP request counts toward that concurrency limit. These limits are implemented in backend/src/api/forwardflow_api.rs and backend/src/access.rs.
The deployed configuration in backend/fly.toml uses two shared CPUs, 2 GB of memory and a 1.2 GB calculation-memory budget. A memory refusal or full queue returns a busy response with a retry interval. Website use consumes the same engine capacity. Limits protect the service; they do not establish a measured number of simultaneous users or a response-time guarantee. Check latency, busy responses and resource use during the pilot before expanding access. Multiple instances have independent counters, not a distributed quota. See capacity and lifecycle for precise error behavior.
Deployment controls and verification
FF_MCP_ALLOWED_HOSTS is a comma-separated exact host/authority allowlist, replacing the defaults localhost,127.0.0.1,[::1],btcnow-forwardflow.fly.dev. Add the real public hostname for a custom domain or tunnel. FF_MCP_ALLOWED_ORIGINS replaces the browser-origin defaults http://localhost:8080,http://127.0.0.1:8080,https://btcnow-forwardflow.fly.dev. Requests without an Origin header are allowed; a supplied Origin must match. Empty entries and wildcards are refused at startup. Configure FF_CORS_ORIGINS consistently for browser clients; CORS permission does not bypass MCP origin validation. These controls protect against browser-origin and DNS-rebinding abuse.
The production dependency is the official rmcp SDK, locked in backend/Cargo.lock. It requires Rust 1.88 or later; the Docker builder uses Rust 1.91. The invitation setup reuses the existing FF_API_KEYS deployment secret; it needs no account service, database or volume.
backend/tests/mcp.rs tests the real router and an official SDK client over a loopback HTTP listener. It covers numerical parity with the API, replay, comparison normalization, missing IRRs, unknown inputs, required keys, independent party revocation and rate allowances, host/origin/body limits, shared admission and cancellation. backend/tests/access.rs also verifies REST Bearer authentication. backend/tests/fixtures/mcp_prompts.json supplies 30 representative analyst prompts: 25 authored argument cases exercised by the server tests and five clarification/unsupported-action cases for evaluation in a real assistant. These fixtures do not claim measured natural-language accuracy. Run the tests with the full backend suite:
cd backend
cargo test --release --workspace
After each service change, deploy the tested source revision, verify its build header, connect a supported client such as Claude Code to the deployed HTTPS URL, and evaluate interpretation and follow-up questions. Local protocol tests do not validate a particular account’s permissions, proxy timeouts, or an assistant’s natural-language interpretation.
Local development only
To work on the engine itself, the development endpoint is http://localhost:8080/mcp. It refers to the developer’s own machine. Hosted clients should use the production endpoint above.
FF_MCP_ACCESS=inherit is the application default for development: it follows FF_API_KEYS, including anonymous access when unset. FF_MCP_ACCESS=open explicitly opens MCP even when REST is keyed. Neither is the production invitation setting.