Goblin Gains MCP
An MCP server that integrates Goblin Gains' coached workout library into AI assistants. It allows users to request, vary, or invent conditioning workouts based on available equipment and time, with results linked back to the app for logging.
Endpoint and access
No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.
https://api.goblingains.com/mcpWhat you can do with it
- Suggest a 20-minute workout with specific equipment
- Generate a Hyrox session for two people
- Invent a new 15-minute workout with a pull-up bar
Source and maintenance
Protocol and capabilities
- Server
- goblin-workouts 1.30.0
- MCP protocol
- 2025-06-18
- Tools
- 7 advertised
- Resources
- 0 advertised
- Resource templates
- 0 advertised
- Prompts
- 0 advertised
{
"tools": {
"listChanged": false
},
"prompts": {
"listChanged": false
},
"resources": {
"subscribe": false,
"listChanged": false
},
"experimental": {}
}Server-provided instructions
Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.
Tools
7 advertised
list_archetypes
The workout archetypes the generator makes, one per line: key, name, formats, minutes, line count, and the session slots it serves.
{
"type": "object",
"title": "list_archetypesArguments",
"properties": {
"style": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Style",
"default": null,
"description": "Keep only one style's archetypes: crossfit, hyrox or hybrid; all when omitted. Example: \"hyrox\"."
}
}
}{
"type": "object",
"title": "list_archetypesOutput",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"title": "Result"
}
}
}{
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}list_equipment
The equipment suggest_workouts' `equipment` takes, one per line: key: name, with "(machine)" on ergometers (rower, ski erg, bikes). Keys, names and common names ("echo", "row erg", "DB", "kb") all work.
{
"type": "object",
"title": "list_equipmentArguments",
"properties": {}
}{
"type": "object",
"title": "list_equipmentOutput",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"title": "Result"
}
}
}{
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}find_movements
Movement slugs whose name holds `query` (e.g. "row", "sled"), for suggest_workouts' include and exclude, machines and runs first.
{
"type": "object",
"title": "find_movementsArguments",
"required": [
"query"
],
"properties": {
"kind": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Kind",
"default": null,
"description": "Keep one movement kind only, one of strength, olympic, plyo, cyclic, carry, mobility (cyclic: row, ski, bike, run); all when omitted. Example: \"cyclic\"."
},
"query": {
"type": "string",
"title": "Query",
"maxLength": 100,
"description": "Text the movement name holds, any case. Example: \"sled\"."
}
}
}{
"type": "object",
"title": "find_movementsOutput",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"title": "Result"
}
}
}{
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}suggest_workouts
New workouts from our generator, as text. Ask this instead of writing workouts yourself. Nothing is saved. Example, two people with an echo bike, rower and ski erg, 40-60 min: suggest_workouts(count=5, people=2, minutes_min=40, minutes_max=60, equipment=["echo-bike", "row-ergometer", "ski-erg"], bodyweight=False) A shortfall says what blocked it.
{
"type": "object",
"title": "suggest_workoutsArguments",
"properties": {
"sex": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Sex",
"default": null,
"description": "Who trains, for the weights and machine doses: \"men\", \"women\", or \"mixed\" (a man and a woman together: each at their own; Hyrox stations at the mixed doubles race load). Omitted when the user did not say: every line reads both, men's/women's (\"9/6 kg\", \"12/10 kcal\"). Anything but men gets only workouts with a women's weight on every loaded line. Example: \"women\"."
},
"only": {
"type": "boolean",
"title": "Only",
"default": false,
"description": "True: the workouts hold the included movements and nothing else (each may repeat). Needs include. Example: true."
},
"count": {
"type": "integer",
"title": "Count",
"default": 3,
"maximum": 5,
"minimum": 1,
"description": "How many workouts, at most 5; from 3 on, a mix of archetypes (at most 2 of one unless nothing else fits). Example: 3."
},
"people": {
"type": "integer",
"title": "People",
"default": 1,
"maximum": 20,
"minimum": 1,
"description": "How many train together with one of each machine. Above 1, only workouts they can share come back: partner workouts (taking turns on a station), or EMOMs/intervals with a different machine on every line and at least one line per person (start apart, rotate). Example: 2."
},
"exclude": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 30
},
{
"type": "null"
}
],
"title": "Exclude",
"default": null,
"description": "Movement slugs or names (from find_movements) every workout must leave out. Example: [\"burpees\"]."
},
"include": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 30
},
{
"type": "null"
}
],
"title": "Include",
"default": null,
"description": "Movement slugs or names (from find_movements) every workout must hold. Example: [\"wallballs\", \"sled-push\"]."
},
"partner": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Partner",
"default": null,
"description": "True: only partner workouts (two people share the work: turns at a station, or each on a station at once, then swap). False: none. Omitted: either. Example: true."
},
"archetype": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Archetype",
"default": null,
"description": "A key or name from list_archetypes; any when omitted. Example: \"A5\" or \"chipper\"."
},
"equipment": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 30
},
{
"type": "null"
}
],
"title": "Equipment",
"default": null,
"description": "What the athletes have, as list_equipment keys or names (\"echo-bike\" or \"echo\", \"row erg\", \"ski erg\"), one item per entry. Say \"1 dumbbell\" or \"1 kettlebell\" when there is only one: movements needing a pair (farmers carry, dumbbell bench press) are left out. Other counts are ignored (\"1 echo\" is the echo bike): say how many train in people. Movements needing anything else (a bench press needs a bench) are left out; runs need \"running\" in the list. A name matching several keys or none is an error naming them. Example: [\"1 dumbbell\", \"box\", \"ski-erg\"]. Omitted is a full gym."
},
"bodyweight": {
"type": "boolean",
"title": "Bodyweight",
"default": true,
"description": "False also leaves out movements needing no equipment (burpees, runs), so only the listed equipment is used. Example: false."
},
"cap_minutes": {
"anyOf": [
{
"type": "integer",
"maximum": 240,
"minimum": 1
},
{
"type": "null"
}
],
"title": "Cap Minutes",
"default": null,
"description": "A time cap the workout must fit, in whole minutes. Example: 30."
},
"minutes_max": {
"anyOf": [
{
"type": "number",
"maximum": 240,
"minimum": 0
},
{
"type": "null"
}
],
"title": "Minutes Max",
"default": null,
"description": "Longest estimated workout length, in minutes. Example: 60."
},
"minutes_min": {
"anyOf": [
{
"type": "number",
"maximum": 240,
"minimum": 0
},
{
"type": "null"
}
],
"title": "Minutes Min",
"default": null,
"description": "Shortest estimated workout length, in minutes. Example: 40."
},
"show_scores": {
"type": "boolean",
"title": "Show Scores",
"default": true,
"description": "True adds a line of scores under each workout: feasibility (0-100, can it be done as written), difficulty (0-100, the chance of not finishing inside the cap), and against the workout it was made from: stimulus (0-1, CrossFit's stimulus kept, with the levers changed), work (x the seed's), mix shift (how far the work moved between movement patterns), design (0-1) and, for Hyrox workouts, race fidelity (0-1). Example: false."
},
"temperature": {
"type": "number",
"title": "Temperature",
"default": 0,
"description": "0 to 1. 0: the same ask always brings the same workouts. Above 0: other ones each call, the higher the further from the library workouts they vary (0.3 close variations, 1 far ones). Example: 0.3."
}
}
}{
"type": "object",
"title": "suggest_workoutsOutput",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"title": "Result"
}
}
}{
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": false,
"destructiveHint": false
}vary_workout
Variations of one library workout from our generator (no AI), as text, in its own format or another. Nothing is saved. A shortfall says what blocked it.
{
"type": "object",
"title": "vary_workoutArguments",
"required": [
"name"
],
"properties": {
"sex": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Sex",
"default": null,
"description": "Who trains, for the weights and machine doses: \"men\", \"women\", or \"mixed\" (a man and a woman together: each at their own; Hyrox stations at the mixed doubles race load). Omitted when the user did not say: every line reads both, men's/women's (\"9/6 kg\", \"12/10 kcal\"). Anything but men gets only workouts with a women's weight on every loaded line. Example: \"women\"."
},
"name": {
"type": "string",
"title": "Name",
"maxLength": 100,
"description": "The library workout's name or part of it, any case; several matches are an error listing them (up to 10) to ask again. Example: \"Fran\"."
},
"count": {
"type": "integer",
"title": "Count",
"default": 3,
"maximum": 5,
"minimum": 1,
"description": "How many variations, at most 5. Example: 3."
},
"format": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Format",
"default": null,
"description": "Turn it into this format first: for_time, amrap, emom, intervals. About its minutes: an EMOM gives each line its own minute when a round is over 40 s, intervals rest as long as a round's work. Omitted keeps its own. Example: \"emom\"."
},
"people": {
"type": "integer",
"title": "People",
"default": 1,
"maximum": 20,
"minimum": 1,
"description": "How many train together with one of each machine. Above 1, only workouts they can share come back: partner workouts (taking turns on a station), or EMOMs/intervals with a different machine on every line and at least one line per person (start apart, rotate). Example: 2."
},
"equipment": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 30
},
{
"type": "null"
}
],
"title": "Equipment",
"default": null,
"description": "What the athletes have, as list_equipment keys or names (\"echo-bike\" or \"echo\", \"row erg\", \"ski erg\"), one item per entry. Say \"1 dumbbell\" or \"1 kettlebell\" when there is only one: movements needing a pair (farmers carry, dumbbell bench press) are left out. Other counts are ignored (\"1 echo\" is the echo bike): say how many train in people. Movements needing anything else (a bench press needs a bench) are left out; runs need \"running\" in the list. A name matching several keys or none is an error naming them. Example: [\"1 dumbbell\", \"box\", \"ski-erg\"]. Omitted is the kit the workout already uses."
},
"bodyweight": {
"type": "boolean",
"title": "Bodyweight",
"default": true,
"description": "False also leaves out movements needing no equipment (burpees, runs), so only the listed equipment is used. Example: false."
},
"show_scores": {
"type": "boolean",
"title": "Show Scores",
"default": true,
"description": "True adds a line of scores under each workout: feasibility (0-100, can it be done as written), difficulty (0-100, the chance of not finishing inside the cap), and against the workout it was made from: stimulus (0-1, CrossFit's stimulus kept, with the levers changed), work (x the seed's), mix shift (how far the work moved between movement patterns), design (0-1) and, for Hyrox workouts, race fidelity (0-1). Example: false."
},
"temperature": {
"type": "number",
"title": "Temperature",
"default": 0.5,
"description": "0 to 1, how far they stray from it (0.2 close, 1 far). Example: 0.5."
}
}
}{
"type": "object",
"title": "vary_workoutOutput",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"title": "Result"
}
}
}{
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": false,
"destructiveHint": false
}generate_workouts
New workouts unlike any in the library, from our generator (no AI), as text: evolved from the library's workouts and movements (more lines, fewer, other formats) into kinds it does not hold. For one person. Nothing is saved; other ones each call. suggest_workouts and vary_workout stay close to library workouts instead. A shortfall says what blocked it.
{
"type": "object",
"title": "generate_workoutsArguments",
"properties": {
"sex": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Sex",
"default": null,
"description": "Who trains, for the weights and machine doses: \"men\", \"women\", or \"mixed\" (a man and a woman together: each at their own; Hyrox stations at the mixed doubles race load). Omitted when the user did not say: every line reads both, men's/women's (\"9/6 kg\", \"12/10 kcal\"). Anything but men gets only workouts with a women's weight on every loaded line. Example: \"women\"."
},
"count": {
"type": "integer",
"title": "Count",
"default": 3,
"maximum": 5,
"minimum": 1,
"description": "How many workouts, at most 5. Example: 3."
},
"format": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Format",
"default": null,
"description": "Only this format: for_time, amrap, emom, intervals. Any when omitted. Example: \"amrap\"."
},
"exclude": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 30
},
{
"type": "null"
}
],
"title": "Exclude",
"default": null,
"description": "Movement slugs or names (from find_movements) every workout must leave out. Example: [\"burpees\"]."
},
"include": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 30
},
{
"type": "null"
}
],
"title": "Include",
"default": null,
"description": "Movement slugs or names (from find_movements) every workout must hold; fewer come back the more are named. Example: [\"wallballs\"]."
},
"equipment": {
"anyOf": [
{
"type": "array",
"items": {
"type": "string",
"maxLength": 100
},
"maxItems": 30
},
{
"type": "null"
}
],
"title": "Equipment",
"default": null,
"description": "What the athletes have, as list_equipment keys or names (\"echo-bike\" or \"echo\", \"row erg\", \"ski erg\"), one item per entry. Say \"1 dumbbell\" or \"1 kettlebell\" when there is only one: movements needing a pair (farmers carry, dumbbell bench press) are left out. Other counts are ignored (\"1 echo\" is the echo bike): say how many train in people. Movements needing anything else (a bench press needs a bench) are left out; runs need \"running\" in the list. A name matching several keys or none is an error naming them. Example: [\"1 dumbbell\", \"box\", \"ski-erg\"]. Omitted is a full gym."
},
"bodyweight": {
"type": "boolean",
"title": "Bodyweight",
"default": true,
"description": "False also leaves out movements needing no equipment (burpees, runs), so only the listed equipment is used. Example: false."
},
"minutes_max": {
"anyOf": [
{
"type": "number",
"maximum": 240,
"minimum": 0
},
{
"type": "null"
}
],
"title": "Minutes Max",
"default": null,
"description": "Longest estimated workout length, in minutes. Example: 25."
},
"minutes_min": {
"anyOf": [
{
"type": "number",
"maximum": 240,
"minimum": 0
},
{
"type": "null"
}
],
"title": "Minutes Min",
"default": null,
"description": "Shortest estimated workout length, in minutes. Example: 10."
},
"show_scores": {
"type": "boolean",
"title": "Show Scores",
"default": true,
"description": "True adds a line of scores under each workout: feasibility (0-100, can it be done as written), difficulty (0-100, the chance of not finishing inside the cap), and against the workout it was made from: stimulus (0-1, CrossFit's stimulus kept, with the levers changed), work (x the seed's), mix shift (how far the work moved between movement patterns), design (0-1) and, for Hyrox workouts, race fidelity (0-1). Example: false."
}
}
}{
"type": "object",
"title": "generate_workoutsOutput",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"title": "Result"
}
}
}{
"readOnlyHint": true,
"openWorldHint": false,
"idempotentHint": false,
"destructiveHint": false
}report_workout
Send Goblin Gains what the user thinks of a workout from these tools. Call it whenever the user points out a mistake (wrong equipment, a weight, a dose that cannot fit) or says a workout is bad or good: the words go to Goblin Gains, nothing else about the user does.
{
"type": "object",
"title": "report_workoutArguments",
"required": [
"note",
"verdict"
],
"properties": {
"note": {
"type": "string",
"title": "Note",
"maxLength": 2000,
"minLength": 1,
"description": "What the user said about the workout, in their words. Example: \"Farmers carry needs two dumbbells; I said I have one.\""
},
"verdict": {
"type": "string",
"title": "Verdict",
"maxLength": 100,
"description": "One of mistake, bad, good: \"mistake\" (something in it is wrong), \"bad\" (it works but is a poor workout), \"good\". Example: \"mistake\"."
},
"workout": {
"anyOf": [
{
"type": "string",
"maxLength": 100
},
{
"type": "null"
}
],
"title": "Workout",
"default": null,
"description": "The workout's save link from suggest_workouts, vary_workout or generate_workouts, or its id; omitted for the tools as a whole. Example: \"https://app.goblingains.com/w/<id>\"."
}
}
}{
"type": "object",
"title": "report_workoutOutput",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"title": "Result"
}
}
}{
"readOnlyHint": false,
"openWorldHint": false,
"idempotentHint": false,
"destructiveHint": false
}Prompts
0 advertised
Resources
0 advertised
30-day availability
Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.
- Successful checks
- 1 of 1 (100%)
- Average latency
- 1215 ms
- 95th percentile latency
- 1215 ms
Maintenance history
Public check and source-refresh events. Editorial and ownership records remain private.
- · probe · passed · 1215 ms · metadata changed · 7 tool(s), 0 resource(s), 0 resource template(s), 0 prompt(s)
Connect from your client
Each snippet registers the same endpoint; pick the client you use.
Claude Code
claude mcp add --transport http goblin-gains-mcp https://api.goblingains.com/mcpCodex
codex mcp add goblin-gains-mcp --url https://api.goblingains.com/mcpCursor
{
"mcpServers": {
"goblin-gains-mcp": {
"url": "https://api.goblingains.com/mcp"
}
}
}Cline
{
"mcpServers": {
"goblin-gains-mcp": {
"type": "streamableHttp",
"url": "https://api.goblingains.com/mcp",
"disabled": false
}
}
}VS Code
{
"servers": {
"goblin-gains-mcp": {
"type": "http",
"url": "https://api.goblingains.com/mcp"
}
}
}Gemini CLI
gemini mcp add --transport http goblin-gains-mcp https://api.goblingains.com/mcpClaude Desktop
{
"mcpServers": {
"goblin-gains-mcp": {
"url": "https://api.goblingains.com/mcp"
}
}
}Windsurf
{
"mcpServers": {
"goblin-gains-mcp": {
"serverUrl": "https://api.goblingains.com/mcp"
}
}
}Let your agent find its tools
Find servers like Goblin Gains MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.
Other productivity and knowledge servers
Do you run Goblin Gains MCP?
Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.