Documentation

Connect AI Tools with MCP

Connect an MCP-compatible AI client to your private rslts.run training and team data.

The rslts.run Model Context Protocol (MCP) endpoint lets supported AI clients read the training, race, notebook, and team data your account can access. OAuth connections and read API keys are read-only. Write API keys can save weekly planner workouts and daily briefs as drafts, and explicitly publish planner weeks.

The endpoint supports OAuth, the standard MCP sign-in flow, so a chat app that can add a custom MCP server by URL connects without an API key. Desktop and command-line tools can use either that flow or an API key you paste into their configuration.

Connect from a chat app

  1. In the app, open its connectors or connected-apps settings and add a custom MCP server.
  2. Enter the server URL https://rslts.run/mcp and connect. Leave any client ID or secret fields empty; rslts.run registers the client automatically.
  3. Your browser opens rslts.run. Sign in if asked, read what will be shared, and click Approve.
  4. You are returned to the app, which can now use the tools listed below.

In Claude on the web, one link does the first two steps for you:

Add rslts.run to Claude

It opens Claude’s Add custom connector dialog with the name and URL already filled in, and tells you the values came from an outside link. Nothing is added until you confirm, and you still approve the connection on rslts.run afterwards. If you are signed out of Claude, you sign in first and land on the same dialog.

Where each app keeps this setting, and which plans include it:

  • ChatGPT: Settings → Apps → Advanced settings → Developer mode, then Settings → Connectors → Create. Developer mode is on ChatGPT for web only, for Plus, Pro, Business, Enterprise, and Edu accounts; a free account cannot add a custom MCP server. See OpenAI’s Developer mode and MCP apps in ChatGPT.
  • Claude: Settings → Connectors → Add custom connector, on Claude for web, Cowork, and Claude Desktop. Every plan can add one, including Free, which is limited to a single custom connector. See Anthropic’s Get started with custom connectors using remote MCP.
  • Gemini: Settings → Connected Apps → Custom apps for Spark. Available on personal Google Accounts for users 18 or over in the US, with Keep Activity on. See Google’s Connect and manage custom apps for Gemini Spark.

Any other client that implements the MCP authorization flow (OAuth 2.1 with dynamic client registration or a Client ID Metadata Document, and PKCE) should work the same way.

The connection lasts 90 days. After that the client asks you to reconnect, and you approve again. To disconnect sooner, open the Developer page and click Disconnect under Connected apps. Disconnecting takes effect immediately.

Approving a connection shares the same data an API key would: every athlete and team your account can read. If you coach, that includes team athletes who are minors. The approval screen says so before you confirm.

For client developers: discovery follows the MCP authorization specification. Protected resource metadata is at https://rslts.run/.well-known/oauth-protected-resource/mcp and authorization server metadata at https://rslts.run/.well-known/oauth-authorization-server. Dynamic client registration and Client ID Metadata Documents are both accepted; PKCE with S256 is required; the only scope is read; no refresh tokens are issued. A client must be able to authenticate at the token endpoint as a public client (none); a document that prefers private_key_jwt is accepted as long as it also lists none. Vendor notes on what their apps expect from a server: OpenAI’s Building MCP servers and Anthropic’s Authentication for connectors.

Connect with an API key

Create a read API key for reading data, or a write API key for editing planner drafts, from the Developer page. Copy the key when it appears; the complete key is shown only once.

The key has this form:

rr_read_KEY_ID_SECRET

Treat the complete key like a password. Anyone who has it can read the same rslts.run data until the key expires or is revoked.

Connection details

Use these values in any client that supports remote HTTP MCP servers:

Setting Value
Name rslts-run
Transport Streamable HTTP
URL https://rslts.run/mcp
Header Authorization: Bearer rr_read_KEY_ID_SECRET

Replace rr_read_KEY_ID_SECRET with the complete key you copied. Do not include quotation marks in a client’s header field unless its configuration format requires them.

For planner writes, use your complete rr_write_KEY_ID_SECRET key in the same header or configuration examples. A write key also supports all read tools and inherits your account’s team management permissions.

JSON configuration

Clients such as Cursor and Claude Desktop can use an HTTP server entry like this:

{
  "mcpServers": {
    "rslts-run": {
      "type": "http",
      "url": "https://rslts.run/mcp",
      "headers": {
        "Authorization": "Bearer rr_read_KEY_ID_SECRET"
      }
    }
  }
}

Where the client stores this configuration depends on the client and operating system. Restart the client after changing its MCP configuration if it does not reload servers automatically.

Command-line clients

Some clients take the same values as a command. Claude Code, for example:

claude mcp add --transport http rslts-run https://rslts.run/mcp \
  --header "Authorization: Bearer rr_read_KEY_ID_SECRET"

Verify the connection

Ask the client:

Use the rslts-run whoami tool and tell me which account and teams this key can access.

A successful response confirms that the client can reach the endpoint and authenticate. If your client can display MCP tools, you should also see the tools listed below.

Ways to use it

Start by asking the model to find an athlete or team, then use the returned ID for more detailed tools. For example:

  • “Find Jordan Example, summarize the last 30 days of training, and call out any abrupt load changes.”
  • “Compare Jordan Example’s last four training weeks. Separate volume, intensity, and consistency.”
  • “Review Jordan Example’s most recent race alongside the preceding training week.”
  • “Summarize the Example Track Club roster’s training for this week and identify athletes with sparse data.”
  • “Show the newest notebook threads that need a coach response, then open the relevant threads.”

Names are convenient for discovery, but detailed tools use stable athlete, team, activity, result, run, or thread IDs. Let the client call a list tool first instead of guessing an ID.

Available tools

Account and athletes

  • whoami() — shows the account and teams available to the key.
  • list_athletes(team_id?, query?, limit?, cursor?) — finds accessible athletes and their IDs.
  • get_athlete_overview(athlete_id, window?) — summarizes an athlete over a window such as 30d, 90d, or 1y.

Activities and training

  • list_activities(athlete_id, from?, to?, activity_type?, limit?, cursor?) — lists an athlete’s activities with optional date and type filters.
  • get_activity(athlete_id, activity_id, include_samples?, include_coach_notes?) — returns one activity, with optional samples and coach notes.
  • get_training_week(athlete_id, week_start) — returns one athlete’s training week. Use an ISO date for week_start. week_start must be a Monday.
  • list_daily_totals(athlete_id, from, to, timezone?) — returns per-day running and cross-training totals for any date range up to 31 days. Use this for windows that do not run Monday to Sunday. Days with no activity are included as zero rows, and the day totals add up to the same figures get_training_week reports for the same span. timezone is an IANA name such as America/Denver and only affects which day is marked is_today.

Races and plans

  • list_race_results(athlete_id?, team_id?, season?, limit?, cursor?) — lists results for either an athlete or a team. Provide exactly one of athlete_id or team_id.
  • get_race_review(athlete_id, result_id) — returns a detailed review of one race result.
  • get_race_plan(team_id, run_id, athlete_id) — returns one athlete’s report from a saved team race-plan run.

Notebook

  • get_notebook_feed(athlete_id?, team_id?, filter?, include_full_threads?, limit?, cursor?) — lists notebook activity for an athlete or team.
  • get_notebook_thread(thread_id) — opens one complete notebook thread.

Teams

  • list_teams() — lists teams available to the key.
  • get_team_roster(team_id, include_tags?, include_contacts?, limit?, cursor?) — returns roster entries, with optional tags and contacts.
  • get_team_training(team_id, date?, week_start?) — summarizes team training for a day or week.

Weekly planner and daily briefs

These tools require team management access. Saving requires a write API key; OAuth connections remain read-only.

  • get_planner_week(team_id, plan_id, week_start, status?) — reads a draft by default, including inherited workouts; status can also be published. Discover plan IDs with get_team_training.
  • save_planner_week(team_id, plan_id, week_start, assignments, scope?) — replaces the complete workout list in a draft. Read the week first and include every workout you want to keep. Dates use YYYY-MM-DD; the week starts on Monday. Assignment fields are assignment_date, title, assignment_type (running, weights, xt, or other), and optional assigned_distance_m, assigned_duration_seconds, details_raw, and display_order. scope defaults to forward; repeating plans carry the week forward when published. once applies only to that week and requires a repeating plan.
  • publish_planner_week(team_id, plan_id, week_start) — publishes the existing draft when explicitly requested.
  • list_daily_briefs(team_id, start_date, end_date?) — lists briefs including drafts, with an inclusive start and exclusive end (default seven days, maximum 90).
  • save_daily_brief(team_id, applicable_date, athlete_id?, tag_ids?, title?, body?, id?) — saves a text-only draft. Choose one athlete or nonempty tags. Supply the returned id for edits; omitting it creates a new brief. Briefs with attachments must be edited in the planner. Schedule briefs in the planner when ready to send.

Draft saves do not publish workouts or schedule brief notifications. Week saves replace existing drafts; they do not detect concurrent edits. Creating a brief again without its saved ID creates another brief, so check the list after an uncertain response before retrying.

Pagination

List tools return up to 50 items by default and accept a maximum limit of 200. When a response includes a non-null next_cursor, pass that value unchanged as cursor in the next call. A null next_cursor means there are no more results.

Continuation tokens are signed and can reveal only the next page permitted by the same API key. Do not edit or construct them; an invalid or mismatched cursor is rejected.

Access and privacy

The API key inherits your account’s current access. An individual account can read its accessible athletes. A coach or team key can also expose data for team athletes, including minors, within that account’s permissions. Depending on the tool, this can include training details, race results, notebook conversations, roster metadata, and contact information.

There is currently no narrower per-key athlete or team scope. Use the shortest practical expiration, avoid pasting keys into prompts or messages, and revoke keys that are no longer needed. Revoking a key immediately disconnects every client using it.

Troubleshooting

Result What to check
401 Unauthorized The bearer header is missing, the complete key was not copied, or the key expired or was revoked.
403 Forbidden The account does not have access to the requested athlete, team, or record. Discover available IDs with whoami, list_athletes, or list_teams.
400 Bad Request A required argument is missing, a date or window is invalid, or a cursor does not belong to this key and query.
404 Not Found The requested record does not exist or is not visible to this account.
405 Method Not Allowed The client is not using the MCP Streamable HTTP transport. The endpoint accepts MCP requests over POST.
429 Too Many Requests The client is sending requests too quickly. Wait briefly and retry with fewer concurrent calls.
The client says it could not reach or connect to the server For a hosted client, confirm the URL is exactly https://rslts.run/mcp, then retry. If your browser never opened rslts.run, the client could not read https://rslts.run/.well-known/oauth-authorization-server.

If authentication works but a model does not use the server, explicitly tell it to use the rslts-run tools and begin with whoami.

Disconnect

Remove the rslts-run server from the client to disconnect that client. To disable the credential everywhere, revoke the API key from the Developer page. A connection approved through the sign-in flow is listed under Connected apps on the same page.