File size: 2,196 Bytes
77d98e2
 
 
dd125ca
076e59d
a65d39f
77d98e2
 
 
c36f28b
77d98e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62cf129
dd125ca
77d98e2
 
8397cce
77d98e2
 
 
8397cce
77d98e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a65d39f
 
77d98e2
 
 
 
 
 
 
a65d39f
77d98e2
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { type InferSchema, type ToolMetadata } from "xmcp";
import { headers } from "xmcp/headers";
import { z } from "zod";
import { getScimBaseUrl } from "../utils/getSCIMBaseUrl";
import { getScimToken } from "../utils/getSCIMToken";
import { readJsonBody } from "../utils/responseBody";

export const metadata: ToolMetadata = {
  name: "add-user-to-group",
  description: "Add a user to a group",
  annotations: {
    title: "Add User to Group",
    readOnlyHint: false,
    destructiveHint: false,
    idempotentHint: true,
    openWorldHint: true,
  },
};

export const schema = {
  groupId: z.string().describe("The unique identifier of the group"),
  userId: z.string().describe("The unique identifier of the user to add to the group"),
};

export default async function addUserToGroup(
  params: InferSchema<typeof schema>
) {
  const requestHeaders = headers();
  const apiToken = getScimToken(requestHeaders);
  const baseUrl = getScimBaseUrl(requestHeaders);

  if (!apiToken) {
    throw new Error("Missing required headers: x-scim-api-token or SCIM_API_TOKEN env");
  }

  if (!baseUrl) {
    throw new Error("Missing required headers: x-scim-base-url or SCIM_API_BASE_URL env");
  }

  const { groupId, userId } = params;

  // According to RFC 7644 Section 3.5.2, adding a member to a group
  // requires a PATCH operation with "add" on the "members" attribute
  const patchOperation = {
    schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
    Operations: [
      {
        op: "add",
        path: "members",
        value: [
          {
            value: userId,
          },
        ],
      },
    ],
  };

  const response = await fetch(`${baseUrl}/Groups/${groupId}`, {
    method: "PATCH",
    headers: {
      "Content-Type": "application/scim+json",
      Authorization: `Bearer ${apiToken}`,
    },
    body: JSON.stringify(patchOperation),
  });

  if (!response.ok) {
    throw new Error(await response.text());
  }

  const data = await readJsonBody(response);

  return {
    content: [
      {
        type: "text",
        text: `User ${userId} added to group ${groupId} successfully`,
      },
    ],
    structuredContent: data ?? undefined,
  };
}