{"openapi":"3.1.0","info":{"title":"Vidext Public API","version":"1.2.0","description":"Vidext's agents turn the documents and procedures your company already has into training for your frontline teams, grounded in your own material. This specification covers the public discovery, authentication, agent registration, and transport surfaces that agent clients use to connect to the Vidext MCP server. Versioning: the MCP surface is versioned by protocol revision (MCP-Protocol-Version header, advertised in /.well-known/mcp); this document's version tracks the REST contract."},"servers":[{"url":"https://app.vidext.io"}],"tags":[{"name":"Docs","description":"Public discovery and documentation endpoints."},{"name":"MCP","description":"Vidext MCP transport endpoints."},{"name":"OAuth","description":"OAuth 2.1 endpoints used by MCP clients."},{"name":"Agent auth","description":"auth.md agentic registration: an agent registers on behalf of a Vidext user, the user confirms with an emailed code, and the agent receives a scoped bearer token. Procedure in /auth.md."}],"externalDocs":{"description":"Developer guide","url":"https://app.vidext.io/developers"},"paths":{"/server.json":{"get":{"operationId":"getRegistryServerMetadata","summary":"Get MCP registry server metadata","description":"Returns a registry-ready server.json document with branding and remote transport metadata for the Vidext MCP server.","tags":["Docs"],"security":[],"responses":{"200":{"description":"MCP registry server definition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpRegistryServerDefinition"}}}}}}},"/.well-known/api-catalog":{"get":{"operationId":"getApiCatalog","summary":"Get API catalog","description":"Returns the RFC 9727 API catalog as an application/linkset+json document so discovery clients can enumerate Vidext's public API surfaces.","tags":["Docs"],"security":[],"responses":{"200":{"description":"API catalog Linkset document","content":{"application/linkset+json":{"schema":{"$ref":"#/components/schemas/ApiCatalogLinkset"}}}}}}},"/.well-known/ard.json":{"get":{"operationId":"getArdCatalog","summary":"Get Agentic Resource Discovery catalog","description":"Returns the ARD manifest listing Vidext's agentic resources (the server cards of the Vidext and docs MCP servers, the Vidext skill, the OpenAPI contract, documentation) as domain-anchored entries.","tags":["Docs"],"security":[],"responses":{"200":{"description":"ARD manifest","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArdManifest"}}}}}}},"/api/agent/auth":{"post":{"operationId":"registerAgent","summary":"Start agent registration","description":"Registers an agent for an existing Vidext user by verified email. Vidext emails the user a six-digit code and returns a one-time claim token. Send Idempotency-Key so a retried request cannot send a second code.","tags":["Agent auth"],"security":[],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Client-generated unique key (a UUID) that makes the request safe to retry. A retry with the same key and body returns the stored response with Idempotent-Replayed: true; the same key with a different body is refused with 422; an overlapping retry gets 409 with Retry-After."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRegistrationRequest"}}}},"responses":{"200":{"description":"Registration created; the user has been emailed a code","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"Quota policy as an IETF RateLimit-Policy structured field, e.g. \"agent-auth-register\";q=60;w=3600 (60 requests per hour per IP)."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window."},"RateLimit":{"schema":{"type":"string"},"description":"The live window as an IETF RateLimit structured field: limit, remaining, and reset seconds."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window resets."},"Idempotent-Replayed":{"schema":{"type":"boolean"},"description":"true when this response was replayed from a previous request with the same Idempotency-Key."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRegistrationResponse"}}}},"400":{"description":"Unsupported identity, assertion, or credential type, or an invalid email","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"409":{"description":"A request with this Idempotency-Key is still in flight","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"422":{"description":"Idempotency-Key reused with a different request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"429":{"description":"Over the per-IP hourly quota (rate_limited). Retry-After says when to try again.","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"Quota policy as an IETF RateLimit-Policy structured field, e.g. \"agent-auth-register\";q=60;w=3600 (60 requests per hour per IP)."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window."},"RateLimit":{"schema":{"type":"string"},"description":"The live window as an IETF RateLimit structured field: limit, remaining, and reset seconds."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"502":{"description":"The verification email could not be delivered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"503":{"description":"A dependency the request needs (rate-limit store, idempotency store, registration state) was unreachable: rate_limit_unavailable, idempotency_unavailable, registration_state_unavailable. Retry later; the request did not run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}}}}},"/api/agent/auth/claim":{"post":{"operationId":"startAgentClaim","summary":"Start an agent claim (reserved)","description":"Reserved for anonymous-start registrations, which Vidext does not enable. Email-required registrations already sent the code, so this endpoint always answers claim_not_required; complete the claim instead.","tags":["Agent auth"],"security":[],"responses":{"400":{"description":"claim_not_required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}}}}},"/api/agent/auth/claim/complete":{"post":{"operationId":"completeAgentClaim","summary":"Complete an agent claim","description":"Exchanges the claim token and the emailed code for a scoped bearer access token. When the user belongs to several workspaces the response lists them and the call is repeated with organization_id. Completion is idempotent per claim token; send Idempotency-Key as well to replay the exact response on a network failure.","tags":["Agent auth"],"security":[],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":255},"description":"Client-generated unique key (a UUID) that makes the request safe to retry. A retry with the same key and body returns the stored response with Idempotent-Replayed: true; the same key with a different body is refused with 422; an overlapping retry gets 409 with Retry-After."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentClaimCompleteRequest"}}}},"responses":{"200":{"description":"Credential issued","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"Quota policy as an IETF RateLimit-Policy structured field, e.g. \"agent-auth-register\";q=60;w=3600 (60 requests per hour per IP)."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window."},"RateLimit":{"schema":{"type":"string"},"description":"The live window as an IETF RateLimit structured field: limit, remaining, and reset seconds."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window resets."},"Idempotent-Replayed":{"schema":{"type":"boolean"},"description":"true when this response was replayed from a previous request with the same Idempotency-Key."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentClaimCompleteResponse"}}}},"400":{"description":"Missing fields or an unknown claim token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"401":{"description":"The code did not match (otp_invalid)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"403":{"description":"The user has no active workspace, or the chosen workspace is not available to them","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"404":{"description":"The verified email does not belong to a Vidext user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"409":{"description":"Workspace selection required (organization_selection_required), the claim is already being completed, or an Idempotency-Key request is in flight","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentOrganizationSelectionRequired"}}}},"410":{"description":"The claim token or code expired; restart registration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"429":{"description":"Over the per-IP hourly quota (rate_limited). Retry-After says when to try again.","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"Quota policy as an IETF RateLimit-Policy structured field, e.g. \"agent-auth-register\";q=60;w=3600 (60 requests per hour per IP)."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window."},"RateLimit":{"schema":{"type":"string"},"description":"The live window as an IETF RateLimit structured field: limit, remaining, and reset seconds."},"RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the current window."},"RateLimit-Reset":{"schema":{"type":"integer"},"description":"Seconds until the window resets."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}},"503":{"description":"A dependency the request needs (rate-limit store, idempotency store, registration state) was unreachable: rate_limit_unavailable, idempotency_unavailable, registration_state_unavailable. Retry later; the request did not run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentAuthError"}}}}}}},"/.well-known/agent-skills/index.json":{"get":{"operationId":"getAgentSkillsIndex","summary":"Get Agent Skills discovery index","description":"Returns the Agent Skills Discovery RFC v0.2.0 index for Vidext-published skills.","tags":["Docs"],"security":[],"responses":{"200":{"description":"Agent Skills discovery index","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSkillsDiscoveryIndex"}}}}}}},"/.well-known/mcp":{"get":{"operationId":"getMcpDiscovery","summary":"Get MCP discovery metadata","description":"Returns discovery metadata for the Vidext MCP server, including transport details, auth discovery, and tool inventory.","tags":["Docs"],"security":[],"responses":{"200":{"description":"MCP discovery metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpDiscovery"}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"operationId":"getOAuthAuthorizationServerMetadata","summary":"Get OAuth authorization server metadata","description":"RFC 8414 authorization server metadata exposed for MCP clients.","tags":["OAuth"],"security":[],"responses":{"200":{"description":"OAuth authorization server metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthAuthorizationServerMetadata"}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"operationId":"getOAuthProtectedResourceMetadata","summary":"Get OAuth protected resource metadata","description":"RFC 9728 protected resource metadata for the Vidext MCP surface.","tags":["OAuth"],"security":[],"responses":{"200":{"description":"OAuth protected resource metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthProtectedResourceMetadata"}}}}}}},"/api/auth/oauth2/authorize":{"get":{"operationId":"authorizeMcpClient","summary":"Start OAuth authorization flow","description":"OAuth 2.1 authorization code + PKCE endpoint, opened in the person's browser. Without a Vidext session it redirects to sign-in. A person who belongs to several workspaces picks one before consent, and the grant is bound to that workspace. A bad request is never answered 400. When client_id names a known, enabled client and redirect_uri is one it registered, the error is redirected there with error, error_description, state, and iss; otherwise (a missing or unknown client_id, an unregistered redirect_uri) it is redirected to https://app.vidext.io/api/auth/error with error and error_description.","tags":["OAuth"],"security":[],"parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","enum":["code"]}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string"},"description":"The client_id from dynamic client registration, or the URL of a client ID metadata document."},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","format":"uri"},"description":"One of the client's registered redirect URIs, matched exactly."},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string"},"description":"PKCE challenge: the base64url SHA-256 of the code_verifier sent to the token endpoint. Required of public clients and, by default, of every client."},{"name":"code_challenge_method","in":"query","required":true,"schema":{"type":"string","enum":["S256"]}},{"name":"scope","in":"query","required":false,"schema":{"type":"string","example":"mcp:read mcp:author offline_access"},"description":"Space-separated scopes. mcp:read for the read tools, mcp:author for the author tools, offline_access for a refresh token; openid, profile, and email are also granted. Omitted, the client's registered scopes apply."},{"name":"state","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque value returned unchanged on the redirect to redirect_uri."},{"name":"resource","in":"query","required":false,"schema":{"type":"string","format":"uri"},"description":"RFC 8707 resource: the MCP endpoint the token is for, https://app.vidext.io/api/mcp. Send it here or on the token request; a grant that names no resource gets an opaque token, which the MCP endpoint refuses."},{"name":"vidext_mcp_organization_id","in":"query","required":false,"schema":{"type":"string"},"description":"The workspace selection, which Vidext's workspace picker signs and adds after the person chooses: the workspace id, an expiry, and a signature bound to the person, the client, the PKCE challenge, redirect_uri, and state. A client leaves it out. A missing, unsigned, tampered, or expired selection sends a person with several workspaces back to the picker."}],"responses":{"200":{"description":"A fetch-driven request (Sec-Fetch-Mode: cors, or Accept: application/json) gets the redirect target as JSON instead of a 302.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeRedirect"}}}},"302":{"description":"Redirect to /sign-in when there is no Vidext session, to the consent page, to redirect_uri with code, state, and iss once the grant is approved, or to an error as the operation description says.","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}},"307":{"description":"The person belongs to several workspaces and none was chosen: redirect to the workspace picker at /sign-in, which comes back here with vidext_mcp_organization_id set.","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}},"403":{"description":"Signed in, but the person authors in no workspace, or the signed selection names a workspace that is no longer theirs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpAuthorizeOrganizationError"}}}},"429":{"description":"Too many requests from this IP for this route. Only X-Retry-After is sent: this route carries no RateLimit-Policy, RateLimit-Limit, or Retry-After headers.","headers":{"X-Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets, as the auth server's limiter reports it."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthServerMessage"}}}}}}},"/api/auth/oauth2/token":{"post":{"operationId":"exchangeMcpToken","summary":"Exchange an authorization code or refresh token","description":"Token endpoint for MCP clients: redeem an authorization code with its PKCE verifier, or rotate a refresh token. Public clients send client_id in the body; confidential clients authenticate with HTTP Basic or client_secret. A token for the MCP endpoint is issued only for a grant bound to a workspace at authorization; one without that binding is refused with invalid_grant. The MCP endpoint does not accept machine (client_credentials) tokens, so that grant is not described here.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"oneOf":[{"$ref":"#/components/schemas/OAuthAuthorizationCodeTokenRequest"},{"$ref":"#/components/schemas/OAuthRefreshTokenRequest"}],"discriminator":{"propertyName":"grant_type","mapping":{"authorization_code":"#/components/schemas/OAuthAuthorizationCodeTokenRequest","refresh_token":"#/components/schemas/OAuthRefreshTokenRequest"}}}}}},"responses":{"200":{"description":"Tokens issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthTokenResponse"}}}},"400":{"description":"OAuth error: invalid_request (a required field is missing), invalid_grant (an unknown, used, or expired code or refresh token; a PKCE or redirect_uri mismatch; or a grant bound to no workspace), invalid_scope, invalid_target, invalid_client (an unknown or disabled public client), or unsupported_grant_type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"invalid_client: HTTP Basic client authentication failed.","headers":{"WWW-Authenticate":{"schema":{"type":"string","example":"Basic"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"415":{"description":"The body is not application/x-www-form-urlencoded (code UNSUPPORTED_MEDIA_TYPE).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthServerMessage"}}}},"429":{"description":"Too many requests from this IP for this route. Only X-Retry-After is sent: this route carries no RateLimit-Policy, RateLimit-Limit, or Retry-After headers.","headers":{"X-Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets, as the auth server's limiter reports it."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthServerMessage"}}}}}}},"/api/auth/oauth2/register":{"post":{"operationId":"registerMcpClient","summary":"Register OAuth client dynamically","description":"RFC 7591 dynamic client registration for MCP clients that do not ship with OAuth client credentials. Registration is open: no initial access token or session is needed. A client registered with token_endpoint_auth_method none is public and must use PKCE; any other gets a client_secret, returned once.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["redirect_uris"],"properties":{"redirect_uris":{"type":"array","minItems":1,"items":{"type":"string","format":"uri"},"description":"Required for the authorization_code grant, which every MCP client uses."},"grant_types":{"type":"array","items":{"type":"string"},"default":["authorization_code"],"description":"authorization_code (the default) and refresh_token. client_credentials is refused unless the request comes from a signed-in Vidext session."},"response_types":{"type":"array","items":{"type":"string","enum":["code"]}},"token_endpoint_auth_method":{"type":"string","enum":["none","client_secret_basic","client_secret_post","private_key_jwt"],"default":"client_secret_basic"},"client_name":{"type":"string"},"scope":{"type":"string","description":"Space-separated scopes the client may request."},"application_type":{"type":"string","enum":["web","native"]}}}}}},"responses":{"201":{"description":"Client registered","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"The policy the /api/auth route adapter advertises for this path, as an IETF RateLimit-Policy structured field, e.g. \"auth\";q=50;w=10."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window: the quota, not what is left."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DynamicClientRegistrationResponse"}}}},"400":{"description":"OAuth error: invalid_redirect_uri, invalid_client_metadata (an unsupported grant type, auth method, or response type combination), or invalid_target.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"Too many requests from this IP for this route.","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"The policy the /api/auth route adapter advertises for this path, as an IETF RateLimit-Policy structured field, e.g. \"auth\";q=50;w=10."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window: the quota, not what is left."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."},"X-Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets, as the auth server's limiter reports it."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthServerMessage"}}}}}}},"/api/auth/oauth2/userinfo":{"get":{"operationId":"getMcpUserInfo","summary":"Get user info","description":"OpenID Connect UserInfo for the person an OAuth access token was issued to. The token needs the openid scope; profile and email add claims. Agent-registration tokens carry no openid scope and are refused.","tags":["OAuth"],"security":[{"oauth2":["openid"]}],"responses":{"200":{"description":"User info response","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"The policy the /api/auth route adapter advertises for this path, as an IETF RateLimit-Policy structured field, e.g. \"auth\";q=50;w=10."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window: the quota, not what is left."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfoResponse"}}}},"400":{"description":"invalid_scope: the token does not carry openid. invalid_request: the token's user no longer exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"No bearer token: invalid_request, with no WWW-Authenticate header. A token that is unknown, expired, or revoked: invalid_token, with a bearer challenge that names no resource metadata.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"Present only when a token was sent and refused.","example":"Bearer error=\"invalid_token\", error_description=\"Invalid access token\""}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"examples":{"missingToken":{"value":{"error":"invalid_request","error_description":"access token not found"}},"invalidToken":{"value":{"error":"invalid_token","error_description":"Invalid access token"}}}}}},"429":{"description":"Too many requests from this IP for this route.","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"The policy the /api/auth route adapter advertises for this path, as an IETF RateLimit-Policy structured field, e.g. \"auth\";q=50;w=10."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window: the quota, not what is left."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."},"X-Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets, as the auth server's limiter reports it."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthServerMessage"}}}}}}},"/api/auth/jwks":{"get":{"operationId":"getMcpJwks","summary":"Get JSON Web Key Set","description":"Returns the JWKS that signs Vidext's OAuth and agent-registration access tokens.","tags":["OAuth"],"security":[],"responses":{"200":{"description":"JWKS response","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"The policy the /api/auth route adapter advertises for this path, as an IETF RateLimit-Policy structured field, e.g. \"auth\";q=50;w=10."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window: the quota, not what is left."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JwksResponse"}}}},"429":{"description":"Too many requests from this IP for this route.","headers":{"RateLimit-Policy":{"schema":{"type":"string"},"description":"The policy the /api/auth route adapter advertises for this path, as an IETF RateLimit-Policy structured field, e.g. \"auth\";q=50;w=10."},"RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per policy window: the quota, not what is left."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."},"X-Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the rate-limit window resets, as the auth server's limiter reports it."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthServerMessage"}}}}}}},"/api/mcp":{"get":{"operationId":"vidextMcpGet","tags":["MCP"],"security":[{"oauth2":["mcp:read"]},{"oauth2":["mcp:author"]},{"agentAuth":[]}],"summary":"GET is not supported","description":"The endpoint is stateless and takes only POST: it never issues an Mcp-Session-Id, so a GET has no server-to-client stream to open, and a DELETE no session to end; both are answered 405. Authentication runs first, so an unauthenticated GET gets 401 and an authenticated one 405.","responses":{"401":{"description":"Missing, malformed, unknown, revoked, or expired bearer token, or one issued for another path. The body is an OAuth error, not JSON-RPC. Re-run OAuth discovery from the challenge.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"RFC 6750 bearer challenge carrying the RFC 9728 resource_metadata URL to start OAuth discovery from.","example":"Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp\""},"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"example":{"error":"invalid_token","error_description":"Missing Authorization header"}}}},"403":{"description":"insufficient_scope: the token holds none of mcp:read, mcp:operator.read, mcp:author; or, on a tools/call, not the scope that tool needs (mcp:read for the read tools, mcp:author for the author tools). The challenge's scope parameter names what to request; a tool's challenge also repeats the scopes the token already holds. The body is an OAuth error.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"RFC 6750 insufficient_scope challenge with the scopes to request and the resource_metadata URL.","example":"Bearer error=\"insufficient_scope\", error_description=\"Token is missing one of the required scopes: mcp:read, mcp:operator.read, mcp:author\", scope=\"mcp:read mcp:author\", resource_metadata=\"https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp\""},"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"405":{"description":"An authenticated GET (or DELETE). Send POST instead.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"},"example":{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}}}},"500":{"description":"The server could not check the token (the token store failed). The body is an OAuth server_error. Retry after a short wait.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"example":{"error":"server_error","error_description":"Internal Server Error"}}}}}},"post":{"operationId":"vidextMcpPost","tags":["MCP"],"security":[{"oauth2":["mcp:read"]},{"oauth2":["mcp:author"]},{"agentAuth":[]}],"summary":"MCP transport","description":"Remote MCP transport for the Vidext MCP server: JSON-RPC over streamable HTTP, POST only. 2026-07-28 requests and 2025-era requests (including an initialize handshake) are each served statelessly; no session is issued. An unauthenticated request gets a bearer challenge that points to OAuth discovery. Rate and concurrency limits come back as tool errors inside a 200 result, never as HTTP 429, and no RateLimit or Retry-After headers are sent.","parameters":[{"name":"MCP-Protocol-Version","in":"header","required":false,"schema":{"type":"string","enum":["2026-07-28","2025-11-25","2025-06-18","2025-03-26"]},"description":"MCP protocol revision the client speaks: the revisions listed in /.well-known/mcp protocolVersions. 2026-07-28 requests carry it on every call; a 2025-era client sends it after its initialize handshake, and every 2025 request is served statelessly over POST. A 2026-07-28 request naming a revision the server does not serve is answered with JSON-RPC error -32022."},{"name":"Mcp-Method","in":"header","required":false,"schema":{"type":"string","example":"tools/call"},"description":"The JSON-RPC method in the body. Required on every 2026-07-28 request (not on notifications); missing or disagreeing with the body, it is answered 400 with JSON-RPC -32020."},{"name":"Mcp-Name","in":"header","required":false,"schema":{"type":"string","example":"list_modules"},"description":"The name the body's params carry: the tool name on tools/call, the URI on resources/read. Required on those 2026-07-28 requests; missing or disagreeing with the body, it is answered 400 with JSON-RPC -32020."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}},"responses":{"200":{"description":"The JSON-RPC response. A call that reports progress while it runs (an author tool waiting on the author) is answered as an event stream; any other is plain JSON. A tool that fails, including on an admission limit, answers with a result whose isError is true.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/JsonRpcSuccessResponse"},{"$ref":"#/components/schemas/JsonRpcErrorResponse"}]}},"text/event-stream":{"schema":{"type":"string","description":"Server-sent events, each carrying one JSON-RPC message: progress notifications, then the response."}}}},"400":{"description":"Refused before dispatch with a JSON-RPC error: -32022 when a 2026-07-28 request names a revision the server does not serve (error.data.supported lists the served revisions of that era); -32000 when a 2025-era request's MCP-Protocol-Version names one it does not serve; -32020 when Mcp-Method or Mcp-Name is missing or does not match the body; -32700 or -32600 when the body is not a JSON-RPC message.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"}}}},"401":{"description":"Missing, malformed, unknown, revoked, or expired bearer token, or one issued for another path. The body is an OAuth error, not JSON-RPC. Re-run OAuth discovery from the challenge.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"RFC 6750 bearer challenge carrying the RFC 9728 resource_metadata URL to start OAuth discovery from.","example":"Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp\""},"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"example":{"error":"invalid_token","error_description":"Missing Authorization header"}}}},"403":{"description":"insufficient_scope: the token holds none of mcp:read, mcp:operator.read, mcp:author; or, on a tools/call, not the scope that tool needs (mcp:read for the read tools, mcp:author for the author tools). The challenge's scope parameter names what to request; a tool's challenge also repeats the scopes the token already holds. The body is an OAuth error.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"RFC 6750 insufficient_scope challenge with the scopes to request and the resource_metadata URL.","example":"Bearer error=\"insufficient_scope\", error_description=\"Token is missing one of the required scopes: mcp:read, mcp:operator.read, mcp:author\", scope=\"mcp:read mcp:author\", resource_metadata=\"https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp\""},"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"406":{"description":"A 2025-era POST whose Accept header does not list both application/json and text/event-stream.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"},"example":{"jsonrpc":"2.0","error":{"code":-32000,"message":"Not Acceptable: Client must accept both application/json and text/event-stream"},"id":null}}}},"415":{"description":"A 2025-era POST whose Content-Type is not application/json.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"},"example":{"jsonrpc":"2.0","error":{"code":-32000,"message":"Unsupported Media Type: Content-Type must be application/json"},"id":null}}}},"500":{"description":"The server could not check the token (the token store failed). The body is an OAuth server_error. Retry after a short wait.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"example":{"error":"server_error","error_description":"Internal Server Error"}}}}}}},"/api/mcp/operator":{"get":{"operationId":"vidextMcpGetDeprecatedAlias","deprecated":true,"tags":["MCP"],"security":[{"oauth2":["mcp:read"]},{"oauth2":["mcp:author"]}],"summary":"GET is not supported (deprecated alias of /api/mcp)","description":"Deprecated alias of /api/mcp, served in full until its Sunset date; every response carries Deprecation, Sunset, and a successor-version Link. Tokens are bound to the path they were issued for, so the alias is not redirected; register new clients against /api/mcp. The endpoint is stateless and takes only POST: it never issues an Mcp-Session-Id, so a GET has no server-to-client stream to open, and a DELETE no session to end; both are answered 405. Authentication runs first, so an unauthenticated GET gets 401 and an authenticated one 405.","responses":{"401":{"description":"Missing, malformed, unknown, revoked, or expired bearer token, or one issued for another path. The body is an OAuth error, not JSON-RPC. Re-run OAuth discovery from the challenge.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"RFC 6750 bearer challenge carrying the RFC 9728 resource_metadata URL to start OAuth discovery from.","example":"Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp/operator\""},"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"example":{"error":"invalid_token","error_description":"Missing Authorization header"}}}},"403":{"description":"insufficient_scope: the token holds none of mcp:read, mcp:operator.read, mcp:author; or, on a tools/call, not the scope that tool needs (mcp:read for the read tools, mcp:author for the author tools). The challenge's scope parameter names what to request; a tool's challenge also repeats the scopes the token already holds. The body is an OAuth error.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"RFC 6750 insufficient_scope challenge with the scopes to request and the resource_metadata URL.","example":"Bearer error=\"insufficient_scope\", error_description=\"Token is missing one of the required scopes: mcp:read, mcp:operator.read, mcp:author\", scope=\"mcp:read mcp:author\", resource_metadata=\"https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp/operator\""},"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"405":{"description":"An authenticated GET (or DELETE). Send POST instead.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"},"example":{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}}}},"500":{"description":"The server could not check the token (the token store failed). The body is an OAuth server_error. Retry after a short wait.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"example":{"error":"server_error","error_description":"Internal Server Error"}}}}}},"post":{"operationId":"vidextMcpPostDeprecatedAlias","deprecated":true,"tags":["MCP"],"security":[{"oauth2":["mcp:read"]},{"oauth2":["mcp:author"]}],"summary":"MCP transport (deprecated alias of /api/mcp)","description":"Deprecated alias of /api/mcp, served in full until its Sunset date; every response carries Deprecation, Sunset, and a successor-version Link. Tokens are bound to the path they were issued for, so the alias is not redirected; register new clients against /api/mcp. Remote MCP transport for the Vidext MCP server: JSON-RPC over streamable HTTP, POST only. 2026-07-28 requests and 2025-era requests (including an initialize handshake) are each served statelessly; no session is issued. An unauthenticated request gets a bearer challenge that points to OAuth discovery. Rate and concurrency limits come back as tool errors inside a 200 result, never as HTTP 429, and no RateLimit or Retry-After headers are sent.","parameters":[{"name":"MCP-Protocol-Version","in":"header","required":false,"schema":{"type":"string","enum":["2026-07-28","2025-11-25","2025-06-18","2025-03-26"]},"description":"MCP protocol revision the client speaks: the revisions listed in /.well-known/mcp protocolVersions. 2026-07-28 requests carry it on every call; a 2025-era client sends it after its initialize handshake, and every 2025 request is served statelessly over POST. A 2026-07-28 request naming a revision the server does not serve is answered with JSON-RPC error -32022."},{"name":"Mcp-Method","in":"header","required":false,"schema":{"type":"string","example":"tools/call"},"description":"The JSON-RPC method in the body. Required on every 2026-07-28 request (not on notifications); missing or disagreeing with the body, it is answered 400 with JSON-RPC -32020."},{"name":"Mcp-Name","in":"header","required":false,"schema":{"type":"string","example":"list_modules"},"description":"The name the body's params carry: the tool name on tools/call, the URI on resources/read. Required on those 2026-07-28 requests; missing or disagreeing with the body, it is answered 400 with JSON-RPC -32020."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}},"responses":{"200":{"description":"The JSON-RPC response. A call that reports progress while it runs (an author tool waiting on the author) is answered as an event stream; any other is plain JSON. A tool that fails, including on an admission limit, answers with a result whose isError is true.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/JsonRpcSuccessResponse"},{"$ref":"#/components/schemas/JsonRpcErrorResponse"}]}},"text/event-stream":{"schema":{"type":"string","description":"Server-sent events, each carrying one JSON-RPC message: progress notifications, then the response."}}}},"400":{"description":"Refused before dispatch with a JSON-RPC error: -32022 when a 2026-07-28 request names a revision the server does not serve (error.data.supported lists the served revisions of that era); -32000 when a 2025-era request's MCP-Protocol-Version names one it does not serve; -32020 when Mcp-Method or Mcp-Name is missing or does not match the body; -32700 or -32600 when the body is not a JSON-RPC message.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"}}}},"401":{"description":"Missing, malformed, unknown, revoked, or expired bearer token, or one issued for another path. The body is an OAuth error, not JSON-RPC. Re-run OAuth discovery from the challenge.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"RFC 6750 bearer challenge carrying the RFC 9728 resource_metadata URL to start OAuth discovery from.","example":"Bearer error=\"invalid_token\", error_description=\"Missing Authorization header\", resource_metadata=\"https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp/operator\""},"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"example":{"error":"invalid_token","error_description":"Missing Authorization header"}}}},"403":{"description":"insufficient_scope: the token holds none of mcp:read, mcp:operator.read, mcp:author; or, on a tools/call, not the scope that tool needs (mcp:read for the read tools, mcp:author for the author tools). The challenge's scope parameter names what to request; a tool's challenge also repeats the scopes the token already holds. The body is an OAuth error.","headers":{"WWW-Authenticate":{"schema":{"type":"string"},"description":"RFC 6750 insufficient_scope challenge with the scopes to request and the resource_metadata URL.","example":"Bearer error=\"insufficient_scope\", error_description=\"Token is missing one of the required scopes: mcp:read, mcp:operator.read, mcp:author\", scope=\"mcp:read mcp:author\", resource_metadata=\"https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp/operator\""},"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"406":{"description":"A 2025-era POST whose Accept header does not list both application/json and text/event-stream.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"},"example":{"jsonrpc":"2.0","error":{"code":-32000,"message":"Not Acceptable: Client must accept both application/json and text/event-stream"},"id":null}}}},"415":{"description":"A 2025-era POST whose Content-Type is not application/json.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"},"example":{"jsonrpc":"2.0","error":{"code":-32000,"message":"Unsupported Media Type: Content-Type must be application/json"},"id":null}}}},"500":{"description":"The server could not check the token (the token store failed). The body is an OAuth server_error. Retry after a short wait.","headers":{"Deprecation":{"schema":{"type":"string"},"description":"RFC 9745 deprecation timestamp (@<unix seconds>), present only when the request's path or MCP-Protocol-Version is scheduled for removal."},"Sunset":{"schema":{"type":"string"},"description":"RFC 8594 HTTP date after which the request's path or MCP-Protocol-Version stops being served; served at least 90 days after Deprecation."},"Link":{"schema":{"type":"string"},"description":"With Deprecation: the deprecation policy (rel=\"deprecation\" and rel=\"sunset\") and, on a deprecated path, the path that replaces it (rel=\"successor-version\")."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"},"example":{"error":"server_error","error_description":"Internal Server Error"}}}}}}}},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","description":"OAuth 2.1 authorization code with PKCE (S256), for an MCP client acting for a person. Discover it from https://app.vidext.io/.well-known/oauth-protected-resource/api/mcp, register at https://app.vidext.io/api/auth/oauth2/register, and send resource=https://app.vidext.io/api/mcp so the token is a JWT the MCP endpoint accepts. The MCP endpoint admits a token with any one of its scopes; mcp:operator.read, the read scope's earlier name, is still accepted but no longer advertised.","flows":{"authorizationCode":{"authorizationUrl":"https://app.vidext.io/api/auth/oauth2/authorize","tokenUrl":"https://app.vidext.io/api/auth/oauth2/token","refreshUrl":"https://app.vidext.io/api/auth/oauth2/token","scopes":{"mcp:read":"Read the workspace over MCP: search its knowledge and list its modules.","mcp:author":"Talk to the Vidext author for the workspace: send the person's messages, answer its questions, stop it, and read what it did.","openid":"Sign the person in with OpenID Connect; needed for userinfo.","profile":"Add the person's name and picture to userinfo.","email":"Add the person's email address to userinfo.","offline_access":"Issue a refresh token with the access token."}}}},"agentAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Access token from agent registration (/api/agent/auth, then /api/agent/auth/claim/complete; procedure in /auth.md). It carries mcp:read and mcp:author for one workspace, lasts 7 days, has no refresh token, and is valid only at /api/mcp."}},"schemas":{"ArdEntry":{"type":"object","required":["identifier","displayName","type","url"],"properties":{"identifier":{"type":"string","pattern":"^urn:air:[a-zA-Z0-9.-]+(:[a-zA-Z0-9._-]+)+$"},"displayName":{"type":"string"},"type":{"type":"string","description":"IANA media type"},"url":{"type":"string","format":"uri"},"version":{"type":"string"},"description":{"type":"string"},"capabilities":{"type":"array","items":{"type":"string"}},"representativeQueries":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"trustManifest":{"type":"object","required":["identity"],"properties":{"identity":{"type":"string","format":"uri"},"identityType":{"type":"string"}},"additionalProperties":true}},"additionalProperties":true},"ArdManifest":{"type":"object","required":["entries"],"properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/ArdEntry"}}}},"AgentRegistrationRequest":{"type":"object","required":["type","assertion_type","assertion"],"properties":{"type":{"type":"string","enum":["identity_assertion"]},"assertion_type":{"type":"string","enum":["verified_email"]},"assertion":{"type":"string","format":"email","description":"Email address of an existing Vidext user."},"requested_credential_type":{"type":"string","enum":["access_token"],"default":"access_token"}},"additionalProperties":false},"AgentRegistrationResponse":{"type":"object","required":["registration_id","registration_type","claim_url","claim_token","claim_token_expires","post_claim_scopes"],"properties":{"registration_id":{"type":"string","example":"reg_..."},"registration_type":{"type":"string","enum":["email-verification"]},"claim_url":{"type":"string","format":"uri"},"claim_token":{"type":"string","description":"Returned once; needed to complete the claim."},"claim_token_expires":{"type":"string","format":"date-time"},"post_claim_scopes":{"type":"array","items":{"type":"string","enum":["mcp:read","mcp:author"]}}}},"AgentClaimCompleteRequest":{"type":"object","required":["claim_token","otp"],"properties":{"claim_token":{"type":"string"},"otp":{"type":"string","pattern":"^[0-9]{6}$","description":"The six-digit code the user received by email."},"organization_id":{"type":"string","format":"uuid","description":"Workspace to bind the credential to; required after an organization_selection_required response."}},"additionalProperties":false},"AgentClaimCompleteResponse":{"type":"object","required":["registration_id","status","credential_type","credential","credential_expires","scopes"],"properties":{"registration_id":{"type":"string"},"status":{"type":"string","enum":["claimed"]},"credential_type":{"type":"string","enum":["access_token"]},"credential":{"type":"string","description":"Bearer token for the Vidext MCP endpoint."},"credential_expires":{"type":"string","format":"date-time"},"scopes":{"type":"array","items":{"type":"string","enum":["mcp:read","mcp:author"]}}}},"AgentOrganizationSelectionRequired":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","enum":["organization_selection_required","claimed_or_in_flight","idempotency_in_flight"]},"message":{"type":"string"},"organizations":{"type":"array","items":{"type":"object","required":["id","name","slug","role"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"role":{"type":"string"}}}}}},"AgentAuthError":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","description":"Error code; the full table is in /auth.md."},"message":{"type":"string"}}},"ApiCatalogLink":{"type":"object","required":["href"],"properties":{"href":{"type":"string","format":"uri"},"type":{"type":"string"}}},"ApiCatalogEntry":{"type":"object","required":["anchor"],"properties":{"anchor":{"type":"string","format":"uri"},"item":{"type":"array","items":{"$ref":"#/components/schemas/ApiCatalogLink"}},"service-desc":{"type":"array","items":{"$ref":"#/components/schemas/ApiCatalogLink"}},"service-doc":{"type":"array","items":{"$ref":"#/components/schemas/ApiCatalogLink"}},"service-meta":{"type":"array","items":{"$ref":"#/components/schemas/ApiCatalogLink"}}}},"ApiCatalogLinkset":{"type":"object","required":["linkset"],"properties":{"linkset":{"type":"array","items":{"$ref":"#/components/schemas/ApiCatalogEntry"}}},"example":{"linkset":[{"anchor":"https://app.vidext.io/.well-known/api-catalog","item":[{"href":"https://app.vidext.io/api/mcp"}]},{"anchor":"https://app.vidext.io/api/mcp","service-desc":[{"href":"https://app.vidext.io/openapi.json","type":"application/json"}],"service-doc":[{"href":"https://app.vidext.io/developers","type":"text/markdown"}]}]}},"AgentSkillEntry":{"type":"object","required":["name","type","description","url","digest"],"properties":{"name":{"type":"string","example":"vidext"},"type":{"type":"string","enum":["skill-md","archive"]},"description":{"type":"string","maxLength":1024},"url":{"type":"string","format":"uri"},"digest":{"type":"string","pattern":"^sha256:[a-f0-9]{64}$"}}},"AgentSkillsDiscoveryIndex":{"type":"object","required":["$schema","skills"],"properties":{"$schema":{"type":"string","format":"uri","example":"https://schemas.agentskills.io/discovery/0.2.0/schema.json"},"skills":{"type":"array","items":{"$ref":"#/components/schemas/AgentSkillEntry"}}},"example":{"$schema":"https://schemas.agentskills.io/discovery/0.2.0/schema.json","skills":[{"name":"vidext","type":"skill-md","description":"Use the Vidext MCP server to search organization knowledge and connected sources, list modules, and talk to the Vidext author that plans and builds them.","url":"https://app.vidext.io/.well-known/agent-skills/vidext/SKILL.md","digest":"sha256:0000000000000000000000000000000000000000000000000000000000000000"}]}},"McpRegistryIcon":{"type":"object","required":["src"],"properties":{"src":{"type":"string","format":"uri"},"mimeType":{"type":"string"},"sizes":{"type":"array","items":{"type":"string"}}}},"McpRegistryServerDefinition":{"type":"object","required":["$schema","name","description","version"],"properties":{"$schema":{"type":"string","format":"uri"},"name":{"type":"string","example":"com.vidext/vidext"},"title":{"type":"string","example":"Vidext"},"description":{"type":"string","example":"Vidext's agents turn the documents and procedures your company already has into training for your frontline teams, grounded in your own material."},"version":{"type":"string","example":"0.7.0"},"websiteUrl":{"type":"string","format":"uri","example":"https://app.vidext.io/developers"},"icons":{"type":"array","items":{"$ref":"#/components/schemas/McpRegistryIcon"}},"remotes":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","example":"streamable-http"},"url":{"type":"string","format":"uri"}}}},"_meta":{"type":"object","additionalProperties":true}},"example":{"$schema":"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json","name":"com.vidext/vidext","title":"Vidext","description":"Vidext's agents turn the documents and procedures your company already has into training for your frontline teams, grounded in your own material.","version":"0.7.0","websiteUrl":"https://app.vidext.io/developers","icons":[{"src":"https://app.vidext.io/apple-icon.png","mimeType":"image/png","sizes":["180x180"]}],"remotes":[{"type":"streamable-http","url":"https://app.vidext.io/api/mcp"}]}},"McpDiscovery":{"type":"object","properties":{"name":{"type":"string","example":"Vidext"},"description":{"type":"string","example":"Vidext's agents turn the documents and procedures your company already has into training for your frontline teams, grounded in your own material."},"mcp":{"type":"object","properties":{"transport":{"type":"string","example":"streamable-http"},"endpoint":{"type":"string","format":"uri","example":"https://app.vidext.io/api/mcp"},"protocolVersions":{"type":"array","items":{"type":"string"},"example":["2026-07-28","2025-11-25","2025-06-18","2025-03-26"]}}},"auth":{"type":"object","properties":{"required":{"type":"boolean"},"type":{"type":"string","example":"oauth2"},"authorizationServer":{"type":"string","format":"uri"},"protectedResource":{"type":"string","format":"uri"}}},"tools":{"type":"array","items":{"type":"string"}},"documentationServer":{"type":"object","description":"The public, unauthenticated documentation MCP server that pairs with the Vidext MCP server.","properties":{"name":{"type":"string","example":"Vidext Documentation"},"description":{"type":"string"},"serverCard":{"type":"string","format":"uri"},"mcp":{"type":"object","properties":{"transport":{"type":"string","example":"streamable-http"},"endpoint":{"type":"string","format":"uri","example":"https://app.vidext.io/api/mcp/docs"},"protocolVersions":{"type":"array","items":{"type":"string"}}}},"auth":{"type":"object","properties":{"required":{"type":"boolean","example":false}}},"tools":{"type":"array","items":{"type":"string"},"example":["list_docs","search_docs","read_doc"]},"instructions":{"type":"string"}}}}},"OAuthAuthorizationServerMetadata":{"type":"object","properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"userinfo_endpoint":{"type":"string","format":"uri"},"jwks_uri":{"type":"string","format":"uri"},"registration_endpoint":{"type":"string","format":"uri"},"scopes_supported":{"type":"array","items":{"type":"string"}},"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"}}}},"OAuthProtectedResourceMetadata":{"type":"object","properties":{"resource":{"type":"string","format":"uri"},"authorization_servers":{"type":"array","items":{"type":"string","format":"uri"}},"jwks_uri":{"type":"string","format":"uri"},"scopes_supported":{"type":"array","items":{"type":"string"}},"bearer_methods_supported":{"type":"array","items":{"type":"string"}}}},"OAuthAuthorizationCodeTokenRequest":{"type":"object","required":["grant_type","code","redirect_uri","code_verifier"],"properties":{"grant_type":{"type":"string","enum":["authorization_code"]},"code":{"type":"string","description":"The code from the authorization redirect: single use, valid for 10 minutes."},"redirect_uri":{"type":"string","format":"uri","description":"The redirect_uri sent to the authorization endpoint, exactly."},"code_verifier":{"type":"string","description":"The PKCE verifier whose S256 hash was sent as code_challenge."},"client_id":{"type":"string","description":"Required unless the client authenticates with HTTP Basic."},"client_secret":{"type":"string","description":"Only for a confidential client registered with client_secret_post."},"resource":{"type":"string","format":"uri","description":"The MCP endpoint the token is for, https://app.vidext.io/api/mcp. If the authorization request named resources, this must be one of them."}}},"OAuthRefreshTokenRequest":{"type":"object","required":["grant_type","refresh_token"],"properties":{"grant_type":{"type":"string","enum":["refresh_token"]},"refresh_token":{"type":"string","description":"The latest refresh token. Each refresh rotates it; repeating the same refresh within 30 seconds returns the same rotated response."},"client_id":{"type":"string","description":"Required unless the client authenticates with HTTP Basic."},"client_secret":{"type":"string","description":"Only for a confidential client registered with client_secret_post."},"scope":{"type":"string","description":"Space-separated subset of the scopes originally granted. Omitted, the original scopes are kept."},"resource":{"type":"string","format":"uri","description":"Must be among the resources the refresh token was issued for."}}},"OAuthTokenResponse":{"type":"object","required":["access_token","token_type","expires_in"],"properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string","description":"Issued only when offline_access was granted."},"token_type":{"type":"string","example":"Bearer"},"expires_in":{"type":"integer"},"scope":{"type":"string"},"id_token":{"type":"string","description":"Issued only when openid was granted."}}},"OAuthError":{"type":"object","required":["error"],"description":"The OAuth error body of RFC 6749 section 5.2 and RFC 6750 section 3.","properties":{"error":{"type":"string","example":"invalid_token"},"error_description":{"type":"string"},"error_uri":{"type":"string","format":"uri"}}},"AuthServerMessage":{"type":"object","required":["message"],"description":"The auth server's own refusal body, used for rate limits and unsupported media types.","properties":{"message":{"type":"string"},"code":{"type":"string","example":"UNSUPPORTED_MEDIA_TYPE"}}},"AuthorizeRedirect":{"type":"object","required":["redirect","url"],"properties":{"redirect":{"type":"boolean","enum":[true]},"url":{"type":"string","format":"uri","description":"Where a browser would have been redirected."}}},"McpAuthorizeOrganizationError":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"A sentence for the person, not an OAuth error code.","example":"Selected organization is not available to this user."}}},"DynamicClientRegistrationResponse":{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","description":"Returned once, and only to a confidential client (token_endpoint_auth_method other than none)."},"client_id_issued_at":{"type":"integer"},"client_secret_expires_at":{"type":"integer","description":"0 when the secret never expires."},"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"}},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_method":{"type":"string"},"scope":{"type":"string"},"resources":{"type":"array","items":{"type":"string","format":"uri"},"description":"The protected resources the client is linked to."}}},"UserInfoResponse":{"type":"object","required":["sub"],"properties":{"sub":{"type":"string"},"name":{"type":"string","description":"With profile."},"picture":{"type":"string","format":"uri","description":"With profile."},"given_name":{"type":"string","description":"With profile."},"family_name":{"type":"string","description":"With profile."},"email":{"type":"string","format":"email","description":"With email."},"email_verified":{"type":"boolean","description":"With email."}}},"Jwk":{"type":"object","properties":{"kty":{"type":"string"},"kid":{"type":"string"},"use":{"type":"string"},"alg":{"type":"string"},"n":{"type":"string"},"e":{"type":"string"}}},"JwksResponse":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/Jwk"}}}},"JsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"type":"string","example":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"method":{"type":"string"},"params":{"type":"object","additionalProperties":true}}},"JsonRpcSuccessResponse":{"type":"object","required":["jsonrpc","id","result"],"properties":{"jsonrpc":{"type":"string","example":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"result":{"type":"object","additionalProperties":true}}},"JsonRpcErrorResponse":{"type":"object","required":["jsonrpc","error","id"],"properties":{"jsonrpc":{"type":"string","example":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer"},"message":{"type":"string"},"data":{"description":"Extra detail, e.g. the served revisions (supported) on a -32022 refusal."}}}}}}}}