{
  "openapi": "3.1.0",
  "info": {
    "title": "Aakaar AI MCP Server",
    "version": "1.0.0",
    "summary": "Remote Model Context Protocol server and OAuth 2.1 endpoints for Aakaar AI.",
    "description": "Aakaar AI exposes its Amazon advertising, Selling Partner and Brand Analytics tools to AI agents through a remote MCP server. This document describes the public, agent-facing HTTP surface only: OAuth discovery, the OAuth 2.1 authorization-code flow with PKCE, and the MCP transport endpoints. Tools are discovered at runtime with the MCP `tools/list` method, not described here.\n\nTypical flow: discover metadata, register a client, send the user through `/mcp/authorize`, exchange the code at `/mcp/token`, then call `POST /mcp` with the access token as a Bearer token. Setup guide: https://www.aakaarai.com/mcp",
    "contact": {
      "name": "Aakaar AI",
      "url": "https://www.aakaarai.com/meeting"
    },
    "termsOfService": "https://www.aakaarai.com/terms-and-conditions"
  },
  "servers": [
    {
      "url": "https://mcp.aakaarai.com",
      "description": "Production MCP server"
    }
  ],
  "tags": [
    { "name": "Discovery", "description": "OAuth metadata for MCP clients (RFC 9728 and RFC 8414). Public, no authentication." },
    { "name": "OAuth", "description": "OAuth 2.1 authorization-code flow with PKCE (S256). Public clients only, no client secret." },
    { "name": "MCP", "description": "Model Context Protocol transport. Every request needs a Bearer access token." }
  ],
  "paths": {
    "/.well-known/oauth-protected-resource": {
      "get": {
        "operationId": "getProtectedResourceMetadata",
        "summary": "OAuth protected resource metadata",
        "description": "Returns RFC 9728 metadata that tells an MCP client which resource this is and which authorization server issues tokens for it. The same document is also served at `/.well-known/oauth-protected-resource/mcp`. Rate limited to 30 requests per minute per IP.",
        "tags": ["Discovery"],
        "security": [],
        "responses": {
          "200": {
            "description": "Protected resource metadata.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProtectedResourceMetadata" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/OAuthRateLimited" }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "operationId": "getAuthorizationServerMetadata",
        "summary": "OAuth authorization server metadata",
        "description": "Returns RFC 8414 metadata: the authorize, token and registration endpoints, the supported scopes and the PKCE method. Rate limited to 30 requests per minute per IP.",
        "tags": ["Discovery"],
        "security": [],
        "responses": {
          "200": {
            "description": "Authorization server metadata.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AuthorizationServerMetadata" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/OAuthRateLimited" }
        }
      }
    },
    "/mcp/register": {
      "post": {
        "operationId": "registerClient",
        "summary": "Register an OAuth client (dynamic client registration)",
        "description": "Accepts a dynamic client registration and returns a client identifier. Registration is optional: the server accepts any `client_id` at the authorize step. Every redirect URI must be on the server's allow-list, otherwise the request is rejected. Rate limited to 30 requests per minute per IP.",
        "tags": ["OAuth"],
        "security": [],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ClientRegistrationRequest" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Client registered.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ClientRegistrationResponse" }
              }
            }
          },
          "400": {
            "description": "A redirect URI is not allowed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OAuthError" },
                "example": { "error": "invalid_redirect_uri", "error_description": "Redirect URI not allowed: https://example.invalid/cb" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/OAuthRateLimited" }
        }
      }
    },
    "/mcp/authorize": {
      "get": {
        "operationId": "authorize",
        "summary": "Start the authorization-code flow",
        "description": "Validates the redirect URI and redirects (302) the user's browser to the Aakaar AI sign-in page, forwarding the OAuth parameters. After the user signs in, the browser is sent to `redirect_uri` with `code` and `state`. Use PKCE with the S256 method. If `scope` is omitted the token is issued with the `read` scope. Rate limited to 30 requests per minute per IP.",
        "tags": ["OAuth"],
        "security": [],
        "parameters": [
          { "name": "response_type", "in": "query", "required": true, "description": "Must be `code`.", "schema": { "type": "string", "enum": ["code"] } },
          { "name": "client_id", "in": "query", "required": true, "description": "Client identifier, for example the one returned by `registerClient`.", "schema": { "type": "string" } },
          { "name": "redirect_uri", "in": "query", "required": true, "description": "Where the browser is sent after sign-in. Must be on the server's allow-list.", "schema": { "type": "string", "format": "uri" } },
          { "name": "code_challenge", "in": "query", "required": true, "description": "PKCE challenge: base64url of the SHA-256 of the code verifier.", "schema": { "type": "string" } },
          { "name": "code_challenge_method", "in": "query", "required": true, "description": "Must be `S256`. No other method is supported.", "schema": { "type": "string", "enum": ["S256"] } },
          { "name": "scope", "in": "query", "required": false, "description": "Space-separated scopes. Defaults to `read`.", "schema": { "type": "string", "examples": ["read", "read write"] } },
          { "name": "state", "in": "query", "required": false, "description": "Opaque value returned unchanged to `redirect_uri`.", "schema": { "type": "string" } }
        ],
        "responses": {
          "302": {
            "description": "Redirect to the Aakaar AI sign-in page.",
            "headers": {
              "Location": { "description": "Sign-in page URL carrying the forwarded OAuth parameters.", "schema": { "type": "string", "format": "uri" } }
            }
          },
          "400": {
            "description": "The redirect URI is missing or not allowed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OAuthError" },
                "example": { "error": "invalid_redirect_uri", "error_description": "Redirect URI not allowed" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/OAuthRateLimited" }
        }
      }
    },
    "/mcp/token": {
      "post": {
        "operationId": "exchangeAuthorizationCode",
        "summary": "Exchange an authorization code for an access token",
        "description": "Exchanges the one-time authorization code for a Bearer access token, after verifying the PKCE `code_verifier`. Codes are single use. The token is valid for 30 days by default and is returned with the scopes it was issued for. Accepts `application/x-www-form-urlencoded` (standard) or JSON. Rate limited to 30 requests per minute per IP.",
        "tags": ["OAuth"],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": { "$ref": "#/components/schemas/TokenRequest" }
            },
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TokenRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Access token issued.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TokenResponse" }
              }
            }
          },
          "400": {
            "description": "The request is invalid: unsupported grant type, missing or already-used code, PKCE failure, or a mismatched client, redirect URI or resource.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OAuthError" },
                "example": { "error": "invalid_grant", "error_description": "Code not found, expired or already used" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/OAuthRateLimited" },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OAuthError" },
                "example": { "error": "server_error" }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "operationId": "sendMcpMessage",
        "summary": "Send a JSON-RPC message to the MCP server (Streamable HTTP)",
        "description": "The main MCP endpoint. Send one JSON-RPC 2.0 message per request. Start with `initialize`; the response carries an `Mcp-Session-Id` header that must be sent on every later request. Notifications (messages without an `id`) are accepted with `202` and no body. Use `tools/list` to discover tools and `tools/call` to run one. Each request needs a Bearer access token. Limited to 100 requests per second per user.",
        "tags": ["MCP"],
        "security": [{ "mcpOAuth": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/McpSessionIdOptional" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/JsonRpcRequest" },
              "examples": {
                "initialize": {
                  "summary": "Open a session",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "initialize",
                    "params": {
                      "protocolVersion": "2025-03-26",
                      "capabilities": {},
                      "clientInfo": { "name": "example-client", "version": "1.0.0" }
                    }
                  }
                },
                "listTools": {
                  "summary": "List the available tools",
                  "value": { "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response. A result for a successful call, or a JSON-RPC error object.",
            "headers": {
              "Mcp-Session-Id": {
                "description": "Returned when the request was `initialize`. Send it on every following request.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JsonRpcResponse" }
              }
            }
          },
          "202": { "description": "Notification accepted. No response body." },
          "400": {
            "description": "A request other than `initialize` was sent without an `Mcp-Session-Id` header.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JsonRpcResponse" },
                "example": { "jsonrpc": "2.0", "error": { "code": -32003, "message": "Bad Request: Mcp-Session-Id header is required for non-initialize requests" }, "id": 2 }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": {
            "description": "The browser Origin header is not allowed, or the session does not belong to the authenticated user.",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    { "$ref": "#/components/schemas/JsonRpcResponse" },
                    { "$ref": "#/components/schemas/OriginError" }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "The session was not found or has expired. Send `initialize` again.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JsonRpcResponse" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/McpRateLimited" },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JsonRpcResponse" },
                "example": { "jsonrpc": "2.0", "error": { "code": -32603, "message": "Internal server error" }, "id": null }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "terminateMcpSession",
        "summary": "End an MCP session",
        "description": "Explicitly closes a session opened with `initialize`. The session must belong to the authenticated user.",
        "tags": ["MCP"],
        "security": [{ "mcpOAuth": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/McpSessionIdRequired" }
        ],
        "responses": {
          "200": { "description": "Session ended." },
          "400": {
            "description": "The `Mcp-Session-Id` header is missing.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SimpleError" },
                "example": { "error": "Missing Mcp-Session-Id header" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": {
            "description": "The session does not belong to the authenticated user, or the browser Origin header is not allowed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SimpleError" },
                "example": { "error": "Forbidden: session does not belong to authenticated user" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/McpRateLimited" }
        }
      },
      "get": {
        "operationId": "openMcpEventStream",
        "summary": "Open a server-sent events stream (legacy HTTP+SSE transport)",
        "description": "Legacy transport from the 2024-11-05 MCP specification, kept for older clients. Opens an event stream; the first event names the URL to POST messages to (`/mcp/messages?sessionId=...`). New clients should use `sendMcpMessage` instead.",
        "deprecated": true,
        "tags": ["MCP"],
        "security": [{ "mcpOAuth": [] }],
        "responses": {
          "200": {
            "description": "Event stream.",
            "content": {
              "text/event-stream": {
                "schema": { "type": "string" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": {
            "description": "The browser Origin header is not allowed.",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/OriginError" } }
            }
          },
          "429": { "$ref": "#/components/responses/McpRateLimited" },
          "500": { "description": "The stream could not be set up." }
        }
      }
    },
    "/mcp/messages": {
      "post": {
        "operationId": "sendMcpEventStreamMessage",
        "summary": "Send a JSON-RPC message on a legacy event-stream session",
        "description": "Legacy transport companion to `openMcpEventStream`. The reply to the message arrives on the event stream, not in this response.",
        "deprecated": true,
        "tags": ["MCP"],
        "security": [{ "mcpOAuth": [] }],
        "parameters": [
          { "name": "sessionId", "in": "query", "required": true, "description": "Session identifier announced by the event stream.", "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/JsonRpcRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Message accepted. The reply is delivered on the event stream.",
            "content": { "text/plain": { "schema": { "type": "string", "examples": ["Accepted"] } } }
          },
          "400": {
            "description": "The `sessionId` query parameter is missing, or the message is not valid JSON-RPC.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JsonRpcResponse" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": {
            "description": "The session does not belong to the authenticated user, or the browser Origin header is not allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    { "$ref": "#/components/schemas/JsonRpcResponse" },
                    { "$ref": "#/components/schemas/OriginError" }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "No event-stream session with that id.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JsonRpcResponse" } } }
          },
          "429": { "$ref": "#/components/responses/McpRateLimited" },
          "500": {
            "description": "Unexpected server error.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JsonRpcResponse" } } }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "mcpOAuth": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization-code flow with PKCE (S256). Public clients only: there is no client secret. Send the issued token as `Authorization: Bearer <token>`.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://mcp.aakaarai.com/mcp/authorize",
            "tokenUrl": "https://mcp.aakaarai.com/mcp/token",
            "scopes": {
              "read": "Read access to the user's Aakaar AI account data. Used when a client requests no scope.",
              "write": "Permission to request changes to the user's account, such as campaigns, bids, budgets and listings. Changes run only after the user approves them."
            }
          }
        }
      }
    },
    "parameters": {
      "McpSessionIdRequired": {
        "name": "Mcp-Session-Id",
        "in": "header",
        "required": true,
        "description": "Session identifier returned by the `initialize` response.",
        "schema": { "type": "string" }
      },
      "McpSessionIdOptional": {
        "name": "Mcp-Session-Id",
        "in": "header",
        "required": false,
        "description": "Session identifier returned by the `initialize` response. Required on every request except `initialize`.",
        "schema": { "type": "string" }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "The Bearer token is missing, expired, invalid or was issued for a different resource. The `WWW-Authenticate` header points to the protected resource metadata. Run the OAuth flow again.",
        "headers": {
          "WWW-Authenticate": {
            "description": "Bearer challenge with the realm and the URL of the protected resource metadata.",
            "schema": { "type": "string" }
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/JsonRpcResponse" },
            "example": { "jsonrpc": "2.0", "error": { "code": -32000, "message": "Missing Bearer token" }, "id": 1 }
          }
        }
      },
      "McpRateLimited": {
        "description": "Rate limit exceeded for this user. Wait the number of seconds in `Retry-After`.",
        "headers": {
          "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer", "minimum": 1 } }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/JsonRpcResponse" },
            "example": { "jsonrpc": "2.0", "error": { "code": -32029, "message": "Rate limit exceeded. Please slow down." }, "id": 1 }
          }
        }
      },
      "OAuthRateLimited": {
        "description": "Too many requests from this IP address. Try again in a minute.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/OAuthError" },
            "example": { "error": "too_many_requests", "error_description": "Rate limit exceeded. Please try again later." }
          }
        }
      }
    },
    "schemas": {
      "ProtectedResourceMetadata": {
        "type": "object",
        "description": "RFC 9728 protected resource metadata.",
        "required": ["resource", "authorization_servers"],
        "properties": {
          "resource": { "type": "string", "format": "uri", "description": "The MCP endpoint this metadata describes.", "examples": ["https://mcp.aakaarai.com/mcp"] },
          "authorization_servers": { "type": "array", "items": { "type": "string", "format": "uri" }, "description": "Issuers that can mint tokens for this resource." },
          "bearer_methods_supported": { "type": "array", "items": { "type": "string" }, "description": "How a token may be presented. Always `header`.", "examples": [["header"]] },
          "resource_documentation": { "type": "string", "format": "uri", "description": "Human-readable documentation for this resource." }
        }
      },
      "AuthorizationServerMetadata": {
        "type": "object",
        "description": "RFC 8414 authorization server metadata.",
        "required": ["issuer", "authorization_endpoint", "token_endpoint"],
        "properties": {
          "issuer": { "type": "string", "format": "uri" },
          "authorization_endpoint": { "type": "string", "format": "uri" },
          "token_endpoint": { "type": "string", "format": "uri" },
          "registration_endpoint": { "type": "string", "format": "uri" },
          "token_endpoint_auth_methods_supported": { "type": "array", "items": { "type": "string" }, "examples": [["none"]] },
          "scopes_supported": { "type": "array", "items": { "type": "string" }, "examples": [["read", "write"]] },
          "response_types_supported": { "type": "array", "items": { "type": "string" }, "examples": [["code"]] },
          "response_modes_supported": { "type": "array", "items": { "type": "string" }, "examples": [["query"]] },
          "grant_types_supported": { "type": "array", "items": { "type": "string" }, "examples": [["authorization_code"]] },
          "code_challenge_methods_supported": { "type": "array", "items": { "type": "string" }, "examples": [["S256"]] },
          "ui_locales_supported": { "type": "array", "items": { "type": "string" }, "examples": [["en-US"]] }
        }
      },
      "ClientRegistrationRequest": {
        "type": "object",
        "properties": {
          "client_name": { "type": "string", "description": "Display name for the client." },
          "redirect_uris": { "type": "array", "items": { "type": "string", "format": "uri" }, "description": "Redirect URIs the client will use. Each must be on the server's allow-list." }
        }
      },
      "ClientRegistrationResponse": {
        "type": "object",
        "required": ["client_id"],
        "properties": {
          "client_id": { "type": "string", "description": "Generated client identifier." },
          "client_name": { "type": "string" },
          "redirect_uris": { "type": "array", "items": { "type": "string", "format": "uri" } },
          "token_endpoint_auth_method": { "type": "string", "examples": ["none"] },
          "grant_types": { "type": "array", "items": { "type": "string" }, "examples": [["authorization_code"]] },
          "response_types": { "type": "array", "items": { "type": "string" }, "examples": [["code"]] }
        }
      },
      "TokenRequest": {
        "type": "object",
        "required": ["grant_type", "code"],
        "properties": {
          "grant_type": { "type": "string", "enum": ["authorization_code"] },
          "code": { "type": "string", "description": "Authorization code received at the redirect URI. Single use." },
          "code_verifier": { "type": "string", "description": "PKCE verifier matching the `code_challenge` sent to `authorize`. Required when a challenge was sent." },
          "client_id": { "type": "string", "description": "Must match the client the code was issued to." },
          "redirect_uri": { "type": "string", "format": "uri", "description": "Must match the redirect URI used at the authorize step." },
          "resource": { "type": "string", "format": "uri", "description": "RFC 8707 resource indicator. Required to match when the code was issued for a specific resource." }
        }
      },
      "TokenResponse": {
        "type": "object",
        "required": ["access_token", "token_type", "expires_in"],
        "properties": {
          "access_token": { "type": "string", "description": "Bearer token for the MCP endpoint." },
          "token_type": { "type": "string", "enum": ["Bearer"] },
          "expires_in": { "type": "integer", "description": "Lifetime in seconds (30 days by default).", "examples": [2592000] },
          "scope": { "type": "string", "description": "Space-separated scopes the token was issued for.", "examples": ["read"] }
        }
      },
      "OAuthError": {
        "type": "object",
        "required": ["error"],
        "description": "OAuth error response.",
        "properties": {
          "error": { "type": "string", "description": "Error code, for example `invalid_request`, `invalid_grant`, `invalid_client`, `invalid_target`, `unsupported_grant_type`, `invalid_redirect_uri`, `too_many_requests` or `server_error`." },
          "error_description": { "type": "string", "description": "Human-readable detail." }
        }
      },
      "SimpleError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string" }
        }
      },
      "OriginError": {
        "type": "object",
        "required": ["error"],
        "description": "Returned when a browser sends an Origin header that is not allowed. Requests without an Origin header, such as those from server-side agents, are not affected.",
        "properties": {
          "error": { "type": "string", "enum": ["origin_not_allowed"] }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": ["jsonrpc", "method"],
        "description": "A JSON-RPC 2.0 request or notification. A message without `id` is a notification.",
        "properties": {
          "jsonrpc": { "type": "string", "enum": ["2.0"] },
          "id": { "type": ["string", "integer"], "description": "Request identifier. Omit for notifications." },
          "method": { "type": "string", "description": "MCP method, for example `initialize`, `tools/list` or `tools/call`." },
          "params": { "type": "object", "description": "Method parameters.", "additionalProperties": true }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": ["jsonrpc"],
        "description": "A JSON-RPC 2.0 response. It carries either `result` or `error`.",
        "properties": {
          "jsonrpc": { "type": "string", "enum": ["2.0"] },
          "id": { "type": ["string", "integer", "null"] },
          "result": { "type": "object", "additionalProperties": true },
          "error": { "$ref": "#/components/schemas/JsonRpcError" }
        }
      },
      "JsonRpcError": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": {
            "type": "integer",
            "description": "Server error codes: -32000 missing or malformed request or token, -32001 invalid or expired token or unknown session, -32003 forbidden or missing session id, -32029 rate limit exceeded, -32603 internal error."
          },
          "message": { "type": "string" }
        }
      }
    }
  }
}
