@toriihq/torii-mcp
Version:
Model Context Protocol server for Torii API
99 lines (97 loc) • 5.37 kB
JavaScript
import { z } from 'zod';
import { makeApiRequest } from './api.js';
import { FUNCTION_NAME_TO_API_PARAMS } from '../api/filters.js';
import { convertArgsToParameters } from './shared.types.js';
// API Functions for Users
export async function getUsers(params) {
const apiRequest = FUNCTION_NAME_TO_API_PARAMS.list_users(params ? convertArgsToParameters(params) : []);
return makeApiRequest(apiRequest.path, apiRequest.method, undefined, apiRequest.headers);
}
export async function getUserById(idUser, params) {
const queryParams = params ? `?${new URLSearchParams(params).toString()}` : '';
return makeApiRequest(`/users/${idUser}${queryParams}`);
}
// Register Users tools with the MCP server
export function registerUsersTools(server) {
// List Users Tool
server.tool('list_users', `
<use_case>
Use this tool to list all users in the organization
</use_case>
<important_notes>
- ALWAYS use AT LEAST one of: aggs, baseFilters and filters (see filters_schema below) for better results.
- ALWAYS user the "view" filter to filter out irrelevant data. If not specified, use the "currentEmployees" view.
- Use the aggs property to perform aggregations over the data, such as grouping, calculations: sum, average, minimum, maximum, etc, date range and more. Follow the aggregations_schema below. Aggregated data is returned under the "aggregations" property.
- ALWAYS use the fields property and ask only for the fields you need.
- Use the get_user_fields tool to list the fields to pass in the "fields" parameter.
</important_notes>
<filters_schema>
Array of
{
key: string
op: equals|notEquals|contains|notContains|anyOf|noneOf|allOf|isExactly|isSet|isNotSet|gt|gte|lt|lte|dayAfter|dayOnOrAfter|dayBefore|dayOnOrBefore|nested|relativeDateToday|relativeDateOn|relativeDateLess|relativeDateMore|exists|notExists|or|and
value: changes based on the type of field used as key
}
</filters_schema>
<aggregations_schema>
AGGREGATION_TYPES = metric | groupBy | date_range | date_histogram
METRIC_FUNCTIONS = sum | avg | max | min (and "total" if aggregationType = groupBy)
AGGREGATION_SORT_ORDERS = min | max
<schema>
{
field: string,
aggregationType: AGGREGATION_TYPES,
options: {
metricFunction: METRIC_FUNCTIONS,
size: number (max: 100),
sort: {
field: string,
aggFunc: METRIC_FUNCTIONS,
order: AGGREGATION_SORT_ORDERS
},
aggs: Nested aggregation with the same structure as the parent
}
</schema>
</aggregations_schema>
`, {
cursor: z
.string()
.optional()
.describe("Pagination cursor taken from the previous response's nextCursor property"),
baseFilters: z
.string()
.optional()
.describe('JSON string representing filters schema. Structure: "{\"email\":string,\"lifecycleStatus\":string,\"isDeletedInIdentitySources\":true if the user has left the organization, false otherwise,\"firstName\":string,\"lastName\":string,\"view\":currentEmployees|pastEmployees|allEmployees|currentUsers|pastUsers|allUsers|externalUsers, \"idUsers\":comma separated list of idUser with a maximum of 50 IDs}"'),
filters: z
.string()
.optional()
.describe('JSON string representing filters schema: "[{\"key\":[field_name],\"op\":operation,\"value\":[field_value}]"; the list can contain multiple filters combined in an "AND" relation'),
fields: z
.string()
.optional()
.describe('Comma-separated list of fields to return for each application; Allowed fields: idOrg, firstName, lastName, email, creationTime, idRole, lifecycleStatus, isDeletedInIdentitySources, isExternal, activeAppsCount, role, additionalEmails and all fields from the get_user_fields tool'),
aggs: z
.string()
.optional()
.describe('JSON string representing aggregation schema. Structure: "{\"field\":\"string\", \"aggregationType\":\"metric|groupBy|date_range|date_histogram\", \"options\":{\"size\":integer, \"sort\":{\"field\":\"string\",\"order\":\"desc|asc\",\"aggFunc\":\"sum|avg|max|min\"}, \"metricFunction\":\"total|sum|avg|max|min\", \"hardBounds\":{\"min\":\"string\",\"max\":\"string\"}, \"extendedBounds\":{\"min\":\"string\",\"max\":\"string\"}, \"datePeriod\":\"weekly|monthly|quarterly|yearly\"}, \"aggs\":Nested aggregation with the same structure as the parent}"')
}, async (params) => {
const users = await getUsers(params);
return {
content: [{ type: 'text', text: JSON.stringify(users, null, 2) }]
};
});
// Get User Tool
server.tool('get_user', 'Get details of a specific user by ID', {
id: z.string().describe('Unique user identifier'),
fields: z.string().optional().describe('Comma-separated list of fields to return')
}, async ({ id, fields }) => {
const params = {};
if (fields)
params.fields = fields;
const user = await getUserById(id, params);
return {
content: [{ type: 'text', text: JSON.stringify(user, null, 2) }]
};
});
}
//# sourceMappingURL=users.js.map