{
  "openapi": "3.0.3",
  "info": {
    "title": "HEDGR public API",
    "version": "1.0.0",
    "description": "HEDGR is the AI FX agent for SME finance teams. This document covers the genuinely public, unauthenticated surface (health checks, public rates, OAuth discovery metadata) plus the MCP endpoint agents use to call Hedgr's read-only dashboard tools. The authenticated /api/* dashboard namespace used by the Hedgr web app is intentionally not enumerated here - see https://hedgr.app/developer-docs for why.",
    "contact": {
      "name": "HEDGR support",
      "email": "support@hedgr.app",
      "url": "https://hedgr.app/support"
    },
    "termsOfService": "https://hedgr.app/terms",
    "x-logo": {
      "url": "https://hedgr.app/hedgr-logo-icon.svg"
    },
    "x-api-version": "2026-08-22",
    "x-versioning-policy": {
      "strategy": "header",
      "header": "Hedgr-API-Version",
      "current_version": "2026-08-22",
      "supported_versions": [
        "2026-08-22"
      ],
      "response_header": "Every /api response carries `Hedgr-API-Version` naming the contract that answered it.",
      "request_pinning": "A client MAY pin by sending `Hedgr-API-Version`. An unrecognised value is rejected with 400 and a typed ApiError rather than silently served the current shape, so a pin is never quietly ignored.",
      "mcp": "The MCP endpoint versions separately, per request, via the JSON-RPC `protocolVersion` field. GET /mcp lists every accepted version in `protocolVersions`; POST /mcp with method=initialize negotiates one and echoes the agreed value.",
      "deprecation": "A version being retired is announced on its responses with the standard `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) headers before removal, and in CHANGELOG.md. Versions are added append-only; an older version keeps serving until its Sunset date passes.",
      "breaking_change_definition": "Removing or renaming a field, narrowing a type, or changing an existing status code. Adding a new optional field is not breaking and does not bump the version."
    }
  },
  "servers": [
    {
      "url": "https://hedgr.app",
      "description": "Production (apex, marketing + MCP)"
    },
    {
      "url": "https://api.hedgr.app",
      "description": "Production (Sage One ZA OAuth callback host only)"
    }
  ],
  "externalDocs": {
    "description": "Developer boundary summary",
    "url": "https://hedgr.app/developer-docs"
  },
  "tags": [
    {
      "name": "Health",
      "description": "Public liveness and operational status checks."
    },
    {
      "name": "Rates",
      "description": "Public FX reference rates."
    },
    {
      "name": "MCP",
      "description": "Model Context Protocol endpoint for agents calling Hedgr's read-only dashboard tools."
    },
    {
      "name": "OAuth discovery",
      "description": "RFC 8414 / RFC 9728 metadata used to authenticate against the MCP endpoint."
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "Health"
        ],
        "summary": "Backend liveness probe",
        "description": "Minimal liveness check used by Railway. No authentication, no per-user data.",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthStatus"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "getApiHealth",
        "tags": [
          "Health"
        ],
        "summary": "Public API liveness probe",
        "description": "Returns a minimal payload for unauthenticated requests. An authenticated session (cookie) receives additional Xero/QuickBooks usage detail not documented here, since that detail is session-specific and not part of the public surface.",
        "security": [],
        "parameters": [
          {
            "name": "Hedgr-API-Version",
            "in": "header",
            "required": false,
            "description": "Optional version pin. Send the version your integration was built against; an unrecognised value is rejected with 400 rather than silently served the current shape. Every response echoes the serving version in the header of the same name.",
            "schema": {
              "type": "string",
              "enum": [
                "2026-08-22"
              ],
              "example": "2026-08-22"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Service is up.",
            "headers": {
              "Hedgr-API-Version": {
                "schema": {
                  "type": "string",
                  "example": "2026-08-22"
                },
                "description": "The API contract version that served this response."
              },
              "Deprecation": {
                "schema": {
                  "type": "string"
                },
                "description": "RFC 9745. Present only while this version is being retired."
              },
              "Sunset": {
                "schema": {
                  "type": "string"
                },
                "description": "RFC 8594. Present only while this version is being retired; the date after which it stops responding."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiHealthStatus"
                }
              }
            }
          },
          "400": {
            "description": "Unrecognised `Hedgr-API-Version` pin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/health/global": {
      "get": {
        "operationId": "getApiHealthGlobal",
        "tags": [
          "Health"
        ],
        "summary": "Aggregate operational health",
        "description": "Platform-wide operational signals for headless monitoring (rate-limit counts, rates freshness, webhook counters, Currencycloud operational status). Aggregate counts only - no per-tenant or per-user data.",
        "security": [],
        "parameters": [
          {
            "name": "Hedgr-API-Version",
            "in": "header",
            "required": false,
            "description": "Optional version pin. Send the version your integration was built against; an unrecognised value is rejected with 400 rather than silently served the current shape. Every response echoes the serving version in the header of the same name.",
            "schema": {
              "type": "string",
              "enum": [
                "2026-08-22"
              ],
              "example": "2026-08-22"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregate health snapshot.",
            "headers": {
              "Hedgr-API-Version": {
                "schema": {
                  "type": "string",
                  "example": "2026-08-22"
                },
                "description": "The API contract version that served this response."
              },
              "Deprecation": {
                "schema": {
                  "type": "string"
                },
                "description": "RFC 9745. Present only while this version is being retired."
              },
              "Sunset": {
                "schema": {
                  "type": "string"
                },
                "description": "RFC 8594. Present only while this version is being retired; the date after which it stops responding."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GlobalHealthStatus"
                }
              }
            }
          },
          "400": {
            "description": "Unrecognised `Hedgr-API-Version` pin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/api/rates/public": {
      "get": {
        "operationId": "getPublicRates",
        "tags": [
          "Rates"
        ],
        "summary": "Public FX reference rates",
        "description": "Public reference rates for CSV/manual-workspace users who have not connected an accounting provider. No authentication required.",
        "security": [],
        "parameters": [
          {
            "name": "Hedgr-API-Version",
            "in": "header",
            "required": false,
            "description": "Optional version pin. Send the version your integration was built against; an unrecognised value is rejected with 400 rather than silently served the current shape. Every response echoes the serving version in the header of the same name.",
            "schema": {
              "type": "string",
              "enum": [
                "2026-08-22"
              ],
              "example": "2026-08-22"
            }
          },
          {
            "name": "baseCurrency",
            "in": "query",
            "required": false,
            "description": "ISO 4217 base currency. Defaults to the platform base currency (GBP).",
            "schema": {
              "type": "string",
              "example": "GBP"
            }
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Rate source override.",
            "schema": {
              "type": "string",
              "default": "frankfurter"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current reference rates against the requested base currency.",
            "headers": {
              "Hedgr-API-Version": {
                "schema": {
                  "type": "string",
                  "example": "2026-08-22"
                },
                "description": "The API contract version that served this response."
              },
              "Deprecation": {
                "schema": {
                  "type": "string"
                },
                "description": "RFC 9745. Present only while this version is being retired."
              },
              "Sunset": {
                "schema": {
                  "type": "string"
                },
                "description": "RFC 8594. Present only while this version is being retired; the date after which it stops responding."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicRates"
                }
              }
            }
          },
          "400": {
            "description": "Unrecognised `Hedgr-API-Version` pin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "500": {
            "description": "Rate source unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "operationId": "getOAuthProtectedResourceMetadata",
        "tags": [
          "OAuth discovery"
        ],
        "summary": "RFC 9728 protected-resource metadata for the MCP endpoint",
        "security": [],
        "responses": {
          "200": {
            "description": "Protected-resource metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedResourceMetadata"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "operationId": "getOAuthAuthorizationServerMetadata",
        "tags": [
          "OAuth discovery"
        ],
        "summary": "RFC 8414 authorization-server metadata for the MCP OAuth flow",
        "security": [],
        "responses": {
          "200": {
            "description": "Authorization-server metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizationServerMetadata"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/mcp": {
      "get": {
        "operationId": "getWellKnownMcp",
        "tags": [
          "MCP"
        ],
        "summary": "Well-known MCP discovery alias",
        "description": "Conventional well-known location some MCP directories probe first. Points at the canonical /mcp discovery document rather than duplicating it.",
        "security": [],
        "responses": {
          "200": {
            "description": "MCP server card plus pointers to the canonical endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpServerCard"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/mcp/server-card.json": {
      "get": {
        "operationId": "getMcpServerCard",
        "tags": [
          "MCP"
        ],
        "summary": "MCP server card",
        "description": "Machine-readable identity, transport, and auth summary for the Hedgr MCP server.",
        "security": [],
        "responses": {
          "200": {
            "description": "MCP server card.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpServerCard"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/api-catalog": {
      "get": {
        "operationId": "getApiCatalog",
        "tags": [
          "OAuth discovery"
        ],
        "summary": "RFC 9727 API catalog",
        "description": "Linkset document naming every HEDGR API surface, with service-desc, service-doc, and status relations (RFC 8631). Served as application/linkset+json.",
        "security": [],
        "responses": {
          "200": {
            "description": "RFC 9727 linkset.",
            "content": {
              "application/linkset+json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCatalog"
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "get": {
        "operationId": "getMcpDiscovery",
        "tags": [
          "MCP"
        ],
        "summary": "MCP server discovery metadata",
        "description": "Public discovery document: server name, version, protocol version, and OAuth endpoints.",
        "security": [],
        "responses": {
          "200": {
            "description": "MCP server metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpDiscovery"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "callMcpTool",
        "tags": [
          "MCP"
        ],
        "summary": "MCP JSON-RPC 2.0 endpoint (Streamable HTTP transport)",
        "description": "Every MCP interaction goes through this single endpoint as a JSON-RPC 2.0 request. It is not a per-tool REST path - the `x-mcp-tools` list on this operation documents the callable tools (name, description, input schema) so an agent can plan a `tools/call` without a live `tools/list` round trip. All tools are read-only.\n\nAUTHENTICATION IS PER-METHOD. The handshake and discovery methods (`initialize`, `ping`, `tools/list`, `resources/list`, `resources/read`) answer with NO token, so an agent can find out what this server is and what it offers before sending a user through OAuth consent. `tools/call` reads a specific user's accounting data and always requires a valid Bearer token; without one it returns 401 with a `WWW-Authenticate` header pointing at the RFC 9728 protected-resource metadata. A token that IS presented is always validated, even on a discovery method.",
        "security": [
          {},
          {
            "mcpOAuth": [
              "fx:read"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC 2.0 response (result or error).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token. Response includes a WWW-Authenticate header pointing at the protected-resource metadata.",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                },
                "description": "Bearer resource_metadata=\"https://hedgr.app/.well-known/oauth-protected-resource/mcp\""
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Request Origin header is not on the allowed list (browser-originated requests only).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        },
        "x-mcp-tools": [
          {
            "name": "get_platform_capabilities",
            "description": "Returns a safe, client-facing capability map for Hedgr: dashboard tabs, data sources, what the MCP already exposes, a structured mcp_gap_register showing covered client-facing surfaces, the Scout/MCP boundary, and what is intentionally not exposed. Use this when the user asks what Hedgr, Scout, or the connector can do. Does not reveal private prompts, formulas, credentials, admin pages, or implementation IP.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns Hedgr's read-only tool catalogue and what each surface can answer for the whole workspace.",
              "properties": {}
            }
          },
          {
            "name": "get_dashboard_context",
            "description": "Returns a compact read-only snapshot of the authenticated Hedgr dashboard: organisation, provider, base currency, selected entity/workspace context, data timestamp, FX currencies, invoice counts, headline exposure and P&L totals, and available rates. Use when the user asks for a dashboard-level summary or when another tool needs the current account context first.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns a whole-workspace snapshot of the current dashboard (headline KPIs, exposure, P&L).",
              "properties": {}
            }
          },
          {
            "name": "get_account_status",
            "description": "Returns the current state of the user's Hedgr account: which accounting systems, Google Sheets workspaces, CSV/manual cloud workspaces, and setup sections are available. Call this first in any agentic session to understand what data is available before making further calls. If connection_status.state='setup_required', surface setup_url and setup_steps exactly. For Xero, QuickBooks, Sage, or Holded, do not ask the user to fill Company & reporting first because Hedgr reads those settings from the accounting system. For Google Sheets or CSV/manual paths, tell the user to complete Company & reporting, then map or upload invoices and bank balances; for CSV/manual, tell them to click Save workspace to cloud before expecting MCP to read the browser-local snapshot. Do not imply Xero is the only setup path.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns workspace connection and onboarding status.",
              "properties": {}
            }
          },
          {
            "name": "list_entities",
            "description": "Lists all connected legal entities with their base currencies and source accounting systems. Use before get_fx_exposure when you need entity-level granularity rather than consolidated group exposure. Multi-entity clients (e.g. UK Ltd + US Inc + DE GmbH) need this to disambiguate which entity's exposure to query.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "include_disconnected": {
                  "type": "boolean",
                  "description": "Include entities that exist in policy config but have no connected accounting system. Useful for showing the user what's missing.",
                  "default": false
                }
              }
            }
          },
          {
            "name": "get_fx_exposure",
            "description": "Returns net FX exposure by currency pair, entity, and time bucket (0-30d, 31-60d, 61-90d, 90d+). Each exposure line distinguishes confirmed (invoices and POs from the accounting system) from forecasted, and includes a source field citing provenance ('€2.3M from 47 Xero invoices'). This is the workhorse tool: get it right and the majority of agent use cases work end-to-end. On multi-entity books the exposure honours the workspace inter-company mode and the response carries an intercompany block naming that mode; realised P&L does not move with that mode, and it is reported as the accounting system recorded it, so settled inter-company invoices stay inside it.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Specific entity ID from list_entities. Omit for consolidated group exposure."
                },
                "currency": {
                  "type": "string",
                  "description": "ISO 4217 code to filter to one currency (e.g. 'EUR', 'USD'). Omit for all currencies.",
                  "pattern": "^[A-Z]{3}$"
                },
                "horizon_days": {
                  "type": "integer",
                  "description": "Forward-looking window in days.",
                  "default": 90,
                  "minimum": 1,
                  "maximum": 730
                },
                "include_forecasted": {
                  "type": "boolean",
                  "description": "Include forecasted exposure alongside confirmed accounting-system data.",
                  "default": true
                },
                "include_chart": {
                  "type": "boolean",
                  "description": "When true, the tool response includes an image/png content block containing a horizontal bar chart of net exposure by currency (green = receivable, red = payable). Requires no additional API calls - uses the same data as the text response.",
                  "default": false
                }
              }
            }
          },
          {
            "name": "get_cash_position",
            "description": "Returns current cash balances by currency and entity. Use alongside get_fx_exposure to understand whether FX cash offsets invoice exposure.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Specific entity ID. Omit for group-level consolidated cash position."
                },
                "currency": {
                  "type": "string",
                  "description": "Filter to a single currency.",
                  "pattern": "^[A-Z]{3}$"
                },
                "include_chart": {
                  "type": "boolean",
                  "description": "When true, includes an image/png content block: horizontal bar chart of cash balance by currency (native units). Blue bars = positive, red = overdraft.",
                  "default": false
                }
              }
            }
          },
          {
            "name": "get_hedge_portfolio",
            "description": "Returns all open forward contracts and hedges with maturity date, notional amount, contracted rate, and current mark-to-market value. Use this to answer 'what is my current hedge ratio on EUR?' without needing execute permissions.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Filter to a single entity's hedges."
                },
                "currency": {
                  "type": "string",
                  "description": "Filter to hedges on a specific currency.",
                  "pattern": "^[A-Z]{3}$"
                },
                "include_expired": {
                  "type": "boolean",
                  "description": "Include hedges that have already matured.",
                  "default": false
                }
              }
            }
          },
          {
            "name": "simulate_scenario",
            "description": "Models the P&L impact of exchange rate moves on the user's current net exposure (invoices + cash) and existing hedges. Two modes: (1) supply explicit `scenarios` for a linear what-if, e.g. 'What happens if GBP/EUR moves 3% before Q3 close?'; (2) set `worst_case: true` (scenarios optional) to revalue each currency at its OWN worst adverse 1-month historical move, the same worst-case the Monitor dashboard shows. Worst-case is a historical realised downside, not a forecast or a recommendation. Cross-currency pairs (neither leg is the reporting currency) are shocked base-neutrally.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "worst_case": {
                  "type": "boolean",
                  "description": "When true, ignore linear shocks and apply each currency's own worst adverse 1-month historical move (adverse-aligned, always a loss). Matches the Monitor worst-case KPI. scenarios becomes optional.",
                  "default": false
                },
                "scenarios": {
                  "type": "array",
                  "description": "Rate shocks to apply (required unless worst_case is true). Multiple entries are applied simultaneously (correlated move).",
                  "minItems": 1,
                  "maxItems": 10,
                  "items": {
                    "type": "object",
                    "required": [
                      "currency_pair",
                      "shock_bps"
                    ],
                    "properties": {
                      "currency_pair": {
                        "type": "string",
                        "description": "Currency pair, e.g. 'GBPEUR' or 'EUR/GBP'. Base currency strengthens when shock_bps is positive."
                      },
                      "shock_bps": {
                        "type": "integer",
                        "description": "Rate shock in basis points. Positive = base currency strengthens. 300 = +3%."
                      }
                    }
                  }
                },
                "horizon_days": {
                  "type": "integer",
                  "description": "Forward-looking exposure window included in the simulation.",
                  "default": 90,
                  "minimum": 1,
                  "maximum": 365
                },
                "include_hedges": {
                  "type": "boolean",
                  "description": "Apply offsetting effect of existing hedges. Set false to see gross (unhedged) impact.",
                  "default": true
                }
              }
            }
          },
          {
            "name": "get_protection_candidates",
            "description": "Policy-derived candidate rows showing suggested notional amounts for open currency exposures. Read-only - does not execute trades, open dealing pages, or transfer assets.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Limit to a single entity. Omit for group-level candidates."
                },
                "currency": {
                  "type": "string",
                  "description": "Limit to a specific currency (e.g. 'EUR').",
                  "pattern": "^[A-Z]{3}$"
                },
                "policy_override": {
                  "type": "object",
                  "description": "Temporary policy adjustments for this calculation only. Does not modify the stored policy.",
                  "properties": {
                    "target_hedge_ratio": {
                      "type": "number",
                      "description": "Override target hedge ratio (0-1). 0.7 = 70% hedged.",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "max_tenor_days": {
                      "type": "integer",
                      "description": "Override maximum forward contract tenor in days.",
                      "minimum": 1,
                      "maximum": 730
                    }
                  }
                }
              }
            }
          },
          {
            "name": "get_policy",
            "description": "Returns the user's active FX policy in structured form: target hedge ratios per currency, allowed instruments, maximum single-trade size, approval thresholds, and blackout windows. See get_fx_guidance('guardrails-no-advice') for methodology.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Fetch the policy for a specific entity. Omit for the group-level policy."
                }
              }
            }
          },
          {
            "name": "get_market_regime",
            "description": "Returns a current Hedgr regime snapshot for one or more currency pairs, including a compact headline, sorted snapshot rows, latest rate, realised-volatility regime, 30-day change, methodology, and dashboard surface. Volatility regimes are Settled / Directional / Choppy / Stressed. Also returns a market_environment block matching the Monitor Market Environment KPI cards when the book has exposure: the exposure-weighted Composite score (0-100), Volatility score, and 30-day Trend (change and direction). Use this to answer market-backdrop questions with label first, plain explanation, basis, and next place to look. Regimes are not trade recommendations. The scores are analytical only. See get_fx_guidance('regimes-methodology') for methodology.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "pairs": {
                  "type": "array",
                  "description": "Currency pairs to query, e.g. ['GBPEUR', 'GBPUSD', 'USDZAR']. Omit to return regimes for all pairs relevant to the user's current exposure.",
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Z]{6}$"
                  },
                  "maxItems": 20
                },
                "include_history": {
                  "type": "boolean",
                  "description": "Include the historical regime series (date + regime + volatility per point). Useful for charting or for the agent to describe how stable the current regime is.",
                  "default": false
                },
                "history_years": {
                  "type": "number",
                  "description": "How many years of history to include when include_history is true. Defaults to 2.",
                  "default": 2,
                  "minimum": 0.25,
                  "maximum": 10
                },
                "include_chart": {
                  "type": "boolean",
                  "description": "When true, includes one or two image/png content blocks: (1) a horizontal bar chart of realised-volatility % by pair, colour-coded by regime (green=Settled, blue=Directional, amber=Choppy, red=Stressed); (2) when include_history is also true, a rate + Bollinger-band line chart for the most-stressed pair.",
                  "default": false
                }
              }
            }
          },
          {
            "name": "get_pnl_attribution",
            "description": "Returns FX P&L broken down by currency with top contributor, unrealised mark-to-market (open invoices, booking rate vs current spot), and realised gain/loss from settled invoices where the accounting system provides it. Use to answer 'which currencies are hurting us?', 'what is our total FX impact this period?', or 'show me P&L by currency'. All amounts are in base currency. Sorts by absolute total P&L so the biggest contributors appear first. See get_fx_guidance('margin-basis-ias21') and get_fx_guidance('realised-vs-unrealised') for methodology.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Filter to a specific entity. Omit for consolidated group."
                },
                "include_unrealised": {
                  "type": "boolean",
                  "description": "Include unrealised P&L from open invoices (booking rate vs current spot). Default true.",
                  "default": true
                },
                "include_realised": {
                  "type": "boolean",
                  "description": "Include realised P&L from settled invoices where the accounting system provides the FX gain/loss. Default true.",
                  "default": true
                },
                "include_chart": {
                  "type": "boolean",
                  "description": "When true, the tool response includes an image/png content block containing a horizontal bar chart of P&L by currency (green = gain, red = loss). Uses the same data as the text response.",
                  "default": false
                }
              }
            }
          },
          {
            "name": "get_limit_status",
            "description": "Compares current net FX exposure against per-currency comfort limits configured in Hedgr's Control tab. Returns breach status per currency: breaching (exposure exceeds limit), approaching (≥80% of limit), within_limit, or no_limit_set. Use to answer 'are we within limits?', 'which currencies need attention?', or 'what is our USD exposure vs our comfort limit?'. Limits are set in Control > Comfort Limits. See get_fx_guidance('guardrails-no-advice') for methodology.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Filter to a specific entity's exposures. Omit for group-level consolidated."
                }
              }
            }
          },
          {
            "name": "get_transaction_log_summary",
            "description": "Returns a safe read-only transaction-log summary for Explain > Detailed Transaction Logs: top open-invoice unrealised FX rows, settled-invoice realised FX rows, bank/cash rows, counts, and row provenance. Does not expose raw provider payloads, hidden reconciliation notes, credentials, or private calculation internals.",
            "inputSchema": {
              "type": "object",
              "description": "Optional scope filters. Omit both for the whole-workspace report.",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Specific entity ID from list_entities. Omit for the whole workspace (all entities)."
                },
                "currency": {
                  "type": "string",
                  "description": "ISO 4217 code to filter to one currency (e.g. 'EUR', 'USD'). Omit for all currencies.",
                  "pattern": "^[A-Z]{3}$"
                }
              }
            }
          },
          {
            "name": "get_overdue_drivers",
            "description": "Returns overdue invoice drivers by currency and top contact, prioritised by largest exposure per currency. Separates total unrealised FX P&L from since-due P&L and explicitly reports when due-date rates are unavailable. Use for questions like 'what is driving overdue invoices?' or 'what did overdue invoices cost us?'.",
            "inputSchema": {
              "type": "object",
              "description": "Optional scope filters. Omit both for the whole-workspace report.",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Specific entity ID from list_entities. Omit for the whole workspace (all entities)."
                },
                "currency": {
                  "type": "string",
                  "description": "ISO 4217 code to filter to one currency (e.g. 'EUR', 'USD'). Omit for all currencies.",
                  "pattern": "^[A-Z]{3}$"
                }
              }
            }
          },
          {
            "name": "get_data_quality",
            "description": "Returns safe import and data-quality diagnostics: duplicate invoice IDs, first visible issue rows, missing currency/date/amount fields, missing booking rates, missing spot rates, and per-currency P&L readiness. Use before answering why CSV imports failed or why P&L is incomplete. See get_fx_guidance('provider-data-quality') for methodology.",
            "inputSchema": {
              "type": "object",
              "description": "Optional scope filters. Omit both for the whole-workspace report.",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Specific entity ID from list_entities. Omit for the whole workspace (all entities)."
                },
                "currency": {
                  "type": "string",
                  "description": "ISO 4217 code to filter to one currency (e.g. 'EUR', 'USD'). Omit for all currencies.",
                  "pattern": "^[A-Z]{3}$"
                }
              }
            }
          },
          {
            "name": "get_payment_patterns",
            "description": "Returns detected payment timing patterns by counterparty and currency where available, or derives a conservative summary from settled invoice dates. Use for factual questions about who pays late or early. Do not treat volatility exposure as realised loss; call P&L or overdue tools for actual gains/losses.",
            "inputSchema": {
              "type": "object",
              "description": "Optional scope filters. Omit both for the whole-workspace report.",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Specific entity ID from list_entities. Omit for the whole workspace (all entities)."
                },
                "currency": {
                  "type": "string",
                  "description": "ISO 4217 code to filter to one currency (e.g. 'EUR', 'USD'). Omit for all currencies.",
                  "pattern": "^[A-Z]{3}$"
                }
              }
            }
          },
          {
            "name": "get_cashflow_timing",
            "description": "Returns FX cashflow timing by currency and bucket, separating receivables, payables, bank cash, and hedge maturities where available. Use for Monitor > Exposure & Cash Flow questions about overdue, next 30, 31-60, 61-90, beyond 90, undated, liquidity timing, or same-currency cash coverage.",
            "inputSchema": {
              "type": "object",
              "description": "Optional scope filters. Omit both for the whole-workspace report.",
              "properties": {
                "entity_id": {
                  "type": "string",
                  "description": "Specific entity ID from list_entities. Omit for the whole workspace (all entities)."
                },
                "currency": {
                  "type": "string",
                  "description": "ISO 4217 code to filter to one currency (e.g. 'EUR', 'USD'). Omit for all currencies.",
                  "pattern": "^[A-Z]{3}$"
                }
              }
            }
          },
          {
            "name": "get_cashflow_forecast",
            "description": "Projects the user's OWN expected net cashflow per currency over the next N weeks (default 8), from their OWN settlement history: expected settlement of existing open invoices (due date shifted by how late each customer usually pays), plus projected recurring and seasonal flows. Returns a per-currency net with a P10-P90 band, named drivers, and the walk-forward accuracy of the settlement model (inside-band % and median error in days). This is deterministic statistics on settlement behaviour, NOT an FX-rate prediction. Always quote the band and accuracy; say 'projected' not 'predicted'; never imply rate direction or guarantee an outcome. If sufficient_history is false, present it as indicative.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "horizon_weeks": {
                  "type": "integer",
                  "description": "Projection horizon in weeks (1-26, default 8)."
                },
                "currency": {
                  "type": "string",
                  "description": "Optional 3-letter currency code to filter to one currency."
                }
              }
            }
          },
          {
            "name": "get_funding_forecast",
            "description": "TMS liquidity/funding view: per-currency running cash balance seeded from the user's REAL bank balances - INCLUDING base currency (which the FX-exposure tools deliberately exclude). Answers whether the user will hold the units to settle upcoming payables/receivables, the first date each currency runs short and by how much, the trade the gap implies (BUY on a projected shortfall by its date, SELL on a surplus), and whether base-currency cash can fund the foreign purchases (can_self_fund + base_funding_shortfall). Uses real bank balances + real invoices plus the projected settlement component with its band and accuracy. Prefer the adverse (conservative) shortfall when warning about funding. Trade DIRECTION is a mechanical consequence of the gap sign and is fine to state; do NOT advise whether/when to hedge and NEVER imply FX-rate direction. Say 'projected' not 'predicted'; if sufficient_history is false, present the projected component as indicative.",
            "inputSchema": {
              "type": "object",
              "properties": {
                "horizon_weeks": {
                  "type": "integer",
                  "description": "Projection horizon in weeks (1-26, default 8)."
                },
                "currency": {
                  "type": "string",
                  "description": "Optional 3-letter currency code to filter to one currency."
                }
              }
            }
          },
          {
            "name": "get_protection_builder_snapshot",
            "description": "Returns the read-only Protection Builder / Scenario Builder snapshot: simulated row inputs, residual exposure after active hedges, cashflow-aware grouping basis, and policy sizing context. It does not execute trades, produce broker instructions, return quote IDs, or recommend a hedge.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns the current Protection Builder simulation snapshot.",
              "properties": {}
            }
          },
          {
            "name": "get_policy_backtest_summary",
            "description": "Returns a saved Control > Backtest policy replay summary when available, plus the policy snapshot used for context. Use for historical policy replay questions only. Does not predict future performance or recommend policy settings.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns the latest FX policy backtest summary.",
              "properties": {}
            }
          },
          {
            "name": "get_rate_assumptions",
            "description": "Returns rate assumptions used by the dashboard: spot rates, source labels, timestamps, custom override presence, missing spot rates, and invoice rows with missing or placeholder booking rates. Use when users ask where a number came from or why a rate/P&L is unavailable. See get_fx_guidance('currency-pair-convention') and get_fx_guidance('forward-tenor-buckets') for methodology.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns the market-rate assumptions (source and as-of date) the tools use.",
              "properties": {}
            }
          },
          {
            "name": "get_export_manifest",
            "description": "Returns a read-only manifest of Hedgr exports available in the dashboard and where to generate them. Does not download files, expose temporary URLs, or generate private report drafts through MCP.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns the reports and exports available for the workspace.",
              "properties": {}
            }
          },
          {
            "name": "get_navigation_targets",
            "description": "Returns safe client-facing Hedgr navigation targets: current tab/subtab labels and what each surface is used for. Use to give Scout-like 'next place to look' guidance without exposing admin routes, operator pages, or feature-flag internals.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns deep-link navigation targets into the Hedgr app.",
              "properties": {}
            }
          },
          {
            "name": "get_workspace_setup_state",
            "description": "Returns setup state for accounting, Google Sheets, and CSV/manual workspaces. Explains whether Company & reporting is required for MCP. Accounting providers supply company settings automatically; Google Sheets and CSV/manual workspaces may need Company & reporting completed.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns onboarding and setup completeness for the workspace.",
              "properties": {}
            }
          },
          {
            "name": "get_fx_guidance",
            "description": "Returns Hedgr's shared FX-guidance canon - the same read-only methodology Scout uses in-app (e.g. margin-basis / IAS 21 and Xero unrealised FX overlap). Use this to answer with consistent, data-grounded FX guidance. Public-safe subset only; internal partner/marketing guidance is filtered out. Not financial, legal, tax, or investment advice.",
            "inputSchema": {
              "type": "object",
              "description": "No inputs. Returns Hedgr's shared read-only FX-guidance canon (methodology, e.g. IAS 21 margin basis).",
              "properties": {}
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "mcpOAuth": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization-code flow with PKCE and dynamic client registration. See /.well-known/oauth-authorization-server.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://hedgr.app/mcp/oauth/authorize",
            "tokenUrl": "https://hedgr.app/mcp/oauth/token",
            "scopes": {
              "fx:read": "Read-only access to FX exposure, cash position, hedge portfolio, P&L, policy, and related dashboard data via MCP tools."
            }
          }
        }
      }
    },
    "schemas": {
      "ApiError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message. Stable enough to match on for known cases (e.g. \"Missing Bearer token\"), but not a separate machine-readable error code today."
          }
        }
      },
      "HealthStatus": {
        "type": "object",
        "description": "Railway liveness payload.",
        "required": [
          "status",
          "timestamp",
          "uptime"
        ],
        "properties": {
          "status": {
            "type": "string",
            "example": "ok"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "port": {
            "type": "string"
          },
          "uptime": {
            "type": "number",
            "description": "Process uptime in seconds."
          },
          "sessionStore": {
            "type": "string",
            "description": "Active session store: redis, postgres, file, or memory."
          }
        }
      },
      "ApiHealthStatus": {
        "type": "object",
        "description": "Public API liveness payload for an unauthenticated caller.",
        "required": [
          "ok",
          "authenticated",
          "timestamp"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "authenticated": {
            "type": "boolean",
            "example": false
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "uptime": {
            "type": "number"
          },
          "rateSource": {
            "type": "string",
            "description": "Current market data source (e.g. frankfurter)."
          }
        }
      },
      "XeroRateLimitSignals": {
        "type": "object",
        "description": "Aggregate Xero API rate-limit signals across all tenants. No per-tenant or per-user data.",
        "properties": {
          "callsSinceStart": {
            "type": "integer"
          },
          "dayLimitRemaining": {
            "type": "integer",
            "nullable": true
          },
          "minLimitRemaining": {
            "type": "integer",
            "nullable": true
          },
          "appMinuteUsed": {
            "type": "integer"
          },
          "activeTenantThrottles": {
            "type": "integer"
          },
          "count429sLast24h": {
            "type": "integer"
          },
          "circuitBreakerTripped": {
            "type": "boolean"
          },
          "rateLimitedForSeconds": {
            "type": "integer"
          }
        }
      },
      "WebhookCounters": {
        "type": "object",
        "description": "Aggregate webhook delivery counters by provider.",
        "properties": {
          "bus": {
            "type": "object",
            "additionalProperties": true,
            "description": "Event-bus counters."
          },
          "providers": {
            "type": "object",
            "properties": {
              "xero": {
                "type": "object",
                "additionalProperties": true
              },
              "quickbooks": {
                "type": "object",
                "additionalProperties": true
              },
              "currencycloud": {
                "type": "object",
                "additionalProperties": true
              }
            }
          },
          "subscribers": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "GlobalHealthStatus": {
        "type": "object",
        "description": "Platform-wide operational snapshot. Aggregate counts only.",
        "required": [
          "ok",
          "timestamp",
          "uptimeSeconds",
          "rates",
          "xero",
          "webhooks"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "uptimeSeconds": {
            "type": "integer"
          },
          "rates": {
            "type": "object",
            "properties": {
              "source": {
                "type": "string",
                "example": "frankfurter"
              },
              "ageSeconds": {
                "type": "integer",
                "nullable": true
              }
            }
          },
          "xero": {
            "$ref": "#/components/schemas/XeroRateLimitSignals"
          },
          "webhooks": {
            "$ref": "#/components/schemas/WebhookCounters"
          },
          "ccOpsHealth": {
            "type": "object",
            "nullable": true,
            "description": "null if the Currencycloud operational-health query failed (fail-soft; never takes this endpoint down).",
            "properties": {
              "degraded": {
                "type": "boolean"
              },
              "failedExecutions24h": {
                "type": "integer",
                "nullable": true
              },
              "webhook401s24h": {
                "type": "integer",
                "nullable": true
              },
              "reconDrift": {
                "description": "Reconciliation drift detail; shape varies."
              }
            }
          },
          "appOpsHealth": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "null if the application operational-health query failed (fail-soft)."
          }
        }
      },
      "PublicRates": {
        "type": "object",
        "description": "Reference FX rates against a base currency.",
        "required": [
          "base",
          "rates",
          "source"
        ],
        "properties": {
          "base": {
            "type": "string",
            "example": "GBP"
          },
          "rates": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "Currency code -> rate against base."
          },
          "source": {
            "type": "string",
            "example": "frankfurter"
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix epoch ms of the cached rate set."
          }
        }
      },
      "McpDiscovery": {
        "type": "object",
        "description": "Public MCP discovery document: capabilities, transport, tools, and the MCP Apps UI surface.",
        "required": [
          "name",
          "protocolVersion",
          "transport",
          "capabilities"
        ],
        "properties": {
          "name": {
            "type": "string",
            "example": "hedgr"
          },
          "display_name": {
            "type": "string",
            "example": "Hedgr FX Risk & Treasury"
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "protocolVersion": {
            "type": "string",
            "description": "Default protocol version offered to a non-negotiating client."
          },
          "protocolVersions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every protocol version this server accepts."
          },
          "transport": {
            "type": "string",
            "enum": [
              "streamable-http"
            ]
          },
          "endpoint": {
            "type": "string",
            "format": "uri"
          },
          "homepage": {
            "type": "string",
            "format": "uri"
          },
          "docs_url": {
            "type": "string",
            "format": "uri"
          },
          "capabilities": {
            "$ref": "#/components/schemas/McpCapabilities"
          },
          "ui": {
            "$ref": "#/components/schemas/McpUiSurface"
          },
          "tools": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/McpToolDefinition"
            }
          },
          "tool_count": {
            "type": "integer"
          },
          "read_only": {
            "type": "boolean",
            "description": "true - no MCP tool mutates data, executes a trade, or moves funds."
          },
          "oauth": {
            "type": "object",
            "properties": {
              "authorization_endpoint": {
                "type": "string"
              },
              "token_endpoint": {
                "type": "string"
              },
              "registration_endpoint": {
                "type": "string"
              },
              "scopes_supported": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "code_challenge_methods_supported": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "protected_resource_metadata": {
                "type": "string",
                "format": "uri"
              },
              "authorization_server_metadata": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "McpCapabilities": {
        "type": "object",
        "description": "MCP server capabilities, identical to the authenticated initialize response.",
        "properties": {
          "tools": {
            "type": "object",
            "additionalProperties": true
          },
          "resources": {
            "type": "object",
            "additionalProperties": true
          },
          "extensions": {
            "type": "object",
            "additionalProperties": true,
            "description": "Declares io.modelcontextprotocol/ui (MCP Apps, SEP-1865) with its supported mime types."
          }
        }
      },
      "McpUiSurface": {
        "type": "object",
        "description": "The MCP Apps (SEP-1865) surface: which ui:// resources exist and which tools render one.",
        "properties": {
          "extension": {
            "type": "string",
            "example": "io.modelcontextprotocol/ui"
          },
          "spec": {
            "type": "string",
            "example": "SEP-1865"
          },
          "mimeType": {
            "type": "string",
            "example": "text/html;profile=mcp-app"
          },
          "resources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "tools_with_ui": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tool": {
                  "type": "string"
                },
                "resourceUri": {
                  "type": "string",
                  "example": "ui://hedgr/fx-exposure-radar"
                }
              }
            }
          }
        }
      },
      "McpToolDefinition": {
        "type": "object",
        "description": "One callable MCP tool, in the shape tools/list returns.",
        "required": [
          "name",
          "description",
          "inputSchema"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "inputSchema": {
            "type": "object",
            "additionalProperties": true,
            "description": "JSON Schema for the tool arguments."
          },
          "_meta": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional; carries ui.resourceUri for tools that render an MCP App."
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "description": "JSON-RPC 2.0 request envelope for the MCP endpoint.",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "enum": [
              "2.0"
            ]
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "description": "Omit for notifications."
          },
          "method": {
            "type": "string",
            "example": "tools/call",
            "enum": [
              "initialize",
              "ping",
              "tools/list",
              "tools/call",
              "resources/list",
              "resources/read",
              "notifications/initialized",
              "notifications/cancelled"
            ]
          },
          "params": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "description": "JSON-RPC 2.0 response envelope. Exactly one of result or error is present.",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "enum": [
              "2.0"
            ]
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ]
          },
          "result": {
            "type": "object",
            "additionalProperties": true
          },
          "error": {
            "$ref": "#/components/schemas/JsonRpcError"
          }
        }
      },
      "JsonRpcError": {
        "type": "object",
        "description": "JSON-RPC 2.0 error object.",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "-32601 unknown method, -32602 bad params, -32000 upstream rate limit, -32001 authentication required, -32603 internal."
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "McpServerCard": {
        "type": "object",
        "description": "Identity, transport, and auth summary for the Hedgr MCP server.",
        "required": [
          "name",
          "server",
          "auth"
        ],
        "properties": {
          "schema_version": {
            "type": "string",
            "example": "1.0"
          },
          "name": {
            "type": "string",
            "example": "hedgr"
          },
          "display_name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "homepage": {
            "type": "string",
            "format": "uri"
          },
          "documentation": {
            "type": "string",
            "format": "uri"
          },
          "logo_uri": {
            "type": "string",
            "format": "uri"
          },
          "privacy_policy": {
            "type": "string",
            "format": "uri"
          },
          "terms_of_service": {
            "type": "string",
            "format": "uri"
          },
          "contact": {
            "type": "string"
          },
          "mcp_server": {
            "type": "string",
            "format": "uri",
            "description": "Present on /.well-known/mcp; points at the canonical endpoint."
          },
          "server_card": {
            "type": "string",
            "format": "uri"
          },
          "server": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri"
              },
              "transport": {
                "type": "string",
                "enum": [
                  "streamable-http"
                ]
              }
            }
          },
          "auth": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "example": "oauth2"
              },
              "authorization_endpoint": {
                "type": "string",
                "format": "uri"
              },
              "token_endpoint": {
                "type": "string",
                "format": "uri"
              },
              "registration_endpoint": {
                "type": "string",
                "format": "uri"
              },
              "code_challenge_methods_supported": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "scopes_supported": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "protected_resource_metadata": {
                "type": "string",
                "format": "uri"
              }
            }
          },
          "read_only": {
            "type": "boolean"
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ApiCatalog": {
        "type": "object",
        "description": "RFC 9727 API catalog in RFC 9264 linkset format.",
        "required": [
          "linkset"
        ],
        "properties": {
          "linkset": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "anchor": {
                  "type": "string",
                  "format": "uri"
                },
                "item": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "href": {
                        "type": "string",
                        "format": "uri"
                      },
                      "title": {
                        "type": "string"
                      }
                    }
                  }
                },
                "service-desc": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "service-doc": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "status": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        }
      },
      "ProtectedResourceMetadata": {
        "type": "object",
        "properties": {
          "resource": {
            "type": "string",
            "format": "uri",
            "example": "https://hedgr.app/mcp"
          },
          "authorization_servers": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "scopes_supported": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "fx:read"
            ]
          },
          "bearer_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "header"
            ]
          },
          "resource_documentation": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "AuthorizationServerMetadata": {
        "type": "object",
        "properties": {
          "issuer": {
            "type": "string",
            "format": "uri"
          },
          "authorization_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "token_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "registration_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "response_types_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "grant_types_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "code_challenge_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scopes_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "mcpOAuth": [
        "fx:read"
      ]
    }
  ]
}
