Skip to main content
Glama
ryanmichaeljames

Dataverse MCP Server

dataverse_list_privileges

Read-onlyIdempotent

Lists defined Dataverse privileges, decoding access rights and grantable depths. Look up what a privilege name means or enumerate privileges for a table.

Instructions

List the privileges DEFINED in the environment — the catalogue of what CAN be granted.

This is the reference list, not an assignment. dataverse_get_role_privileges, dataverse_get_team_privileges and dataverse_retrieve_user_privileges answer "who HOLDS what"; this answers "what privileges exist, what access right does each carry, and at which depths can it be granted". Use it to look up the privilege behind a name those tools return ('prvReadAccount'), or to enumerate everything that exists for one table.

ACCESS RIGHTS ARE DECODED BY A HAND-ROLLED MAP, AND THAT IS THE POINT. The accessright column is an integer with NO option set behind it anywhere in Dataverse: the PicklistAttributeMetadata cast 404s, GlobalOptionSetDefinitions for it 404s, and annotation-included FormattedValues return only the integer with thousands separators. So access_right_name comes from a map derived empirically and cross-checked across every privilege in the environment: 0 None · 1 ReadAccess · 2 WriteAccess · 4 AppendAccess · 16 AppendToAccess · 32 CreateAccess · 65536 DeleteAccess · 262144 ShareAccess · 524288 AssignAccess The gaps are real (8 and 16-32768 are unused), so a name is never derived by shifting bits. AN UNRECOGNISED VALUE IS REPORTED RAW: access_right still carries it, access_right_name is ABSENT, and the value is listed under unmapped_access_rights. Nothing is invented — a wrong access-level label is more dangerous than an unlabelled one, the same discipline dataverse_get_team_privileges applies to Depth. accessright 0 marks the non-CRUD privileges (prvActOnBehalfOf... and friends); it is a real value, not "unknown".

depths COLLAPSES THE FOUR canbe* FLAGS into one ordered list, e.g. ["Basic","Local","Deep","Global"] — the depths at which that privilege may be granted, by increasing scope (Basic = the user's own records, Global = org-wide). Only six combinations exist in practice and nearly every privilege allows Global. An EMPTY depths list is unexpected and means the flags could not be read, not that the privilege can be granted nowhere.

total_count COMES FROM AN AGGREGATION, NOT @odata.count. On this collection @odata.count CAPS AT 5,000 and lies — ?$count=true reports 5,000 where the true catalogue is ~7,346 — so the count is taken with $apply=aggregate($count as c), which bypasses the cap. If a trustworthy total cannot be obtained, total_count is OMITTED and message says so; a capped number is never reported as the truth. count is the size of the returned page, has_more says whether anything was trimmed.

TABLE SCOPING GOES THROUGH A JOIN TABLE, NOT THROUGH PRIVILEGE NAMES. Passing table_logical_name queries privilegeobjecttypecodesset, whose objecttypecode column holds the table's LOGICAL NAME STRING. Filtering by name instead — endswith(name,'Account') — is WRONG in general even though it looks right on the tables people test with: endswith(name,'Role') returns 25 privileges spanning FOUR different tables (role, connectionrole, relationshiprole, mspp_webrole). Privileges are also many-to-many with tables (one privilege can map to as many as 14), which a name can never express. That join table is private and undocumented, so if it fails you get a clear error naming it — never a silent fall back to name matching.

AN UNKNOWN TABLE NAME IS AN ERROR, NOT AN EMPTY LIST. objecttypecode is an EntityName column, so Dataverse validates it: an unknown, misspelled or plural logical name answers HTTP 400 [0x80041102] "The entity with a name = '…' with namemapping = 'Logical' was not found in the MetadataCache", naming the offending entity — that message is the reliable signal for a bad table name, and it is what the error surfaces first. Casing is never the cause: table_logical_name is lowercased for you, matching name_startswith's case-insensitivity on both routes. An EMPTY privileges list means the opposite — the table EXISTS and genuinely has no privileges mapped to it, live-confirmed on 'privilege' itself, which returns 0.

source names the route that actually ran ('privileges' or 'privilegeobjecttypecodesset'); the response shape is identical either way. On the join route, name_startswith and access_right are applied client-side, so count/total_count describe the filtered set.

Each entry: name, privilege_id, access_right (raw integer), access_right_name (absent when unknown), depths, can_be_entity_reference, can_be_parent_entity_reference. Bulky and empty columns are deliberately dropped (privilegetype does not exist on this entity at all).

If the response carries no readable collection, nothing is guessed: normalized is false, no counts are reported, and the body comes back under raw_response. An empty privileges list with normalized: true is a real answer; a missing container is not.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this readOnly, openWorld, idempotent and non-destructive; the description adds substantial context beyond those flags: a hand-rolled access-right map with unmapped values reported raw, @odata.count capping at 5,000 bypassed by aggregation, join-table scoping versus name-matching, and explicit error behavior for unknown table names. It also states the response's normalization discipline (empty list is real, missing container is not), so no guesswork is left to the agent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but it is organized into capitalized topic paragraphs and every paragraph introduces a behavioral nuance the agent must know (access-right decoding, depth collapsing, count aggregation, join-table scoping, error semantics). It is front-loaded with the core purpose and only then dives into edge cases; still, it is verbose enough that some agents might need to parse several paragraphs for a simple list operation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema exists, so return-value details need not be spelled out; the description instead covers failure modes, count accuracy, route differences, and normalization semantics. Combined with rich parameter docs in the input schema, the description leaves virtually no ambiguity about when and how to invoke this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents each parameter with detailed descriptions (case-insensitivity, join-table scoping, 'None' as a real value), so the baseline is high. The tool description reinforces and extends this by explaining the integer mapping for access_right, that name_startswith is case-insensitive on both routes, and what total_count/count/has_more mean for top, adding meaning beyond the structured schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a crisp active statement: 'List the privileges DEFINED in the environment — the catalogue of what CAN be granted.' It explicitly contrasts with dataverse_get_role_privileges, dataverse_get_team_privileges, and dataverse_retrieve_user_privileges, stating those answer 'who HOLDS what' whereas this answers 'what privileges exist, what access right does each carry, and at which depths can it be granted.' This is a specific verb+resource with clear sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description names the sibling tools that answer 'who HOLDS what' and tells the agent to use this tool as the reference catalogue: 'Use it to look up the privilege behind a name those tools return... or to enumerate everything that exists for one table.' It also gives concrete guidance about when to apply table_logical_name and warns against name-based filtering, making the usage context explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/ryanmichaeljames/dataverse-mcp'

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