Integrations

OAuth

probr is its own OAuth 2.1 authorization server. If you are connecting a standard MCP client you do not need this page — MCP is enough, and the client does all of it for you. This is for writing one.

What kind of server this is

Public clients with PKCE, and nothing else. There are no client secrets, no implicit grant, and no client_credentials — every token is issued on behalf of a person who approved it in a browser.

SettingValue
Issuerhttps://api.probr.ai
Metadatahttps://api.probr.ai/.well-known/oauth-authorization-server
Grantsauthorization_code, refresh_token
PKCERequired, S256 only
Client authnone — public clients
Scopeprobr.read
Access token1 hour
Refresh token30 days

Start from the metadata document rather than from this table. It is the same information, it is machine-readable, and it stays correct if anything moves.

1 · Register

Dynamic client registration, no credentials required. redirect_uris is the only required field.

curl -X POST https://api.probr.ai/oauth/register \
  -H 'Content-Type: application/json' \
  -d '{
    "client_name": "My assistant",
    "redirect_uris": ["http://127.0.0.1:8976/callback"]
  }'

You get back a client_id. There is no secret to store — hold the id and register again if you lose it.

2 · Authorize

Send the user's browser to /oauth/authorize:

https://api.probr.ai/oauth/authorize
  ?response_type=code
  &client_id=<client_id>
  &redirect_uri=http://127.0.0.1:8976/callback
  &code_challenge=<S256 of your verifier>
  &code_challenge_method=S256
  &scope=probr.read
  &state=<random>
  &resource=https://mcp.probr.ai/mcp

resource names what the token is for, and the token's audience is bound to it. For MCP, pass the MCP endpoint.

probr redirects to a consent screen showing which client is asking, which probr account is granting, and what probr.read covers. The user signs in if they are not already, then approves or declines.

On approval you are redirected back with code and your state. The code is single-use and expires in five minutes.

Two ways this fails before consent, and they behave differently on purpose. An unknown client_id or a redirect_uri that does not match a registered one returns an error directly — there is nowhere safe to redirect to. Everything else — a missing PKCE challenge, a scope that does not exist, a response type other than code — comes back to your redirect_uri as ?error=…, which is where a client can actually handle it.

3 · Token

curl -X POST https://api.probr.ai/oauth/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code' \
  -d 'code=<code>' \
  -d 'client_id=<client_id>' \
  -d 'redirect_uri=http://127.0.0.1:8976/callback' \
  -d 'code_verifier=<the verifier>' \
  -d 'resource=https://mcp.probr.ai/mcp'

Returns an access token, a refresh token, and expires_in. Refresh the same way with grant_type=refresh_token.

4 · Call

Authorization: Bearer <access_token>

The MCP server checks three things on every request, not just the first: the signature, that the audience matches its own address, and that the workspace is on a paid plan. A token minted for a different resource is rejected even if it is otherwise valid.

Errors you will meet

401 with a WWW-Authenticate header. The token is missing, expired, or has the wrong audience. The header points at the protected-resource metadata, which is how a client rediscovers where to authenticate.

403 MCP access is not included in your current plan. The token is fine and the workspace has no live plan — the trial or a subscription ended. This also fails earlier, at consent — the approval step refuses before a token is ever issued, so the user finds out before connecting rather than after.

400 at the token endpoint. Almost always the PKCE verifier not matching the challenge, or a code that has already been used. Codes are single-use; a retried request is a second use.

Scopes

Two, and asking for the first is the normal case:

ScopeGrants
probr.readevery competitor, every signal, every brief in the workspace
probr.writeadditionally: add, pause, resume and stop watching a competitor

There is nothing narrower than probr.read — it is the whole workspace or nothing.

probr.write is separate because reading is reversible and writing spends a plan slot or stops delivery. Ask for it only if your client needs it: the MCP server does not advertise its write tools to a token without it, so a read-only client is never offered something it cannot do.

A caution about what you build

A token grants read access to the whole workspace. An agent holding one can read all of it, and anything the agent sends onward goes with it. Be as deliberate about where that output lands as you would be about a report link.