MCP dynamic client registration at Sume: 10 redirect URIs, no secret
Sume's /oauth/register takes at most 10 redirect_uris, requires auth method none and returns invalid_redirect_uri for a bad entry. See what each error means.

A client that registers itself with Sume's hosted MCP server at POST /oauth/register must send a non-empty redirect_uris array of at most 10 strings, each an allowed redirect, and use the token auth method none. Break one of those rules and the server answers with a specific OAuth error: invalid_redirect_uri for the list or an entry, invalid_client_metadata for too many entries, and an error for any auth method other than none.
This is the page for developers who build or debug a connector that registers on its own, rather than people who just add the URL to Claude or Cursor.
The reason to read the rules before you write a registration client is that the errors are specific, and each one tells you which field to fix. The same parser also runs the redirect check that the authorize step uses, so a callback that registers cleanly is also accepted at authorize time.
Treat the registration response as the contract for the rest of the flow. It carries the client_id that you will send to the authorize and token endpoints, and the redirect list that the server accepted. If the two differ from what you intended, stop and fix the request before you send a user to a browser, because a failed consent page is much harder to debug than a 400 from a JSON endpoint.
The rules and the errors
Each rule comes from the registration parser in the Sume source.
The checks run in this order: the redirect list first, then the auth method, then grant types. Fix the first error and resend, because a later one will not show until the earlier one is gone.
Teams that run a connector in several environments, such as a laptop callback and a staging callback, can register both in one request as long as the total stays within the limit of 10.
| Request problem | Error code | Fix |
|---|---|---|
| redirect_uris missing, not an array or empty | invalid_redirect_uri | Send a non-empty array |
| More than 10 redirect_uris | invalid_client_metadata | Register 10 or fewer |
| An entry that is not a string | invalid_redirect_uri | Send strings only |
| An entry that fails the redirect allow-rules | invalid_redirect_uri | Use an allowed redirect |
| token_endpoint_auth_method other than none | Rejected: must be none for public MCP clients | Omit it or send none |
Defaults that save you a field
Duplicates in the list collapse to one entry. A missing or empty auth method defaults to none, so the shortest valid body is the client name and the redirect list. The grant type defaults to authorization_code; a refresh_token entry is dropped, as covered in the refresh-token post.
The normalization step turns each entry into its canonical URL string, so two spellings of the same address count as one. Compare the list in the response with the list you sent when you debug a callback that the browser refuses.
The redirect must match later
Registration is also bound to later steps. At authorize time, the redirect_uri has to be one that the client registered; a mismatch fails with "OAuth redirect_uri is not registered for this client." Register every callback your client can use, including a port that changes, up to the limit of 10.
If a user reports that the browser stops on an error page after consent, check this match first: the value in the registration and the value in the authorize request must be the same string, not just the same host.
This request creates a client with one callback, using only the standard library:
Keep the returned client_id and reuse it. A client that registers again on every start creates a new record each time and loses any consent state the user already gave, so store the id next to the redirect list.
import json, urllib.request
body = {
"client_name": "My MCP bridge",
"redirect_uris": ["http://127.0.0.1:8123/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code"],
}
req = urllib.request.Request(
"https://mcp.sume.com/oauth/register",
data=json.dumps(body).encode(),
headers={"Content-Type": "application/json"},
)
with urllib.request.urlopen(req) as res:
print(json.load(res))Next step
After registration, run the code flow with S256 as described in the MCP OAuth and API keys page, and request mcp:read, or mcp:read mcp:write if the user will turn Write on. An unsupported scope returns invalid_scope.
Last, remember that a registered client is not a login. The user still has to sign in on the consent page of the MCP host, and the Write toggle is off by default, so a connector that needs tools that change data must ask for the write scope and the user must switch it on.
Sources
Related posts
More in Integrations
- POST /oauth/revoke on Sume MCP: 200 even for a token it never saw
Revoke a Sume MCP OAuth access token with POST /oauth/revoke. It answers 200 with an empty body, also when the token is unknown, so check by calling the API.
- MCP unsupported_payload_keys: read the allowed array
A key a Sume MCP tool does not list returns unsupported_payload_keys with unexpected, allowed, tool and sometimes path. Fix it from the allowed list.
- MCP unsupported arguments: move the field into payload
A Sume MCP call with quality beside payload fails with unsupported_tool_arguments. Read hint move_to_payload and the adjustments array, then retry once.
- MCP wrong_tool from generate_video: lip sync and motion control
Sume's generate_video refuses minimax/h3-max/lip-sync and the Kling 3.0 motion-control model with wrong_tool. next_action names the tool to call instead.
Written by Sume