{
  "openapi": "3.0.1",
  "info": {
    "title": "Fluid Board Manager MCP API",
    "version": "1.0.0",
    "description": "Curated MCP-facing definition for kanban board lookup, card (item) listing, and card status mutations. Hand-authored with inline request schemas so MCP bridges expose typed parameters and bodies."
  },
  "servers": [
    {
      "url": "https://{tenant}.fluid.work",
      "description": "Your Fluid tenant. Replace {tenant} with your organisation's subdomain.",
      "variables": {
        "tenant": {
          "default": "your-tenant",
          "description": "Fluid tenant subdomain, e.g. 'acme' for https://acme.fluid.work. Sandbox tenants use '{tenant}-sandbox'."
        }
      }
    }
  ],
  "security": [
    {
      "basicAuth": []
    }
  ],
  "tags": [
    {
      "name": "Board Manager",
      "description": "Kanban board lookup, card listing, and card status mutations."
    }
  ],
  "paths": {
    "/rest/api/board-manager/find": {
      "get": {
        "tags": [
          "Board Manager"
        ],
        "summary": "Find boards by name",
        "description": "Finds boards whose name matches the query. Returns board metadata including PrincipalGuid, ProcessGuid, and column definitions. Use the returned PrincipalGuid with the other board-manager operations.",
        "operationId": "bm-find-boards",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Board name search text (case-insensitive)."
          },
          {
            "name": "skip",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Number of results to skip (paging)."
          },
          {
            "name": "take",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 50
            },
            "description": "Number of results to return (max 50)."
          }
        ],
        "responses": {
          "200": {
            "description": "Matching boards with column definitions. Custom property definitions are not included here - call bm-get-board for those."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    },
    "/rest/api/board-manager/board": {
      "get": {
        "tags": [
          "Board Manager"
        ],
        "summary": "Get a board by PrincipalGuid",
        "description": "Returns board metadata and column definitions for a single board identified by its PrincipalGuid. Also returns the board's custom property definitions, which are the source of truth for valid propKey/propValue combinations on bm-get-items.",
        "operationId": "bm-get-board",
        "parameters": [
          {
            "name": "principalGuid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The board's PrincipalGuid."
          }
        ],
        "responses": {
          "200": {
            "description": "Board metadata and column definitions. Also returns customProperties: the custom property DEFINITIONS for cards on this board (key, dataType, options, required). Read these to learn the valid propKey names and option values before filtering bm-get-items. The value on a definition is the board-level default, not any card's value."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    },
    "/rest/api/board-manager/items": {
      "get": {
        "tags": [
          "Board Manager"
        ],
        "summary": "List cards (items) on a board",
        "description": "Lists the cards on a board. A card is an Action scoped to the board. Optional filters: filter='backlog' (items not in any sprint), 'uncompleted' (not in a completed column and not archived), 'archived' (archived items), or omit for all active items. status filters to a specific column state (e.g. 'In Development'). assignee='me' returns only cards assigned to the current user. Set includeCustomProperties=true to return each card's custom property values. Use propKey (optionally with propValue) to filter by a custom property - filtering is applied before paging, so TotalCount reflects the filtered set. A propKey filter scans at most 2000 candidate cards and returns 400 with guidance if the board is larger, rather than silently truncating; narrow it with filter/status/assignee first.",
        "operationId": "bm-get-items",
        "parameters": [
          {
            "name": "principalGuid",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The board's PrincipalGuid."
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "backlog",
                "uncompleted",
                "archived"
              ]
            },
            "description": "Optional item filter. Omit for all active items."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter to a specific column state, e.g. 'Not Started', 'In Development', 'Completed'."
          },
          {
            "name": "assignee",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Set to 'me' to return only cards assigned to the current user."
          },
          {
            "name": "skip",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Number of results to skip (paging)."
          },
          {
            "name": "take",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 50
            },
            "description": "Number of results to return (max 50)."
          },
          {
            "name": "includeCustomProperties",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Return each card's custom property values. Off by default because it costs a per-card lookup. Automatically on when propKey is used."
          },
          {
            "name": "propKey",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter to cards by custom property name, e.g. 'Train'. Call bm-get-board first for the exact keys this board defines. Without propValue, matches any card that has a non-empty value for this key."
          },
          {
            "name": "propValue",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Value the propKey must equal, e.g. 'Train 18.3'. Case-insensitive. For multi-value properties, matches if any selection equals it. Ignored unless propKey is set."
          }
        ],
        "responses": {
          "200": {
            "description": "Cards (Actions) on the board, with paging metadata. Each card carries a customProperties array when includeCustomProperties=true or a propKey filter was used; each entry has key, dataType, options and value (multi-value properties join selections with '||'). TotalCount reflects the filtered set, so it stays consistent with the rows returned."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    },
    "/rest/api/board-manager/move-item": {
      "post": {
        "tags": [
          "Board Manager"
        ],
        "summary": "Move a card to a different column",
        "description": "Moves a card to a new column by setting its status to the target column state. The status must match one of the board's column states (see bm-get-board).",
        "operationId": "bm-move-item",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "principalGuid",
                  "guid",
                  "status"
                ],
                "properties": {
                  "principalGuid": {
                    "type": "string",
                    "description": "The board's PrincipalGuid."
                  },
                  "guid": {
                    "type": "string",
                    "description": "The card (Action) GUID to move."
                  },
                  "status": {
                    "type": "string",
                    "description": "Target column state, e.g. 'In Development'. Must match a board column state."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Move result (Success and Message)."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    },
    "/rest/api/board-manager/backlog-item": {
      "post": {
        "tags": [
          "Board Manager"
        ],
        "summary": "Send a card to the backlog",
        "description": "Removes the card from its current sprint and sets its status to backlog.",
        "operationId": "bm-backlog-item",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "principalGuid",
                  "guid"
                ],
                "properties": {
                  "principalGuid": {
                    "type": "string",
                    "description": "The board's PrincipalGuid."
                  },
                  "guid": {
                    "type": "string",
                    "description": "The card (Action) GUID."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Backlog result (Success and Message)."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    },
    "/rest/api/board-manager/archive-item": {
      "post": {
        "tags": [
          "Board Manager"
        ],
        "summary": "Archive a card",
        "description": "Archives the card, hiding it from the board.",
        "operationId": "bm-archive-item",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "principalGuid",
                  "guid"
                ],
                "properties": {
                  "principalGuid": {
                    "type": "string",
                    "description": "The board's PrincipalGuid."
                  },
                  "guid": {
                    "type": "string",
                    "description": "The card (Action) GUID."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Archive result (Success and Message)."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    },
    "/rest/api/board-manager/create-item": {
      "post": {
        "tags": [
          "Board Manager"
        ],
        "summary": "Create a new card on a board",
        "description": "Creates a new card (Action) under the board's PrincipalGuid. Supply sprintGuid to attach the card to a sprint so it appears in the sprint board view. status, when supplied, must match one of the board's column states (see bm-get-board); if omitted the card lands in the board's default (not-started) column. Supports writing custom properties via customProperties - call bm-get-board first for the valid keys and option values. The response echoes the stored properties back so you can confirm what actually landed.",
        "operationId": "bm-create-item",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "principalGuid",
                  "title"
                ],
                "properties": {
                  "principalGuid": {
                    "type": "string",
                    "description": "The board's PrincipalGuid."
                  },
                  "title": {
                    "type": "string",
                    "description": "The card title."
                  },
                  "status": {
                    "type": "string",
                    "description": "Optional target column state, e.g. 'In Development'. Must match a board column state."
                  },
                  "sprintGuid": {
                    "type": "string",
                    "description": "Sprint GUID to attach the card to, so it shows in the sprint board view. Supplying this is explicit intent and is always honoured as-is. Leave it unset to let the board's own convention decide: boards with SkipBacklog enabled route the card to the board's active sprint instead of the backlog; other boards leave it in the backlog as before."
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional card description."
                  },
                  "theme": {
                    "type": "string",
                    "description": "Optional theme/epic grouping for the card."
                  },
                  "priority": {
                    "type": "string",
                    "description": "Optional priority, e.g. 'Low', 'Medium', 'High'."
                  },
                  "impediment": {
                    "type": "integer",
                    "description": "Optional impediment flag/level."
                  },
                  "assignee": {
                    "type": "string",
                    "description": "Optional assignee — a person's name (or principal id). Resolved to the nearest matching person; use bm-find-person to look up candidates."
                  },
                  "customProperties": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "key"
                      ],
                      "properties": {
                        "key": {
                          "type": "string",
                          "description": "Property name exactly as bm-get-board reports it, e.g. 'Train'. Unknown keys are rejected, not ignored."
                        },
                        "value": {
                          "type": "string",
                          "description": "Value for a single-valued property. For Option types it must match one of the board's defined options (case-insensitive)."
                        },
                        "values": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Selections for a MultiOption property, as a JSON array. Each entry is matched in full - nothing is split - so option names containing commas are safe. Supply an empty array to clear."
                        }
                      },
                      "description": "A custom property value to write. Use 'value' for single-valued properties and 'values' for MultiOption."
                    },
                    "description": "Custom property values to set. Keys and option values must match the board's definitions from bm-get-board; an unknown key, an invalid option, a read-only or expression-driven property, or an unsupported data type is rejected with 400 rather than silently skipped. Writable data types: Text, TextArea, RichText, Option, MultiOption, YesNo, Number, Percentage, Date, DateTime, HyperLink. Person/Project/MultiPerson/MultiProject, ValuedOptionCalc, CascadingOption, Table and Document are not writable through this API. Properties are validated before the card is created, so a rejected value leaves nothing behind."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created card (Action)."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    },
    "/rest/api/board-manager/find-person": {
      "get": {
        "tags": [
          "Board Manager"
        ],
        "summary": "Find people by name",
        "description": "Searches for people (principals) by name. Returns matches with principalId, guid, name and userName. Use the returned name (or principalId) as the assignee on bm-create-item / bm-update-item.",
        "operationId": "bm-find-person",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Person name search text (case-insensitive)."
          },
          {
            "name": "take",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 50
            },
            "description": "Maximum number of results (max 50)."
          }
        ],
        "responses": {
          "200": {
            "description": "Matching people with principalId, guid, name and userName."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    },
    "/rest/api/board-manager/update-item": {
      "post": {
        "tags": [
          "Board Manager"
        ],
        "summary": "Update fields on an existing card",
        "description": "Partial update — only the supplied fields are changed; omitted fields keep their current values. status, when supplied, must match a board column state (see bm-get-board). assignee is resolved by name (or principalId) to the nearest matching person. Supports writing custom properties via customProperties - call bm-get-board first for the valid keys and option values. The response echoes the stored properties back so you can confirm what actually landed.",
        "operationId": "bm-update-item",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "principalGuid",
                  "guid"
                ],
                "properties": {
                  "principalGuid": {
                    "type": "string",
                    "description": "The board's PrincipalGuid."
                  },
                  "guid": {
                    "type": "string",
                    "description": "The card (Action) GUID to update."
                  },
                  "title": {
                    "type": "string",
                    "description": "New title."
                  },
                  "description": {
                    "type": "string",
                    "description": "New description."
                  },
                  "status": {
                    "type": "string",
                    "description": "Target column state, e.g. 'In Development'. Must match a board column state."
                  },
                  "theme": {
                    "type": "string",
                    "description": "Theme/epic grouping for the card."
                  },
                  "priority": {
                    "type": "string",
                    "description": "Priority, e.g. 'Low', 'Medium', 'High'."
                  },
                  "impediment": {
                    "type": "integer",
                    "description": "Impediment flag/level."
                  },
                  "assignee": {
                    "type": "string",
                    "description": "Assignee — a person's name (or principal id); resolved to the nearest matching person."
                  },
                  "customProperties": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "key"
                      ],
                      "properties": {
                        "key": {
                          "type": "string",
                          "description": "Property name exactly as bm-get-board reports it, e.g. 'Train'. Unknown keys are rejected, not ignored."
                        },
                        "value": {
                          "type": "string",
                          "description": "Value for a single-valued property. For Option types it must match one of the board's defined options (case-insensitive)."
                        },
                        "values": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Selections for a MultiOption property, as a JSON array. Each entry is matched in full - nothing is split - so option names containing commas are safe. Supply an empty array to clear."
                        }
                      },
                      "description": "A custom property value to write. Use 'value' for single-valued properties and 'values' for MultiOption."
                    },
                    "description": "Custom property values to set. Keys and option values must match the board's definitions from bm-get-board; an unknown key, an invalid option, a read-only or expression-driven property, or an unsupported data type is rejected with 400 rather than silently skipped. Writable data types: Text, TextArea, RichText, Option, MultiOption, YesNo, Number, Percentage, Date, DateTime, HyperLink. Person/Project/MultiPerson/MultiProject, ValuedOptionCalc, CascadingOption, Table and Document are not writable through this API. Partial, like the other fields: only the keys supplied are written and properties omitted keep their current values."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated card (Action)."
          }
        },
        "security": [
          {
            "basicAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "basicAuth": {
        "type": "http",
        "scheme": "basic",
        "description": "Use your current Fluid PAT or a previously issued Base64 PAT token."
      }
    }
  }
}
