post_orgs_join
Calls POST /api/orgs/join as the signed-in person · REST reference
Request membership of an organization
Authentication only — ANY signed-in person may ASK to join ANY organization by id. The request lands as a REQUESTED membership of the org's MEMBER group — the group every org is created with, carrying the read-only ORG_USER role — so it grants nothing until someone holding admin.groups.members.add IN THAT organization approves it (POST /api/org-admin/{orgId}/join-requests/{userId}/approve), and then only reading the org, its users and its groups. The DAL takes the requester from the caller's own session (the route forwards it); nothing in the body names a user. A pending invitation or an existing membership is left as it is and reported in status (INVITED — accept it from your invitations; ACTIVE — already a member). An organization whose signup the platform has not approved takes no requests.
Arguments
| Argument | Type | Description | |
|---|---|---|---|
bodyJSON | object | required | The request body, as a JSON object. Its fields are listed below. |
Fields of body
| Field | Type | Description | |
|---|---|---|---|
orgId | string (uuid) | required |
Example call
A client sends this over the MCP session; Claude and other agents build it for you. The values are placeholders — the shape is real.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "post_orgs_join",
"arguments": {
"body": {
"orgId": "11111111-1111-4111-8111-111111111111"
}
}
}
}Result
On success (HTTP 200) the tool returns one text item holding the API's JSON, pretty-printed.
The membership request was recorded. 200, not 201 — nothing addressable is created for the caller to fetch.
{
"message": "Membership request submitted",
"nextSteps": {
"message": "string"
},
"organization": {
"id": "11111111-1111-4111-8111-111111111111",
"name": "string",
"type": "string"
},
"status": "INVITED"
}Fields
| Field | Type | Description |
|---|---|---|
message | string | |
nextSteps | object | |
nextSteps.message | string | |
organization | object | Narrow projection — three fields only. |
organization.id | string (uuid) | |
organization.name | string | |
organization.type | string | |
status | "INVITED" | "REQUESTED" | "ACCEPTED" | "APPROVED" | "ACTIVE" | "DECLINED" | … (8 values) | The caller's membership of the org's MEMBER group as the DAL read it back: REQUESTED for a new request; INVITED when the org had already invited them (they accept it instead); ACTIVE or APPROVED when they are already a member. |
When it fails
A failed call returns isError: true with the API's message as text. A change the person declines, or lets time out, also comes back this way and nothing changes.
400orgIdmissing from the body.403A donor-realm bearer, refused by
authenticate.404No such resource — or none this caller may see.
409The organization takes no requests (
code: NO_JOINABLE_GROUP): it has no MEMBER group to request membership of (every org is created with one, so a live org without one needs repair), or its signup has not been approved by the platform.
What the model is shown
This is the tool exactly as the server lists it in tools/list. The description starts with the REST call it makes.
{
"name": "post_orgs_join",
"description": "POST /api/orgs/join — Authentication only — ANY signed-in person may ASK to join ANY organization by id. The request lands as a REQUESTED membership of the org's MEMBER group — the group every org is created with, carrying the read-only ORG_USER role — so it grants nothing until someone holding `admin.groups.members.add` IN THAT organization approves it (`POST /api/org-admin/{orgId}/join-requests/{userId}/approve`), and then only reading the org, its users and its groups. The DAL takes the requester from the caller's own session (the route forwards it); nothing in the body names a user. A pending invitation or an existing membership is left as it is and reported in `status` (INVITED — accept it from your invitations; ACTIVE — already a member). An organization whose signup the platform has not approved takes no requests.\n\nThis changes data. The person is asked to confirm it before it runs, and nothing happens if they decline.",
"inputSchema": {
"type": "object",
"properties": {
"body": {
"type": "string",
"description": "The JSON request body: { orgId*: string }"
}
},
"required": [
"body"
]
},
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"idempotentHint": false,
"openWorldHint": false
}
}