cURL
curl -sS -X POST "https://phosra-api-sandbox-production.up.railway.app/api/v1/mcp-tokens" \
-H "Authorization: Bearer $PHOSRA_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "Claude Desktop"
}'const BASE = "https://phosra-api-sandbox-production.up.railway.app/api/v1";
const res = await fetch(`${BASE}/mcp-tokens`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.PHOSRA_SESSION_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"label": "Claude Desktop"
}),
});
console.log(res.status, await res.json());
import os, requests
BASE = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
res = requests.post(
f"{BASE}/mcp-tokens",
headers={"Authorization": f"Bearer {os.environ['PHOSRA_SESSION_TOKEN']}"},
json={
"label": "Claude Desktop"
},
)
print(res.status_code, res.json())
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
base := "https://phosra-api-sandbox-production.up.railway.app/api/v1"
body := bytes.NewBufferString(`{
"label": "Claude Desktop"
}`)
req, _ := http.NewRequest("POST", base+"/mcp-tokens", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PHOSRA_SESSION_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(out))
}
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://phosra-api-sandbox-production.up.railway.app/api/v1/mcp-tokens",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'label' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.post("https://phosra-api-sandbox-production.up.railway.app/api/v1/mcp-tokens")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://phosra-api-sandbox-production.up.railway.app/api/v1/mcp-tokens")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"label\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"token": {
"id": "f456e4ac-d77c-411b-9061-88a7a1befc3b",
"user_id": "06c5090f-ea5b-4841-a611-e8c9d67df0c5",
"family_id": "63069024-1a49-4b95-80e8-f1b1b769355e",
"label": "Untitled",
"token_prefix": "phomcp_ZTFPEH7X",
"created_at": "0001-01-01T00:00:00Z"
},
"plain": "phomcp_ZTFPEH7X4BJLABIULVPZE6CCZY5WVEU6"
}{
"error": "Bad Request",
"message": "invalid body",
"code": 400
}{
"error": "Unauthorized",
"message": "auth required",
"code": 401
}{
"error": "Too Many Requests",
"message": "rate limit exceeded",
"code": 429
}{
"error": "Internal Server Error",
"message": "internal error",
"code": 500
}MCP Tokens
Create MCP token
Issues a new MCP token bound to the authenticated user’s first family. The plaintext token (plain, prefix phomcp_) is returned once in CreatedMcpToken and never stored server-side — the caller must display it to the user immediately.
POST
/
mcp-tokens
cURL
curl -sS -X POST "https://phosra-api-sandbox-production.up.railway.app/api/v1/mcp-tokens" \
-H "Authorization: Bearer $PHOSRA_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"label": "Claude Desktop"
}'const BASE = "https://phosra-api-sandbox-production.up.railway.app/api/v1";
const res = await fetch(`${BASE}/mcp-tokens`, {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.PHOSRA_SESSION_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"label": "Claude Desktop"
}),
});
console.log(res.status, await res.json());
import os, requests
BASE = "https://phosra-api-sandbox-production.up.railway.app/api/v1"
res = requests.post(
f"{BASE}/mcp-tokens",
headers={"Authorization": f"Bearer {os.environ['PHOSRA_SESSION_TOKEN']}"},
json={
"label": "Claude Desktop"
},
)
print(res.status_code, res.json())
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
)
func main() {
base := "https://phosra-api-sandbox-production.up.railway.app/api/v1"
body := bytes.NewBufferString(`{
"label": "Claude Desktop"
}`)
req, _ := http.NewRequest("POST", base+"/mcp-tokens", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PHOSRA_SESSION_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(out))
}
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://phosra-api-sandbox-production.up.railway.app/api/v1/mcp-tokens",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'label' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.post("https://phosra-api-sandbox-production.up.railway.app/api/v1/mcp-tokens")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"label\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://phosra-api-sandbox-production.up.railway.app/api/v1/mcp-tokens")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"label\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"token": {
"id": "f456e4ac-d77c-411b-9061-88a7a1befc3b",
"user_id": "06c5090f-ea5b-4841-a611-e8c9d67df0c5",
"family_id": "63069024-1a49-4b95-80e8-f1b1b769355e",
"label": "Untitled",
"token_prefix": "phomcp_ZTFPEH7X",
"created_at": "0001-01-01T00:00:00Z"
},
"plain": "phomcp_ZTFPEH7X4BJLABIULVPZE6CCZY5WVEU6"
}{
"error": "Bad Request",
"message": "invalid body",
"code": 400
}{
"error": "Unauthorized",
"message": "auth required",
"code": 401
}{
"error": "Too Many Requests",
"message": "rate limit exceeded",
"code": 429
}{
"error": "Internal Server Error",
"message": "internal error",
"code": 500
}Authorizations
A logged-in user session bearer token (WorkOS AuthKit access token from signup/login).
Body
application/json
Human-readable label for the token. Defaults to Untitled if omitted or empty.
Response
Token created. The raw plain token is returned only in this response.
Returned only at MCP token creation time. The plain field is the raw plaintext token — show it to the user once and never persist it.
⌘I