> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://api.docs.modulards.com/modular-ds-public-api/oauth/client-registration/register-an-mcp-client/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://api.docs.modulards.com/_mcp/server. # Register an MCP client POST https://api.modulards.com/oauth/register Content-Type: application/json Registers a public OAuth client (RFC 7591) so an MCP client can start the authorization flow. Use it once per client installation, then keep the returned `client_id`. The client is public: it uses the authorization code flow with PKCE (`S256`) and no client secret. Any other RFC 7591 metadata you send is ignored. Registrations that never obtain a token are removed after 30 days. Public and throttled to 10 requests per minute per IP address; the eleventh answers 429. Served at the root of the MCP host, without the `/api` prefix. **Body** - `redirect_uris` (array of strings, required): 1 to 5 addresses the authorization code may be sent to. Each one must be one of these: - An `https` address on any host. The approval screen shows the user the origin the code will be sent to. - An `http` address on a loopback host (`127.0.0.1`, `[::1]` or `localhost`), on any port, for native and desktop clients (RFC 8252). `http` on any other host is refused. - A private-use scheme with a host, which native clients use for their callback (RFC 8252), such as `cursor://anysphere.cursor-retrieval/oauth/callback`. Any scheme is accepted except those a browser runs, reads from disk or keeps for itself (for example `javascript`, `data`, `file`, `ftp`, `ws`, `chrome-extension`). Whatever the origin or scheme, an address with a comma, `@`, backslash, whitespace, control character, user name, password or fragment is refused, and so is a host that Modular DS has blocked (with its subdomains). A refused address answers `400` with `invalid_redirect_uri`. - `client_name` (string, optional): the name the approval screen shows to the user, at most 100 characters and no control characters. It is shown next to the address the authorization will be sent to. **Errors** - **400**: a redirect URI is missing, more than five are sent or one is not accepted (`invalid_redirect_uri`). - **400**: `client_name` is too long or contains control characters (`invalid_client_metadata`). Reference: https://api.docs.modulards.com/modular-ds-public-api/oauth/client-registration/register-an-mcp-client ## Request ### Body (application/json) This endpoint expects an object. - `client_name` (string, optional) - `redirect_uris` (list of string, optional) ## Response ### 201 201 Created - `client_id` (string, optional) — Identifier of the new client; keep it to start the authorization flow. - `grant_types` (list of enum, optional) — Grant types the client may use: `authorization_code` and `refresh_token`. - Allowed values: `authorization_code`, `refresh_token` - `redirect_uris` (list of string, optional) — The redirect addresses that were registered. - `response_types` (list of enum, optional) — Response types the client may use; always `code`. - Allowed values: `code` - `scope` (string, optional) — Scope granted to the client: `mcp:use`. - `token_endpoint_auth_method` (enum, optional) — How the client authenticates at the token endpoint; always `none`, because the client is public. - Allowed values: `none` ## Errors ### 400 Bad Request Error 400 Invalid redirect URI - `error` (enum, optional) — `invalid_redirect_uri` when a redirect address is refused, `invalid_client_metadata` for any other invalid field. - Allowed values: `invalid_redirect_uri`, `invalid_client_metadata` - `error_description` (string, optional) — Sentence saying which field was refused. ## Examples ### 201 Created **Response** ```json { "client_id": "9d7f2c1e-4b3a-4f8e-9c2d-1a5b6e7f8a90", "grant_types": [ "authorization_code", "refresh_token" ], "redirect_uris": [ "https://claude.ai/api/mcp/auth_callback" ], "response_types": [ "code" ], "scope": "mcp:use", "token_endpoint_auth_method": "none" } ``` **SDK Code** ```python 201 Created import requests url = "https://api.modulards.com/oauth/register" response = requests.post(url) print(response.json()) ``` ```javascript 201 Created const url = 'https://api.modulards.com/oauth/register'; const options = {method: 'POST'}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go 201 Created package main import ( "fmt" "net/http" "io" ) func main() { url := "https://api.modulards.com/oauth/register" req, _ := http.NewRequest("POST", url, nil) res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby 201 Created require 'uri' require 'net/http' url = URI("https://api.modulards.com/oauth/register") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) response = http.request(request) puts response.read_body ``` ```java 201 Created import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.modulards.com/oauth/register") .asString(); ``` ```php 201 Created request('POST', 'https://api.modulards.com/oauth/register'); echo $response->getBody(); ``` ```csharp 201 Created using RestSharp; var client = new RestClient("https://api.modulards.com/oauth/register"); var request = new RestRequest(Method.POST); IRestResponse response = client.Execute(request); ``` ```swift 201 Created import Foundation let request = NSMutableURLRequest(url: NSURL(string: "https://api.modulards.com/oauth/register")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ``` ### Register an MCP client **Request** ```json { "client_name": "My MCP client", "redirect_uris": [ "http://example.com/callback" ] } ``` **Response** ```json { "client_id": "9d7f2c1e-4b3a-4f8e-9c2d-1a5b6e7f8a90", "grant_types": [ "authorization_code", "refresh_token" ], "redirect_uris": [ "https://claude.ai/api/mcp/auth_callback" ], "response_types": [ "code" ], "scope": "mcp:use", "token_endpoint_auth_method": "none" } ``` **SDK Code** ```python Register an MCP client import requests url = "https://api.modulards.com/oauth/register" payload = { "client_name": "My MCP client", "redirect_uris": ["http://example.com/callback"] } headers = {"Content-Type": "application/json"} response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ```javascript Register an MCP client const url = 'https://api.modulards.com/oauth/register'; const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"client_name":"My MCP client","redirect_uris":["http://example.com/callback"]}' }; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go Register an MCP client package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.modulards.com/oauth/register" payload := strings.NewReader("{\n \"client_name\": \"My MCP client\",\n \"redirect_uris\": [\n \"http://example.com/callback\"\n ]\n}") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby Register an MCP client require 'uri' require 'net/http' url = URI("https://api.modulards.com/oauth/register") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["Content-Type"] = 'application/json' request.body = "{\n \"client_name\": \"My MCP client\",\n \"redirect_uris\": [\n \"http://example.com/callback\"\n ]\n}" response = http.request(request) puts response.read_body ``` ```java Register an MCP client import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.modulards.com/oauth/register") .header("Content-Type", "application/json") .body("{\n \"client_name\": \"My MCP client\",\n \"redirect_uris\": [\n \"http://example.com/callback\"\n ]\n}") .asString(); ``` ```php Register an MCP client request('POST', 'https://api.modulards.com/oauth/register', [ 'body' => '{ "client_name": "My MCP client", "redirect_uris": [ "http://example.com/callback" ] }', 'headers' => [ 'Content-Type' => 'application/json', ], ]); echo $response->getBody(); ``` ```csharp Register an MCP client using RestSharp; var client = new RestClient("https://api.modulards.com/oauth/register"); var request = new RestRequest(Method.POST); request.AddHeader("Content-Type", "application/json"); request.AddParameter("application/json", "{\n \"client_name\": \"My MCP client\",\n \"redirect_uris\": [\n \"http://example.com/callback\"\n ]\n}", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift Register an MCP client import Foundation let headers = ["Content-Type": "application/json"] let parameters = [ "client_name": "My MCP client", "redirect_uris": ["http://example.com/callback"] ] as [String : Any] let postData = JSONSerialization.data(withJSONObject: parameters, options: []) let request = NSMutableURLRequest(url: NSURL(string: "https://api.modulards.com/oauth/register")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```