Spaces:
Sleeping
Sleeping
File size: 2,874 Bytes
0ef4703 | 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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 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 { maskPII, PII_FIELDS } from "../utils/piiMasking";
import { readJsonBody } from "../utils/responseBody";
export const metadata: ToolMetadata = {
name: "get-one-user",
description: "Retrieve a single SCIM user resource by ID",
annotations: {
title: "Get One User Resource",
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
},
};
export const schema = {
userId: z.string().describe("The ID of the user"),
attributes: z
.string()
.optional()
.describe(
"Comma-separated list of attribute names to return. Per RFC 7644 Section 3.9, only specified attributes will be returned (e.g., 'userName,emails')"
),
excludedAttributes: z
.string()
.optional()
.describe(
"Comma-separated list of attribute names to exclude from the response. Per RFC 7644 Section 3.9"
),
piiMasking: z
.boolean()
.optional()
.default(true)
.describe(
"Enable PII masking for sensitive fields (username, emails, phone numbers, addresses). When true, values are partially masked while maintaining readability. Default: true"
),
};
export default async function getOneUser(params: InferSchema<typeof schema>) {
const {
userId,
attributes,
excludedAttributes,
piiMasking = true,
} = params;
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 url = new URL(`${baseUrl}/Users/${userId}`);
if (attributes) {
url.searchParams.append("attributes", attributes);
}
if (excludedAttributes) {
url.searchParams.append("excludedAttributes", excludedAttributes);
}
const response = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/scim+json",
Authorization: `Bearer ${apiToken}`,
},
});
if (!response.ok) {
const errorBody = await readJsonBody(response);
throw new Error(
`Failed to get user: ${response.status} ${response.statusText}. ${JSON.stringify(errorBody)}`
);
}
let data = await response.json();
// Apply PII masking if enabled
if (piiMasking) {
data = maskPII(data, PII_FIELDS);
}
return {
content: [
{
type: "text",
text: `Get one user successfully`,
},
],
structuredContent: data ?? undefined,
};
}
|