Skip to main content
Glama

Dataverse MCP Server

by mwhesse
team-tools.ts21.5 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import { DataverseClient } from "../dataverse-client.js"; export function createTeamTool(server: McpServer, client: DataverseClient) { server.registerTool( "create_dataverse_team", { title: "Create Dataverse Team", description: "Creates a new team in Dataverse for organizing users and managing permissions. Teams can be owner teams (for record ownership) or access teams (for sharing records). Use this to establish groups of users who work together and need similar access levels.", inputSchema: { name: z.string().max(160).describe("Name of the team"), description: z.string().max(2000).optional().describe("Description of the team"), businessUnitId: z.string().optional().describe("Business unit ID to associate the team with (defaults to root business unit)"), administratorId: z.string().describe("User ID of the team administrator"), teamType: z.enum(['0', '1', '2', '3']).default('0').describe("Team type: 0=Owner, 1=Access, 2=Security Group, 3=Office Group"), membershipType: z.enum(['0', '1', '2', '3']).default('0').describe("Membership type: 0=Members and guests, 1=Members, 2=Owners, 3=Guests"), emailAddress: z.string().max(100).optional().describe("Email address for the team"), yomiName: z.string().max(160).optional().describe("Pronunciation of the team name in phonetic characters"), azureActiveDirectoryObjectId: z.string().optional().describe("Azure AD Object ID for the team"), queueId: z.string().optional().describe("Default queue ID for the team"), teamTemplateId: z.string().optional().describe("Team template ID to associate with the team"), delegatedAuthorizationId: z.string().optional().describe("Delegated authorization context for the team"), transactionCurrencyId: z.string().optional().describe("Currency ID associated with the team") } }, async (params) => { try { const teamData: any = { name: params.name, description: params.description, teamtype: parseInt(params.teamType), membershiptype: parseInt(params.membershipType), emailaddress: params.emailAddress, yominame: params.yomiName, azureactivedirectoryobjectid: params.azureActiveDirectoryObjectId }; // Set administrator teamData['administratorid@odata.bind'] = `/systemusers(${params.administratorId})`; // Set business unit (default to root if not provided) if (params.businessUnitId) { teamData['businessunitid@odata.bind'] = `/businessunits(${params.businessUnitId})`; } else { // Get the root business unit const businessUnits = await client.get('businessunits?$filter=parentbusinessunitid eq null&$select=businessunitid'); if (businessUnits.value && businessUnits.value.length > 0) { teamData['businessunitid@odata.bind'] = `/businessunits(${businessUnits.value[0].businessunitid})`; } } // Set optional relationships if (params.queueId) { teamData['queueid@odata.bind'] = `/queues(${params.queueId})`; } if (params.teamTemplateId) { teamData['teamtemplateid@odata.bind'] = `/teamtemplates(${params.teamTemplateId})`; } if (params.delegatedAuthorizationId) { teamData['delegatedauthorizationid@odata.bind'] = `/delegatedauthorizations(${params.delegatedAuthorizationId})`; } if (params.transactionCurrencyId) { teamData['transactioncurrencyid@odata.bind'] = `/transactioncurrencies(${params.transactionCurrencyId})`; } const response = await client.post('teams', teamData); return { content: [ { type: "text", text: `Successfully created team '${params.name}'.\n\nTeam created successfully.\n\nResponse: ${JSON.stringify(response, null, 2)}` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error creating team: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } export function getTeamTool(server: McpServer, client: DataverseClient) { server.registerTool( "get_dataverse_team", { title: "Get Dataverse Team", description: "Retrieves detailed information about a specific team including its properties, administrator, business unit association, and configuration settings. Use this to inspect team definitions and understand team structure.", inputSchema: { teamId: z.string().describe("ID of the team to retrieve") } }, async (params) => { try { const team = await client.get(`teams(${params.teamId})?$select=teamid,name,description,teamtype,membershiptype,emailaddress,yominame,azureactivedirectoryobjectid,businessunitid,administratorid,queueid,delegatedauthorizationid,transactioncurrencyid,createdon,modifiedon,createdby,modifiedby,isdefault,systemmanaged&$expand=administratorid($select=fullname),businessunitid($select=name),createdby($select=fullname),modifiedby($select=fullname)`); const teamInfo = { teamId: team.teamid, name: team.name, description: team.description, teamType: team.teamtype, teamTypeLabel: getTeamTypeLabel(team.teamtype), membershipType: team.membershiptype, membershipTypeLabel: getMembershipTypeLabel(team.membershiptype), emailAddress: team.emailaddress, yomiName: team.yominame, azureActiveDirectoryObjectId: team.azureactivedirectoryobjectid, businessUnitId: team.businessunitid, businessUnitName: team.businessunitid?.name, administratorId: team.administratorid, administratorName: team.administratorid?.fullname, queueId: team.queueid, teamTemplateId: team.teamtemplateid, delegatedAuthorizationId: team.delegatedauthorizationid, transactionCurrencyId: team.transactioncurrencyid, createdOn: team.createdon, modifiedOn: team.modifiedon, createdBy: team.createdby?.fullname, modifiedBy: team.modifiedby?.fullname, isDefault: team.isdefault, systemManaged: team.systemmanaged }; return { content: [ { type: "text", text: `Team information:\n\n${JSON.stringify(teamInfo, null, 2)}` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error retrieving team: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } export function updateTeamTool(server: McpServer, client: DataverseClient) { server.registerTool( "update_dataverse_team", { title: "Update Dataverse Team", description: "Updates the properties and configuration of an existing team. Use this to modify team settings like name, description, administrator, or other team properties without changing team membership.", inputSchema: { teamId: z.string().describe("ID of the team to update"), name: z.string().max(160).optional().describe("New name of the team"), description: z.string().max(2000).optional().describe("New description of the team"), teamType: z.enum(['0', '1', '2', '3']).optional().describe("Team type: 0=Owner, 1=Access, 2=Security Group, 3=Office Group"), membershipType: z.enum(['0', '1', '2', '3']).optional().describe("Membership type: 0=Members and guests, 1=Members, 2=Owners, 3=Guests"), emailAddress: z.string().max(100).optional().describe("Email address for the team"), yomiName: z.string().max(160).optional().describe("Pronunciation of the team name in phonetic characters"), azureActiveDirectoryObjectId: z.string().optional().describe("Azure AD Object ID for the team"), administratorId: z.string().optional().describe("New administrator user ID"), queueId: z.string().optional().describe("Default queue ID for the team"), teamTemplateId: z.string().optional().describe("Team template ID to associate with the team"), delegatedAuthorizationId: z.string().optional().describe("Delegated authorization context for the team"), transactionCurrencyId: z.string().optional().describe("Currency ID associated with the team") } }, async (params) => { try { const updateData: any = {}; if (params.name !== undefined) updateData.name = params.name; if (params.description !== undefined) updateData.description = params.description; if (params.teamType !== undefined) updateData.teamtype = parseInt(params.teamType); if (params.membershipType !== undefined) updateData.membershiptype = parseInt(params.membershipType); if (params.emailAddress !== undefined) updateData.emailaddress = params.emailAddress; if (params.yomiName !== undefined) updateData.yominame = params.yomiName; if (params.azureActiveDirectoryObjectId !== undefined) updateData.azureactivedirectoryobjectid = params.azureActiveDirectoryObjectId; // Set optional relationships if (params.administratorId !== undefined) { updateData['administratorid@odata.bind'] = `/systemusers(${params.administratorId})`; } if (params.queueId !== undefined) { updateData['queueid@odata.bind'] = params.queueId ? `/queues(${params.queueId})` : null; } if (params.teamTemplateId !== undefined) { updateData['teamtemplateid@odata.bind'] = params.teamTemplateId ? `/teamtemplates(${params.teamTemplateId})` : null; } if (params.delegatedAuthorizationId !== undefined) { updateData['delegatedauthorizationid@odata.bind'] = params.delegatedAuthorizationId ? `/delegatedauthorizations(${params.delegatedAuthorizationId})` : null; } if (params.transactionCurrencyId !== undefined) { updateData['transactioncurrencyid@odata.bind'] = params.transactionCurrencyId ? `/transactioncurrencies(${params.transactionCurrencyId})` : null; } await client.patch(`teams(${params.teamId})`, updateData); return { content: [ { type: "text", text: `Successfully updated team.` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error updating team: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } export function deleteTeamTool(server: McpServer, client: DataverseClient) { server.registerTool( "delete_dataverse_team", { title: "Delete Dataverse Team", description: "Permanently deletes a team from Dataverse. WARNING: This action cannot be undone and will fail if the team owns records or has assigned security roles. Ensure the team is not in use before deletion.", inputSchema: { teamId: z.string().describe("ID of the team to delete") } }, async (params) => { try { await client.delete(`teams(${params.teamId})`); return { content: [ { type: "text", text: `Successfully deleted team.` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error deleting team: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } export function listTeamsTool(server: McpServer, client: DataverseClient) { server.registerTool( "list_dataverse_teams", { title: "List Dataverse Teams", description: "Retrieves a list of teams in the Dataverse environment with filtering options. Use this to discover available teams, find teams by business unit or type, or get an overview of team organization. Supports filtering by business unit, team type, and system-managed status.", inputSchema: { businessUnitId: z.string().optional().describe("Filter teams by business unit ID"), teamType: z.enum(['0', '1', '2', '3']).optional().describe("Filter by team type: 0=Owner, 1=Access, 2=Security Group, 3=Office Group"), systemManagedOnly: z.boolean().default(false).describe("Whether to list only system-managed teams"), excludeDefault: z.boolean().default(false).describe("Whether to exclude default business unit teams"), top: z.number().optional().describe("Maximum number of teams to return (default: 50)"), filter: z.string().optional().describe("OData filter expression") } }, async (params) => { try { let queryParams: Record<string, any> = { $select: 'teamid,name,description,teamtype,membershiptype,emailaddress,businessunitid,administratorid,isdefault,systemmanaged,createdon', $expand: 'administratorid($select=fullname),businessunitid($select=name)', $top: params.top || 50 }; const filters: string[] = []; if (params.businessUnitId) { filters.push(`businessunitid eq ${params.businessUnitId}`); } if (params.teamType !== undefined) { filters.push(`teamtype eq ${parseInt(params.teamType)}`); } if (params.systemManagedOnly) { filters.push(`systemmanaged eq true`); } if (params.excludeDefault) { filters.push(`isdefault eq false`); } if (params.filter) { filters.push(params.filter); } if (filters.length > 0) { queryParams.$filter = filters.join(' and '); } const response = await client.get('teams', queryParams); const teams = response.value?.map((team: any) => ({ teamId: team.teamid, name: team.name, description: team.description, teamType: team.teamtype, teamTypeLabel: getTeamTypeLabel(team.teamtype), membershipType: team.membershiptype, membershipTypeLabel: getMembershipTypeLabel(team.membershiptype), emailAddress: team.emailaddress, businessUnitId: team.businessunitid, businessUnitName: team.businessunitid?.name, administratorId: team.administratorid, administratorName: team.administratorid?.fullname, isDefault: team.isdefault, systemManaged: team.systemmanaged, createdOn: team.createdon })) || []; return { content: [ { type: "text", text: `Found ${teams.length} teams:\n\n${JSON.stringify(teams, null, 2)}` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error listing teams: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } export function addMembersToTeamTool(server: McpServer, client: DataverseClient) { server.registerTool( "add_members_to_team", { title: "Add Members to Team", description: "Adds users as members to a team, granting them access to team-owned records and team-based permissions. Use this to expand team membership and provide users with team-level access to resources.", inputSchema: { teamId: z.string().describe("ID of the team to add members to"), memberIds: z.array(z.string()).describe("Array of user IDs to add as team members") } }, async (params) => { try { await client.callAction('AddMembersTeam', { TeamId: params.teamId, MemberIds: params.memberIds }); return { content: [ { type: "text", text: `Successfully added ${params.memberIds.length} member(s) to team.` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error adding members to team: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } export function removeMembersFromTeamTool(server: McpServer, client: DataverseClient) { server.registerTool( "remove_members_from_team", { title: "Remove Members from Team", description: "Removes users from team membership, revoking their access to team-owned records and team-based permissions. Use this when users no longer need team access or are changing roles.", inputSchema: { teamId: z.string().describe("ID of the team to remove members from"), memberIds: z.array(z.string()).describe("Array of user IDs to remove from team") } }, async (params) => { try { await client.callAction('RemoveMembersTeam', { TeamId: params.teamId, MemberIds: params.memberIds }); return { content: [ { type: "text", text: `Successfully removed ${params.memberIds.length} member(s) from team.` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error removing members from team: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } export function getTeamMembersTool(server: McpServer, client: DataverseClient) { server.registerTool( "get_team_members", { title: "Get Team Members", description: "Retrieves a list of all users who are members of a specific team, including their basic information and status. Use this to audit team membership and understand who has team-based access.", inputSchema: { teamId: z.string().describe("ID of the team to retrieve members for") } }, async (params) => { try { // Get team members through the many-to-many relationship const response = await client.get(`teams(${params.teamId})/teammembership_association?$select=systemuserid,fullname,domainname,businessunitid,isdisabled&$expand=businessunitid($select=name)`); const members = response.value?.map((member: any) => ({ userId: member.systemuserid, fullName: member.fullname, domainName: member.domainname, businessUnitId: member.businessunitid, businessUnitName: member.businessunitid?.name, isDisabled: member.isdisabled })) || []; return { content: [ { type: "text", text: `Team has ${members.length} member(s):\n\n${JSON.stringify(members, null, 2)}` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error retrieving team members: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } export function convertOwnerTeamToAccessTeamTool(server: McpServer, client: DataverseClient) { server.registerTool( "convert_owner_team_to_access_team", { title: "Convert Owner Team to Access Team", description: "Converts an owner team to an access team, changing how the team can be used for record ownership and sharing. WARNING: This action cannot be undone and affects how records owned by this team are managed.", inputSchema: { teamId: z.string().describe("ID of the owner team to convert to access team") } }, async (params) => { try { await client.callAction('ConvertOwnerTeamToAccessTeam', { TeamId: params.teamId }); return { content: [ { type: "text", text: `Successfully converted owner team to access team.` } ] }; } catch (error) { return { content: [ { type: "text", text: `Error converting team: ${error instanceof Error ? error.message : 'Unknown error'}` } ], isError: true }; } } ); } // Helper functions function getTeamTypeLabel(teamType: number): string { switch (teamType) { case 0: return 'Owner'; case 1: return 'Access'; case 2: return 'Security Group'; case 3: return 'Office Group'; default: return 'Unknown'; } } function getMembershipTypeLabel(membershipType: number): string { switch (membershipType) { case 0: return 'Members and guests'; case 1: return 'Members'; case 2: return 'Owners'; case 3: return 'Guests'; default: return 'Unknown'; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mwhesse/mcp-dataverse'

If you have feedback or need assistance with the MCP directory API, please join our Discord server