mcp-dataverse 0.4.5 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CAPABILITIES.md +92 -33
- package/README.md +1 -1
- package/dist/chunk-FSM3J3WD.js +35 -0
- package/dist/dataverse-client-advanced-EASNSX3M.js +1 -0
- package/dist/doctor.js +1 -1
- package/dist/server.js +22 -11
- package/package.json +2 -2
- package/server.json +3 -3
- package/dist/chunk-MPWVUZBX.js +0 -35
- package/dist/dataverse-client-advanced-ZG4OPCGR.js +0 -1
package/dist/server.js
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as ue}from"./chunk-SUDI4JM6.js";import{a as pe}from"./chunk-PAX4NW5B.js";import"./chunk-24RDOMG4.js";import{a as h,b as me}from"./chunk-MPWVUZBX.js";import{Server as gn}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as yn}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as hn,ListToolsRequestSchema as vn,ListResourcesRequestSchema as bn,ListResourceTemplatesRequestSchema as _n,ReadResourceRequestSchema as wn}from"@modelcontextprotocol/sdk/types.js";import{readFileSync as Tn}from"fs";import{join as Sn,dirname as Nn}from"path";import{fileURLToPath as Rn}from"url";function fe(){let a=process.argv.slice(2),r="stdio",o=3e3;for(let e=0;e<a.length;e++){if(a[e]==="--transport"&&a[e+1]){let t=a[e+1];(t==="http"||t==="stdio")&&(r=t),e++}if(a[e]==="--port"&&a[e+1]){let t=parseInt(a[e+1],10);!isNaN(t)&&t>0&&t<65536&&(o=t),e++}}return{transport:r,port:o}}var ee=class{map=new Map;register(r){for(let o of r.tools){if(this.map.has(o.name))throw new Error(`Duplicate tool name: ${o.name}`);this.map.set(o.name,{definition:o,handler:r.handler})}}getHandler(r){return this.map.get(r)?.handler}getAllDefinitions(){return Array.from(this.map.values()).map(r=>r.definition)}has(r){return this.map.has(r)}get size(){return this.map.size}};function ge(a){let r=new ee;for(let o of a)r.register(o);return r}var G=class{server;token;constructor(r,o){this.server=r??null,this.token=o??null}async report(r,o){if(!(!this.server||this.token==null))try{await this.server.notification({method:"notifications/progress",params:{progressToken:this.token,progress:r,total:o}})}catch{}}},On=new G;function C(a){let r=a.errorCategory!==void 0,o={content:[{type:"text",text:JSON.stringify(r?{...a,isError:!0}:a,null,2)}]};return r&&(o.isError=!0),o}function u(a,r,o,e){return C({summary:a,data:r,suggestions:o,warnings:e})}function H(a,r,o){return C({summary:`${r.length} ${a} found.`,data:r,suggestions:o})}function j(a){let r={feature_disabled:"ENV_LIMITATION",permission_required:"PERMISSIONS",schema_missing:"SCHEMA_MISMATCH"};return C({summary:`Blocked: ${a.cannotProceedBecause}`,data:null,prerequisite:a,errorCategory:r[a.type]})}var te="@OData.Community.Display.V1.FormattedValue";function F(a){return a.map(r=>{if(typeof r!="object"||r===null)return r;let o=r,e={};for(let n of Object.keys(o))if(n.endsWith(te)){let i=n.slice(0,-te.length);e[i]=o[n]}if(Object.keys(e).length===0)return r;let t={};for(let n of Object.keys(o))n.endsWith(te)||(Object.prototype.hasOwnProperty.call(e,n)?t[n]={value:o[n],label:e[n]}:t[n]=o[n]);return t})}var ye=[{name:"dataverse_whoami",description:"Returns the current authenticated user context from Dataverse WhoAmI: userId, businessUnitId, organizationId, organizationName, and environmentUrl. Use this to verify authentication is working, retrieve the current user context, or obtain IDs needed for subsequent operations. WHEN TO USE: Verifying authentication, getting current user/org context, or obtaining IDs for downstream operations. BEST PRACTICES: Call first to confirm connectivity before other tools. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function he(a,r,o){if(a==="dataverse_whoami"){let e=await o.whoAmI(),t={userId:e.UserId,businessUnitId:e.BusinessUnitId,organizationId:e.OrganizationId,organizationName:e.OrganizationName,environmentUrl:e.EnvironmentUrl};return u(`Authenticated as ${e.OrganizationName}`,t,["Use dataverse_list_tables to discover available tables","Use dataverse_get_table_metadata to inspect a table schema"])}throw new Error(`Unknown auth tool: ${a}`)}import{z as S}from"zod";var ae=[{name:"dataverse_list_tables",description:"Lists all Dataverse tables. By default returns ONLY custom (non-system) tables. Set includeSystemTables=true to include all ~1700+ system tables. WHEN TO USE: Discovering which tables exist in the environment. BEST PRACTICES: Start without includeSystemTables to focus on custom tables; use dataverse_get_table_metadata for column details. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{includeSystemTables:{type:"boolean",description:"Include system tables. Default false = custom tables only."}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_table_metadata",description:"Returns full schema metadata for a Dataverse table: all attribute (column) logical names, display names, data types, required levels, and lookup target entities. Use this before writing queries or creating/updating records to confirm correct field names and types. Set includeAttributes=false if you only need table-level metadata without column details. WHEN TO USE: Before building queries or creating/updating records to validate field names, types, and required levels. BEST PRACTICES: Set includeAttributes=false for table-level info only; call once and reuse results. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{logicalName:{type:"string",description:'The logical name of the table (e.g., "account", "contact", "new_mytable")'},includeAttributes:{type:"boolean",description:"Include attribute (column) definitions. Default: true"}},required:["logicalName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_relationships",description:"Returns all relationship definitions (1:N, N:1, N:N) for a Dataverse table, including relationship schema names, referenced/referencing entity names, and lookup attribute names. Use to determine the correct relationshipName for dataverse_associate/dataverse_disassociate, or to map lookup fields before building FetchXML joins. Use relationshipType to filter results. WHEN TO USE: Finding relationship schema names for associate/disassociate, or mapping lookups for FetchXML joins. BEST PRACTICES: Filter by relationshipType to reduce output size. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{logicalName:{type:"string",description:"The logical name of the table"},relationshipType:{type:"string",enum:["OneToMany","ManyToOne","ManyToMany","All"],description:"Filter by relationship type. Default: All"}},required:["logicalName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_global_option_sets",description:"Lists all global (shared) option sets defined in the Dataverse environment, returning their names and metadata IDs. Use this to discover available option sets before calling dataverse_get_option_set to retrieve their values. Prefer this over dataverse_get_table_metadata when you need to find option sets that are reused across multiple tables. WHEN TO USE: Discovering shared option sets reused across multiple tables. BEST PRACTICES: Follow up with dataverse_get_option_set to retrieve individual option values. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_option_set",description:"Returns all option labels and their integer values for a named global option set. Use this to look up the numeric code for a picklist value before filtering records (e.g., statecode or statuscode equivalents), or to populate dropdowns with correct option values. WHEN TO USE: Looking up numeric codes for picklist filtering or record creation. BEST PRACTICES: Use the integer values in $filter expressions, not the label text. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{name:{type:"string",description:"The name of the global option set"}},required:["name"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_entity_key",description:"Returns all alternate key definitions for a Dataverse table. Useful before using dataverse_upsert to know which fields serve as alternate keys, their index status (Active/InProgress/Failed), and whether they are customizable. WHEN TO USE: Before using dataverse_upsert to verify which fields serve as alternate keys. BEST PRACTICES: Check that key index status is Active before relying on a key. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{tableName:{type:"string",description:'Logical name of the table (e.g., "account", "contact")'}},required:["tableName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_attribute_option_set",description:"Returns all option labels and integer values for a table-specific attribute (Picklist, MultiSelectPicklist, Status, or State field). Use to look up the numeric codes for a column's choices before filtering or updating records. WHEN TO USE: Looking up option values for a specific table's picklist, multi-select picklist, status, or state column. BEST PRACTICES: Use the integer values in $filter and when setting fields in create/update. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:'Logical name of the table (e.g., "account", "contact")'},attributeLogicalName:{type:"string",description:'Logical name of the attribute (e.g., "statuscode", "industrycode", "new_tags")'}},required:["entityLogicalName","attributeLogicalName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],qt=S.object({logicalName:S.string().min(1),includeAttributes:S.boolean().optional().default(!0)}),Pt=S.object({logicalName:S.string().min(1),relationshipType:S.enum(["OneToMany","ManyToOne","ManyToMany","All"]).optional()}),$t=S.object({includeSystemTables:S.boolean().default(!1).optional().describe("Include system tables. Default false = custom tables only.")}),Mt=S.object({name:S.string().min(1)}),Wt=S.object({tableName:S.string().min(1).describe('Logical name of the table (e.g., "account", "contact")')}),ve=/^[a-z_][a-z0-9_]*$/,jt=S.object({entityLogicalName:S.string().min(1).regex(ve,"Invalid Dataverse logical name"),attributeLogicalName:S.string().min(1).regex(ve,"Invalid Dataverse logical name")});async function be(a,r,o){switch(a){case"dataverse_list_tables":{let{includeSystemTables:e=!1}=$t.parse(r??{}),t=!e,n=await o.listTables(t),i=Array.isArray(n)?n:[];return H(`tables (${t?"custom only":"including system"})`,i,["Use dataverse_get_table_metadata to inspect a specific table's columns and types"])}case"dataverse_get_table_metadata":{let{logicalName:e,includeAttributes:t}=qt.parse(r),n=await o.getTableMetadata(e,t),i=Array.isArray(n?.Attributes)?n.Attributes.length:0;return u(`Metadata for ${e}: ${i} attributes`,n,["Use dataverse_query to read records from this table","Use dataverse_get_relationships to see related tables"])}case"dataverse_get_relationships":{let{logicalName:e,relationshipType:t}=Pt.parse(r),n=await o.getRelationships(e),i=e.toLowerCase(),s=n.filter(p=>p.RelationshipType==="OneToManyRelationship"&&p.ReferencedEntity?.toLowerCase()===i),l=n.filter(p=>p.RelationshipType==="OneToManyRelationship"&&p.ReferencingEntity?.toLowerCase()===i),d=n.filter(p=>p.RelationshipType==="ManyToManyRelationship"),c=!t||t==="All",m=[...c||t==="OneToMany"?s:[],...c||t==="ManyToOne"?l:[],...c||t==="ManyToMany"?d:[]];return u(`${m.length} relationships found for ${e}`,{tableName:e,oneToMany:c||t==="OneToMany"?s:void 0,manyToOne:c||t==="ManyToOne"?l:void 0,manyToMany:c||t==="ManyToMany"?d:void 0},["Use dataverse_associate or dataverse_disassociate to manage N:N relationships"])}case"dataverse_list_global_option_sets":{let e=await o.listGlobalOptionSets(),t=Array.isArray(e)?e:[];return H("global option sets",t,["Use dataverse_get_option_set with a name to see the values"])}case"dataverse_get_option_set":{let{name:e}=Mt.parse(r),t=await o.getOptionSet(e),n=Array.isArray(t?.Options)?t.Options:[];return u(`Option set '${e}': ${n.length} options`,t,["Use these values in $filter expressions or when creating/updating records"])}case"dataverse_get_entity_key":{let{tableName:e}=Wt.parse(r),t=await o.getEntityKeys(e);return u(`${t.length} alternate keys for ${e}`,{tableName:e,keys:t,count:t.length},["Use dataverse_upsert with these keys for create-or-update operations"])}case"dataverse_get_attribute_option_set":{let{entityLogicalName:e,attributeLogicalName:t}=jt.parse(r),n=await o.getAttributeOptionSet(e,t),i=Array.isArray(n?.options)?n.options:[];return u(`Attribute '${t}' on '${e}': ${i.length} options`,n,["Use these integer values in $filter or when creating/updating records"])}default:throw new Error(`Unknown metadata-read tool: ${a}`)}}import{z as $}from"zod";var Ft=new Set(["dataverse_delete","dataverse_delete_file","dataverse_update_entity","dataverse_delete_attribute"]);function ne(a){let r=[];return a.top!==void 0&&a.top>5e3&&r.push({code:"LARGE_RESULT_SET",message:`Large result set requested (top=${a.top}). Consider reducing $top or using paging.`,severity:"warning"}),(!a.select||a.select.length===0)&&r.push({code:"NO_SELECT",message:"No $select specified \u2014 all columns will be returned. Specify columns to reduce payload size.",severity:"warning"}),a.filter||r.push({code:"NO_FILTER",message:"No filter \u2014 consider adding one to reduce results and improve performance.",severity:"info"}),r}function L(a){let r=[];return Ft.has(a.toolName)&&r.push({code:"DESTRUCTIVE_OP",message:"Destructive operation \u2014 confirm with user before proceeding. This action cannot be undone.",severity:"warning"}),a.toolName==="dataverse_batch_execute"&&r.push({code:"BATCH_OP",message:"Batch operations may modify multiple records in a single transaction.",severity:"info"}),r}var _e=[{name:"dataverse_update_entity",description:"Updates configuration flags on an existing Dataverse entity definition \u2014 enables or disables Notes (HasNotes), Change Tracking, and Audit. Requires System Customizer or System Administrator privileges. WHEN TO USE: Enabling notes/attachments support, change tracking, or audit on a table. BEST PRACTICES: Set autoPublish=true (default) to make changes visible immediately. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Logical name of the entity to update (e.g. 'account', 'new_mytable')"},hasNotes:{type:"boolean",description:"Enable or disable the Notes/Attachments feature for this entity"},changeTrackingEnabled:{type:"boolean",description:"Enable or disable change tracking (required for delta sync)"},isAuditEnabled:{type:"boolean",description:"Enable or disable auditing on this entity"},autoPublish:{type:"boolean",description:"Publish the customization after update (default: true). Set false to defer publishing."},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional schema modification to Dataverse entity metadata"}},required:["entityLogicalName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],Bt=$.object({entityLogicalName:$.string().min(1).regex(/^[a-z_][a-z0-9_]*$/,"Invalid logical name"),confirm:$.literal(!0,{errorMap:()=>({message:"Set confirm: true to modify entity metadata"})}),hasNotes:$.boolean().optional(),changeTrackingEnabled:$.boolean().optional(),isAuditEnabled:$.boolean().optional(),autoPublish:$.boolean().optional().default(!0)}).refine(a=>a.hasNotes!==void 0||a.changeTrackingEnabled!==void 0||a.isAuditEnabled!==void 0,{message:"At least one of hasNotes, changeTrackingEnabled, or isAuditEnabled must be provided"});async function we(a,r,o){switch(a){case"dataverse_update_entity":{let{entityLogicalName:e,hasNotes:t,changeTrackingEnabled:n,isAuditEnabled:i,autoPublish:s}=Bt.parse(r),l=L({toolName:"dataverse_update_entity",entitySetName:e}).map(g=>`[${g.severity.toUpperCase()}] ${g.code}: ${g.message}`),d={};t!==void 0&&(d.HasNotes=t),n!==void 0&&(d.ChangeTrackingEnabled=n),i!==void 0&&(d.IsAuditEnabled=i);try{await o.getTableMetadata(e,!1)}catch{return C({summary:`Entity '${e}' does not exist in this Dataverse environment.`,data:{error:"ENTITY_NOT_FOUND",entityLogicalName:e},errorCategory:"SCHEMA_MISMATCH",suggestions:["Use dataverse_list_tables to find the correct entity logical name"]})}let c={"@odata.type":"#Microsoft.Dynamics.CRM.EntityMetadata"};t!==void 0&&(c.HasNotes=t),n!==void 0&&(c.ChangeTrackingEnabled=n),i!==void 0&&(c.IsAuditEnabled={Value:i});try{await o.updateEntityDefinition(e,c)}catch(g){if((g instanceof Error?g.message:String(g)).includes("0x80060888")){let Y=Object.keys(d),Lt={IsAuditEnabled:"IsAuditEnabled requires organization-level auditing to be enabled first: Power Platform admin center > Settings > Audit and logs > Start Auditing",ChangeTrackingEnabled:"ChangeTrackingEnabled may be blocked if the entity is part of a managed solution",HasNotes:"HasNotes=true/false should work for custom (unmanaged) entities"},Ht=Y.map(Z=>Lt[Z]).filter(Z=>Z!==void 0);return C({summary:`Cannot update entity '${e}': operation not supported by Dataverse.`,data:{error:"0x80060888",entityLogicalName:e,requestedChanges:d},errorCategory:"SCHEMA_MISMATCH",suggestions:Ht})}throw g}let m=Object.entries(d).map(([g,k])=>`${g}=${String(k)}`).join(", "),p="autoPublish=false (skipped)";return s&&(await o.publishCustomizations({entities:[e]}),p="published successfully"),u(`Entity '${e}' updated: ${m}. ${p}.`,{entityLogicalName:e,changes:d,published:s,...l.length>0&&{warnings:l}},["Use dataverse_get_table_metadata to verify the changes","Enable HasNotes=true before using dataverse_create_annotation"])}default:throw new Error(`Unknown metadata tool: ${a}`)}}var Te=[...ae,..._e];async function Se(a,r,o){return new Set(ae.map(t=>t.name)).has(a)?be(a,r,o):we(a,r,o)}import{z as _}from"zod";import{z as Ne}from"zod";var Re=/^[a-zA-Z_][a-zA-Z0-9_]*$/,b=Ne.string().min(1).regex(Re,"entitySetName must contain only letters, digits, or underscores"),re=Ne.string().min(1).regex(Re,"relationshipName must contain only letters, digits, or underscores");var Gt={opportunity:"opportunities",territory:"territories",category:"categories",activityparty:"activityparties",activitymimeattachment:"activitymimeattachments",queue:"queues",queueitem:"queueitems",dependency:"dependencies",salesliteratureitem:"salesliteratureitems",contractdetail:"contractdetails",discounttype:"discounttypes",entitlementtemplate:"entitlementtemplates",pricelevel:"pricelevels"},xe=[{name:"dataverse_query",description:"Queries a Dataverse table using OData ($filter, $select, $orderby, $top, $expand, $count). Use for simple to moderate reads on a single table or with shallow $expand for related fields. Always specify $select to minimize payload. For complex aggregations (count, sum, avg), multi-entity joins, many-to-many traversal, or advanced FetchXML-only operators, use dataverse_execute_fetchxml instead. WHEN TO USE: Single-table reads, simple filters, shallow expands, or server-side aggregation via $apply. BEST PRACTICES: Always pass $select; cap with $top; use $apply for server-side counts/grouping. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'The OData entity set name (e.g., "accounts", "contacts", "new_mytables")'},select:{type:"array",items:{type:"string"},description:"Columns to return. Always specify to minimize payload."},filter:{type:"string",description:'OData $filter expression (e.g., "statecode eq 0 and new_amount gt 1000")'},orderby:{type:"string",description:'OData $orderby expression (e.g., "createdon desc")'},top:{type:"number",description:"Maximum number of records to return (default: 50)"},expand:{type:"string",description:'OData $expand for related entities (e.g., "parentaccountid($select=name)")'},count:{type:"boolean",description:"Include total record count in response"},apply:{type:"string",description:'OData $apply for server-side aggregation (e.g., "groupby((statuscode),aggregate($count as count))")'},formattedValues:{type:"boolean",description:"When true, includes human-readable labels for picklist fields alongside raw integer codes (e.g., { value: 1, label: 'Active' }). Uses OData formatted-value annotations."}},required:["entitySetName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_execute_fetchxml",description:'Executes a FetchXML query against Dataverse \u2014 use for complex scenarios requiring aggregations (count, sum, avg, min, max with grouping), linked-entity joins across multiple tables, many-to-many relationship traversal, or advanced filtering not expressible in OData. Returns a typed array of records. entitySetName is optional \u2014 if omitted it is extracted from the <entity name="..."> element in the FetchXML. WHEN TO USE: Multi-table joins, aggregations with groupby, N:N traversal, or filtering not supported by OData. BEST PRACTICES: Add page/count attributes for large result sets; prefer dataverse_query for simple reads. WORKFLOW: query_data.',inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name of the root entity (e.g., "accounts"). If omitted, extracted from the <entity name="..."> element in the FetchXML.'},fetchXml:{type:"string",description:"The complete FetchXML query string"},formattedValues:{type:"boolean",description:"When true, includes human-readable labels for picklist fields alongside raw integer codes."}},required:["fetchXml"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_retrieve_multiple_with_paging",description:"Retrieves ALL records matching a query by automatically following OData nextLink pages. Use instead of dataverse_query when you need more than 5000 records or all records in a table. Returns totalRetrieved count. Set maxTotal to cap retrieval (default 5000, max 50000) to avoid overwhelming the context. WHEN TO USE: You need all matching records beyond the 5000-row OData page limit or a full table export. BEST PRACTICES: Always set $select; use maxTotal to cap results and avoid context overflow. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name (e.g., "accounts")'},select:{type:"array",items:{type:"string"}},filter:{type:"string"},orderby:{type:"string"},expand:{type:"string"},maxTotal:{type:"number",description:"Maximum records to retrieve (default: 5000, max: 50000)"},formattedValues:{type:"boolean",description:"Include formatted label annotations."}},required:["entitySetName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],zt=_.object({entitySetName:b,select:_.array(_.string()).optional(),filter:_.string().optional(),orderby:_.string().optional(),top:_.number().positive().max(5e3).optional().default(50),expand:_.string().optional(),count:_.boolean().optional(),apply:_.string().optional(),formattedValues:_.boolean().optional()}),Vt=_.object({fetchXml:_.string().min(1).describe("Complete FetchXML query string"),entitySetName:_.string().optional().describe('OData entity set name (e.g., "accounts"). If omitted, extracted from the <entity name="..."> element in the FetchXML.'),formattedValues:_.boolean().optional()}),Kt=_.object({entitySetName:b,select:_.array(_.string()).optional(),filter:_.string().optional(),orderby:_.string().optional(),expand:_.string().optional(),maxTotal:_.number().positive().max(5e4).optional(),formattedValues:_.boolean().optional()});async function Ae(a,r,o,e){switch(a){case"dataverse_query":{let t=zt.parse(r),n={};t.select!==void 0&&(n.select=t.select),t.filter!==void 0&&(n.filter=t.filter),t.orderby!==void 0&&(n.orderby=t.orderby),t.top!==void 0&&(n.top=t.top),t.expand!==void 0&&(n.expand=t.expand),t.count!==void 0&&(n.count=t.count),t.apply!==void 0&&(n.apply=t.apply),t.formattedValues!==void 0&&(n.formattedValues=t.formattedValues);let i=await o.query(t.entitySetName,n),s=Array.isArray(i?.value)?i.value:[],l=i["@odata.count"],d=l!==void 0?l===s.length?" (showing all results)":` (total in dataset: ${l})`:"",c=t.formattedValues?F(s):s,m=t.formattedValues&&Array.isArray(i?.value)?{...i,value:c}:i,p=ne({...t.top!==void 0?{top:t.top}:{},...t.select!==void 0?{select:t.select}:{},...t.filter!==void 0?{filter:t.filter}:{},entitySetName:t.entitySetName}).map(g=>`[${g.severity.toUpperCase()}] ${g.code}: ${g.message}`);return u(`${s.length} records returned from ${t.entitySetName}${d}`,m,["Use dataverse_execute_fetchxml for complex joins or aggregations","Add $select to minimize payload"],p.length>0?p:void 0)}case"dataverse_execute_fetchxml":{let t=Vt.parse(r),n=t.entitySetName,{fetchXml:i}=t;if(!n){let c=i.match(/<entity\s+name=["']([^"']+)["']/i);if(!c)return{content:[{type:"text",text:JSON.stringify({isError:!0,error:"entitySetName is required when not present in FetchXML <entity> element"})}]};let m=c[1];n=Gt[m]??m+"s"}let s=await o.executeFetchXml(n,i,t.formattedValues),l=Array.isArray(s)?s:Array.isArray(s?.value)?s.value:[],d=t.formattedValues?F(l):l;return u(`${d.length} records returned via FetchXML`,t.formattedValues&&Array.isArray(s?.value)?{...s,value:d}:s,["Use dataverse_query for simple OData reads","Add page/count attributes for large result sets"])}case"dataverse_retrieve_multiple_with_paging":{let t=Kt.parse(r),n={};t.select!==void 0&&(n.select=t.select),t.filter!==void 0&&(n.filter=t.filter),t.orderby!==void 0&&(n.orderby=t.orderby),t.expand!==void 0&&(n.expand=t.expand),t.maxTotal!==void 0&&(n.maxTotal=t.maxTotal),await e?.report(0,1);let i=await o.queryWithPaging(t.entitySetName,n),s=i?.totalRetrieved??(Array.isArray(i?.value)?i.value.length:0),l=i?.pageCount??1;await e?.report(1,1);let d=Array.isArray(i?.records)?i.records:[],c=t.formattedValues&&d.length>0?{...i,records:F(d)}:i,m=ne({...t.select!==void 0?{select:t.select}:{},...t.filter!==void 0?{filter:t.filter}:{},entitySetName:t.entitySetName}).map(p=>`[${p.severity.toUpperCase()}] ${p.code}: ${p.message}`);return u(`${s} records retrieved across ${l} pages from ${t.entitySetName}`,c,["Set maxTotal to limit retrieval","Use $select to minimize payload size"],m.length>0?m:void 0)}default:throw new Error(`Unknown query tool: ${a}`)}}import{z as y}from"zod";var Ee=[{name:"dataverse_get",description:"Retrieves a single Dataverse record by its GUID. Use when you already know the exact record ID and want specific fields \u2014 faster and more precise than dataverse_query with a GUID filter. Specify select to limit returned columns and reduce payload size. WHEN TO USE: You have the exact record GUID and want specific fields. BEST PRACTICES: Always specify select; use the returned etag for subsequent optimistic-concurrency updates. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:"OData entity set name"},id:{type:"string",description:"Record GUID"},select:{type:"array",items:{type:"string"},description:"Columns to return"},expand:{type:"string",description:'OData $expand for related entities (e.g., "parentaccountid($select=name)")'},formattedValues:{type:"boolean",description:"When true, annotates picklist fields with human-readable labels. Note: dataverse_get always requests all OData annotations."}},required:["entitySetName","id"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_create",description:`Creates a new record in a Dataverse table and returns the new record's GUID. Use dataverse_get_table_metadata first to confirm correct logical field names and required fields. For setting lookup fields, use the format "_fieldname_value" with the related record GUID. For bulk creation of multiple records, consider dataverse_batch_execute to reduce HTTP round-trips. WHEN TO USE: Creating a single new record in a known table. BEST PRACTICES: Validate field names via dataverse_get_table_metadata first; use dataverse_batch_execute for bulk inserts. WORKFLOW: create_record.`,inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:"OData entity set name"},data:{type:"object",description:"Record data as key-value pairs using logical names"}},required:["entitySetName","data"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_update",description:"Updates an existing Dataverse record using PATCH semantics \u2014 only the fields provided in data are changed, all other fields remain unchanged. Requires the record GUID. Use dataverse_upsert instead if you want to create-or-update using an alternate key without knowing the GUID upfront. WHEN TO USE: Modifying specific fields on an existing record with a known GUID. BEST PRACTICES: Pass etag for optimistic concurrency; include only changed fields in data. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string",description:"Record GUID"},data:{type:"object",description:"Fields to update"},etag:{type:"string",description:"ETag value from a prior dataverse_get response. When provided, the update only succeeds if the record has not been modified since (optimistic concurrency). Prevents lost updates."}},required:["entitySetName","id","data"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_delete",description:"Permanently deletes a Dataverse record by its GUID. This operation is irreversible \u2014 you MUST set confirm=true to proceed. Use dataverse_list_dependencies to check if the record is referenced by workflows, plugins, or other components before deleting shared or configuration records. WHEN TO USE: Permanently removing a record you are certain should be deleted. BEST PRACTICES: Call dataverse_list_dependencies first for shared records; always set confirm=true. WORKFLOW: delete_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string",description:"Record GUID"},confirm:{type:"boolean",description:"Must be explicitly true to proceed with deletion"}},required:["entitySetName","id","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!0,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_upsert",description:'Creates or updates a Dataverse record using an alternate key (no GUID needed). Returns operation="created" or "updated". Use mode="createOnly" to fail with an error if the record already exists, or mode="updateOnly" to fail if the record does not exist. Default mode="upsert" creates or updates. Supports compound alternate keys via the alternateKeys parameter. WHEN TO USE: Create-or-update when you have an alternate key but no GUID. BEST PRACTICES: Verify alternate keys with dataverse_get_entity_key first; use mode to control behavior. WORKFLOW: create_record.',inputSchema:{type:"object",properties:{entitySetName:{type:"string"},alternateKey:{type:"string",description:"Alternate key attribute name (for single key)"},alternateKeyValue:{type:"string",description:"Alternate key value (for single key)"},alternateKeys:{type:"object",description:'Compound alternate key as key-value map (e.g., {"key1":"val1","key2":"val2"}). Use instead of alternateKey/alternateKeyValue for multi-field keys.'},data:{type:"object",description:"Record data"},mode:{type:"string",enum:["upsert","createOnly","updateOnly"],description:"upsert=create or update (default), createOnly=fail if exists, updateOnly=fail if not found"}},required:["entitySetName","data"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_assign",description:"Assigns a Dataverse record to a different user or team owner. Sets the ownerid lookup field using the OData bind syntax. WHEN TO USE: Changing the owner of a record to a different user or team. BEST PRACTICES: Use dataverse_list_users or dataverse_list_teams to find valid owner GUIDs first. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:"OData entity set name of the record to assign"},id:{type:"string",description:"Record GUID"},ownerType:{type:"string",enum:["systemuser","team"],description:'Type of the new owner: "systemuser" for a user, "team" for a team'},ownerId:{type:"string",description:"GUID of the user or team to assign the record to"}},required:["entitySetName","id","ownerType","ownerId"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],Xt=y.object({entitySetName:b,id:y.string().uuid(),select:y.array(y.string()).optional(),expand:y.string().optional(),formattedValues:y.boolean().optional()}),Qt=y.object({entitySetName:b,data:y.record(y.unknown())}),Jt=y.object({entitySetName:b,id:y.string().uuid(),data:y.record(y.unknown()),etag:y.string().optional()}),Yt=y.object({entitySetName:b,id:y.string().uuid(),confirm:y.boolean()}),Zt=y.object({entitySetName:b,alternateKey:y.string().min(1).optional(),alternateKeyValue:y.string().min(1).optional(),alternateKeys:y.record(y.string()).optional(),data:y.record(y.unknown()),mode:y.enum(["upsert","createOnly","updateOnly"]).default("upsert").optional().describe("upsert=create or update (default), createOnly=fail if exists, updateOnly=fail if not found")}).refine(a=>a.alternateKey&&a.alternateKeyValue||a.alternateKeys&&Object.keys(a.alternateKeys).length>0,{message:"Provide either (alternateKey + alternateKeyValue) or alternateKeys"}),ea=y.object({entitySetName:b,id:y.string().uuid(),ownerType:y.enum(["systemuser","team"]),ownerId:y.string().uuid()});async function ke(a,r,o){switch(a){case"dataverse_get":{let{entitySetName:e,id:t,select:n,expand:i,formattedValues:s}=Xt.parse(r),{record:l,etag:d}=await o.getRecord(e,t,n,i),c=s?F([l])[0]??l:l;return u(`Retrieved record ${t} from ${e}`,{id:t,record:c,etag:d},["Use dataverse_update to modify this record","Use dataverse_get_relationships to explore related records"])}case"dataverse_create":{let{entitySetName:e,data:t}=Qt.parse(r),n=await o.createRecord(e,t);return u(`Created record ${n} in ${e}`,{id:n,message:"Record created successfully"},["Use dataverse_get to retrieve the full record","Use dataverse_associate to link related records"])}case"dataverse_update":{let{entitySetName:e,id:t,data:n,etag:i}=Jt.parse(r);return await o.updateRecord(e,t,n,i),u(`Updated record ${t} in ${e}`,{message:"Record updated successfully"},["Use dataverse_get to verify the update","Use etag parameter for optimistic concurrency"])}case"dataverse_delete":{let{entitySetName:e,id:t,confirm:n}=Yt.parse(r);return n?(await o.deleteRecord(e,t),u(`Deleted record ${t} from ${e}`,{message:"Record deleted successfully"},["This operation is irreversible"])):{content:[{type:"text",text:JSON.stringify({message:`Deletion not performed. Set 'confirm: true' to delete record '${t}' from '${e}'.`})}]}}case"dataverse_upsert":{let e=Zt.parse(r),{entitySetName:t,alternateKey:n,alternateKeyValue:i,alternateKeys:s,data:l,mode:d="upsert"}=e,c;s&&Object.keys(s).length>0&&(c=Object.entries(s).map(([p,g])=>`${h(p)}='${h(g)}'`).join(","));let m=await o.upsertRecord(t,n??"",i??"",l,d,c);return u(`Upsert ${m.operation}: record in ${t}`,{operation:m.operation,id:m.id,message:`Record ${m.operation} successfully`},["Use dataverse_get_entity_key to verify alternate key definitions"])}case"dataverse_assign":{let{entitySetName:e,id:t,ownerType:n,ownerId:i}=ea.parse(r),s=n==="systemuser"?"systemusers":"teams";return await o.updateRecord(e,t,{"ownerid@odata.bind":`/${s}(${i})`}),u(`Assigned record ${t} in ${e} to new owner`,{message:"Record assigned successfully"},["Use dataverse_list_users or dataverse_list_teams to find valid owners"])}default:throw new Error(`Unknown CRUD tool: ${a}`)}}import{z as M}from"zod";var De=[{name:"dataverse_associate",description:"Creates an association between two Dataverse records via a named N:N or 1:N relationship. Requires the relationship schema name obtainable from dataverse_get_relationships. Use for N:N relationships or to link records without modifying a lookup field directly \u2014 for simple 1:N lookups, setting the lookup field in dataverse_update is simpler. WHEN TO USE: Linking two records via an N:N relationship or 1:N navigation property. BEST PRACTICES: Get the relationship schema name from dataverse_get_relationships first; for simple 1:N lookups use dataverse_update. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string",description:"Source record GUID"},relationshipName:{type:"string",description:"Relationship schema name"},relatedEntitySetName:{type:"string",description:"Related entity set name"},relatedId:{type:"string",description:"Related record GUID"}},required:["entitySetName","id","relationshipName","relatedEntitySetName","relatedId"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_disassociate",description:"Removes an existing association between two Dataverse records on a named relationship. For N:N relationships, provide relatedId and relatedEntitySetName to build the correct $id URL. For 1:N relationships, relatedId and relatedEntitySetName are optional. Use dataverse_get_relationships to find the correct relationship schema name. WHEN TO USE: Removing an N:N or 1:N link between two records without deleting either record. BEST PRACTICES: Get the relationship schema name from dataverse_get_relationships; relatedId is required for N:N. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string"},relationshipName:{type:"string"},relatedId:{type:"string",description:"Required for N:N relationships"},relatedEntitySetName:{type:"string",description:'Entity set name of the related record (required for N:N). E.g., "contacts"'},confirm:{type:"boolean",const:!0,description:"Must be explicitly true to confirm removal of the association"}},required:["entitySetName","id","relationshipName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!0,idempotentHint:!0,openWorldHint:!0}}],ta=M.object({entitySetName:b,id:M.string().uuid(),relationshipName:re,relatedEntitySetName:b,relatedId:M.string().uuid()}),aa=M.object({entitySetName:b,id:M.string().uuid(),relationshipName:re,relatedId:M.string().uuid().optional(),relatedEntitySetName:b.optional(),confirm:M.literal(!0)});async function Ce(a,r,o){switch(a){case"dataverse_associate":{let{entitySetName:e,id:t,relationshipName:n,relatedEntitySetName:i,relatedId:s}=ta.parse(r);return await o.associate(e,t,n,i,s),u(`Associated ${e}(${t}) with ${i}(${s}) via ${n}`,{message:"Records associated successfully"},["Use dataverse_get_relationships to verify relationship names"])}case"dataverse_disassociate":{let{entitySetName:e,id:t,relationshipName:n,relatedId:i,relatedEntitySetName:s}=aa.parse(r);return await o.disassociate(e,t,n,i,s),u(`Disassociated records via ${n}`,{message:"Records disassociated successfully"},["This removes the N:N link but does not delete records"])}default:throw new Error(`Unknown relation tool: ${a}`)}}import{z as v}from"zod";var Oe=[{name:"dataverse_execute_action",description:"Executes a global (unbound) Dataverse action that is not tied to a specific record \u2014 for example WinOpportunity, SendEmail, or custom process actions. Use dataverse_execute_bound_action when the action must operate on a particular record. Actions differ from functions in that they are state-changing operations; for read-only operations use dataverse_execute_function. WHEN TO USE: Invoking global Dataverse actions or custom process actions like WinOpportunity or SendEmail. BEST PRACTICES: Check action parameters via metadata or docs; use dataverse_execute_bound_action for record-scoped actions. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{actionName:{type:"string",description:'Action logical name (e.g., "WinOpportunity")'},parameters:{type:"object",description:"Action parameters"}},required:["actionName"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_execute_function",description:"Executes a global (unbound) Dataverse OData function that is read-only and returns data without side effects \u2014 for example RetrieveTotalRecordCount or InitializeFrom. Use dataverse_execute_action for state-changing operations. Use dataverse_execute_bound_action when the function/action requires a specific record context. WHEN TO USE: Calling global read-only OData functions like RetrieveTotalRecordCount or InitializeFrom. BEST PRACTICES: Functions are side-effect-free and safe to retry; use dataverse_execute_action for mutations. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{functionName:{type:"string",description:'Function name (e.g., "WhoAmI", "RetrieveTotalRecordCount")'},parameters:{type:"object",description:"Function parameters: strings are quoted inline, numbers/booleans inlined as-is, objects serialized as aliased OData parameters"}},required:["functionName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_execute_bound_action",description:"Executes a Dataverse action bound to a specific record instance, passing the entity set name and record GUID as context (e.g., QualifyLead on a lead, or a custom action scoped to an account). The actionName should not include the Microsoft.Dynamics.CRM namespace prefix. Use dataverse_execute_action for global unbound actions that do not require a record context. WHEN TO USE: Running an action scoped to a specific record, e.g. QualifyLead on a lead. BEST PRACTICES: Omit the Microsoft.Dynamics.CRM namespace prefix; ensure the record exists first. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string",description:"Record GUID"},actionName:{type:"string",description:"Action name (without Microsoft.Dynamics.CRM prefix)"},parameters:{type:"object",description:"Action parameters"}},required:["entitySetName","id","actionName"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_retrieve_dependencies_for_delete",description:"Checks what solution components would block deletion of a specific component. Provide the Dataverse component type code (1=Entity, 2=Attribute, 26=SavedQuery, 29=Workflow, 92=PluginAssembly) and the component GUID. Use before deleting shared Dataverse customization components. WHEN TO USE: Before deleting a solution component to check for blocking dependencies. BEST PRACTICES: Resolve all dependencies before attempting deletion. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{componentType:{type:"number",description:"Dataverse component type code (1=Entity, 2=Attribute, 29=Workflow, 92=PluginAssembly)"},objectId:{type:"string",description:"Component GUID"}},required:["componentType","objectId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_execute_bound_function",description:"Executes a Dataverse function bound to a specific record (e.g., CalculateRollupField, GetQuantityAvailable). Use for read-only computed operations on a single record. Unlike bound actions, bound functions do not modify data. WHEN TO USE: Calling a read-only computed function on a specific record, e.g. CalculateRollupField. BEST PRACTICES: Functions are side-effect-free and safe to call repeatedly; pass parameters as string key-value pairs. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name of the table (e.g., "accounts")'},id:{type:"string",description:"GUID of the record"},functionName:{type:"string",description:'Name of the bound function (e.g., "CalculateRollupField")'},parameters:{type:"object",description:"Function parameters as key-value pairs of strings",additionalProperties:{type:"string"}}},required:["entitySetName","id","functionName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_dependencies",description:"Lists workflows, Power Automate flows, Business Rules, and custom actions that reference a given table. Use to detect hidden dependencies before modifying or removing a table. Returns component name, type, state (Active/Draft), trigger event (Create/Update/Delete), and count. WHEN TO USE: Before modifying or removing a table, to discover workflows, flows, and plugins that reference it. BEST PRACTICES: Filter by componentType to focus on specific dependency kinds. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{tableName:{type:"string",description:'Logical name of the table to check (e.g., "account", "contact")'},componentType:{type:"array",items:{type:"string",enum:["Workflow","Flow","BusinessRule","Action","BusinessProcessFlow","Plugin","CustomAPI"]},description:"Filter by component type. Default: all types."}},required:["tableName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],K=/^[a-zA-Z0-9_.]+$/,na=v.object({actionName:v.string().min(1).regex(K,"actionName must contain only letters, digits, underscores, or dots"),parameters:v.record(v.unknown()).optional().default({})}),ra=v.object({functionName:v.string().min(1).regex(K,"functionName must contain only letters, digits, underscores, or dots"),parameters:v.record(v.unknown()).optional().default({})}),oa=v.object({entitySetName:b,id:v.string().uuid(),actionName:v.string().min(1).regex(K,"actionName must contain only letters, digits, underscores, or dots"),parameters:v.record(v.unknown()).optional().default({})}),ia=v.object({componentType:v.number().int().positive(),objectId:v.string().uuid()}),sa=["Workflow","Flow","BusinessRule","Action","BusinessProcessFlow","Plugin","CustomAPI"],la=v.object({tableName:v.string().min(1),componentType:v.array(v.enum(sa)).optional()}),da=v.object({entitySetName:b,id:v.string().uuid(),functionName:v.string().min(1).regex(K,"functionName must contain only letters, digits, underscores, or dots"),parameters:v.record(v.unknown()).optional().default({})});async function Ie(a,r,o){switch(a){case"dataverse_execute_action":{let{actionName:e,parameters:t}=na.parse(r),n=await o.executeAction(e,t);return u(`Executed unbound action ${e}`,n,["Use dataverse_list_custom_actions to discover available actions"])}case"dataverse_execute_function":{let{functionName:e,parameters:t}=ra.parse(r),n=await o.executeFunction(e,t);return u(`Executed function ${e}`,n,["Functions are read-only operations"])}case"dataverse_execute_bound_action":{let{entitySetName:e,id:t,actionName:n,parameters:i}=oa.parse(r),s=await o.executeBoundAction(e,t,n,i);return u(`Executed bound action ${n} on ${e}(${t})`,s)}case"dataverse_list_dependencies":{let{tableName:e,componentType:t}=la.parse(r),n=await o.listTableDependencies(e,t);return u(`${n.count} dependencies found for component`,n,["Use this information before deleting or modifying the component"])}case"dataverse_retrieve_dependencies_for_delete":{let{componentType:e,objectId:t}=ia.parse(r),n=await o.listDependencies(e,t),i=Array.isArray(n)?n:n.value??[n];return u(`${i.length} dependencies found`,n,["Review dependencies before deleting the component"])}case"dataverse_execute_bound_function":{let{entitySetName:e,id:t,functionName:n,parameters:i}=da.parse(r),s=await o.executeBoundFunction(e,t,n,i);return u(`Executed bound function ${n} on ${e}(${t})`,s)}default:throw new Error(`Unknown action tool: ${a}`)}}import{z as q}from"zod";var Ue=[{name:"dataverse_batch_execute",description:"Executes multiple Dataverse operations in a single HTTP $batch request to reduce network round-trips and improve throughput. Accepts up to 1000 individual GET, POST, PATCH, or DELETE requests. Use for bulk creates, updates, or deletes that need to be grouped for performance. Set useChangeset=true to wrap all mutating operations (POST/PATCH/DELETE) in an atomic changeset \u2014 a failure rolls back ALL changeset operations. Individual per-operation results (status, body) are returned as an array in the same order as the input requests. WHEN TO USE: Bulk creates, updates, or deletes (up to 1000 ops) needing a single HTTP round-trip. BEST PRACTICES: Use useChangeset=true for atomic all-or-nothing mutations; batch GETs for parallel reads. WORKFLOW: bulk_operations.",inputSchema:{type:"object",properties:{requests:{type:"array",description:"Array of batch requests to execute",items:{type:"object",properties:{method:{type:"string",enum:["GET","POST","PATCH","DELETE"],description:"HTTP method"},url:{type:"string",description:'Relative URL (e.g., "accounts(guid)" or "contacts")'},body:{type:"object",description:"Request body for POST/PATCH operations"}},required:["method","url"]}},useChangeset:{type:"boolean",description:"Wrap mutating operations (POST/PATCH/DELETE) in an atomic changeset. A failure rolls back ALL operations in the changeset. Defaults to false."}},required:["requests"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}],ca=q.object({method:q.enum(["GET","POST","PATCH","DELETE"]),url:q.string().min(1).refine(a=>!/[\r\n]/.test(a),{message:"Batch URL must not contain CR or LF characters"}).refine(a=>!a.startsWith("http"),{message:"Batch URL must be a relative path, not an absolute URL"}).refine(a=>!/(\.\.[\/\\])|(^\.\.$)/.test(a),{message:"Batch URL must not contain path traversal sequences"}),body:q.record(q.unknown()).optional()}),ua=q.object({requests:q.array(ca).min(1).max(1e3),useChangeset:q.boolean().default(!1).describe("Wrap mutating operations (POST/PATCH/DELETE) in an atomic changeset. A failure rolls back ALL operations in the changeset.")});async function Le(a,r,o,e){if(a==="dataverse_batch_execute"){let{requests:t,useChangeset:n}=ua.parse(r),i=t.map(d=>({method:d.method,url:d.url,body:d.body}));await e?.report(0,t.length);let s=await o.batchExecute(i,n);await e?.report(t.length,t.length);let l=s.filter(d=>d===null||!d.error).length;return u(`Batch executed: ${l}/${s.length} operations succeeded`,{results:s,count:s.length},["Use batch for bulk create/update operations to reduce HTTP round-trips"])}throw new Error(`Unknown batch tool: ${a}`)}import{z as X}from"zod";var He=[{name:"dataverse_change_detection",description:"Detects new, modified, and deleted records since a previous sync using Dataverse change tracking (delta queries). On first call, pass deltaToken=null to get an initial snapshot and receive a token. On subsequent calls, pass the returned token to retrieve only changes since last sync. Change tracking must be enabled on the table in Dataverse settings. Returns newAndModified records, deleted record IDs, and the nextDeltaToken for the next call. WHEN TO USE: Incremental sync \u2014 detecting records created, updated, or deleted since a previous snapshot. BEST PRACTICES: Store the deltaToken persistently; always specify $select to minimize payload. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name (e.g., "accounts")'},deltaToken:{anyOf:[{type:"string"},{type:"null"}],description:"Delta token from a previous call, or null for the initial sync"},select:{type:"array",items:{type:"string"},description:"Columns to return (recommended to minimise payload)"}},required:["entitySetName","deltaToken"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],pa=X.object({entitySetName:b,deltaToken:X.string().nullable(),select:X.array(X.string()).optional()});async function qe(a,r,o){if(a==="dataverse_change_detection"){let{entitySetName:e,deltaToken:t,select:n}=pa.parse(r),i;try{i=await o.getChangedRecords(e,t,n)}catch(l){let d=l instanceof Error?l.message:String(l);if(/change.?track|0x80072491/i.test(d))return j({type:"feature_disabled",feature:"Change Tracking",cannotProceedBecause:`Change tracking is not enabled on '${e}', so delta queries cannot be executed.`,adminPortal:"Power Apps Maker Portal",steps:["Open Power Apps maker portal (make.powerapps.com)",`Navigate to Tables \u2192 search for '${e}'`,"Open the table \u2192 click the Settings (gear) icon",'Enable "Track changes"',"Save the table, then publish customizations"],fixableViaToolName:"dataverse_update_entity"});throw l}let s=Array.isArray(i?.newAndModified)?i.newAndModified:[];return u(`${s.length} changed records detected`,i,["Store the returned deltaToken for subsequent incremental sync"])}throw new Error(`Unknown tracking tool: ${a}`)}import{z as T}from"zod";var ma=T.object({includeManaged:T.boolean().optional().default(!1),nameFilter:T.string().optional(),top:T.number().int().min(1).max(200).optional().default(50)}),fa=T.object({solutionName:T.string().min(1).describe("Unique name of the solution (not the display name)"),componentType:T.number().int().optional().describe("Filter by Dataverse component type code (1=Entity, 29=Workflow, 97=WebResource, 90=PluginAssembly, etc.). Omit for all types."),top:T.number().int().min(1).max(5e3).default(200).optional()}),ga=T.object({components:T.object({entities:T.array(T.string()).optional().describe("Entity logical names to publish"),webResources:T.array(T.string()).optional().describe("Web resource names to publish"),optionSets:T.array(T.string()).optional().describe("Global OptionSet names to publish")}).optional().describe("Specific components to publish. If omitted, ALL unpublished customizations are published.")}),Pe=[{name:"dataverse_list_solutions",description:"Lists Dataverse solutions in the environment. By default returns only unmanaged solutions. Set includeManaged=true to include managed (imported) solutions. Use nameFilter to search by unique name. WHEN TO USE: Discovering solutions in the environment for inspection or management. BEST PRACTICES: Use nameFilter for targeted lookup; check version and publisher for managed solutions. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{includeManaged:{type:"boolean",description:"Include managed (imported) solutions. Default: false"},nameFilter:{type:"string",description:"Filter solutions by unique name (contains match)"},top:{type:"number",description:"Maximum number of solutions to return (default 50, max 200)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_solution_components",description:"Lists all components in a named Dataverse solution (entities, attributes, workflows, web resources, plugins, etc.). Use the unique solution name (not display name). Optionally filter by component type code (1=Entity, 29=Workflow, 97=WebResource, 90=PluginAssembly). WHEN TO USE: Inspecting which entities, workflows, or web resources belong to a specific solution. BEST PRACTICES: Filter by componentType code to reduce noise; use unique name, not display name. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{solutionName:{type:"string",description:"Unique name of the solution"},componentType:{type:"number",description:"Filter by component type code"},top:{type:"number",description:"Max results (default 200, max 5000)"}},required:["solutionName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_publish_customizations",description:'Publishes unpublished Dataverse customizations. Without parameters, publishes ALL pending customizations (equivalent to clicking "Publish All" in Power Apps maker portal). Optionally specify entities, webResources, or optionSets to publish only those components. WARNING: Publishing all can take 30-120 seconds in large environments. WHEN TO USE: After making schema or UI changes that need to be visible to users. BEST PRACTICES: Publish specific entities when possible to reduce duration; full publish can take 30-120s. WORKFLOW: manage_solution.',inputSchema:{type:"object",properties:{components:{type:"object",description:"Specific components. Omit to publish all.",properties:{entities:{type:"array",items:{type:"string"}},webResources:{type:"array",items:{type:"string"}},optionSets:{type:"array",items:{type:"string"}}}}},required:[]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function $e(a,r,o){switch(a){case"dataverse_list_solutions":{let e=ma.parse(r??{}),t=["isvisible eq true"];e.includeManaged||t.push("ismanaged eq false"),e.nameFilter&&t.push(`contains(uniquename,'${h(e.nameFilter)}')`);let i=((await o.query("solutions",{select:["solutionid","uniquename","friendlyname","version","ismanaged","installedon"],filter:t.join(" and "),expand:"publisherid($select=friendlyname)",orderby:"friendlyname asc",top:e.top})).value??[]).map(s=>({solutionId:s.solutionid,uniqueName:s.uniquename,friendlyName:s.friendlyname,version:s.version,isManaged:s.ismanaged,installedOn:s.installedon,publisher:s.publisherid?.friendlyname??null}));return u(`${i.length} solutions found`,{solutions:i,count:i.length},["Use dataverse_solution_components to inspect a specific solution"])}case"dataverse_solution_components":{let{solutionName:e,componentType:t,top:n=200}=fa.parse(r),i=await o.getSolutionComponents(e,t,n);return u(`${i.count} components in solution '${e}'`,i,["Filter by componentType for specific component kinds"])}case"dataverse_publish_customizations":{let{components:e}=ga.parse(r??{}),t=await o.publishCustomizations(e);return u("Customizations published successfully",t,["Changes are now visible to all users in the environment"])}default:throw new Error(`Unknown solution tool: ${a}`)}}import{z}from"zod";var ya=z.object({callerId:z.string().uuid().describe('Azure AD Object ID (GUID) of the Dataverse system user to impersonate. Requires the executing account to have the "Act on behalf of another user" privilege in Dataverse.'),toolName:z.string().min(1).describe('Name of the MCP tool to execute on behalf of the user (e.g., "dataverse_create", "dataverse_query")'),toolArgs:z.record(z.unknown()).describe("Arguments for the wrapped tool, as an object")}),oe=[{name:"dataverse_impersonate",description:'Executes another Dataverse tool on behalf of a different system user by injecting the MSCRMCallerId header. Requires the executing account to have the "Act on behalf of another user" privilege in Dataverse. The impersonation applies ONLY to the single tool call specified. Use for auditing workflows that must create or update records under a specific user identity. WHEN TO USE: Creating or updating records under a specific user identity for audit-trail purposes. BEST PRACTICES: Impersonation applies to the single wrapped tool call only; cannot impersonate System Administrators. WORKFLOW: update_record.',inputSchema:{type:"object",properties:{callerId:{type:"string",description:"GUID (Azure AD Object ID) of the Dataverse system user to impersonate"},toolName:{type:"string",description:'MCP tool to execute while impersonating (e.g., "dataverse_create")'},toolArgs:{type:"object",description:"Arguments for the wrapped tool"}},required:["callerId","toolName","toolArgs"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function Me(a,r,o,e){if(a!=="dataverse_impersonate")throw new Error(`Unknown impersonate tool: ${a}`);let{callerId:t,toolName:n,toolArgs:i}=ya.parse(r);try{if(((await o.query(`systemusers(${h(t)})/systemuserroles_association`,{select:["name"],filter:"name eq 'System Administrator'",top:1})).value?.length??0)>0)throw new Error("Security policy: impersonation of users with System Administrator role is prohibited to prevent privilege escalation.")}catch(d){throw d instanceof Error&&d.message.includes("Security policy")?d:new Error(`Security policy: cannot verify callerId roles \u2014 impersonation denied. Cause: ${String(d)}`)}let s=o.http,l=s.defaultHeaders.MSCRMCallerId;try{s.defaultHeaders.MSCRMCallerId=t;let d=await e(n,i,o);return u(`Impersonated as ${t}, executed ${n}`,{impersonatedAs:t,tool:n,result:JSON.parse(d.content[0].text)},["Impersonation applies to this single call only"])}finally{l===void 0?delete s.defaultHeaders.MSCRMCallerId:s.defaultHeaders.MSCRMCallerId=l}}import{z as N}from"zod";var ha={10:"Pre-validation",20:"Pre-operation",40:"Post-operation",45:"Post-operation (deprecated)"},va={0:"Synchronous",1:"Asynchronous"},ba=N.object({workflowId:N.string().uuid(),activate:N.boolean()}),We=[{name:"dataverse_list_custom_actions",description:"Lists all custom actions (custom API / SDK messages) registered in the environment. Returns the message name, category, bound entity (if any), execute privilege, and whether it is customizable. Useful for discovering available automation entry points and agent-callable actions. WHEN TO USE: Discovering available custom API / SDK messages for automation. BEST PRACTICES: Use nameFilter to search; follow up with dataverse_execute_action to invoke. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Max records (default 100, max 500)"},nameFilter:{type:"string",description:"Filter by name (substring match)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_plugin_steps",description:"Lists plugin steps (SdkMessageProcessingStep registrations) in the environment. Shows plugin assembly, step name, message (Create/Update/Delete/\u2026), entity, stage (pre/post), mode (sync/async), and state (enabled/disabled). Essential for understanding what custom business logic fires on Dataverse operations. WHEN TO USE: Understanding what custom business logic fires on CRUD operations for a table. BEST PRACTICES: Filter by entityLogicalName; check stage and mode to understand execution order and timing. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Max records (default 100, max 500)"},activeOnly:{type:"boolean",description:"Return only enabled steps (default: true)"},entityLogicalName:{type:"string",description:"Filter by entity logical name (e.g. 'account')"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_set_workflow_state",description:"Activates or deactivates a Dataverse workflow (classic workflow / real-time workflow / action). Set activate=true to activate (statecode 1, statuscode 2) or activate=false to deactivate (statecode 0, statuscode 1). Returns the new state. WHEN TO USE: Activating or deactivating a classic workflow, real-time workflow, or action. BEST PRACTICES: Verify workflow ID first; deactivation stops future triggers but does not cancel in-progress runs. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{workflowId:{type:"string",description:"The workflow GUID"},activate:{type:"boolean",description:"true = activate, false = deactivate (draft)"}},required:["workflowId","activate"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_connection_references",description:"Lists all Power Automate connection references defined in the environment, showing their display name, connector ID, connection ID, and active status. Use this before importing a solution containing flows to detect broken or unmapped connections that would cause silent import failures. WHEN TO USE: Pre-deployment solution validation, auditing connection health, identifying broken flow connections. BEST PRACTICES: Look for inactive (isActive=false) references \u2014 these indicate flows that will fail after deployment. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{connectorId:{type:"string",description:"Filter by connector ID substring (e.g. '/providers/Microsoft.PowerApps/apis/shared_sharepointonline')"},activeOnly:{type:"boolean",description:"Return only active connection references (default: false = return all)"},top:{type:"number",description:"Maximum records to return (default 100, max 500)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],_a=N.object({top:N.number().positive().max(500).optional().default(100),nameFilter:N.string().optional()}),wa=N.object({top:N.number().positive().max(500).optional().default(100),activeOnly:N.boolean().optional().default(!0),entityLogicalName:N.string().optional()}),Ta=N.object({connectorId:N.string().optional(),activeOnly:N.boolean().optional().default(!1),top:N.number().int().positive().max(500).optional().default(100)});async function je(a,r,o){switch(a){case"dataverse_list_custom_actions":{let{top:e,nameFilter:t}=_a.parse(r??{}),n=["isprivate eq false"];t&&n.push(`contains(name,'${h(t)}')`);let s=(await o.query("sdkmessages",{select:["sdkmessageid","name","categoryname","isprivate","isreadonly","isvalidforexecuteasync"],filter:n.join(" and "),top:e})).value.map(l=>({id:l.sdkmessageid,name:l.name,category:l.categoryname??"",isPrivate:l.isprivate,isReadOnly:l.isreadonly,asyncSupported:l.isvalidforexecuteasync}));return u(`${s.length} custom actions found`,{total:s.length,messages:s},["Use dataverse_execute_action to run an action"])}case"dataverse_list_plugin_steps":{let{top:e,activeOnly:t,entityLogicalName:n}=wa.parse(r??{}),i={select:["sdkmessageprocessingstepid","name","stage","mode","rank","statecode","filteringattributes","asyncautodelete"],expand:"sdkmessageid($select=name,categoryname),plugintypeid($select=name,assemblyname),sdkmessagefilterid($select=primaryobjecttypecode)",top:e};t&&(i.filter="statecode eq 0");let l=(await o.query("sdkmessageprocessingsteps",i)).value;if(n){let c=n.toLowerCase();l=l.filter(m=>m.sdkmessagefilterid?.primaryobjecttypecode?.toLowerCase()===c)}let d=l.map(c=>({id:c.sdkmessageprocessingstepid,name:c.name,message:c.sdkmessageid?.name??"",entity:c.sdkmessagefilterid?.primaryobjecttypecode??"",assembly:c.plugintypeid?.assemblyname??"",pluginType:c.plugintypeid?.name??"",stage:c.stage,stageName:ha[c.stage]??`Stage ${c.stage}`,mode:c.mode,modeName:va[c.mode]??`Mode ${c.mode}`,rank:c.rank,isActive:c.statecode===0,filteringAttributes:c.filteringattributes??null,asyncAutoDelete:c.asyncautodelete}));return u(`${d.length} plugin steps found`,{total:d.length,steps:d},["Use dataverse_get_plugin_trace_logs for debugging plugin issues"])}case"dataverse_set_workflow_state":{let{workflowId:e,activate:t}=ba.parse(r);try{await o.updateRecord("workflows",e,{statecode:t?1:0,statuscode:t?2:1})}catch(n){let i=n instanceof Error?n.message:String(n);throw/0x80040203|does not refer to a valid workflow|404/i.test(i)?new Error(`Workflow '${e}' not found. Use dataverse_list_workflows to retrieve valid workflow GUIDs in this environment. Original error: ${i}`):n}return u(`Workflow state updated for ${e}`,{workflowId:e,newState:t?"Activated":"Draft",statecode:t?1:0,statuscode:t?2:1})}case"dataverse_list_connection_references":{let{connectorId:e,activeOnly:t,top:n}=Ta.parse(r??{}),i=[];t&&i.push("statecode eq 0"),e&&i.push(`contains(connectorid,'${h(e)}')`);let s={select:["connectionreferenceid","connectionreferencelogicalname","connectionreferencedisplayname","connectorid","connectionid","statecode","statuscode"],orderby:"connectionreferencedisplayname asc",top:n};i.length&&(s.filter=i.join(" and "));let d=((await o.query("connectionreferences",s)).value??[]).map(p=>({id:p.connectionreferenceid??"",logicalName:p.connectionreferencelogicalname??"",displayName:p.connectionreferencedisplayname??"",connectorId:p.connectorid??"",connectionId:p.connectionid??null,isActive:p.statecode===0,statusCode:p.statuscode??null})),c=d.filter(p=>!p.isActive).length,m=c>0?`${d.length} connection references found (${c} inactive \u2014 check before deploying)`:`${d.length} connection references found`;return u(m,{connectionReferences:d,count:d.length,inactiveCount:c},["Inactive references (isActive=false) indicate broken connections that will cause flow failures","Use the Power Apps maker portal to reconnect or replace broken connection references before deploying"])}default:throw new Error(`Unknown customization tool: ${a}`)}}import{z as x}from"zod";var Sa={1e8:"String",100000001:"Number",100000002:"Boolean",100000003:"JSON",100000004:"DataSource"},Na={String:1e8,Integer:100000001,Boolean:100000002,JSON:100000003},Fe=[{name:"dataverse_get_environment_variable",description:"Retrieves an environment variable's definition and current value from Dataverse. Returns the schema name, display name, type, default value, and the current override value (if set). Useful for reading feature flags, configuration values, and integration settings stored in Dataverse environment variables. WHEN TO USE: Reading configuration values, feature flags, or integration settings stored as environment variables. BEST PRACTICES: Check both defaultValue and currentValue; the effective value is currentValue ?? defaultValue. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{schemaName:{type:"string",description:"The schema name of the environment variable (e.g. 'new_MyConfig')"}},required:["schemaName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_set_environment_variable",description:"Sets or updates an environment variable value in Dataverse. If a value record already exists for the variable, it is updated; otherwise a new value record is created. The schemaName must match an existing environment variable definition. WHEN TO USE: Updating configuration values or feature flags stored in Dataverse environment variables. BEST PRACTICES: Verify the variable exists first with dataverse_get_environment_variable; schemaName must match exactly. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{schemaName:{type:"string",description:"The schema name of the environment variable"},value:{type:"string",description:"The new value to set"}},required:["schemaName","value"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_create_environment_variable",description:"Creates a new Dataverse environment variable definition and sets its initial value. Use this when the variable does not yet exist \u2014 use dataverse_set_environment_variable to update an existing one. WHEN TO USE: Initial setup of configuration flags, feature toggles, or integration settings. BEST PRACTICES: Use a solution-prefixed schemaName (e.g. 'myprefix_MyConfig'); provide solutionUniqueName to register in a solution. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{schemaName:{type:"string",description:"Schema name of the new variable (e.g. 'new_MyConfig'). Case-sensitive."},displayName:{type:"string",description:"Human-readable display name"},type:{type:"string",enum:["String","Integer","Boolean","JSON"],description:"Variable type"},value:{type:"string",description:"Initial value to set"},description:{type:"string",description:"Optional description"},defaultValue:{type:"string",description:"Optional default value (fallback when no override value is set)"},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional creation of a new environment variable definition"}},required:["schemaName","displayName","type","value","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}],Ra=x.object({schemaName:x.string().min(1)}),xa=x.object({schemaName:x.string().min(1),value:x.string()}),Aa=x.object({schemaName:x.string().min(1),displayName:x.string().min(1),type:x.enum(["String","Integer","Boolean","JSON"]),value:x.string(),description:x.string().optional(),defaultValue:x.string().optional(),confirm:x.literal(!0,{errorMap:()=>({message:"Set confirm: true to create a new environment variable definition"})})});async function Ea(a,r){let{schemaName:o}=Ra.parse(a),t=(await r.query("environmentvariabledefinitions",{filter:`schemaname eq '${h(o)}'`,select:["environmentvariabledefinitionid","schemaname","displayname","description","type","defaultvalue","isrequired"],top:1})).value;if(t.length===0)throw new Error(`Environment variable '${o}' not found. Check the schema name (it is case-sensitive, e.g. 'new_MyConfig'). To browse existing variables: Power Apps maker portal \u2192 Solutions \u2192 your solution \u2192 Environment Variables. To create a new one: open a solution \u2192 New \u2192 More \u2192 Environment Variable.`);let n=t[0],i=n.environmentvariabledefinitionid,l=(await r.query("environmentvariablevalues",{filter:`_environmentvariabledefinitionid_value eq ${i}`,select:["environmentvariablevalueid","value"],top:1})).value,d=l.length>0?l[0]:null,c=n.type,m=d?d.value??null:null,p=n.defaultvalue??null,g={schemaName:n.schemaname,displayName:n.displayname??"",description:n.description??"",type:c,typeName:Sa[c]??"Unknown",defaultValue:p,currentValue:m,valueId:d?d.environmentvariablevalueid:null,isRequired:n.isrequired??!1,effectiveValue:m??p};return u(`Environment variable '${g.schemaName}': ${g.typeName} = ${g.effectiveValue??"(not set)"}`,g,["Use dataverse_set_environment_variable to update the value"])}async function ka(a,r){let{schemaName:o,value:e}=xa.parse(a),n=(await r.query("environmentvariabledefinitions",{filter:`schemaname eq '${h(o)}'`,select:["environmentvariabledefinitionid","schemaname"],top:1})).value;if(n.length===0)throw new Error(`Environment variable definition '${o}' not found. This tool can only update the value of an existing variable. To create a new environment variable: Power Apps maker portal \u2192 Solutions \u2192 your solution \u2192 New \u2192 More \u2192 Environment variable. Then call this tool to set its value.`);let i=n[0].environmentvariabledefinitionid,l=(await r.query("environmentvariablevalues",{filter:`_environmentvariabledefinitionid_value eq ${i}`,select:["environmentvariablevalueid","value"],top:1})).value,d,c;l.length>0?(c=l[0].environmentvariablevalueid,await r.updateRecord("environmentvariablevalues",c,{value:e}),d="updated"):(c=await r.createRecord("environmentvariablevalues",{value:e,"EnvironmentVariableDefinitionId@odata.bind":`/environmentvariabledefinitions(${i})`}),d="created");let m={schemaName:o,operation:d,valueId:c,value:e};return u(`Environment variable '${o}' set to new value`,m,["Use dataverse_get_environment_variable to verify the update"])}async function Da(a,r){let{schemaName:o,displayName:e,type:t,value:n,description:i,defaultValue:s}=Aa.parse(a),l=L({toolName:"dataverse_create_environment_variable"}).map(k=>`[${k.severity.toUpperCase()}] ${k.code}: ${k.message}`);if((await r.query("environmentvariabledefinitions",{filter:`schemaname eq '${h(o)}'`,select:["environmentvariabledefinitionid"],top:1})).value.length>0)throw new Error(`Environment variable '${o}' already exists. Use dataverse_set_environment_variable to update its value.`);let c=Na[t]??1e8,m={schemaname:o,displayname:e,type:c};i&&(m.description=i),s!==void 0&&(m.defaultvalue=s);let p=await r.createRecord("environmentvariabledefinitions",m),g=await r.createRecord("environmentvariablevalues",{value:n,"EnvironmentVariableDefinitionId@odata.bind":`/environmentvariabledefinitions(${p})`});return u(`Environment variable '${o}' created (type: ${t}, value: '${n}').`,{schemaName:o,displayName:e,type:t,typeCode:c,definitionId:p,valueId:g,value:n,...l.length>0&&{warnings:l}},["Use dataverse_get_environment_variable to verify","Use dataverse_set_environment_variable to update the value later"])}async function Be(a,r,o){switch(a){case"dataverse_get_environment_variable":return Ea(r,o);case"dataverse_set_environment_variable":return ka(r,o);case"dataverse_create_environment_variable":return Da(r,o);default:throw new Error(`Unknown environment tool: ${a}`)}}import{z as I}from"zod";var Ca={0:"Execute",1:"Create",2:"Retrieve",3:"RetrieveMultiple",4:"GetParent",5:"Update",6:"Delete",7:"Assign"},Oa={0:"Waiting",10:"WaitingForResources",20:"InProgress",21:"Pausing",22:"Canceling",30:"Succeeded",31:"Failed",32:"Canceled"},Ia={0:"ReadyToRun",1:"Suspended",2:"Locked",3:"Completed"},Ua=["plugintracelogid","typename","messagename","primaryentity","depth","operationtype","exceptiondetails","messageblock","createdon","performanceexecutionduration","correlationid","requestid"],La=["asyncoperationid","name","operationtype","statuscode","statecode","message","createdon","startedon","completedon"],Ge=[{name:"dataverse_get_plugin_trace_logs",description:"Retrieves recent plugin and custom workflow activity trace logs from Dataverse. Shows execution details including plugin type name, triggering message, entity, execution duration, trace messages written by the developer, and exception details if the plugin failed. Requires the Plugin Trace Log feature to be enabled in Dataverse settings (Settings > Administration > System Settings > Customization tab > 'Enable logging to plugin trace log'). Essential for debugging plugin failures in production. WHEN TO USE: Debugging plugin failures or performance issues in production. BEST PRACTICES: Enable Plugin Trace Log in Dataverse settings first; filter by plugin name or entity to narrow results. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Max records to return (default 50, max 200)"},pluginTypeFilter:{type:"string",description:"Filter by plugin type name (substring match, e.g. 'AccountValidation')"},messageFilter:{type:"string",description:"Filter by message name (e.g. 'Create', 'Update')"},entityFilter:{type:"string",description:"Filter by entity logical name (e.g. 'account')"},exceptionsOnly:{type:"boolean",description:"Return only traces where an exception occurred (default false)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_workflow_trace_logs",description:"Retrieves background workflow (Power Automate classic / legacy workflow engine) execution records from Dataverse. These are the AsyncOperation records for workflow-type operations, useful for diagnosing failures in background workflows and real-time workflows running asynchronously. Note: For modern cloud flows (Power Automate), use the Power Automate portal instead. WHEN TO USE: Diagnosing failures in classic/legacy background workflows. BEST PRACTICES: Use failedOnly=true to focus on errors; for modern cloud flows use Power Automate portal. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Max records (default 50, max 200)"},failedOnly:{type:"boolean",description:"Return only failed workflows (statuscode eq 31, default false)"},entityFilter:{type:"string",description:"Filter by regarding entity type (e.g. 'account')"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],Ha=I.object({top:I.number().int().positive().max(200).optional().default(50),pluginTypeFilter:I.string().optional(),messageFilter:I.string().optional(),entityFilter:I.string().optional(),exceptionsOnly:I.boolean().optional().default(!1)}),qa=I.object({top:I.number().int().positive().max(200).optional().default(50),failedOnly:I.boolean().optional().default(!1),entityFilter:I.string().optional()});function O(a){return typeof a=="string"?a:""}function Pa(a){return typeof a=="number"?a:null}async function ze(a,r,o){switch(a){case"dataverse_get_plugin_trace_logs":{let e=Ha.parse(r),t=[];e.pluginTypeFilter&&t.push(`contains(typename,'${h(e.pluginTypeFilter)}')`),e.messageFilter&&t.push(`messagename eq '${h(e.messageFilter)}'`),e.entityFilter&&t.push(`primaryentity eq '${h(e.entityFilter)}'`),e.exceptionsOnly&&t.push("exceptiondetails ne null");let n=t.length>0?t.join(" and "):void 0,l=((await o.query("plugintracelogs",{select:Ua,orderby:"createdon desc",top:e.top,...n!==void 0?{filter:n}:{}})).value??[]).map(c=>{let m=typeof c.operationtype=="number"?c.operationtype:0,p=c.exceptiondetails;return{id:O(c.plugintracelogid),typeName:O(c.typename),message:O(c.messagename),entity:O(c.primaryentity),depth:typeof c.depth=="number"?c.depth:0,operationType:m,operationTypeName:Ca[m]??String(m),createdOn:O(c.createdon),durationMs:Pa(c.performanceexecutionduration),correlationId:O(c.correlationid),requestId:O(c.requestid),hasException:p!=null&&p!=="",exceptionDetails:typeof p=="string"?p:null,messageBlock:typeof c.messageblock=="string"?c.messageblock:null}}),d={total:l.length,logs:l};return u(`${l.length} plugin trace logs found`,d,["Filter by plugin name or correlation ID for specific traces"])}case"dataverse_get_workflow_trace_logs":{let e=qa.parse(r),t=["operationtype eq 10"];e.failedOnly&&t.push("statuscode eq 31");let n=t.join(" and "),l=((await o.query("asyncoperations",{select:La,filter:n,orderby:"createdon desc",top:e.top})).value??[]).map(c=>{let m=typeof c.statuscode=="number"?c.statuscode:0,p=typeof c.statecode=="number"?c.statecode:0,g=c.message;return{id:O(c.asyncoperationid),name:O(c.name),statusCode:m,statusName:Oa[m]??String(m),stateCode:p,stateName:Ia[p]??String(p),createdOn:O(c.createdon),startedOn:typeof c.startedon=="string"?c.startedon:null,completedOn:typeof c.completedon=="string"?c.completedon:null,errorMessage:typeof g=="string"?g:null}}),d={total:l.length,workflows:l};return u(`${l.length} workflow trace logs found`,d,["Filter by status or entity type for specific workflow traces"])}default:throw new Error(`Unknown trace tool: ${a}`)}}import{z as R}from"zod";var Ve=[{name:"dataverse_search",description:"Full-text Relevance Search across all configured Dataverse tables. Returns ranked results with entity name, record ID, score, and matched fields. Requires Relevance Search to be enabled in Dataverse admin settings. Use when you need to find records without knowing which table they belong to. WHEN TO USE: Cross-table free-text search when you don't know which table contains the data. BEST PRACTICES: Narrow with entities[] and $filter; use searchType=full for Lucene operators (AND, OR, NOT, wildcards). WORKFLOW: search_data.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Full-text search string (supports Lucene syntax with searchType=full)"},entities:{type:"array",items:{type:"string"},description:"Restrict to specific table logical names (omit to search all configured tables). Required when using select."},top:{type:"number",description:"Max results (default 10, max 50)"},searchMode:{type:"string",enum:["any","all"],description:"Match any or all terms (default: any)"},searchType:{type:"string",enum:["simple","full"],description:"Search syntax: simple (default) or full (enables Lucene syntax: AND, OR, NOT, wildcards, fuzzy, proximity, regex)"},filter:{type:"string",description:'OData $filter to apply on search results (e.g., "statecode eq 0")'},facets:{type:"array",items:{type:"string"},description:'Fields to return faceted counts for (e.g., ["entityname,count:100","statecode"])'},orderby:{type:"array",items:{type:"string"},description:'Result sort order (e.g., ["@search.score desc","modifiedon desc"])'},select:{type:"array",items:{type:"string"},description:"Columns to return per result. Only applies when entities is also specified."}},required:["query"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],$a=R.object({query:R.string().min(1),entities:R.array(R.string()).optional(),top:R.number().int().positive().max(50).optional().default(10),searchMode:R.enum(["any","all"]).optional().default("any"),searchType:R.enum(["simple","full"]).optional(),filter:R.string().optional(),facets:R.array(R.string()).optional(),orderby:R.array(R.string()).optional(),select:R.array(R.string()).optional()});async function Ke(a,r,o){switch(a){case"dataverse_search":{let e=$a.parse(r),t={search:e.query,top:e.top};if(e.entities?.length){let l=e.entities.map(d=>({name:d,...e.select?.length?{selectColumns:e.select}:{}}));t.entities=JSON.stringify(l)}e.searchType==="full"&&(t.options=JSON.stringify({querytype:"lucene"})),e.filter&&(t.filter=e.filter),e.facets?.length&&(t.facets=JSON.stringify(e.facets)),e.orderby?.length&&(t.orderby=JSON.stringify(e.orderby));let n;try{n=await o.search(t)}catch(l){let d=l instanceof Error?l.message:String(l);if(/404|not.?found|search.{0,20}disabl|relevance.?search|0x80048[Dd]0[Bb]|search.{0,20}not.{0,20}config|search.{0,20}unavail/i.test(d))return j({type:"feature_disabled",feature:"Dataverse Search (Relevance Search)",cannotProceedBecause:"Relevance Search is not enabled for this Dataverse environment, so full-text cross-table search is unavailable.",adminPortal:"Power Platform Admin Center",steps:["Open Power Platform Admin Center (admin.powerplatform.microsoft.com)","Select your environment \u2192 Settings","Navigate to Product \u2192 Features",'Under "Search", toggle "Dataverse Search" to On',"Save \u2014 indexing may take a few minutes before search is available"]});throw l}let i=(n.value??[]).map(l=>({entityName:l.entityname??"",objectId:l.objectid??"",score:l.score??0,highlights:l.highlights??{},fields:l.attributes??{}})),s={totalRecordCount:n.totalrecordcount??0,results:i};return n.facets&&(s.facets=n.facets),u(`${i.length} search results for '${e.query}'`,s,["Use dataverse_get to retrieve full record details","Narrow results with entities[] filter"])}default:throw new Error(`Unknown search tool: ${a}`)}}import{z as P}from"zod";var ie={1:"Create",2:"Update",3:"Delete",4:"Activate",5:"Deactivate",11:"Share",12:"Unshare",13:"Assign",104:"Access"},Ma=Object.fromEntries(Object.entries(ie).map(([a,r])=>[r,Number(a)])),Xe=[{name:"dataverse_get_audit_log",description:"Retrieves audit log entries from Dataverse. Returns operation details, user info, and parsed change data for each entry. At least one filter (recordId, entityLogicalName, userId, fromDate, or operations) is recommended to avoid large result sets. Audit must be enabled on the environment and table \u2014 returns a clear error if auditing is disabled (HTTP 403). WHEN TO USE: Tracking who changed what and when on Dataverse records. BEST PRACTICES: Always provide at least one filter; audit must be enabled on the table. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{recordId:{type:"string",description:"GUID of a specific record to retrieve audit entries for"},entityLogicalName:{type:"string",description:'Logical name of the entity to filter audit entries (e.g., "account", "contact")'},userId:{type:"string",description:"GUID of the user who made the changes"},fromDate:{type:"string",description:"ISO 8601 date string \u2014 only return audit entries created on or after this date"},top:{type:"number",description:"Maximum number of audit entries to return (default: 50, max: 500)"},operations:{type:"array",items:{type:"string"},description:'Filter by operation names: "Create", "Update", "Delete", "Activate", "Deactivate", "Share", "Unshare", "Assign", "Access"'}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],Wa=P.object({recordId:P.string().uuid().optional(),entityLogicalName:P.string().min(1).optional(),userId:P.string().uuid().optional(),fromDate:P.string().datetime({offset:!0}).optional(),top:P.number().positive().max(500).optional().default(50),operations:P.array(P.string().min(1)).optional()});function ja(a){if(!a)return{};try{return JSON.parse(a)}catch{return a}}function Fa(a){return{auditId:a.auditid,operation:a.operation,operationName:ie[a.operation]??`Unknown(${a.operation})`,action:a.action,actionName:ie[a.action]??`Unknown(${a.action})`,createdOn:a.createdon,userId:a._userid_value,userFullName:a.userid?.fullname??"",userDomainName:a.userid?.domainname??"",objectId:a._objectid_value,objectTypeCode:a.objecttypecode,changes:ja(a.changedata)}}async function Qe(a,r,o){switch(a){case"dataverse_get_audit_log":{let e=Wa.parse(r),t=[];if(e.recordId&&t.push(`_objectid_value eq ${e.recordId}`),e.entityLogicalName){let n=h(e.entityLogicalName);t.push(`objecttypecode eq '${n}'`)}if(e.userId&&t.push(`_userid_value eq ${e.userId}`),e.fromDate&&t.push(`createdon ge ${e.fromDate}`),e.operations?.length){let n=e.operations.map(i=>Ma[i]).filter(i=>i!==void 0);if(n.length>0){let i=n.map(s=>`action eq ${s}`).join(" or ");t.push(`(${i})`)}}try{let i=(await o.query("audits",{select:["auditid","action","operation","createdon","_objectid_value","objecttypecode","changedata","_userid_value"],...t.length>0?{filter:t.join(" and ")}:{},orderby:"createdon desc",top:e.top,expand:"userid($select=fullname,domainname)"})).value.map(Fa);return u(`${i.length} audit records for ${e.entityLogicalName??e.recordId??"query"}`,{entries:i,count:i.length},["Filter by operation type for specific changes"])}catch(n){let i=n instanceof Error?n.message:String(n);if(i.includes("403")||i.includes("Forbidden"))return{content:[{type:"text",text:JSON.stringify({isError:!0,error:"Audit log access denied (HTTP 403). Ensure auditing is enabled on the Dataverse environment and the target table, and that the authenticated user has sufficient privileges."})}]};throw n}}default:throw new Error(`Unknown audit tool: ${a}`)}}import{z as B}from"zod";var Je=new Map,Ye=[{name:"dataverse_detect_duplicates",description:"Checks for potential duplicate records before creating, using a FetchXML query that matches records sharing the same field values as the prospective record (OR conditions on the provided fields). Pass the prospective record fields to check against existing records. WHEN TO USE: Before creating a new record to check if a similar record already exists. BEST PRACTICES: Pass only the key identifying fields (e.g., name, email); too many fields will return fewer matches. WORKFLOW: create_record.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:'Table to check, e.g., "account"'},record:{type:"object",description:"The prospective record fields to check for duplicates"},top:{type:"number",description:"Maximum number of duplicates to return (default 5, max 20)"}},required:["entityLogicalName","record"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],Ba=B.object({entityLogicalName:B.string().min(1).regex(/^[a-z_][a-z0-9_]*$/i,"Must be a valid Dataverse logical name"),record:B.record(B.string(),B.unknown()),top:B.number().int().positive().max(20).optional().default(5)});async function Ze(a,r,o){switch(a){case"dataverse_detect_duplicates":{let n=function(p){return String(p).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")};var e=n;let t=Ba.parse(r),i=Object.entries(t.record).filter(([,p])=>p!=null).map(([p,g])=>`<condition attribute="${n(p)}" operator="eq" value="${n(String(g))}" />`).join(`
|
|
3
|
-
`);if(!
|
|
2
|
+
import{a as he}from"./chunk-SUDI4JM6.js";import{a as be}from"./chunk-PAX4NW5B.js";import"./chunk-24RDOMG4.js";import{a as v,b as _e}from"./chunk-FSM3J3WD.js";import{Server as Wn}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as jn}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Fn,ListToolsRequestSchema as Bn,ListResourcesRequestSchema as Gn,ListResourceTemplatesRequestSchema as zn,ReadResourceRequestSchema as Vn}from"@modelcontextprotocol/sdk/types.js";import{readFileSync as Kn}from"fs";import{join as Xn,dirname as Qn}from"path";import{fileURLToPath as Yn}from"url";function we(){let a=process.argv.slice(2),i="stdio",r=3e3;for(let e=0;e<a.length;e++){if(a[e]==="--transport"&&a[e+1]){let t=a[e+1];(t==="http"||t==="stdio")&&(i=t),e++}if(a[e]==="--port"&&a[e+1]){let t=parseInt(a[e+1],10);!isNaN(t)&&t>0&&t<65536&&(r=t),e++}}return{transport:i,port:r}}var se=class{map=new Map;register(i){for(let r of i.tools){if(this.map.has(r.name))throw new Error(`Duplicate tool name: ${r.name}`);this.map.set(r.name,{definition:r,handler:i.handler})}}getHandler(i){return this.map.get(i)?.handler}getAllDefinitions(){return Array.from(this.map.values()).map(i=>i.definition)}has(i){return this.map.has(i)}get size(){return this.map.size}};function Se(a){let i=new se;for(let r of a)i.register(r);return i}var J=class{server;token;constructor(i,r){this.server=i??null,this.token=r??null}async report(i,r){if(!(!this.server||this.token==null))try{await this.server.notification({method:"notifications/progress",params:{progressToken:this.token,progress:i,total:r}})}catch{}}},rr=new J;function O(a){let i=a.errorCategory!==void 0,r=i?{...a,isError:!0,content:[{type:"text",text:a.summary}]}:a,e={content:[{type:"text",text:JSON.stringify(r,null,2)}]};return i&&(e.isError=!0),e}function u(a,i,r,e){return O({summary:a,data:i,suggestions:r,warnings:e})}function H(a,i,r){return O({summary:`${i.length} ${a} found.`,data:i,suggestions:r})}function te(a,i="UNKNOWN",r){return O({summary:a,data:null,errorCategory:i,suggestions:r})}function X(a){let i={feature_disabled:"ENV_LIMITATION",permission_required:"PERMISSIONS",schema_missing:"SCHEMA_MISMATCH"};return O({summary:`Blocked: ${a.cannotProceedBecause}`,data:null,prerequisite:a,errorCategory:i[a.type]})}var le="@OData.Community.Display.V1.FormattedValue";function G(a){return a.map(i=>{if(typeof i!="object"||i===null)return i;let r=i,e={};for(let n of Object.keys(r))if(n.endsWith(le)){let o=n.slice(0,-le.length);e[o]=r[n]}if(Object.keys(e).length===0)return i;let t={};for(let n of Object.keys(r))n.endsWith(le)||(Object.prototype.hasOwnProperty.call(e,n)?t[n]={value:r[n],label:e[n]}:t[n]=r[n]);return t})}var Te=[{name:"dataverse_whoami",description:"Returns the current authenticated user context from Dataverse WhoAmI: userId, businessUnitId, organizationId, organizationName, and environmentUrl. Use this to verify authentication is working, retrieve the current user context, or obtain IDs needed for subsequent operations. WHEN TO USE: Verifying authentication, getting current user/org context, or obtaining IDs for downstream operations. BEST PRACTICES: Call first to confirm connectivity before other tools. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function Ne(a,i,r){if(a==="dataverse_whoami"){let e=await r.whoAmI(),t={userId:e.UserId,businessUnitId:e.BusinessUnitId,organizationId:e.OrganizationId,organizationName:e.OrganizationName,environmentUrl:e.EnvironmentUrl};return u(`Authenticated as ${e.OrganizationName}`,t,["Use dataverse_list_tables to discover available tables","Use dataverse_get_table_metadata to inspect a table schema"])}throw new Error(`Unknown auth tool: ${a}`)}import{z as ke}from"zod";import{z as R}from"zod";var de=[{name:"dataverse_list_tables",description:"Lists all Dataverse tables. By default returns ONLY custom (non-system) tables. Set includeSystemTables=true to include all ~1700+ system tables. WHEN TO USE: Discovering which tables exist in the environment. BEST PRACTICES: Start without includeSystemTables to focus on custom tables; use dataverse_get_table_metadata for column details. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{includeSystemTables:{type:"boolean",description:"Include system tables. Default false = custom tables only."}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_table_metadata",description:"Returns full schema metadata for a Dataverse table: all attribute (column) logical names, display names, data types, required levels, and lookup target entities. Use this before writing queries or creating/updating records to confirm correct field names and types. Set includeAttributes=false if you only need table-level metadata without column details. WHEN TO USE: Before building queries or creating/updating records to validate field names, types, and required levels. BEST PRACTICES: Set includeAttributes=false for table-level info only; call once and reuse results. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{logicalName:{type:"string",description:'The logical name of the table (e.g., "account", "contact", "new_mytable")'},includeAttributes:{type:"boolean",description:"Include attribute (column) definitions. Default: true"}},required:["logicalName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_relationships",description:"Returns all relationship definitions (1:N, N:1, N:N) for a Dataverse table, including relationship schema names, referenced/referencing entity names, and lookup attribute names. Use to determine the correct relationshipName for dataverse_associate/dataverse_disassociate, or to map lookup fields before building FetchXML joins. Use relationshipType to filter results. WHEN TO USE: Finding relationship schema names for associate/disassociate, or mapping lookups for FetchXML joins. BEST PRACTICES: Filter by relationshipType to reduce output size. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{logicalName:{type:"string",description:"The logical name of the table"},relationshipType:{type:"string",enum:["OneToMany","ManyToOne","ManyToMany","All"],description:"Filter by relationship type. Default: All"}},required:["logicalName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_global_option_sets",description:"Lists all global (shared) option sets defined in the Dataverse environment, returning their names and metadata IDs. Use this to discover available option sets before calling dataverse_get_option_set to retrieve their values. Prefer this over dataverse_get_table_metadata when you need to find option sets that are reused across multiple tables. WHEN TO USE: Discovering shared option sets reused across multiple tables. BEST PRACTICES: Follow up with dataverse_get_option_set to retrieve individual option values. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_option_set",description:"Returns all option labels and their integer values for a named global option set. Use this to look up the numeric code for a picklist value before filtering records (e.g., statecode or statuscode equivalents), or to populate dropdowns with correct option values. WHEN TO USE: Looking up numeric codes for picklist filtering or record creation. BEST PRACTICES: Use the integer values in $filter expressions, not the label text. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{name:{type:"string",description:"The name of the global option set"}},required:["name"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_entity_key",description:"Returns all alternate key definitions for a Dataverse table. Useful before using dataverse_upsert to know which fields serve as alternate keys, their index status (Active/InProgress/Failed), and whether they are customizable. WHEN TO USE: Before using dataverse_upsert to verify which fields serve as alternate keys. BEST PRACTICES: Check that key index status is Active before relying on a key. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{tableName:{type:"string",description:'Logical name of the table (e.g., "account", "contact")'}},required:["tableName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_attribute_option_set",description:"Returns all option labels and integer values for a table-specific attribute (Picklist, MultiSelectPicklist, Status, or State field). Use to look up the numeric codes for a column's choices before filtering or updating records. WHEN TO USE: Looking up option values for a specific table's picklist, multi-select picklist, status, or state column. BEST PRACTICES: Use the integer values in $filter and when setting fields in create/update. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:'Logical name of the table (e.g., "account", "contact")'},attributeLogicalName:{type:"string",description:'Logical name of the attribute (e.g., "statuscode", "industrycode", "new_tags")'}},required:["entityLogicalName","attributeLogicalName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],Yt=R.object({logicalName:R.string().min(1),includeAttributes:R.boolean().optional().default(!0)}),Jt=R.object({logicalName:R.string().min(1),relationshipType:R.enum(["OneToMany","ManyToOne","ManyToMany","All"]).optional()}),Zt=R.object({includeSystemTables:R.boolean().default(!1).optional().describe("Include system tables. Default false = custom tables only.")}),ea=R.object({name:R.string().min(1)}),ta=R.object({tableName:R.string().min(1).describe('Logical name of the table (e.g., "account", "contact")')}),Re=/^[a-z_][a-z0-9_]*$/,aa=R.object({entityLogicalName:R.string().min(1).regex(Re,"Invalid Dataverse logical name"),attributeLogicalName:R.string().min(1).regex(Re,"Invalid Dataverse logical name")});async function Ae(a,i,r){switch(a){case"dataverse_list_tables":{let{includeSystemTables:e=!1}=Zt.parse(i??{}),t=!e,n=await r.listTables(t),o=Array.isArray(n)?n:[];return H(`tables (${t?"custom only":"including system"})`,o,["Use dataverse_get_table_metadata to inspect a specific table's columns and types"])}case"dataverse_get_table_metadata":{let{logicalName:e,includeAttributes:t}=Yt.parse(i),n=await r.getTableMetadata(e,t),o=Array.isArray(n?.Attributes)?n.Attributes.length:0;return u(`Metadata for ${e}: ${o} attributes`,n,["Use dataverse_query to read records from this table","Use dataverse_get_relationships to see related tables"])}case"dataverse_get_relationships":{let{logicalName:e,relationshipType:t}=Jt.parse(i),n=await r.getRelationships(e),o=e.toLowerCase(),l=n.filter(m=>m.RelationshipType==="OneToManyRelationship"&&m.ReferencedEntity?.toLowerCase()===o),s=n.filter(m=>m.RelationshipType==="OneToManyRelationship"&&m.ReferencingEntity?.toLowerCase()===o),d=n.filter(m=>m.RelationshipType==="ManyToManyRelationship"),c=!t||t==="All",p=[...c||t==="OneToMany"?l:[],...c||t==="ManyToOne"?s:[],...c||t==="ManyToMany"?d:[]];return u(`${p.length} relationships found for ${e}`,{tableName:e,oneToMany:c||t==="OneToMany"?l:void 0,manyToOne:c||t==="ManyToOne"?s:void 0,manyToMany:c||t==="ManyToMany"?d:void 0},["Use dataverse_associate or dataverse_disassociate to manage N:N relationships"])}case"dataverse_list_global_option_sets":{let e=await r.listGlobalOptionSets(),t=Array.isArray(e)?e:[];return H("global option sets",t,["Use dataverse_get_option_set with a name to see the values"])}case"dataverse_get_option_set":{let{name:e}=ea.parse(i),t=await r.getOptionSet(e),n=Array.isArray(t?.Options)?t.Options:[];return u(`Option set '${e}': ${n.length} options`,t,["Use these values in $filter expressions or when creating/updating records"])}case"dataverse_get_entity_key":{let{tableName:e}=ta.parse(i),t=await r.getEntityKeys(e);return u(`${t.length} alternate keys for ${e}`,{tableName:e,keys:t,count:t.length},["Use dataverse_upsert with these keys for create-or-update operations"])}case"dataverse_get_attribute_option_set":{let{entityLogicalName:e,attributeLogicalName:t}=aa.parse(i),n=await r.getAttributeOptionSet(e,t),o=Array.isArray(n?.options)?n.options:[];return u(`Attribute '${t}' on '${e}': ${o.length} options`,n,["Use these integer values in $filter or when creating/updating records"])}default:throw new Error(`Unknown metadata-read tool: ${a}`)}}import{z}from"zod";var na=new Set(["dataverse_delete","dataverse_delete_file","dataverse_update_entity","dataverse_delete_attribute"]);function ce(a){let i=[];return a.top!==void 0&&a.top>5e3&&i.push({code:"LARGE_RESULT_SET",message:`Large result set requested (top=${a.top}). Consider reducing $top or using paging.`,severity:"warning"}),(!a.select||a.select.length===0)&&i.push({code:"NO_SELECT",message:"No $select specified \u2014 all columns will be returned. Specify columns to reduce payload size.",severity:"warning"}),a.filter||i.push({code:"NO_FILTER",message:"No filter \u2014 consider adding one to reduce results and improve performance.",severity:"info"}),i}function q(a){let i=[];return na.has(a.toolName)&&i.push({code:"DESTRUCTIVE_OP",message:"Destructive operation \u2014 confirm with user before proceeding. This action cannot be undone.",severity:"warning"}),a.toolName==="dataverse_batch_execute"&&i.push({code:"BATCH_OP",message:"Batch operations may modify multiple records in a single transaction.",severity:"info"}),i}var Ee=[{name:"dataverse_update_entity",description:"Updates configuration flags on an existing Dataverse entity definition \u2014 enables or disables Notes (HasNotes), Change Tracking, and Audit. Requires System Customizer or System Administrator privileges. WHEN TO USE: Enabling notes/attachments support, change tracking, or audit on a table. BEST PRACTICES: Leave autoPublish=false (default) when making multiple changes and call dataverse_publish_customizations once at the end. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Logical name of the entity to update (e.g. 'account', 'new_mytable')"},hasNotes:{type:"boolean",description:"Enable or disable the Notes/Attachments feature for this entity"},changeTrackingEnabled:{type:"boolean",description:"Enable or disable change tracking (required for delta sync)"},isAuditEnabled:{type:"boolean",description:"Enable or disable auditing on this entity"},autoPublish:{type:"boolean",description:"Publish the customization after update (default: false). For batch operations leave false and publish once at the end."},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional schema modification to Dataverse entity metadata"}},required:["entityLogicalName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],ra=z.object({entityLogicalName:z.string().min(1).regex(/^[a-z_][a-z0-9_]*$/,"Invalid logical name"),confirm:z.literal(!0,{errorMap:()=>({message:"Set confirm: true to modify entity metadata"})}),hasNotes:z.boolean().optional(),changeTrackingEnabled:z.boolean().optional(),isAuditEnabled:z.boolean().optional(),autoPublish:z.boolean().optional().default(!1)}).refine(a=>a.hasNotes!==void 0||a.changeTrackingEnabled!==void 0||a.isAuditEnabled!==void 0,{message:"At least one of hasNotes, changeTrackingEnabled, or isAuditEnabled must be provided"});async function xe(a,i,r){switch(a){case"dataverse_update_entity":{let{entityLogicalName:e,hasNotes:t,changeTrackingEnabled:n,isAuditEnabled:o,autoPublish:l}=ra.parse(i),s=q({toolName:"dataverse_update_entity",entitySetName:e}).map(f=>`[${f.severity.toUpperCase()}] ${f.code}: ${f.message}`),d={};t!==void 0&&(d.HasNotes=t),n!==void 0&&(d.ChangeTrackingEnabled=n),o!==void 0&&(d.IsAuditEnabled=o);try{await r.getTableMetadata(e,!1)}catch{return O({summary:`Entity '${e}' does not exist in this Dataverse environment.`,data:{error:"ENTITY_NOT_FOUND",entityLogicalName:e},errorCategory:"SCHEMA_MISMATCH",suggestions:["Use dataverse_list_tables to find the correct entity logical name"]})}let c={"@odata.type":"#Microsoft.Dynamics.CRM.EntityMetadata"};t!==void 0&&(c.HasNotes=t),n!==void 0&&(c.ChangeTrackingEnabled=n),o!==void 0&&(c.IsAuditEnabled={Value:o});try{await r.updateEntityDefinition(e,c)}catch(f){if((f instanceof Error?f.message:String(f)).includes("0x80060888")){let K=Object.keys(d),F={IsAuditEnabled:"IsAuditEnabled requires organization-level auditing to be enabled first: Power Platform admin center > Settings > Audit and logs > Start Auditing",ChangeTrackingEnabled:"ChangeTrackingEnabled may be blocked if the entity is part of a managed solution",HasNotes:"HasNotes=true/false should work for custom (unmanaged) entities"},Y=K.map(B=>F[B]).filter(B=>B!==void 0);return O({summary:`Cannot update entity '${e}': operation not supported by Dataverse.`,data:{error:"0x80060888",entityLogicalName:e,requestedChanges:d},errorCategory:"SCHEMA_MISMATCH",suggestions:Y})}throw f}let p=Object.entries(d).map(([f,N])=>`${f}=${String(N)}`).join(", "),m="autoPublish=false (skipped)";return l&&(await r.publishCustomizations({entities:[e]}),m="published successfully"),u(`Entity '${e}' updated: ${p}. ${m}.`,{entityLogicalName:e,changes:d,published:l,...s.length>0&&{warnings:s}},["Use dataverse_get_table_metadata to verify the changes","Enable HasNotes=true before using dataverse_create_annotation"])}default:throw new Error(`Unknown metadata tool: ${a}`)}}var ia={name:"dataverse_resolve_entity_name",description:"Resolves entity names bidirectionally: input a logicalName (e.g. 'account') or entitySetName (e.g. 'accounts') and get both representations plus metadata. Essential for avoiding 404/0x80060888 errors caused by using logicalName in OData URLs (which require entitySetName). WHEN TO USE: Any time you're unsure whether to use logicalName vs entitySetName, or to look up PrimaryIdAttribute/PrimaryNameAttribute for new entities. EXAMPLES: 'account' \u2192 LogicalName:account, EntitySetName:accounts, PrimaryId:accountid. WORKFLOW: read_record, inspect_audit.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Entity name to resolve \u2014 either logicalName (e.g. 'account') or entitySetName (e.g. 'accounts')"}},required:["name"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},oa=ke.object({name:ke.string().min(1)}),Ie=[...de,ia,...Ee];async function De(a,i,r){if(a==="dataverse_resolve_entity_name"){let{name:t}=oa.parse(i),n=`LogicalName eq '${t}' or EntitySetName eq '${t}'`,l=(await r.query("EntityDefinitions",{filter:n,select:["LogicalName","EntitySetName","DisplayName","PrimaryIdAttribute","PrimaryNameAttribute","OwnershipType","IsCustomEntity"]})).value??[];if(l.length===0)return u(`No entity found matching '${t}'`,{name:t,matches:[]},["Try dataverse_list_tables to see available table names"]);let s=l[0],d=s.DisplayName?.UserLocalizedLabel?.Label??null;return u(`Resolved '${t}' \u2192 LogicalName: ${s.LogicalName}, EntitySetName: ${s.EntitySetName}`,{logicalName:s.LogicalName,entitySetName:s.EntitySetName,displayName:d,primaryIdAttribute:s.PrimaryIdAttribute,primaryNameAttribute:s.PrimaryNameAttribute,ownershipType:s.OwnershipType,isCustomEntity:s.IsCustomEntity},["Use entitySetName in OData Web API URLs (dataverse_query, dataverse_read_record)","Use logicalName in FetchXML and metadata API calls"])}return new Set(de.map(t=>t.name)).has(a)?Ae(a,i,r):xe(a,i,r)}import{z as _}from"zod";import{z as Oe}from"zod";var Ce=/^[a-zA-Z_][a-zA-Z0-9_]*$/,h=Oe.string().min(1).regex(Ce,"entitySetName must contain only letters, digits, or underscores"),ae=Oe.string().min(1).regex(Ce,"relationshipName must contain only letters, digits, or underscores");var sa={opportunity:"opportunities",territory:"territories",category:"categories",activityparty:"activityparties",activitymimeattachment:"activitymimeattachments",queue:"queues",queueitem:"queueitems",dependency:"dependencies",salesliteratureitem:"salesliteratureitems",contractdetail:"contractdetails",discounttype:"discounttypes",entitlementtemplate:"entitlementtemplates",pricelevel:"pricelevels"},Ue=[{name:"dataverse_query",description:"Queries a Dataverse table using OData ($filter, $select, $orderby, $top, $expand, $count). Use for simple to moderate reads on a single table or with shallow $expand for related fields. Always specify $select to minimize payload. For complex aggregations (count, sum, avg), multi-entity joins, many-to-many traversal, or advanced FetchXML-only operators, use dataverse_execute_fetchxml instead. WHEN TO USE: Single-table reads, simple filters, shallow expands, or server-side aggregation via $apply. BEST PRACTICES: Always pass $select; cap with $top; use $apply for server-side counts/grouping. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'The OData entity set name (e.g., "accounts", "contacts", "new_mytables")'},select:{type:"array",items:{type:"string"},description:"Columns to return. Always specify to minimize payload."},filter:{type:"string",description:'OData $filter expression (e.g., "statecode eq 0 and new_amount gt 1000")'},orderby:{type:"string",description:'OData $orderby expression (e.g., "createdon desc")'},top:{type:"number",description:"Maximum number of records to return (default: 50)"},expand:{type:"string",description:'OData $expand for related entities (e.g., "parentaccountid($select=name)")'},count:{type:"boolean",description:"Include total record count in response"},apply:{type:"string",description:'OData $apply for server-side aggregation (e.g., "groupby((statuscode),aggregate($count as count))")'},formattedValues:{type:"boolean",description:"When true, includes human-readable labels for picklist fields alongside raw integer codes (e.g., { value: 1, label: 'Active' }). Uses OData formatted-value annotations."}},required:["entitySetName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_execute_fetchxml",description:'Executes a FetchXML query against Dataverse \u2014 use for complex scenarios requiring aggregations (count, sum, avg, min, max with grouping), linked-entity joins across multiple tables, many-to-many relationship traversal, or advanced filtering not expressible in OData. Returns a typed array of records. entitySetName is optional \u2014 if omitted it is extracted from the <entity name="..."> element in the FetchXML. Set fetchAll=true to automatically paginate through all pages (up to 100 pages / 50,000 records for safety). Default behavior returns first page only. WHEN TO USE: Multi-table joins, aggregations with groupby, N:N traversal, or filtering not supported by OData. BEST PRACTICES: Add page/count attributes for large result sets; prefer dataverse_query for simple reads; use fetchAll=true to retrieve all records beyond the first page. WORKFLOW: query_data.',inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name of the root entity (e.g., "accounts"). If omitted, extracted from the <entity name="..."> element in the FetchXML.'},fetchXml:{type:"string",description:"The complete FetchXML query string"},fetchAll:{type:"boolean",description:"When true, automatically paginates through all result pages (up to 100 pages / 50,000 records). Default false returns the first page only."},formattedValues:{type:"boolean",description:"When true, includes human-readable labels for picklist fields alongside raw integer codes."}},required:["fetchXml"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_retrieve_multiple_with_paging",description:"Retrieves ALL records matching a query by automatically following OData nextLink pages. Use instead of dataverse_query when you need more than 5000 records or all records in a table. Returns totalRetrieved count. Set maxTotal to cap retrieval (default 5000, max 50000) to avoid overwhelming the context. WHEN TO USE: You need all matching records beyond the 5000-row OData page limit or a full table export. BEST PRACTICES: Always set $select; use maxTotal to cap results and avoid context overflow. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name (e.g., "accounts")'},select:{type:"array",items:{type:"string"}},filter:{type:"string"},orderby:{type:"string"},expand:{type:"string"},maxTotal:{type:"number",description:"Maximum records to retrieve (default: 5000, max: 50000)"},formattedValues:{type:"boolean",description:"Include formatted label annotations."}},required:["entitySetName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],la=_.object({entitySetName:h,select:_.array(_.string()).optional(),filter:_.string().optional(),orderby:_.string().optional(),top:_.number().positive().max(5e3).optional().default(50),expand:_.string().optional(),count:_.boolean().optional(),apply:_.string().optional(),formattedValues:_.boolean().optional()}),da=_.object({fetchXml:_.string().min(1).describe("Complete FetchXML query string"),entitySetName:_.string().optional().describe('OData entity set name (e.g., "accounts"). If omitted, extracted from the <entity name="..."> element in the FetchXML.'),fetchAll:_.boolean().optional(),formattedValues:_.boolean().optional()}),ca=_.object({entitySetName:h,select:_.array(_.string()).optional(),filter:_.string().optional(),orderby:_.string().optional(),expand:_.string().optional(),maxTotal:_.number().positive().max(5e4).optional(),formattedValues:_.boolean().optional()});async function Le(a,i,r,e){switch(a){case"dataverse_query":{let t=la.parse(i),n={};t.select!==void 0&&(n.select=t.select),t.filter!==void 0&&(n.filter=t.filter),t.orderby!==void 0&&(n.orderby=t.orderby),t.top!==void 0&&(n.top=t.top),t.expand!==void 0&&(n.expand=t.expand),t.count!==void 0&&(n.count=t.count),t.apply!==void 0&&(n.apply=t.apply),t.formattedValues!==void 0&&(n.formattedValues=t.formattedValues);let o;try{o=await r.query(t.entitySetName,n)}catch(f){let N=f,F=N?.data?.error?.message,Y=f instanceof Error?f.message:String(f),B=N?.status,Qt=B===403||B===401?"PERMISSIONS":B===404?"SCHEMA_MISMATCH":"UNKNOWN";return te(`dataverse_query failed on '${t.entitySetName}': ${F??Y}`,Qt,["Use dataverse_list_tables to verify the entity set name","Check OData filter syntax and column names"])}let l=Array.isArray(o?.value)?o.value:[],s=o["@odata.count"],d=s!==void 0?s===l.length?" (showing all results)":` (total in dataset: ${s})`:"",c=t.formattedValues?G(l):l,p=t.formattedValues&&Array.isArray(o?.value)?{...o,value:c}:o,m=ce({...t.top!==void 0?{top:t.top}:{},...t.select!==void 0?{select:t.select}:{},...t.filter!==void 0?{filter:t.filter}:{},entitySetName:t.entitySetName}).map(f=>`[${f.severity.toUpperCase()}] ${f.code}: ${f.message}`);return u(`${l.length} records returned from ${t.entitySetName}${d}`,p,["Use dataverse_execute_fetchxml for complex joins or aggregations","Add $select to minimize payload"],m.length>0?m:void 0)}case"dataverse_execute_fetchxml":{let t=da.parse(i),n=t.entitySetName,{fetchXml:o}=t;if(!n){let c=o.match(/<entity\s+name=["']([^"']+)["']/i);if(!c)return{content:[{type:"text",text:JSON.stringify({isError:!0,error:"entitySetName is required when not present in FetchXML <entity> element"})}]};let p=c[1];n=sa[p]??p+"s"}if(t.fetchAll){let c=await r.executeFetchXmlAllPages(n,o),p=t.formattedValues?G(c):c;return u(`${p.length} records retrieved via FetchXML (all pages)`,p,["Use dataverse_query for simple OData reads","fetchAll paginated through all available pages (up to 100)"])}let l=await r.executeFetchXml(n,o,t.formattedValues),s=Array.isArray(l)?l:Array.isArray(l?.value)?l.value:[],d=t.formattedValues?G(s):s;return u(`${d.length} records returned via FetchXML`,t.formattedValues&&Array.isArray(l?.value)?{...l,value:d}:l,["Use dataverse_query for simple OData reads","Add page/count attributes for large result sets"])}case"dataverse_retrieve_multiple_with_paging":{let t=ca.parse(i),n={};t.select!==void 0&&(n.select=t.select),t.filter!==void 0&&(n.filter=t.filter),t.orderby!==void 0&&(n.orderby=t.orderby),t.expand!==void 0&&(n.expand=t.expand),t.maxTotal!==void 0&&(n.maxTotal=t.maxTotal),await e?.report(0,1);let o=await r.queryWithPaging(t.entitySetName,n),l=o?.totalRetrieved??(Array.isArray(o?.value)?o.value.length:0),s=o?.pageCount??1;await e?.report(1,1);let d=Array.isArray(o?.records)?o.records:[],c=t.formattedValues&&d.length>0?{...o,records:G(d)}:o,p=ce({...t.select!==void 0?{select:t.select}:{},...t.filter!==void 0?{filter:t.filter}:{},entitySetName:t.entitySetName}).map(m=>`[${m.severity.toUpperCase()}] ${m.code}: ${m.message}`);return u(`${l} records retrieved across ${s} pages from ${t.entitySetName}`,c,["Set maxTotal to limit retrieval","Use $select to minimize payload size"],p.length>0?p:void 0)}default:throw new Error(`Unknown query tool: ${a}`)}}import{z as y}from"zod";var Pe=[{name:"dataverse_get",description:"Retrieves a single Dataverse record by its GUID. Use when you already know the exact record ID and want specific fields \u2014 faster and more precise than dataverse_query with a GUID filter. Specify select to limit returned columns and reduce payload size. WHEN TO USE: You have the exact record GUID and want specific fields. BEST PRACTICES: Always specify select; use the returned etag for subsequent optimistic-concurrency updates. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:"OData entity set name"},id:{type:"string",description:"Record GUID"},select:{type:"array",items:{type:"string"},description:"Columns to return"},expand:{type:"string",description:'OData $expand for related entities (e.g., "parentaccountid($select=name)")'},formattedValues:{type:"boolean",description:"When true, annotates picklist fields with human-readable labels. Note: dataverse_get always requests all OData annotations."}},required:["entitySetName","id"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_create",description:`Creates a new record in a Dataverse table and returns the new record's GUID. Use dataverse_get_table_metadata first to confirm correct logical field names and required fields. For setting lookup fields, use the format "_fieldname_value" with the related record GUID. For bulk creation of multiple records, consider dataverse_batch_execute to reduce HTTP round-trips. WHEN TO USE: Creating a single new record in a known table. BEST PRACTICES: Validate field names via dataverse_get_table_metadata first; use dataverse_batch_execute for bulk inserts. WORKFLOW: create_record.`,inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:"OData entity set name"},data:{type:"object",description:"Record data as key-value pairs using logical names"}},required:["entitySetName","data"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_update",description:"Updates an existing Dataverse record using PATCH semantics \u2014 only the fields provided in data are changed, all other fields remain unchanged. Requires the record GUID. Use dataverse_upsert instead if you want to create-or-update using an alternate key without knowing the GUID upfront. WHEN TO USE: Modifying specific fields on an existing record with a known GUID. BEST PRACTICES: Pass etag for optimistic concurrency; include only changed fields in data. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string",description:"Record GUID"},data:{type:"object",description:"Fields to update"},etag:{type:"string",description:"ETag value from a prior dataverse_get response. When provided, the update only succeeds if the record has not been modified since (optimistic concurrency). Prevents lost updates."}},required:["entitySetName","id","data"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_delete",description:"Permanently deletes a Dataverse record by its GUID. This operation is irreversible \u2014 you MUST set confirm=true to proceed. Use dataverse_list_dependencies to check if the record is referenced by workflows, plugins, or other components before deleting shared or configuration records. WHEN TO USE: Permanently removing a record you are certain should be deleted. BEST PRACTICES: Call dataverse_list_dependencies first for shared records; always set confirm=true. WORKFLOW: delete_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string",description:"Record GUID"},confirm:{type:"boolean",description:"Must be explicitly true to proceed with deletion"}},required:["entitySetName","id","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!0,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_upsert",description:'Creates or updates a Dataverse record using an alternate key (no GUID needed). Returns operation="created" or "updated". Use mode="createOnly" to fail with an error if the record already exists, or mode="updateOnly" to fail if the record does not exist. Default mode="upsert" creates or updates. Supports compound alternate keys via the alternateKeys parameter. WHEN TO USE: Create-or-update when you have an alternate key but no GUID. BEST PRACTICES: Verify alternate keys with dataverse_get_entity_key first; use mode to control behavior. WORKFLOW: create_record.',inputSchema:{type:"object",properties:{entitySetName:{type:"string"},alternateKey:{type:"string",description:"Alternate key attribute name (for single key)"},alternateKeyValue:{type:"string",description:"Alternate key value (for single key)"},alternateKeys:{type:"object",description:'Compound alternate key as key-value map (e.g., {"key1":"val1","key2":"val2"}). Use instead of alternateKey/alternateKeyValue for multi-field keys.'},data:{type:"object",description:"Record data"},mode:{type:"string",enum:["upsert","createOnly","updateOnly"],description:"upsert=create or update (default), createOnly=fail if exists, updateOnly=fail if not found"}},required:["entitySetName","data"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_assign",description:"Assigns a Dataverse record to a different user or team owner. Sets the ownerid lookup field using the OData bind syntax. WHEN TO USE: Changing the owner of a record to a different user or team. BEST PRACTICES: Use dataverse_list_users or dataverse_list_teams to find valid owner GUIDs first. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:"OData entity set name of the record to assign"},id:{type:"string",description:"Record GUID"},ownerType:{type:"string",enum:["systemuser","team"],description:'Type of the new owner: "systemuser" for a user, "team" for a team'},ownerId:{type:"string",description:"GUID of the user or team to assign the record to"}},required:["entitySetName","id","ownerType","ownerId"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],ua=y.object({entitySetName:h,id:y.string().uuid(),select:y.array(y.string()).optional(),expand:y.string().optional(),formattedValues:y.boolean().optional()}),pa=y.object({entitySetName:h,data:y.record(y.unknown())}),ma=y.object({entitySetName:h,id:y.string().uuid(),data:y.record(y.unknown()),etag:y.string().optional()}),ga=y.object({entitySetName:h,id:y.string().uuid(),confirm:y.boolean()}),fa=y.object({entitySetName:h,alternateKey:y.string().min(1).optional(),alternateKeyValue:y.string().min(1).optional(),alternateKeys:y.record(y.string()).optional(),data:y.record(y.unknown()),mode:y.enum(["upsert","createOnly","updateOnly"]).default("upsert").optional().describe("upsert=create or update (default), createOnly=fail if exists, updateOnly=fail if not found")}).refine(a=>a.alternateKey&&a.alternateKeyValue||a.alternateKeys&&Object.keys(a.alternateKeys).length>0,{message:"Provide either (alternateKey + alternateKeyValue) or alternateKeys"}),ya=y.object({entitySetName:h,id:y.string().uuid(),ownerType:y.enum(["systemuser","team"]),ownerId:y.string().uuid()});async function qe(a,i,r){switch(a){case"dataverse_get":{let{entitySetName:e,id:t,select:n,expand:o,formattedValues:l}=ua.parse(i),s,d;try{let p=await r.getRecord(e,t,n,o);s=p.record,d=p.etag}catch(p){let m=p,N=m?.data?.error?.message,K=p instanceof Error?p.message:String(p),F=m?.status,Y=F===403||F===401?"PERMISSIONS":F===404?"SCHEMA_MISMATCH":"UNKNOWN";return te(`dataverse_get failed for '${t}' in '${e}': ${N??K}`,Y,["Use dataverse_list_tables to verify the entity set name","Verify the record ID exists with dataverse_query"])}let c=l?G([s])[0]??s:s;return u(`Retrieved record ${t} from ${e}`,{id:t,record:c,etag:d},["Use dataverse_update to modify this record","Use dataverse_get_relationships to explore related records"])}case"dataverse_create":{let{entitySetName:e,data:t}=pa.parse(i),n=await r.createRecord(e,t);return u(`Created record ${n} in ${e}`,{id:n,message:"Record created successfully"},["Use dataverse_get to retrieve the full record","Use dataverse_associate to link related records"])}case"dataverse_update":{let{entitySetName:e,id:t,data:n,etag:o}=ma.parse(i);return await r.updateRecord(e,t,n,o),u(`Updated record ${t} in ${e}`,{message:"Record updated successfully"},["Use dataverse_get to verify the update","Use etag parameter for optimistic concurrency"])}case"dataverse_delete":{let{entitySetName:e,id:t,confirm:n}=ga.parse(i);return n?(await r.deleteRecord(e,t),u(`Deleted record ${t} from ${e}`,{message:"Record deleted successfully"},["This operation is irreversible"])):{content:[{type:"text",text:JSON.stringify({message:`Deletion not performed. Set 'confirm: true' to delete record '${t}' from '${e}'.`})}]}}case"dataverse_upsert":{let e=fa.parse(i),{entitySetName:t,alternateKey:n,alternateKeyValue:o,alternateKeys:l,data:s,mode:d="upsert"}=e,c;l&&Object.keys(l).length>0&&(c=Object.entries(l).map(([m,f])=>`${v(m)}='${v(f)}'`).join(","));let p=await r.upsertRecord(t,n??"",o??"",s,d,c);return u(`Upsert ${p.operation}: record in ${t}`,{operation:p.operation,id:p.id,message:`Record ${p.operation} successfully`},["Use dataverse_get_entity_key to verify alternate key definitions"])}case"dataverse_assign":{let{entitySetName:e,id:t,ownerType:n,ownerId:o}=ya.parse(i),l=n==="systemuser"?"systemusers":"teams";return await r.updateRecord(e,t,{"ownerid@odata.bind":`/${l}(${o})`}),u(`Assigned record ${t} in ${e} to new owner`,{message:"Record assigned successfully"},["Use dataverse_list_users or dataverse_list_teams to find valid owners"])}default:throw new Error(`Unknown CRUD tool: ${a}`)}}import{z as S}from"zod";var He=[{name:"dataverse_associate",description:"Creates an association between two Dataverse records via a named N:N or 1:N relationship. Requires the relationship schema name obtainable from dataverse_get_relationships. Use for N:N relationships or to link records without modifying a lookup field directly \u2014 for simple 1:N lookups, setting the lookup field in dataverse_update is simpler. WHEN TO USE: Linking two records via an N:N relationship or 1:N navigation property. BEST PRACTICES: Get the relationship schema name from dataverse_get_relationships first; for simple 1:N lookups use dataverse_update. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string",description:"Source record GUID"},relationshipName:{type:"string",description:"Relationship schema name"},relatedEntitySetName:{type:"string",description:"Related entity set name"},relatedId:{type:"string",description:"Related record GUID"}},required:["entitySetName","id","relationshipName","relatedEntitySetName","relatedId"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_associate_bulk",description:"Associates one source record with multiple related records at once via a named relationship, executing all associations in parallel. Unlike dataverse_associate (one pair at a time), this accepts an array of related IDs and runs them concurrently. Uses Promise.allSettled semantics \u2014 individual failures are reported per item without aborting the others. WHEN TO USE: Bulk N:N association setup (e.g., assigning many privileges to a role, linking many contacts to a campaign). BEST PRACTICES: Check existing associations first with dataverse_query; runs concurrently so order is not guaranteed. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:"Source entity set name"},id:{type:"string",description:"Source record GUID"},relationshipName:{type:"string",description:"Relationship schema name"},relatedEntitySetName:{type:"string",description:"Related entity set name"},relatedIds:{type:"array",items:{type:"string"},description:"GUIDs of records to associate (1\u2013200)",minItems:1,maxItems:200}},required:["entitySetName","id","relationshipName","relatedEntitySetName","relatedIds"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_disassociate",description:"Removes an existing association between two Dataverse records on a named relationship. For N:N relationships, provide relatedId and relatedEntitySetName to build the correct $id URL. For 1:N relationships, relatedId and relatedEntitySetName are optional. Use dataverse_get_relationships to find the correct relationship schema name. WHEN TO USE: Removing an N:N or 1:N link between two records without deleting either record. BEST PRACTICES: Get the relationship schema name from dataverse_get_relationships; relatedId is required for N:N. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string"},relationshipName:{type:"string"},relatedId:{type:"string",description:"Required for N:N relationships"},relatedEntitySetName:{type:"string",description:'Entity set name of the related record (required for N:N). E.g., "contacts"'},confirm:{type:"boolean",const:!0,description:"Must be explicitly true to confirm removal of the association"}},required:["entitySetName","id","relationshipName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!0,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_query_associations",description:"Reads existing N:N associations for a record by querying through a navigation property. Returns the related records \u2014 use to verify what's already linked before calling dataverse_associate or dataverse_disassociate. WHEN TO USE: Check if a role already has specific privileges before adding them; check campaign members; check group participants. BEST PRACTICES: Use $select to return only needed columns; set $top to limit results. Example: to check role privileges, query entitySetName='roles', navigationProperty='roleprivileges_association' with $select='name,privilegeid'. WORKFLOW: read_record, inspect_audit.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:"Source entity set name, e.g. 'roles'"},id:{type:"string",description:"Source record GUID"},navigationProperty:{type:"string",description:"Navigation property name, e.g. 'roleprivileges_association'"},select:{type:"string",description:"Comma-separated columns to return on related records"},top:{type:"number",description:"Max records to return. Default 50, max 1000"},filter:{type:"string",description:"OData $filter expression applied to related records"}},required:["entitySetName","id","navigationProperty"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],va=S.object({entitySetName:h,id:S.string().uuid(),relationshipName:ae,relatedEntitySetName:h,relatedIds:S.array(S.string().uuid()).min(1).max(200)}),ha=S.object({entitySetName:h,id:S.string().uuid(),relationshipName:ae,relatedEntitySetName:h,relatedId:S.string().uuid()}),ba=S.object({entitySetName:h,id:S.string().uuid(),relationshipName:ae,relatedId:S.string().uuid().optional(),relatedEntitySetName:h.optional(),confirm:S.literal(!0)}),_a=/^[A-Za-z_][A-Za-z0-9_]*$/,wa=S.object({entitySetName:h,id:S.string().uuid(),navigationProperty:S.string().min(1).regex(_a,"Invalid navigation property name"),select:S.string().optional(),top:S.number().int().min(1).max(1e3).optional(),filter:S.string().optional()});async function $e(a,i,r){switch(a){case"dataverse_associate_bulk":{let{entitySetName:e,id:t,relationshipName:n,relatedEntitySetName:o,relatedIds:l}=va.parse(i),s=await Promise.allSettled(l.map(p=>r.associate(e,t,n,o,p))),d=[],c=[];return s.forEach((p,m)=>{p.status==="fulfilled"?d.push(l[m]):c.push({id:l[m],error:p.reason instanceof Error?p.reason.message:String(p.reason)})}),u(`${d.length}/${l.length} associations succeeded`,{entitySetName:e,id:t,relationshipName:n,succeeded:d,failed:c,successCount:d.length,failureCount:c.length},c.length>0?["Some associations failed \u2014 check the 'failed' array for details"]:["All associations processed (Dataverse returns 204 for both new and duplicate associations \u2014 use dataverse_query_associations to verify current state)"])}case"dataverse_associate":{let{entitySetName:e,id:t,relationshipName:n,relatedEntitySetName:o,relatedId:l}=ha.parse(i);return await r.associate(e,t,n,o,l),u(`Associated ${e}(${t}) with ${o}(${l}) via ${n}`,{message:"Records associated successfully"},["Use dataverse_get_relationships to verify relationship names"])}case"dataverse_disassociate":{let{entitySetName:e,id:t,relationshipName:n,relatedId:o,relatedEntitySetName:l}=ba.parse(i);return await r.disassociate(e,t,n,o,l),u(`Disassociated records via ${n}`,{message:"Records disassociated successfully"},["This removes the N:N link but does not delete records"])}case"dataverse_query_associations":{let{entitySetName:e,id:t,navigationProperty:n,select:o,top:l,filter:s}=wa.parse(i),d=`${e}(${t})/${n}`,p=(await r.query(d,{...o?{select:o.split(",").map(m=>m.trim())}:{},top:l??50,...s?{filter:s}:{}})).value??[];return u(`${p.length} associated records via ${n}`,{entitySetName:e,id:t,navigationProperty:n,count:p.length,records:p},["Use dataverse_associate to add new associations","Use dataverse_disassociate to remove existing ones"])}default:throw new Error(`Unknown relation tool: ${a}`)}}import{z as b}from"zod";var Me=[{name:"dataverse_execute_action",description:"Executes a global (unbound) Dataverse action that is not tied to a specific record \u2014 for example WinOpportunity, SendEmail, or custom process actions. Use dataverse_execute_bound_action when the action must operate on a particular record. Actions differ from functions in that they are state-changing operations; for read-only operations use dataverse_execute_function. WHEN TO USE: Invoking global Dataverse actions or custom process actions like WinOpportunity or SendEmail. BEST PRACTICES: Check action parameters via metadata or docs; use dataverse_execute_bound_action for record-scoped actions. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{actionName:{type:"string",description:'Action logical name (e.g., "WinOpportunity")'},parameters:{type:"object",description:"Action parameters"}},required:["actionName"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_execute_function",description:"Executes a global (unbound) Dataverse OData function that is read-only and returns data without side effects \u2014 for example RetrieveTotalRecordCount or InitializeFrom. Use dataverse_execute_action for state-changing operations. Use dataverse_execute_bound_action when the function/action requires a specific record context. WHEN TO USE: Calling global read-only OData functions like RetrieveTotalRecordCount or InitializeFrom. BEST PRACTICES: Functions are side-effect-free and safe to retry; use dataverse_execute_action for mutations. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{functionName:{type:"string",description:'Function name (e.g., "WhoAmI", "RetrieveTotalRecordCount")'},parameters:{type:"object",description:"Function parameters: strings are quoted inline, numbers/booleans inlined as-is, objects serialized as aliased OData parameters"}},required:["functionName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_execute_bound_action",description:"Executes a Dataverse action bound to a specific record instance, passing the entity set name and record GUID as context (e.g., QualifyLead on a lead, or a custom action scoped to an account). The actionName should not include the Microsoft.Dynamics.CRM namespace prefix. Use dataverse_execute_action for global unbound actions that do not require a record context. WHEN TO USE: Running an action scoped to a specific record, e.g. QualifyLead on a lead. BEST PRACTICES: Omit the Microsoft.Dynamics.CRM namespace prefix; ensure the record exists first. WORKFLOW: update_record.",inputSchema:{type:"object",properties:{entitySetName:{type:"string"},id:{type:"string",description:"Record GUID"},actionName:{type:"string",description:"Action name (without Microsoft.Dynamics.CRM prefix)"},parameters:{type:"object",description:"Action parameters"}},required:["entitySetName","id","actionName"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_retrieve_dependencies_for_delete",description:"Checks what solution components would block deletion of a specific component. Provide the Dataverse component type code (1=Entity, 2=Attribute, 26=SavedQuery, 29=Workflow, 92=PluginAssembly) and the component GUID. Use before deleting shared Dataverse customization components. WHEN TO USE: Before deleting a solution component to check for blocking dependencies. BEST PRACTICES: Resolve all dependencies before attempting deletion. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{componentType:{type:"number",description:"Dataverse component type code (1=Entity, 2=Attribute, 29=Workflow, 92=PluginAssembly)"},objectId:{type:"string",description:"Component GUID"}},required:["componentType","objectId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_execute_bound_function",description:"Executes a Dataverse function bound to a specific record (e.g., CalculateRollupField, GetQuantityAvailable). Use for read-only computed operations on a single record. Unlike bound actions, bound functions do not modify data. WHEN TO USE: Calling a read-only computed function on a specific record, e.g. CalculateRollupField. BEST PRACTICES: Functions are side-effect-free and safe to call repeatedly; pass parameters as string key-value pairs. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name of the table (e.g., "accounts")'},id:{type:"string",description:"GUID of the record"},functionName:{type:"string",description:'Name of the bound function (e.g., "CalculateRollupField")'},parameters:{type:"object",description:"Function parameters as key-value pairs of strings",additionalProperties:{type:"string"}}},required:["entitySetName","id","functionName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_dependencies",description:"Lists workflows, Power Automate flows, Business Rules, and custom actions that reference a given table. Use to detect hidden dependencies before modifying or removing a table. Returns component name, type, state (Active/Draft), trigger event (Create/Update/Delete), and count. WHEN TO USE: Before modifying or removing a table, to discover workflows, flows, and plugins that reference it. BEST PRACTICES: Filter by componentType to focus on specific dependency kinds. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{tableName:{type:"string",description:'Logical name of the table to check (e.g., "account", "contact")'},componentType:{type:"array",items:{type:"string",enum:["Workflow","Flow","BusinessRule","Action","BusinessProcessFlow","Plugin","CustomAPI"]},description:"Filter by component type. Default: all types."}},required:["tableName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],ne=/^[a-zA-Z0-9_.]+$/,Sa=b.object({actionName:b.string().min(1).regex(ne,"actionName must contain only letters, digits, underscores, or dots"),parameters:b.record(b.unknown()).optional().default({})}),Ta=b.object({functionName:b.string().min(1).regex(ne,"functionName must contain only letters, digits, underscores, or dots"),parameters:b.record(b.unknown()).optional().default({})}),Na=b.object({entitySetName:h,id:b.string().uuid(),actionName:b.string().min(1).regex(ne,"actionName must contain only letters, digits, underscores, or dots"),parameters:b.record(b.unknown()).optional().default({})}),Ra=b.object({componentType:b.number().int().positive(),objectId:b.string().uuid()}),Aa=["Workflow","Flow","BusinessRule","Action","BusinessProcessFlow","Plugin","CustomAPI"],Ea=b.object({tableName:b.string().min(1),componentType:b.array(b.enum(Aa)).optional()}),xa=b.object({entitySetName:h,id:b.string().uuid(),functionName:b.string().min(1).regex(ne,"functionName must contain only letters, digits, underscores, or dots"),parameters:b.record(b.unknown()).optional().default({})});async function We(a,i,r){switch(a){case"dataverse_execute_action":{let{actionName:e,parameters:t}=Sa.parse(i),n=await r.executeAction(e,t);return u(`Executed unbound action ${e}`,n,["Use dataverse_list_custom_actions to discover available actions"])}case"dataverse_execute_function":{let{functionName:e,parameters:t}=Ta.parse(i),n=await r.executeFunction(e,t);return u(`Executed function ${e}`,n,["Functions are read-only operations"])}case"dataverse_execute_bound_action":{let{entitySetName:e,id:t,actionName:n,parameters:o}=Na.parse(i),l=await r.executeBoundAction(e,t,n,o);return u(`Executed bound action ${n} on ${e}(${t})`,l)}case"dataverse_list_dependencies":{let{tableName:e,componentType:t}=Ea.parse(i),n=await r.listTableDependencies(e,t);return u(`${n.count} dependencies found for component`,n,["Use this information before deleting or modifying the component"])}case"dataverse_retrieve_dependencies_for_delete":{let{componentType:e,objectId:t}=Ra.parse(i),n=await r.listDependencies(e,t),o=Array.isArray(n)?n:n.value??[n];return u(`${o.length} dependencies found`,n,["Review dependencies before deleting the component"])}case"dataverse_execute_bound_function":{let{entitySetName:e,id:t,functionName:n,parameters:o}=xa.parse(i),l=await r.executeBoundFunction(e,t,n,o);return u(`Executed bound function ${n} on ${e}(${t})`,l)}default:throw new Error(`Unknown action tool: ${a}`)}}import{z as $}from"zod";var je=[{name:"dataverse_batch_execute",description:`Executes multiple Dataverse operations in a single HTTP $batch request to reduce network round-trips and improve throughput. Accepts up to 1000 individual GET, POST, PATCH, or DELETE requests. Use for bulk creates, updates, or deletes that need to be grouped for performance. Set useChangeset=true to wrap all mutating operations (POST/PATCH/DELETE) in an atomic changeset \u2014 a failure rolls back ALL changeset operations. Individual per-operation results (status, body) are returned as an array in the same order as the input requests. $REF OPERATIONS (N:N/1:N associations): POST to a collection-valued navigation property (N:N): url='roles({id})/roleprivileges_association/$ref', body must contain { "@odata.id": "https://<org_url>/api/data/v9.2/privileges({privilegeId})" } with an ABSOLUTE URL \u2014 a relative URL will cause a 400 error. PUT to a single-valued navigation property (lookup/1:N): url='contacts({id})/account_primary_contact/$ref', body must contain { "@odata.id": "https://<org_url>/api/data/v9.2/accounts({accountId})" } with an ABSOLUTE URL. Example: { method: 'POST', url: 'roles({roleId})/roleprivileges_association/$ref', body: { '@odata.id': 'https://org.crm.dynamics.com/api/data/v9.2/privileges({privilegeId})' } }. WHEN TO USE: Bulk creates, updates, or deletes (up to 1000 ops) needing a single HTTP round-trip; batched $ref associations. BEST PRACTICES: Use useChangeset=true for atomic all-or-nothing mutations; batch GETs for parallel reads; always use absolute URLs in @odata.id for $ref bodies. WORKFLOW: bulk_operations.`,inputSchema:{type:"object",properties:{requests:{type:"array",description:"Array of batch requests to execute",items:{type:"object",properties:{method:{type:"string",enum:["GET","POST","PATCH","DELETE"],description:"HTTP method"},url:{type:"string",description:'Relative URL (e.g., "accounts(guid)" or "contacts"). For $ref operations (e.g. "roles({id})/roleprivileges_association/$ref"), the request body MUST include "@odata.id" with an ABSOLUTE URL \u2014 relative URLs in @odata.id cause 400 errors.'},body:{type:"object",description:"Request body for POST/PATCH operations"}},required:["method","url"]}},useChangeset:{type:"boolean",description:"Wrap mutating operations (POST/PATCH/DELETE) in an atomic changeset. A failure rolls back ALL operations in the changeset. Defaults to false."}},required:["requests"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}],ka=$.object({method:$.enum(["GET","POST","PATCH","DELETE"]),url:$.string().min(1).refine(a=>!/[\r\n]/.test(a),{message:"Batch URL must not contain CR or LF characters"}).refine(a=>!a.startsWith("http"),{message:"Batch URL must be a relative path, not an absolute URL"}).refine(a=>!/(\.\.[\/\\])|(^\.\.$)/.test(a),{message:"Batch URL must not contain path traversal sequences"}),body:$.record($.unknown()).optional()}),Ia=$.object({requests:$.array(ka).min(1).max(1e3),useChangeset:$.boolean().default(!1).describe("Wrap mutating operations (POST/PATCH/DELETE) in an atomic changeset. A failure rolls back ALL operations in the changeset.")});async function Fe(a,i,r,e){if(a==="dataverse_batch_execute"){let{requests:t,useChangeset:n}=Ia.parse(i),o=t.map(d=>({method:d.method,url:d.url,body:d.body}));await e?.report(0,t.length);let l=await r.batchExecute(o,n);await e?.report(t.length,t.length);let s=l.filter(d=>d===null||!d.error).length;return u(`Batch executed: ${s}/${l.length} operations succeeded`,{results:l,count:l.length},["Use batch for bulk create/update operations to reduce HTTP round-trips"])}throw new Error(`Unknown batch tool: ${a}`)}import{z as re}from"zod";var Be=[{name:"dataverse_change_detection",description:"Detects new, modified, and deleted records since a previous sync using Dataverse change tracking (delta queries). On first call, pass deltaToken=null to get an initial snapshot and receive a token. On subsequent calls, pass the returned token to retrieve only changes since last sync. Change tracking must be enabled on the table in Dataverse settings. Returns newAndModified records, deleted record IDs, and the nextDeltaToken for the next call. WHEN TO USE: Incremental sync \u2014 detecting records created, updated, or deleted since a previous snapshot. BEST PRACTICES: Store the deltaToken persistently; always specify $select to minimize payload. WORKFLOW: query_data.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name (e.g., "accounts")'},deltaToken:{anyOf:[{type:"string"},{type:"null"}],description:"Delta token from a previous call, or null for the initial sync"},select:{type:"array",items:{type:"string"},description:"Columns to return (recommended to minimise payload)"}},required:["entitySetName","deltaToken"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],Da=re.object({entitySetName:h,deltaToken:re.string().nullable(),select:re.array(re.string()).optional()});async function Ge(a,i,r){if(a==="dataverse_change_detection"){let{entitySetName:e,deltaToken:t,select:n}=Da.parse(i),o;try{o=await r.getChangedRecords(e,t,n)}catch(s){let d=s instanceof Error?s.message:String(s);if(/change.?track|0x80072491/i.test(d))return X({type:"feature_disabled",feature:"Change Tracking",cannotProceedBecause:`Change tracking is not enabled on '${e}', so delta queries cannot be executed.`,adminPortal:"Power Apps Maker Portal",steps:["Open Power Apps maker portal (make.powerapps.com)",`Navigate to Tables \u2192 search for '${e}'`,"Open the table \u2192 click the Settings (gear) icon",'Enable "Track changes"',"Save the table, then publish customizations"],fixableViaToolName:"dataverse_update_entity"});throw s}let l=Array.isArray(o?.newAndModified)?o.newAndModified:[];return u(`${l.length} changed records detected`,o,["Store the returned deltaToken for subsequent incremental sync"])}throw new Error(`Unknown tracking tool: ${a}`)}import{z as M}from"zod";var Oa=M.object({components:M.object({entities:M.array(M.string()).optional().describe("Entity logical names to publish"),webResources:M.array(M.string()).optional().describe("Web resource names to publish"),optionSets:M.array(M.string()).optional().describe("Global OptionSet names to publish")}).optional().describe("Specific components to publish. If omitted, ALL unpublished customizations are published.")}),ze=[{name:"dataverse_publish_customizations",description:'Publishes unpublished Dataverse customizations. \u26A0\uFE0F WITHOUT components \u2192 calls PublishAllXml, an EXCLUSIVE ORG-WIDE LOCK lasting 30-120s. While active, ALL other publish calls (scoped or global) fail with "already in progress". \u2705 ALWAYS prefer specifying components.entities/webResources/optionSets to use the scoped PublishXml action instead \u2014 faster and does NOT block other operations. \u274C DO NOT call without components after each individual change \u2014 batch ALL your schema changes first, then publish ONCE at the end. If you receive a "publish already in progress" error, the MCP will auto-retry every 30s (up to 2 minutes) \u2014 do NOT call the tool again; wait for the previous call to return. WHEN TO USE: Once at the end of a series of schema changes (table/column/relationship/form creation). BEST PRACTICES: Pass components.entities with the list of modified entity logical names. Full publish only if you cannot enumerate the changed components. WORKFLOW: manage_solution.',inputSchema:{type:"object",properties:{components:{type:"object",description:"Specific components. Omit to publish all.",properties:{entities:{type:"array",items:{type:"string"}},webResources:{type:"array",items:{type:"string"}},optionSets:{type:"array",items:{type:"string"}}}}},required:[]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function Ve(a,i,r){switch(a){case"dataverse_publish_customizations":{let{components:e}=Oa.parse(i??{}),t=await r.publishCustomizations(e);return u("Customizations published successfully",t,["Changes are now visible to all users in the environment"])}default:throw new Error(`Unknown solution tool: ${a}`)}}import{z as Z}from"zod";var Ca=Z.object({callerId:Z.string().uuid().describe('Azure AD Object ID (GUID) of the Dataverse system user to impersonate. Requires the executing account to have the "Act on behalf of another user" privilege in Dataverse.'),toolName:Z.string().min(1).describe('Name of the MCP tool to execute on behalf of the user (e.g., "dataverse_create", "dataverse_query")'),toolArgs:Z.record(Z.unknown()).describe("Arguments for the wrapped tool, as an object")}),ue=[{name:"dataverse_impersonate",description:'Executes another Dataverse tool on behalf of a different system user by injecting the MSCRMCallerId header. Requires the executing account to have the "Act on behalf of another user" privilege in Dataverse. The impersonation applies ONLY to the single tool call specified. Use for auditing workflows that must create or update records under a specific user identity. WHEN TO USE: Creating or updating records under a specific user identity for audit-trail purposes. BEST PRACTICES: Impersonation applies to the single wrapped tool call only; cannot impersonate System Administrators. WORKFLOW: update_record.',inputSchema:{type:"object",properties:{callerId:{type:"string",description:"GUID (Azure AD Object ID) of the Dataverse system user to impersonate"},toolName:{type:"string",description:'MCP tool to execute while impersonating (e.g., "dataverse_create")'},toolArgs:{type:"object",description:"Arguments for the wrapped tool"}},required:["callerId","toolName","toolArgs"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function Ke(a,i,r,e){if(a!=="dataverse_impersonate")throw new Error(`Unknown impersonate tool: ${a}`);let{callerId:t,toolName:n,toolArgs:o}=Ca.parse(i);try{if(((await r.query(`systemusers(${v(t)})/systemuserroles_association`,{select:["name"],filter:"name eq 'System Administrator'",top:1})).value?.length??0)>0)throw new Error("Security policy: impersonation of users with System Administrator role is prohibited to prevent privilege escalation.")}catch(d){throw d instanceof Error&&d.message.includes("Security policy")?d:new Error(`Security policy: cannot verify callerId roles \u2014 impersonation denied. Cause: ${String(d)}`)}let l=r.http,s=l.defaultHeaders.MSCRMCallerId;try{l.defaultHeaders.MSCRMCallerId=t;let d=await e(n,o,r);return u(`Impersonated as ${t}, executed ${n}`,{impersonatedAs:t,tool:n,result:JSON.parse(d.content[0].text)},["Impersonation applies to this single call only"])}finally{s===void 0?delete l.defaultHeaders.MSCRMCallerId:l.defaultHeaders.MSCRMCallerId=s}}import{z as A}from"zod";var Ua={10:"Pre-validation",20:"Pre-operation",40:"Post-operation",45:"Post-operation (deprecated)"},La={0:"Synchronous",1:"Asynchronous"},Pa=A.object({workflowId:A.string().uuid(),activate:A.boolean()}),Xe=[{name:"dataverse_list_custom_actions",description:"Lists all custom actions (custom API / SDK messages) registered in the environment. Returns the message name, category, bound entity (if any), execute privilege, and whether it is customizable. Useful for discovering available automation entry points and agent-callable actions. WHEN TO USE: Discovering available custom API / SDK messages for automation. BEST PRACTICES: Use nameFilter to search; follow up with dataverse_execute_action to invoke. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Max records (default 100, max 500)"},nameFilter:{type:"string",description:"Filter by name (substring match)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_plugin_steps",description:"Lists plugin steps (SdkMessageProcessingStep registrations) in the environment. Shows plugin assembly, step name, message (Create/Update/Delete/\u2026), entity, stage (pre/post), mode (sync/async), and state (enabled/disabled). Essential for understanding what custom business logic fires on Dataverse operations. WHEN TO USE: Understanding what custom business logic fires on CRUD operations for a table. BEST PRACTICES: Filter by entityLogicalName; check stage and mode to understand execution order and timing. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Max records (default 100, max 500)"},activeOnly:{type:"boolean",description:"Return only enabled steps (default: true)"},entityLogicalName:{type:"string",description:"Filter by entity logical name (e.g. 'account')"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_set_workflow_state",description:"Activates or deactivates a Dataverse workflow (classic workflow / real-time workflow / action). Set activate=true to activate (statecode 1, statuscode 2) or activate=false to deactivate (statecode 0, statuscode 1). Returns the new state. WHEN TO USE: Activating or deactivating a classic workflow, real-time workflow, or action. BEST PRACTICES: Verify workflow ID first; deactivation stops future triggers but does not cancel in-progress runs. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{workflowId:{type:"string",description:"The workflow GUID"},activate:{type:"boolean",description:"true = activate, false = deactivate (draft)"}},required:["workflowId","activate"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_connection_references",description:"Lists all Power Automate connection references defined in the environment, showing their display name, connector ID, connection ID, and active status. Use this before importing a solution containing flows to detect broken or unmapped connections that would cause silent import failures. WHEN TO USE: Pre-deployment solution validation, auditing connection health, identifying broken flow connections. BEST PRACTICES: Look for inactive (isActive=false) references \u2014 these indicate flows that will fail after deployment. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{connectorId:{type:"string",description:"Filter by connector ID substring (e.g. '/providers/Microsoft.PowerApps/apis/shared_sharepointonline')"},activeOnly:{type:"boolean",description:"Return only active connection references (default: false = return all)"},top:{type:"number",description:"Maximum records to return (default 100, max 500)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],qa=A.object({top:A.number().positive().max(500).optional().default(100),nameFilter:A.string().optional()}),Ha=A.object({top:A.number().positive().max(500).optional().default(100),activeOnly:A.boolean().optional().default(!0),entityLogicalName:A.string().optional()}),$a=A.object({connectorId:A.string().optional(),activeOnly:A.boolean().optional().default(!1),top:A.number().int().positive().max(500).optional().default(100)});async function Qe(a,i,r){switch(a){case"dataverse_list_custom_actions":{let{top:e,nameFilter:t}=qa.parse(i??{}),n=["isprivate eq false"];t&&n.push(`contains(name,'${v(t)}')`);let l=(await r.query("sdkmessages",{select:["sdkmessageid","name","categoryname","isprivate","isreadonly","isvalidforexecuteasync"],filter:n.join(" and "),top:e})).value.map(s=>({id:s.sdkmessageid,name:s.name,category:s.categoryname??"",isPrivate:s.isprivate,isReadOnly:s.isreadonly,asyncSupported:s.isvalidforexecuteasync}));return u(`${l.length} custom actions found`,{total:l.length,messages:l},["Use dataverse_execute_action to run an action"])}case"dataverse_list_plugin_steps":{let{top:e,activeOnly:t,entityLogicalName:n}=Ha.parse(i??{}),o={select:["sdkmessageprocessingstepid","name","stage","mode","rank","statecode","filteringattributes","asyncautodelete"],expand:"sdkmessageid($select=name,categoryname),plugintypeid($select=name,assemblyname),sdkmessagefilterid($select=primaryobjecttypecode)",top:e};t&&(o.filter="statecode eq 0");let s=(await r.query("sdkmessageprocessingsteps",o)).value;if(n){let c=n.toLowerCase();s=s.filter(p=>p.sdkmessagefilterid?.primaryobjecttypecode?.toLowerCase()===c)}let d=s.map(c=>({id:c.sdkmessageprocessingstepid,name:c.name,message:c.sdkmessageid?.name??"",entity:c.sdkmessagefilterid?.primaryobjecttypecode??"",assembly:c.plugintypeid?.assemblyname??"",pluginType:c.plugintypeid?.name??"",stage:c.stage,stageName:Ua[c.stage]??`Stage ${c.stage}`,mode:c.mode,modeName:La[c.mode]??`Mode ${c.mode}`,rank:c.rank,isActive:c.statecode===0,filteringAttributes:c.filteringattributes??null,asyncAutoDelete:c.asyncautodelete}));return u(`${d.length} plugin steps found`,{total:d.length,steps:d},["Use dataverse_get_plugin_trace_logs for debugging plugin issues"])}case"dataverse_set_workflow_state":{let{workflowId:e,activate:t}=Pa.parse(i);try{await r.updateRecord("workflows",e,{statecode:t?1:0,statuscode:t?2:1})}catch(n){let o=n instanceof Error?n.message:String(n);throw/0x80040203|does not refer to a valid workflow|404/i.test(o)?new Error(`Workflow '${e}' not found. Use dataverse_list_workflows to retrieve valid workflow GUIDs in this environment. Original error: ${o}`):n}return u(`Workflow state updated for ${e}`,{workflowId:e,newState:t?"Activated":"Draft",statecode:t?1:0,statuscode:t?2:1})}case"dataverse_list_connection_references":{let{connectorId:e,activeOnly:t,top:n}=$a.parse(i??{}),o=[];t&&o.push("statecode eq 0"),e&&o.push(`contains(connectorid,'${v(e)}')`);let l={select:["connectionreferenceid","connectionreferencelogicalname","connectionreferencedisplayname","connectorid","connectionid","statecode","statuscode"],orderby:"connectionreferencedisplayname asc",top:n};o.length&&(l.filter=o.join(" and "));let d=((await r.query("connectionreferences",l)).value??[]).map(m=>({id:m.connectionreferenceid??"",logicalName:m.connectionreferencelogicalname??"",displayName:m.connectionreferencedisplayname??"",connectorId:m.connectorid??"",connectionId:m.connectionid??null,isActive:m.statecode===0,statusCode:m.statuscode??null})),c=d.filter(m=>!m.isActive).length,p=c>0?`${d.length} connection references found (${c} inactive \u2014 check before deploying)`:`${d.length} connection references found`;return u(p,{connectionReferences:d,count:d.length,inactiveCount:c},["Inactive references (isActive=false) indicate broken connections that will cause flow failures","Use the Power Apps maker portal to reconnect or replace broken connection references before deploying"])}default:throw new Error(`Unknown customization tool: ${a}`)}}import{z as x}from"zod";var Ma={1e8:"String",100000001:"Number",100000002:"Boolean",100000003:"JSON",100000004:"DataSource"},Wa={String:1e8,Integer:100000001,Boolean:100000002,JSON:100000003},Ye=[{name:"dataverse_get_environment_variable",description:"Retrieves an environment variable's definition and current value from Dataverse. Returns the schema name, display name, type, default value, and the current override value (if set). Useful for reading feature flags, configuration values, and integration settings stored in Dataverse environment variables. WHEN TO USE: Reading configuration values, feature flags, or integration settings stored as environment variables. BEST PRACTICES: Check both defaultValue and currentValue; the effective value is currentValue ?? defaultValue. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{schemaName:{type:"string",description:"The schema name of the environment variable (e.g. 'new_MyConfig')"}},required:["schemaName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_set_environment_variable",description:"Sets or updates an environment variable value in Dataverse. If a value record already exists for the variable, it is updated; otherwise a new value record is created. The schemaName must match an existing environment variable definition. WHEN TO USE: Updating configuration values or feature flags stored in Dataverse environment variables. BEST PRACTICES: Verify the variable exists first with dataverse_get_environment_variable; schemaName must match exactly. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{schemaName:{type:"string",description:"The schema name of the environment variable"},value:{type:"string",description:"The new value to set"}},required:["schemaName","value"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_create_environment_variable",description:"Creates a new Dataverse environment variable definition and sets its initial value. Use this when the variable does not yet exist \u2014 use dataverse_set_environment_variable to update an existing one. WHEN TO USE: Initial setup of configuration flags, feature toggles, or integration settings. BEST PRACTICES: Use a solution-prefixed schemaName (e.g. 'myprefix_MyConfig'); provide solutionUniqueName to register in a solution. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{schemaName:{type:"string",description:"Schema name of the new variable (e.g. 'new_MyConfig'). Case-sensitive."},displayName:{type:"string",description:"Human-readable display name"},type:{type:"string",enum:["String","Integer","Boolean","JSON"],description:"Variable type"},value:{type:"string",description:"Initial value to set"},description:{type:"string",description:"Optional description"},defaultValue:{type:"string",description:"Optional default value (fallback when no override value is set)"},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional creation of a new environment variable definition"}},required:["schemaName","displayName","type","value","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_environment_capabilities",description:"Returns a comprehensive snapshot of the Dataverse environment: identity (WhoAmI), organization settings (name, version, language, audit config), unmanaged solution count, and environment variable count. Use at the start of a session to orient yourself to the environment and its configuration. WHEN TO USE: Beginning of any Dataverse automation session, before bulk operations, or when debugging unexpected behavior. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],ja=x.object({schemaName:x.string().min(1)}),Fa=x.object({schemaName:x.string().min(1),value:x.string()}),Ba=x.object({schemaName:x.string().min(1),displayName:x.string().min(1),type:x.enum(["String","Integer","Boolean","JSON"]),value:x.string(),description:x.string().optional(),defaultValue:x.string().optional(),confirm:x.literal(!0,{errorMap:()=>({message:"Set confirm: true to create a new environment variable definition"})})});async function Ga(a,i){let{schemaName:r}=ja.parse(a),t=(await i.query("environmentvariabledefinitions",{filter:`schemaname eq '${v(r)}'`,select:["environmentvariabledefinitionid","schemaname","displayname","description","type","defaultvalue","isrequired"],top:1})).value;if(t.length===0)throw new Error(`Environment variable '${r}' not found. Check the schema name (it is case-sensitive, e.g. 'new_MyConfig'). To browse existing variables: Power Apps maker portal \u2192 Solutions \u2192 your solution \u2192 Environment Variables. To create a new one: open a solution \u2192 New \u2192 More \u2192 Environment Variable.`);let n=t[0],o=n.environmentvariabledefinitionid,s=(await i.query("environmentvariablevalues",{filter:`_environmentvariabledefinitionid_value eq ${o}`,select:["environmentvariablevalueid","value"],top:1})).value,d=s.length>0?s[0]:null,c=n.type,p=d?d.value??null:null,m=n.defaultvalue??null,f={schemaName:n.schemaname,displayName:n.displayname??"",description:n.description??"",type:c,typeName:Ma[c]??"Unknown",defaultValue:m,currentValue:p,valueId:d?d.environmentvariablevalueid:null,isRequired:n.isrequired??!1,effectiveValue:p??m};return u(`Environment variable '${f.schemaName}': ${f.typeName} = ${f.effectiveValue??"(not set)"}`,f,["Use dataverse_set_environment_variable to update the value"])}async function za(a,i){let{schemaName:r,value:e}=Fa.parse(a),n=(await i.query("environmentvariabledefinitions",{filter:`schemaname eq '${v(r)}'`,select:["environmentvariabledefinitionid","schemaname"],top:1})).value;if(n.length===0)throw new Error(`Environment variable definition '${r}' not found. This tool can only update the value of an existing variable. To create a new environment variable: Power Apps maker portal \u2192 Solutions \u2192 your solution \u2192 New \u2192 More \u2192 Environment variable. Then call this tool to set its value.`);let o=n[0].environmentvariabledefinitionid,s=(await i.query("environmentvariablevalues",{filter:`_environmentvariabledefinitionid_value eq ${o}`,select:["environmentvariablevalueid","value"],top:1})).value,d,c;s.length>0?(c=s[0].environmentvariablevalueid,await i.updateRecord("environmentvariablevalues",c,{value:e}),d="updated"):(c=await i.createRecord("environmentvariablevalues",{value:e,"EnvironmentVariableDefinitionId@odata.bind":`/environmentvariabledefinitions(${o})`}),d="created");let p={schemaName:r,operation:d,valueId:c,value:e};return u(`Environment variable '${r}' set to new value`,p,["Use dataverse_get_environment_variable to verify the update"])}async function Va(a,i){let{schemaName:r,displayName:e,type:t,value:n,description:o,defaultValue:l}=Ba.parse(a),s=q({toolName:"dataverse_create_environment_variable"}).map(N=>`[${N.severity.toUpperCase()}] ${N.code}: ${N.message}`);if((await i.query("environmentvariabledefinitions",{filter:`schemaname eq '${v(r)}'`,select:["environmentvariabledefinitionid"],top:1})).value.length>0)throw new Error(`Environment variable '${r}' already exists. Use dataverse_set_environment_variable to update its value.`);let c=Wa[t]??1e8,p={schemaname:r,displayname:e,type:c};o&&(p.description=o),l!==void 0&&(p.defaultvalue=l);let m=await i.createRecord("environmentvariabledefinitions",p),f=await i.createRecord("environmentvariablevalues",{value:n,"EnvironmentVariableDefinitionId@odata.bind":`/environmentvariabledefinitions(${m})`});return u(`Environment variable '${r}' created (type: ${t}, value: '${n}').`,{schemaName:r,displayName:e,type:t,typeCode:c,definitionId:m,valueId:f,value:n,...s.length>0&&{warnings:s}},["Use dataverse_get_environment_variable to verify","Use dataverse_set_environment_variable to update the value later"])}async function Je(a,i,r){switch(a){case"dataverse_get_environment_variable":return Ga(i,r);case"dataverse_set_environment_variable":return za(i,r);case"dataverse_create_environment_variable":return Va(i,r);case"dataverse_environment_capabilities":{let[e,t,n,o]=await Promise.allSettled([r.executeFunction("WhoAmI",{}),r.query("organizations",{select:["uniquename","friendlyname","version","languagecode","isauditenabled"],top:1}),r.query("solutions",{filter:"ismanaged eq false",select:["uniquename"]}),r.query("environmentvariabledefinitions",{select:["schemaname"],top:1})]),l=e.status==="fulfilled"?e.value:null,s=t.status==="fulfilled"?t.value.value:[],d=n.status==="fulfilled"?n.value.value:[],c=o.status==="fulfilled"?o.value.value:[];return u("Environment capabilities retrieved",{identity:l,organization:s[0]??null,unmanagedSolutionsCount:d.length,environmentVariablesCount:c.length},["Use dataverse_list_solutions for full solution list","Use dataverse_get_environment_variable to read specific env vars"])}default:throw new Error(`Unknown environment tool: ${a}`)}}import{z as L}from"zod";var Ka={0:"Execute",1:"Create",2:"Retrieve",3:"RetrieveMultiple",4:"GetParent",5:"Update",6:"Delete",7:"Assign"},Xa={0:"Waiting",10:"WaitingForResources",20:"InProgress",21:"Pausing",22:"Canceling",30:"Succeeded",31:"Failed",32:"Canceled"},Qa={0:"ReadyToRun",1:"Suspended",2:"Locked",3:"Completed"},Ya=["plugintracelogid","typename","messagename","primaryentity","depth","operationtype","exceptiondetails","messageblock","createdon","performanceexecutionduration","correlationid","requestid"],Ja=["asyncoperationid","name","operationtype","statuscode","statecode","message","createdon","startedon","completedon"],Ze=[{name:"dataverse_get_plugin_trace_logs",description:"Retrieves recent plugin and custom workflow activity trace logs from Dataverse. Shows execution details including plugin type name, triggering message, entity, execution duration, trace messages written by the developer, and exception details if the plugin failed. Requires the Plugin Trace Log feature to be enabled in Dataverse settings (Settings > Administration > System Settings > Customization tab > 'Enable logging to plugin trace log'). Essential for debugging plugin failures in production. WHEN TO USE: Debugging plugin failures or performance issues in production. BEST PRACTICES: Enable Plugin Trace Log in Dataverse settings first; filter by plugin name or entity to narrow results. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Max records to return (default 50, max 200)"},pluginTypeFilter:{type:"string",description:"Filter by plugin type name (substring match, e.g. 'AccountValidation')"},messageFilter:{type:"string",description:"Filter by message name (e.g. 'Create', 'Update')"},entityFilter:{type:"string",description:"Filter by entity logical name (e.g. 'account')"},exceptionsOnly:{type:"boolean",description:"Return only traces where an exception occurred (default false)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_get_workflow_trace_logs",description:"Retrieves background workflow (Power Automate classic / legacy workflow engine) execution records from Dataverse. These are the AsyncOperation records for workflow-type operations, useful for diagnosing failures in background workflows and real-time workflows running asynchronously. Note: For modern cloud flows (Power Automate), use the Power Automate portal instead. WHEN TO USE: Diagnosing failures in classic/legacy background workflows. BEST PRACTICES: Use failedOnly=true to focus on errors; for modern cloud flows use Power Automate portal. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Max records (default 50, max 200)"},failedOnly:{type:"boolean",description:"Return only failed workflows (statuscode eq 31, default false)"},entityFilter:{type:"string",description:"Filter by regarding entity type (e.g. 'account')"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],Za=L.object({top:L.number().int().positive().max(200).optional().default(50),pluginTypeFilter:L.string().optional(),messageFilter:L.string().optional(),entityFilter:L.string().optional(),exceptionsOnly:L.boolean().optional().default(!1)}),en=L.object({top:L.number().int().positive().max(200).optional().default(50),failedOnly:L.boolean().optional().default(!1),entityFilter:L.string().optional()});function U(a){return typeof a=="string"?a:""}function tn(a){return typeof a=="number"?a:null}async function et(a,i,r){switch(a){case"dataverse_get_plugin_trace_logs":{let e=Za.parse(i),t=[];e.pluginTypeFilter&&t.push(`contains(typename,'${v(e.pluginTypeFilter)}')`),e.messageFilter&&t.push(`messagename eq '${v(e.messageFilter)}'`),e.entityFilter&&t.push(`primaryentity eq '${v(e.entityFilter)}'`),e.exceptionsOnly&&t.push("exceptiondetails ne null");let n=t.length>0?t.join(" and "):void 0,s=((await r.query("plugintracelogs",{select:Ya,orderby:"createdon desc",top:e.top,...n!==void 0?{filter:n}:{}})).value??[]).map(c=>{let p=typeof c.operationtype=="number"?c.operationtype:0,m=c.exceptiondetails;return{id:U(c.plugintracelogid),typeName:U(c.typename),message:U(c.messagename),entity:U(c.primaryentity),depth:typeof c.depth=="number"?c.depth:0,operationType:p,operationTypeName:Ka[p]??String(p),createdOn:U(c.createdon),durationMs:tn(c.performanceexecutionduration),correlationId:U(c.correlationid),requestId:U(c.requestid),hasException:m!=null&&m!=="",exceptionDetails:typeof m=="string"?m:null,messageBlock:typeof c.messageblock=="string"?c.messageblock:null}}),d={total:s.length,logs:s};return u(`${s.length} plugin trace logs found`,d,["Filter by plugin name or correlation ID for specific traces"])}case"dataverse_get_workflow_trace_logs":{let e=en.parse(i),t=["operationtype eq 10"];e.failedOnly&&t.push("statuscode eq 31");let n=t.join(" and "),s=((await r.query("asyncoperations",{select:Ja,filter:n,orderby:"createdon desc",top:e.top})).value??[]).map(c=>{let p=typeof c.statuscode=="number"?c.statuscode:0,m=typeof c.statecode=="number"?c.statecode:0,f=c.message;return{id:U(c.asyncoperationid),name:U(c.name),statusCode:p,statusName:Xa[p]??String(p),stateCode:m,stateName:Qa[m]??String(m),createdOn:U(c.createdon),startedOn:typeof c.startedon=="string"?c.startedon:null,completedOn:typeof c.completedon=="string"?c.completedon:null,errorMessage:typeof f=="string"?f:null}}),d={total:s.length,workflows:s};return u(`${s.length} workflow trace logs found`,d,["Filter by status or entity type for specific workflow traces"])}default:throw new Error(`Unknown trace tool: ${a}`)}}import{z as E}from"zod";var tt=[{name:"dataverse_search",description:"Full-text Relevance Search across all configured Dataverse tables. Returns ranked results with entity name, record ID, score, and matched fields. Requires Relevance Search to be enabled in Dataverse admin settings. Use when you need to find records without knowing which table they belong to. WHEN TO USE: Cross-table free-text search when you don't know which table contains the data. BEST PRACTICES: Narrow with entities[] and $filter; use searchType=full for Lucene operators (AND, OR, NOT, wildcards). WORKFLOW: search_data.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Full-text search string (supports Lucene syntax with searchType=full)"},entities:{type:"array",items:{type:"string"},description:"Restrict to specific table logical names (omit to search all configured tables). Required when using select."},top:{type:"number",description:"Max results (default 10, max 50)"},searchMode:{type:"string",enum:["any","all"],description:"Match any or all terms (default: any)"},searchType:{type:"string",enum:["simple","full"],description:"Search syntax: simple (default) or full (enables Lucene syntax: AND, OR, NOT, wildcards, fuzzy, proximity, regex)"},filter:{type:"string",description:'OData $filter to apply on search results (e.g., "statecode eq 0")'},facets:{type:"array",items:{type:"string"},description:'Fields to return faceted counts for (e.g., ["entityname,count:100","statecode"])'},orderby:{type:"array",items:{type:"string"},description:'Result sort order (e.g., ["@search.score desc","modifiedon desc"])'},select:{type:"array",items:{type:"string"},description:"Columns to return per result. Only applies when entities is also specified."}},required:["query"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],an=E.object({query:E.string().min(1),entities:E.array(E.string()).optional(),top:E.number().int().positive().max(50).optional().default(10),searchMode:E.enum(["any","all"]).optional().default("any"),searchType:E.enum(["simple","full"]).optional(),filter:E.string().optional(),facets:E.array(E.string()).optional(),orderby:E.array(E.string()).optional(),select:E.array(E.string()).optional()});async function at(a,i,r){switch(a){case"dataverse_search":{let e=an.parse(i),t={search:e.query,top:e.top};if(e.entities?.length){let s=e.entities.map(d=>({name:d,...e.select?.length?{selectColumns:e.select}:{}}));t.entities=JSON.stringify(s)}e.searchType==="full"&&(t.options=JSON.stringify({querytype:"lucene"})),e.filter&&(t.filter=e.filter),e.facets?.length&&(t.facets=JSON.stringify(e.facets)),e.orderby?.length&&(t.orderby=JSON.stringify(e.orderby));let n;try{n=await r.search(t)}catch(s){let d=s instanceof Error?s.message:String(s);if(/404|not.?found|search.{0,20}disabl|relevance.?search|0x80048[Dd]0[Bb]|search.{0,20}not.{0,20}config|search.{0,20}unavail/i.test(d))return X({type:"feature_disabled",feature:"Dataverse Search (Relevance Search)",cannotProceedBecause:"Relevance Search is not enabled for this Dataverse environment, so full-text cross-table search is unavailable.",adminPortal:"Power Platform Admin Center",steps:["Open Power Platform Admin Center (admin.powerplatform.microsoft.com)","Select your environment \u2192 Settings","Navigate to Product \u2192 Features",'Under "Search", toggle "Dataverse Search" to On',"Save \u2014 indexing may take a few minutes before search is available"]});throw s}let o=(n.value??[]).map(s=>({entityName:s.entityname??"",objectId:s.objectid??"",score:s.score??0,highlights:s.highlights??{},fields:s.attributes??{}})),l={totalRecordCount:n.totalrecordcount??0,results:o};return n.facets&&(l.facets=n.facets),u(`${o.length} search results for '${e.query}'`,l,["Use dataverse_get to retrieve full record details","Narrow results with entities[] filter"])}default:throw new Error(`Unknown search tool: ${a}`)}}import{z as W}from"zod";var pe={1:"Create",2:"Update",3:"Delete",4:"Activate",5:"Deactivate",11:"Share",12:"Unshare",13:"Assign",104:"Access"},nn=Object.fromEntries(Object.entries(pe).map(([a,i])=>[i,Number(a)])),nt=[{name:"dataverse_get_audit_log",description:"Retrieves audit log entries from Dataverse. Returns operation details, user info, and parsed change data for each entry. At least one filter (recordId, entityLogicalName, userId, fromDate, or operations) is recommended to avoid large result sets. Audit must be enabled on the environment and table \u2014 returns a clear error if auditing is disabled (HTTP 403). WHEN TO USE: Tracking who changed what and when on Dataverse records. BEST PRACTICES: Always provide at least one filter; audit must be enabled on the table. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{recordId:{type:"string",description:"GUID of a specific record to retrieve audit entries for"},entityLogicalName:{type:"string",description:'Logical name of the entity to filter audit entries (e.g., "account", "contact")'},userId:{type:"string",description:"GUID of the user who made the changes"},fromDate:{type:"string",description:"ISO 8601 date string \u2014 only return audit entries created on or after this date"},top:{type:"number",description:"Maximum number of audit entries to return (default: 50, max: 500)"},operations:{type:"array",items:{type:"string"},description:'Filter by operation names: "Create", "Update", "Delete", "Activate", "Deactivate", "Share", "Unshare", "Assign", "Access"'}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],rn=W.object({recordId:W.string().uuid().optional(),entityLogicalName:W.string().min(1).optional(),userId:W.string().uuid().optional(),fromDate:W.string().datetime({offset:!0}).optional(),top:W.number().positive().max(500).optional().default(50),operations:W.array(W.string().min(1)).optional()});function on(a){if(!a)return{};try{return JSON.parse(a)}catch{return a}}function sn(a){return{auditId:a.auditid,operation:a.operation,operationName:pe[a.operation]??`Unknown(${a.operation})`,action:a.action,actionName:pe[a.action]??`Unknown(${a.action})`,createdOn:a.createdon,userId:a._userid_value,userFullName:a.userid?.fullname??"",userDomainName:a.userid?.domainname??"",objectId:a._objectid_value,objectTypeCode:a.objecttypecode,changes:on(a.changedata)}}async function rt(a,i,r){switch(a){case"dataverse_get_audit_log":{let e=rn.parse(i),t=[];if(e.recordId&&t.push(`_objectid_value eq ${e.recordId}`),e.entityLogicalName){let n=v(e.entityLogicalName);t.push(`objecttypecode eq '${n}'`)}if(e.userId&&t.push(`_userid_value eq ${e.userId}`),e.fromDate&&t.push(`createdon ge ${e.fromDate}`),e.operations?.length){let n=e.operations.map(o=>nn[o]).filter(o=>o!==void 0);if(n.length>0){let o=n.map(l=>`action eq ${l}`).join(" or ");t.push(`(${o})`)}}try{let o=(await r.query("audits",{select:["auditid","action","operation","createdon","_objectid_value","objecttypecode","changedata","_userid_value"],...t.length>0?{filter:t.join(" and ")}:{},orderby:"createdon desc",top:e.top,expand:"userid($select=fullname,domainname)"})).value.map(sn);return u(`${o.length} audit records for ${e.entityLogicalName??e.recordId??"query"}`,{entries:o,count:o.length},["Filter by operation type for specific changes"])}catch(n){let o=n instanceof Error?n.message:String(n);if(o.includes("403")||o.includes("Forbidden"))return{content:[{type:"text",text:JSON.stringify({isError:!0,error:"Audit log access denied (HTTP 403). Ensure auditing is enabled on the Dataverse environment and the target table, and that the authenticated user has sufficient privileges."})}]};throw n}}default:throw new Error(`Unknown audit tool: ${a}`)}}import{z as Q}from"zod";var it=new Map,ot=[{name:"dataverse_detect_duplicates",description:"Checks for potential duplicate records before creating, using a FetchXML query that matches records sharing the same field values as the prospective record (OR conditions on the provided fields). Pass the prospective record fields to check against existing records. WHEN TO USE: Before creating a new record to check if a similar record already exists. BEST PRACTICES: Pass only the key identifying fields (e.g., name, email); too many fields will return fewer matches. WORKFLOW: create_record.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:'Table to check, e.g., "account"'},record:{type:"object",description:"The prospective record fields to check for duplicates"},top:{type:"number",description:"Maximum number of duplicates to return (default 5, max 20)"}},required:["entityLogicalName","record"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}],ln=Q.object({entityLogicalName:Q.string().min(1).regex(/^[a-z_][a-z0-9_]*$/i,"Must be a valid Dataverse logical name"),record:Q.record(Q.string(),Q.unknown()),top:Q.number().int().positive().max(20).optional().default(5)});async function st(a,i,r){switch(a){case"dataverse_detect_duplicates":{let n=function(m){return String(m).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")};var e=n;let t=ln.parse(i),o=Object.entries(t.record).filter(([,m])=>m!=null).map(([m,f])=>`<condition attribute="${n(m)}" operator="eq" value="${n(String(f))}" />`).join(`
|
|
3
|
+
`);if(!o)return u("No fields provided for duplicate detection",{hasDuplicates:!1,duplicateCount:0,duplicates:[]},["Provide at least one field value to check for duplicates"]);let l=it.get(t.entityLogicalName);l||(l=(await r.getTableMetadata(t.entityLogicalName,!1)).EntitySetName,it.set(t.entityLogicalName,l));let s=`<fetch top="${t.top}" distinct="true">
|
|
4
4
|
<entity name="${n(t.entityLogicalName)}">
|
|
5
5
|
<all-attributes />
|
|
6
6
|
<filter type="or">
|
|
7
|
-
${
|
|
7
|
+
${o}
|
|
8
8
|
</filter>
|
|
9
9
|
</entity>
|
|
10
|
-
</fetch>`,d=await o.executeFetchXml(s,l),m=(Array.isArray(d.value)?d.value:[]).map(p=>{let g={};for(let[k,Y]of Object.entries(p))k.startsWith("@")||(g[k]=Y);return g});return u(`Duplicate detection: ${m.length>0?`${m.length} potential duplicate(s) found`:"no duplicates found"}`,{hasDuplicates:m.length>0,duplicateCount:m.length,duplicates:m,note:"Field exact-match candidates (OR across provided fields). Dataverse duplicate detection rules are not applied via REST API."},["Review candidate records before creating","For rule-based duplicate detection, configure rules in Dataverse admin"])}default:throw new Error(`Unknown quality tool: ${a}`)}}import{z as A}from"zod";var Ga=A.object({recordId:A.string().uuid(),includeContent:A.boolean().optional().default(!1),top:A.number().int().positive().max(100).optional().default(20),mimeTypeFilter:A.string().optional()}),za=A.object({recordId:A.string().uuid(),entitySetName:b,noteText:A.string().optional(),subject:A.string().optional(),fileName:A.string().optional(),mimeType:A.string().optional(),documentBody:A.string().optional()}).strict().refine(a=>!!a.noteText||!!a.documentBody,{message:"At least one of noteText or documentBody is required"});function Va(a){return{opportunities:"opportunity",territories:"territory",categories:"category",queues:"queue",activities:"activitypointer"}[a]??a.replace(/s$/,"")}var et=[{name:"dataverse_get_annotations",description:"Retrieves notes and file attachments (annotations) linked to a Dataverse record. Returns note text, file metadata (name, size, MIME type), owner, and timestamps. Set includeContent=true to also retrieve base64 file content (warning: can be very large). WHEN TO USE: Retrieving notes or file attachments linked to a specific record. BEST PRACTICES: Avoid includeContent=true unless you need file data \u2014 base64 payloads can be very large. WORKFLOW: file_operations.",inputSchema:{type:"object",properties:{recordId:{type:"string",description:"The parent record's GUID"},includeContent:{type:"boolean",description:"If true, include documentbody (base64). WARNING: can be very large.",default:!1},top:{type:"number",description:"Maximum number of annotations to return (default 20, max 100)",default:20},mimeTypeFilter:{type:"string",description:'Filter by MIME type (e.g. "application/pdf")'}},required:["recordId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_create_annotation",description:"Creates a note or file attachment (annotation) linked to a Dataverse record. Provide notetext for a text note, documentbody (base64) for a file attachment, or both. The parent record is identified by entitySetName and recordId. WHEN TO USE: Adding a text note or file attachment to an existing record. BEST PRACTICES: Provide filename and mimetype when attaching files; at least notetext or documentbody is required. WORKFLOW: file_operations.",inputSchema:{type:"object",properties:{recordId:{type:"string",description:"The parent record's GUID"},entitySetName:{type:"string",description:'The OData entity set name of the parent record (e.g., "accounts", "contacts")'},noteText:{type:"string",description:"Text content of the note"},subject:{type:"string",description:"Subject/title of the note"},fileName:{type:"string",description:"File name (required when attaching a file)"},mimeType:{type:"string",description:'MIME type of the file (e.g., "application/pdf")'},documentBody:{type:"string",description:"Base64-encoded file content"}},required:["recordId","entitySetName"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function tt(a,r,o){switch(a){case"dataverse_get_annotations":{let e=Ga.parse(r),t=["annotationid","subject","notetext","filename","filesize","mimetype","isdocument","createdon","modifiedon","_ownerid_value"];e.includeContent&&t.push("documentbody");let n=[`_objectid_value eq ${e.recordId}`];e.mimeTypeFilter&&n.push(`mimetype eq '${h(e.mimeTypeFilter)}'`);let l=((await o.query("annotations",{select:t,filter:n.join(" and "),orderby:"createdon desc",top:e.top})).value??[]).map(d=>{let c={id:d.annotationid??"",subject:d.subject??null,noteText:d.notetext??null,isDocument:d.isdocument===!0,createdOn:d.createdon??"",modifiedOn:d.modifiedon??"",owner:d._ownerid_value??null};return d.isdocument===!0&&(c.fileName=d.filename??null,c.fileSize=d.filesize??null,c.mimeType=d.mimetype??null),e.includeContent&&d.documentbody&&(c.documentBody=d.documentbody),c});return u(`${l.length} annotations found for record ${e.recordId}`,{recordId:e.recordId,annotations:l,count:l.length},["Use dataverse_create_annotation to add a note or attachment"])}case"dataverse_create_annotation":{let e=za.parse(r),t=Va(e.entitySetName),n={[`objectid_${t}@odata.bind`]:`/${e.entitySetName}(${e.recordId})`,objecttypecode:t};e.noteText!==void 0&&(n.notetext=e.noteText),e.subject!==void 0&&(n.subject=e.subject),e.fileName!==void 0&&(n.filename=e.fileName),e.mimeType!==void 0&&(n.mimetype=e.mimeType),e.documentBody!==void 0&&(n.documentbody=e.documentBody,n.isdocument=!0);let i;try{i=await o.createRecord("annotations",n)}catch(s){let l=String(s);if(l.includes("0x80048d19")||l.includes("objectid_")&&l.includes("undeclared"))return j({type:"feature_disabled",feature:"Notes (HasNotes)",cannotProceedBecause:`The table '${t}' does not have Notes enabled (HasNotes=false), so annotations cannot be created.`,adminPortal:"Power Apps Maker Portal",steps:["Open Power Apps maker portal (make.powerapps.com)",`Navigate to Tables \u2192 search for '${t}'`,"Open the table \u2192 click Properties or Settings",'Enable "Notes (includes file attachments)"',"Save the table, then publish customizations"],fixableViaToolName:"dataverse_update_entity"});throw s}return u(`Created annotation ${i}`,{created:!0,annotationId:i,parentRecordId:e.recordId,entitySetName:e.entitySetName},["Use dataverse_get_annotations to list all notes for this record"])}default:throw new Error(`Unknown annotation tool: ${a}`)}}import{z as w}from"zod";var Ka=w.object({userId:w.string().uuid()}),Xa=w.object({search:w.string().optional(),businessUnitId:w.string().optional(),includeDisabled:w.boolean().optional().default(!1),includeApplicationUsers:w.boolean().optional().default(!1),top:w.number().int().positive().max(100).optional().default(20)}),Qa=w.object({nameContains:w.string().optional(),businessUnitId:w.string().optional(),top:w.number().int().positive().max(200).optional().default(50)}),Ja=w.object({userId:w.string().uuid(),roleId:w.string().uuid(),confirm:w.literal(!0,{errorMap:()=>({message:"confirm must be true to assign a role"})})}),Ya=w.object({userId:w.string().uuid(),roleId:w.string().uuid(),confirm:w.literal(!0,{errorMap:()=>({message:"confirm must be true to remove a role"})})}),at=[{name:"dataverse_get_user_roles",description:"Returns all security roles assigned to a Dataverse system user. Provide the user GUID to retrieve full name, domain name (UPN), and the list of roles with role ID, name, and managed status. WHEN TO USE: Checking what security roles a user has for permission auditing or troubleshooting. BEST PRACTICES: Use the userId from dataverse_whoami or dataverse_list_users. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{userId:{type:"string",description:"The system user GUID"}},required:["userId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_users",description:"Searches Dataverse system users by name or email. Returns user ID, full name, domain name (UPN), email, business unit, and disabled status. Excludes application users and disabled users by default. WHEN TO USE: Finding user GUIDs for impersonation, record assignment, or permission review. BEST PRACTICES: Search by name or email; set includeDisabled=true for former employees. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{search:{type:"string",description:"Full-name or email contains-search"},businessUnitId:{type:"string",description:"Restrict to a business unit (GUID)"},includeDisabled:{type:"boolean",description:"Include disabled users (default false)"},includeApplicationUsers:{type:"boolean",description:"Include application/service users (default false)"},top:{type:"number",description:"Maximum number of results (default 20, max 100)"}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_roles",description:"Lists security roles in the Dataverse environment. Returns role ID, name, business unit, and managed status. Use this to discover role GUIDs before assigning roles to users or teams via dataverse_assign_role_to_user or dataverse_assign_role_to_team. WHEN TO USE: Looking up security role GUIDs before RBAC assignment. BEST PRACTICES: Filter by businessUnitId or nameContains to narrow results. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{nameContains:{type:"string",description:"Filter roles by name (case-insensitive substring match)"},businessUnitId:{type:"string",description:"Filter roles to a specific business unit (GUID)"},top:{type:"number",description:"Maximum number of roles to return (default 50, max 200)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_assign_role_to_user",description:"Assigns a security role to a Dataverse system user. Use dataverse_list_roles to find the role GUID and dataverse_list_users to find the user GUID. Requires System Administrator or System Customizer privileges. WARNING: This operation modifies user permissions. Set confirm=true to proceed. WHEN TO USE: Granting a security role to a user during onboarding or permission changes. BEST PRACTICES: Verify role and user GUIDs first; check existing roles with dataverse_get_user_roles. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{userId:{type:"string",description:"GUID of the system user"},roleId:{type:"string",description:"GUID of the security role to assign"},confirm:{type:"boolean",description:"Must be true to proceed with role assignment"}},required:["userId","roleId","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_remove_role_from_user",description:"Removes a security role from a Dataverse system user. Uses the same N:N disassociation pattern as dataverse_disassociate. WARNING: This modifies user permissions. Set confirm=true to proceed. WHEN TO USE: Revoking access by removing a security role from a user. BEST PRACTICES: Verify the role is assigned first with dataverse_get_user_roles. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{userId:{type:"string",description:"GUID of the system user"},roleId:{type:"string",description:"GUID of the security role to remove"},confirm:{type:"boolean",description:"Must be true to proceed with role removal"}},required:["userId","roleId","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function nt(a,r,o){switch(a){case"dataverse_get_user_roles":{let{userId:e}=Ka.parse(r),n=(await o.query("systemusers",{filter:`systemuserid eq ${e}`,select:["fullname","domainname"],expand:"systemuserroles_association($select=name,roleid,ismanaged)",top:1})).value??[];if(n.length===0)throw new Error(`User with ID '${e}' not found`);let i=n[0],l=(i.systemuserroles_association??[]).map(d=>({roleId:d.roleid??"",name:d.name??"",isManaged:d.ismanaged===!0}));return u(`${l.length} roles assigned to user`,{userId:e,fullname:i.fullname??"",domainname:i.domainname??"",roles:l,roleCount:l.length},["Use dataverse_impersonate to execute operations as this user"])}case"dataverse_list_users":{let e=Xa.parse(r),t=[];if(e.includeDisabled||t.push("isdisabled eq false"),e.includeApplicationUsers||t.push("applicationid eq null"),e.search){let l=h(e.search);t.push(`(contains(fullname,'${l}') or contains(internalemailaddress,'${l}'))`)}e.businessUnitId&&t.push(`_businessunitid_value eq ${e.businessUnitId}`);let s=((await o.query("systemusers",{select:["systemuserid","fullname","domainname","internalemailaddress","applicationid","isdisabled"],filter:t.join(" and "),expand:"businessunitid($select=name)",orderby:"fullname asc",top:e.top})).value??[]).map(l=>({id:l.systemuserid??"",fullName:l.fullname??"",domainName:l.domainname??"",email:l.internalemailaddress??"",businessUnit:l.businessunitid?.name??null,isDisabled:l.isdisabled===!0,isApplicationUser:l.applicationid!=null}));return u(`${s.length} users found`,{users:s,count:s.length},["Use dataverse_get_user_roles to inspect specific user permissions"])}case"dataverse_list_roles":{let{nameContains:e,businessUnitId:t,top:n}=Qa.parse(r),i=[];e&&i.push(`contains(name,'${h(e)}')`),t&&i.push(`_businessunitid_value eq ${t}`);let s=i.length?i.join(" and "):void 0,d=((await o.query("roles",{select:["roleid","name","description","ismanaged","_businessunitid_value"],...s!==void 0?{filter:s}:{},orderby:"name asc",top:n})).value??[]).map(c=>({id:c.roleid??"",name:c.name??"",businessUnitId:c._businessunitid_value??null,isManaged:c.ismanaged===!0,description:c.description??""}));return u(`${d.length} security roles found`,{roles:d,count:d.length},["Use dataverse_assign_role_to_user or dataverse_assign_role_to_team with the role ID"])}case"dataverse_assign_role_to_user":{let{userId:e,roleId:t}=Ja.parse(r);return(((await o.query("systemusers",{filter:`systemuserid eq ${e}`,select:["systemuserid"],expand:`systemuserroles_association($select=roleid;$filter=roleid eq ${t};$top=1)`,top:1})).value??[])[0]?.systemuserroles_association??[]).length>0?u("Role is already assigned to this user.",{userId:e,roleId:t,status:"already_assigned"},["Use dataverse_get_user_roles to see current role assignments"]):(await o.associate("systemusers",e,"systemuserroles_association","roles",t),u("Role assigned to user successfully.",{userId:e,roleId:t,status:"assigned"},["Use dataverse_get_user_roles to verify the new assignment"]))}case"dataverse_remove_role_from_user":{let{userId:e,roleId:t}=Ya.parse(r);return(((await o.query("systemusers",{filter:`systemuserid eq ${e}`,select:["systemuserid"],expand:`systemuserroles_association($select=roleid;$filter=roleid eq ${t};$top=1)`,top:1})).value??[])[0]?.systemuserroles_association??[]).length===0?u("This role is not currently assigned to the user.",{userId:e,roleId:t,status:"not_assigned"},["Use dataverse_get_user_roles to see current role assignments"]):(await o.disassociate("systemusers",e,"systemuserroles_association",t,"roles"),u("Role removed from user successfully.",{userId:e,roleId:t,status:"removed"},["Use dataverse_get_user_roles to verify the updated assignments"]))}default:throw new Error(`Unknown user tool: ${a}`)}}import{z as Q}from"zod";var Za=Q.object({entityLogicalName:Q.string().min(1),includePersonal:Q.boolean().optional().default(!1),top:Q.number().int().positive().max(100).optional().default(20)}),rt=[{name:"dataverse_list_views",description:"Lists saved views (system and optionally personal) for a Dataverse table. System views come from savedqueries; personal views come from userqueries. Returns view name, ID, default flag, query type, and description. WHEN TO USE: Discovering saved system or personal views for a table. BEST PRACTICES: Use the view's FetchXML with dataverse_execute_fetchxml to run it. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:'Logical name of the entity to list views for (e.g., "account")'},includePersonal:{type:"boolean",description:"Include personal (user) views in addition to system views (default false)"},top:{type:"number",description:"Maximum number of results per category (default 20, max 100)"}},required:["entityLogicalName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function ot(a,r,o){switch(a){case"dataverse_list_views":{let{entityLogicalName:e,includePersonal:t,top:n}=Za.parse(r),i=h(e),l=(await o.query("savedqueries",{filter:`returnedtypecode eq '${i}' and statecode eq 0`,select:["savedqueryid","name","isdefault","querytype","description"],orderby:"name asc",top:n})).value.map(m=>({id:m.savedqueryid,name:m.name,isDefault:m.isdefault,queryType:m.querytype,description:m.description??null,viewType:"system"})),d=[];t&&(d=(await o.query("userqueries",{filter:`returnedtypecode eq '${i}'`,select:["userqueryid","name","description"],orderby:"name asc",top:n})).value.map(p=>({id:p.userqueryid,name:p.name,description:p.description??null,viewType:"personal"})));let c=l.length+d.length;return u(`${c} views found for ${e}`,{entityLogicalName:e,systemViews:l,systemViewCount:l.length,personalViews:t?d:void 0,personalViewCount:t?d.length:void 0},["Use the view's fetchxml with dataverse_execute_fetchxml to run it"])}default:throw new Error(`Unknown view tool: ${a}`)}}import{z as se}from"zod";var en=se.object({top:se.number().int().positive().max(200).optional().default(50),includeDisabled:se.boolean().optional().default(!1)}),it=[{name:"dataverse_list_business_units",description:"Lists business units in the Dataverse environment. Returns name, ID, parent business unit ID, disabled status, and creation date. By default only active business units are returned. WHEN TO USE: Finding business unit IDs for user management, team setup, or security role scope. BEST PRACTICES: The root business unit is the parent of all others; filter disabled units by default. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Maximum number of results (default 50, max 200)"},includeDisabled:{type:"boolean",description:"Include disabled business units (default false)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function st(a,r,o){switch(a){case"dataverse_list_business_units":{let{top:e,includeDisabled:t}=en.parse(r??{}),n=t?void 0:"isdisabled eq false",s=(await o.query("businessunits",{select:["businessunitid","name","parentbusinessunitid","isdisabled","createdon"],...n?{filter:n}:{},orderby:"name asc",top:e})).value.map(l=>({id:l.businessunitid,name:l.name,parentBusinessUnitId:l.parentbusinessunitid??null,isDisabled:l.isdisabled,createdOn:l.createdon}));return u(`${s.length} business units found`,{businessUnits:s,count:s.length},["Use business unit IDs for user management or security role assignment"])}default:throw new Error(`Unknown org tool: ${a}`)}}import{z as U}from"zod";var lt=/^[a-zA-Z0-9_]+$/,dt=/\.\.|[/\\]/,tn=U.object({entitySetName:U.string().min(1).refine(a=>!dt.test(a),{message:"entitySetName must not contain path traversal characters"}),recordId:U.string().uuid(),columnName:U.string().min(1).refine(a=>lt.test(a),{message:"columnName must be alphanumeric/underscore only"}),fileContent:U.string().min(1).describe("Base64-encoded file content"),fileName:U.string().min(1)}),an=U.object({entitySetName:U.string().min(1).refine(a=>!dt.test(a),{message:"entitySetName must not contain path traversal characters"}),recordId:U.string().uuid(),columnName:U.string().min(1).refine(a=>lt.test(a),{message:"columnName must be alphanumeric/underscore only"})}),ct=[{name:"dataverse_upload_file_column",description:"Uploads a file to a Dataverse file column. Provide the entity set name, record GUID, column name, base64-encoded file content, and file name. The file is stored in the specified file-type column on the record. WHEN TO USE: Uploading a file to a file-type column on a Dataverse record. BEST PRACTICES: Base64-encode the file content; verify the column is a file-type column via dataverse_get_table_metadata. WORKFLOW: file_operations.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name (e.g., "accounts")'},recordId:{type:"string",description:"Record GUID"},columnName:{type:"string",description:"File column logical name"},fileContent:{type:"string",description:"Base64-encoded file content"},fileName:{type:"string",description:'File name including extension (e.g., "report.pdf")'}},required:["entitySetName","recordId","columnName","fileContent","fileName"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_download_file_column",description:"Downloads a file from a Dataverse file column. Returns the file content as a base64-encoded string along with the file name and size. WHEN TO USE: Downloading a file stored in a file-type column on a Dataverse record. BEST PRACTICES: The response is base64-encoded; decode before saving or processing. WORKFLOW: file_operations.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name (e.g., "accounts")'},recordId:{type:"string",description:"Record GUID"},columnName:{type:"string",description:"File column logical name"}},required:["entitySetName","recordId","columnName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function ut(a,r,o){let e=o.http;switch(a){case"dataverse_upload_file_column":{let{entitySetName:t,recordId:n,columnName:i,fileContent:s,fileName:l}=tn.parse(r),d=Buffer.from(s,"base64"),c=`${t}(${n})/${i}`;return await e.patch(c,d,{headers:{"Content-Type":"application/octet-stream","x-ms-file-name":l}}),u(`Uploaded file to ${i} on ${t}(${n})`,{success:!0,entitySetName:t,recordId:n,columnName:i,fileName:l,sizeBytes:d.length},["Use dataverse_download_file_column to retrieve the file"])}case"dataverse_download_file_column":{let{entitySetName:t,recordId:n,columnName:i}=an.parse(r),s=`${t}(${n})/${i}/$value`,l=await e.get(s,{responseType:"text"}),d=l.data,c=Buffer.from(d,"binary").toString("base64"),m=l.headers["x-ms-file-name"]??l.headers["content-disposition"]?.match(/filename="?([^";\n]+)"?/)?.[1]??"download",p=parseInt(l.headers["content-length"]??"0",10)||c.length;return u(`Downloaded file from ${i} on ${t}(${n})`,{entitySetName:t,recordId:n,columnName:i,fileName:m,sizeBytes:p,contentBase64:c})}default:throw new Error(`Unknown file tool: ${a}`)}}import{z as D}from"zod";var nn={0:"Owner",1:"Access",2:"Office",3:"Security"},rn=D.object({top:D.number().int().positive().max(200).optional().default(50),teamType:D.union([D.literal(0),D.literal(1),D.literal(2),D.literal(3)]).optional()}),on=D.object({teamId:D.string().uuid(),roleId:D.string().uuid(),confirm:D.literal(!0,{errorMap:()=>({message:"confirm must be true to assign a role to a team"})})}),pt=[{name:"dataverse_list_teams",description:"Lists Dataverse teams in the environment. Useful for finding team owners for record assignment and sharing. teamtype: 0=Owner, 1=Access, 2=AAD Office Group, 3=AAD Security Group. WHEN TO USE: Finding team IDs for record assignment or sharing. BEST PRACTICES: Filter by teamType to distinguish owner, access, and AAD group teams. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Maximum number of teams to return (1\u2013200, default 50)"},teamType:{type:"number",enum:[0,1,2,3],description:"Filter by team type: 0=Owner, 1=Access, 2=Office Group, 3=Security Group"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_assign_role_to_team",description:"Assigns a security role to a Dataverse team. All team members inherit the role permissions. Use dataverse_list_roles to find the role GUID and dataverse_list_teams to find the team GUID. WARNING: This modifies team permissions for ALL members. Set confirm=true to proceed. WHEN TO USE: Providing role-based permissions to an entire team during configuration. BEST PRACTICES: Prefer team-based RBAC over individual user assignments for maintainability. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{teamId:{type:"string",description:"GUID of the team"},roleId:{type:"string",description:"GUID of the security role to assign"},confirm:{type:"boolean",description:"Must be true to proceed with role assignment"}},required:["teamId","roleId","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function mt(a,r,o){switch(a){case"dataverse_list_teams":{let{top:e,teamType:t}=rn.parse(r),i={select:["teamid","name","teamtype","description","isdefault","createdon","_businessunitid_value"],top:e,orderby:"name asc"};t!==void 0&&(i.filter=`teamtype eq ${t}`);let l=(await o.query("teams",i)).value.map(d=>({...d,teamTypeName:nn[d.teamtype]??"Unknown"}));return u(`${l.length} teams found`,{teams:l,count:l.length},["Use dataverse_assign with a team ID to assign records to a team"])}case"dataverse_assign_role_to_team":{let{teamId:e,roleId:t}=on.parse(r);try{await o.associate("teams",e,"teamroles_association","roles",t)}catch(n){let i=n instanceof Error?n.message:String(n);if(i.toLowerCase().includes("duplicate")||i.includes("0x80040237"))return u("Role is already assigned to this team.",{teamId:e,roleId:t,status:"already_assigned"},["Use dataverse_list_teams to view current team configuration"]);throw n}return u("Role assigned to team successfully.",{teamId:e,roleId:t,status:"assigned"},["All members of this team now inherit the assigned role"])}default:throw new Error(`Unknown team tool: ${a}`)}}var V={dataverse_query:["query","read","odata"],dataverse_execute_fetchxml:["query","read","fetchxml","aggregate"],dataverse_create:["write","crud","create"],dataverse_update:["write","crud","update"],dataverse_delete:["write","crud","delete","destructive"],dataverse_get:["read","crud","get"],dataverse_search:["search","read","fulltext"],dataverse_list_tables:["metadata","schema","read"],dataverse_get_table_metadata:["metadata","schema","read"],dataverse_get_relationships:["metadata","schema","relations","read"],dataverse_list_views:["metadata","views","read"],dataverse_get_view_definition:["metadata","views","read"],dataverse_batch_execute:["write","bulk","batch"],dataverse_whoami:["auth","identity","read"],dataverse_list_solutions:["solutions","read","alm"],dataverse_get_solution_components:["solutions","read","alm"],dataverse_export_solution:["solutions","write","alm"],dataverse_import_solution:["solutions","write","alm"],dataverse_track_changes:["sync","delta","read"],dataverse_execute_action:["actions","write","custom"],dataverse_execute_bound_action:["actions","write","custom"],dataverse_publish_customizations:["customization","write"],dataverse_upsert:["write","crud","upsert"],dataverse_count:["query","read","count"],dataverse_retrieve_multiple_with_paging:["query","read","paging"],dataverse_audit_get_history:["audit","read"],dataverse_audit_get_detail:["audit","read"],dataverse_list_users:["admin","users","read"],dataverse_get_user_roles:["admin","users","security","read"],dataverse_get_user_teams:["admin","users","teams","read"],dataverse_list_teams:["admin","teams","read"],dataverse_get_team_members:["admin","teams","read"],dataverse_upload_file:["files","write","upload"],dataverse_download_file:["files","read","download"],dataverse_delete_file:["files","write","delete"],dataverse_associate:["relations","write"],dataverse_disassociate:["relations","write"],dataverse_impersonate:["security","admin"],dataverse_impersonate_clear:["security","admin"],dataverse_list_environments:["admin","environments","read"],dataverse_get_environment_details:["admin","environments","read"],dataverse_get_environment_settings:["admin","environments","read"],dataverse_get_trace_logs:["debug","trace","read"],dataverse_get_plugin_types:["debug","plugins","read"],dataverse_get_sdkmessageprocessingsteps:["debug","plugins","read"],dataverse_get_workflow_definitions:["debug","workflows","read"],dataverse_validate_entity:["quality","read","validation"],dataverse_list_duplicate_rules:["quality","read"],dataverse_list_notes:["notes","read"],dataverse_create_note:["notes","write"],dataverse_get_org_details:["admin","org","read"],dataverse_get_org_settings:["admin","org","read"],dataverse_get_global_option_set:["metadata","schema","read"],dataverse_publish_component:["customization","write"],dataverse_get_entity_xml:["customization","metadata","read"],dataverse_create_attribute:["metadata","schema","write","attribute"],dataverse_update_attribute:["metadata","schema","write","attribute"],dataverse_delete_attribute:["metadata","schema","write","attribute","destructive"],dataverse_create_lookup_attribute:["metadata","schema","write","attribute","relations"],dataverse_detect_duplicates:["quality","read","validation"]},le={dataverse_query:"Query Dataverse tables using OData syntax",dataverse_execute_fetchxml:"Execute FetchXML queries with aggregation support",dataverse_create:"Create a new record in a Dataverse table",dataverse_update:"Update an existing Dataverse record",dataverse_delete:"Delete a Dataverse record",dataverse_get:"Retrieve a single record by ID",dataverse_search:"Full-text search across Dataverse tables",dataverse_list_tables:"List available Dataverse tables",dataverse_get_table_metadata:"Get column definitions for a table",dataverse_get_relationships:"Get relationships for a table",dataverse_list_views:"List saved views for a table",dataverse_get_view_definition:"Get the definition of a saved view",dataverse_batch_execute:"Execute multiple operations in a batch",dataverse_whoami:"Get current authenticated user context",dataverse_list_solutions:"List solutions in the environment",dataverse_get_solution_components:"Get components of a solution",dataverse_export_solution:"Export a solution as a ZIP file",dataverse_import_solution:"Import a solution from a ZIP file",dataverse_track_changes:"Track changes (delta sync) for a table",dataverse_execute_action:"Execute a custom unbound action",dataverse_execute_bound_action:"Execute a custom bound action",dataverse_publish_customizations:"Publish all customizations",dataverse_upsert:"Create or update a record by alternate key",dataverse_count:"Count records in a table",dataverse_retrieve_multiple_with_paging:"Query with automatic paging",dataverse_audit_get_history:"Get audit history for a record",dataverse_audit_get_detail:"Get audit detail for a specific change",dataverse_list_users:"List system users",dataverse_get_user_roles:"Get security roles for a user",dataverse_get_user_teams:"Get teams a user belongs to",dataverse_list_teams:"List teams in the environment",dataverse_get_team_members:"Get members of a team",dataverse_upload_file:"Upload a file to a record",dataverse_download_file:"Download a file from a record",dataverse_delete_file:"Delete a file from a record",dataverse_associate:"Associate two records via a relationship",dataverse_disassociate:"Remove association between two records",dataverse_impersonate:"Set impersonation for subsequent calls",dataverse_impersonate_clear:"Clear impersonation",dataverse_list_environments:"List available environments",dataverse_get_environment_details:"Get environment details",dataverse_get_environment_settings:"Get environment settings",dataverse_get_trace_logs:"Get plugin trace logs",dataverse_get_plugin_types:"Get registered plugin types",dataverse_get_sdkmessageprocessingsteps:"Get SDK message processing steps",dataverse_get_workflow_definitions:"Get workflow/flow definitions",dataverse_validate_entity:"Validate entity configuration quality",dataverse_list_duplicate_rules:"List duplicate detection rules",dataverse_list_notes:"List notes/annotations on a record",dataverse_create_note:"Create a note on a record",dataverse_get_org_details:"Get organization details",dataverse_get_org_settings:"Get organization settings",dataverse_get_global_option_set:"Get a global option set definition",dataverse_publish_component:"Publish a single component",dataverse_get_entity_xml:"Get entity customization XML",dataverse_create_attribute:"Create a column on a Dataverse table",dataverse_update_attribute:"Update mutable properties of a column",dataverse_delete_attribute:"Delete a column and all its data from a table",dataverse_create_lookup_attribute:"Create a Lookup column via a One-to-Many relationship",dataverse_detect_duplicates:"Check for potential duplicate records before creating"};function sn(a){return a.toLowerCase().replace(/[^a-z0-9_]/g," ").split(/\s+/).filter(r=>r.length>1)}function ln(a,r){let o=V[a]??[],e=(le[a]??"").toLowerCase(),t=a.toLowerCase(),n=0;for(let i of r)o.includes(i)&&(n+=3),t.includes(i)&&(n+=2),e.includes(i)&&(n+=1);return n}function dn(a){let r=sn(a);if(r.length===0)return["dataverse_whoami","dataverse_list_tables","dataverse_query","dataverse_search","dataverse_get_table_metadata"].map(t=>({name:t,description:le[t]??"",tags:V[t]??[],score:1}));let o=[];for(let e of Object.keys(V)){let t=ln(e,r);t>0&&o.push({name:e,description:le[e]??"",tags:V[e]??[],score:t})}return o.sort((e,t)=>t.score-e.score),o.slice(0,5)}function cn(){let a=new Map;for(let r of Object.values(V))for(let o of r)a.set(o,(a.get(o)??0)+1);return Array.from(a.entries()).map(([r,o])=>({tag:r,toolCount:o})).sort((r,o)=>o.toolCount-r.toolCount)}var ft=[{name:"dataverse_suggest_tools",description:"Suggests the most relevant Dataverse tools for a given intent. Provide a natural-language description of what you want to do and this tool returns the top 5 matching tools with descriptions and tags.",inputSchema:{type:"object",properties:{intent:{type:"string",description:"Natural language description of the desired action"}},required:["intent"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1}},{name:"dataverse_list_tool_tags",description:"Lists all available tool tags with the number of tools in each category. Use this to discover what kinds of operations are available.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1}}];async function gt(a,r,o){if(a==="dataverse_suggest_tools"){let{intent:e}=r??{},t=dn(e??""),n=t.length>0?[`Try: ${t[0].name}`]:["Use dataverse_list_tool_tags to explore categories"];return u(`${t.length} tools match intent "${e??""}"`,t,n)}if(a==="dataverse_list_tool_tags"){let e=cn();return H("tags",e,["Use dataverse_suggest_tools with an intent to find specific tools"])}throw new Error(`Unknown router tool: ${a}`)}var un=[{uriTemplate:"dataverse://tables/{tableName}/schema",name:"Table Schema",description:"Returns the full schema (columns, types, requirements) for a Dataverse table",mimeType:"application/json"},{uriTemplate:"dataverse://tables/{tableName}/relationships",name:"Table Relationships",description:"Returns all 1:N and N:N relationships for a Dataverse table",mimeType:"application/json"}],pn=[{uri:"dataverse://tables",name:"Available Tables",description:"Lists all custom tables in the connected Dataverse environment",mimeType:"application/json"},{uri:"dataverse://server/instructions",name:"Server Instructions",description:"Usage guidelines and best practices for interacting with this Dataverse MCP server",mimeType:"text/plain"}];function mn(a){let r="dataverse://";if(!a.startsWith(r))throw new Error(`Unknown resource URI: ${a}`);let o=a.slice(r.length);if(o==="tables")return{type:"tables"};if(o==="server/instructions")return{type:"instructions"};let e=/^tables\/([^/]+)\/schema$/.exec(o);if(e)return{type:"schema",tableName:e[1]};let t=/^tables\/([^/]+)\/relationships$/.exec(o);if(t)return{type:"relationships",tableName:t[1]};throw new Error(`Unknown resource URI: ${a}`)}function yt(){return pn}function ht(){return un}async function vt(a,r,o){let e=mn(a);switch(e.type){case"tables":{let t=await r.listTables(!0);return{uri:a,mimeType:"application/json",text:JSON.stringify(t,null,2)}}case"schema":{let t=await r.getTableMetadata(e.tableName);return{uri:a,mimeType:"application/json",text:JSON.stringify(t,null,2)}}case"relationships":{let t=await r.getRelationships(e.tableName);return{uri:a,mimeType:"application/json",text:JSON.stringify(t,null,2)}}case"instructions":return{uri:a,mimeType:"text/plain",text:o}}}var J=new Map([["query_data",{name:"query_data",description:"Query data from Dataverse tables. Authenticate, discover tables, inspect schema, then query with OData or FetchXML.",tags:["query","data","fetchxml","odata","read"],steps:[{order:1,tool:"dataverse_whoami",description:"Verify authentication and get user context",required:!0},{order:2,tool:"dataverse_list_tables",description:"Discover available tables",required:!0,tips:"Use customOnly=true to focus on custom tables"},{order:3,tool:"dataverse_get_table_metadata",description:"Inspect column names, types, and required fields",required:!0,tips:"Note logical names for use in $select and $filter"},{order:4,tool:"dataverse_query",description:"Execute OData query or use dataverse_execute_fetchxml for complex joins",required:!0,tips:"Always use $select to limit columns; use $top to limit rows"}]}],["explore_schema",{name:"explore_schema",description:"Explore the Dataverse schema: tables, columns, relationships, and saved views.",tags:["schema","metadata","tables","relationships","views"],steps:[{order:1,tool:"dataverse_whoami",description:"Verify authentication",required:!0},{order:2,tool:"dataverse_list_tables",description:"List all available tables",required:!0},{order:3,tool:"dataverse_get_table_metadata",description:"Get detailed column metadata for a table",required:!0},{order:4,tool:"dataverse_get_relationships",description:"Discover one-to-many and many-to-many relationships",required:!1,tips:"Useful before building FetchXML joins"},{order:5,tool:"dataverse_list_views",description:"List saved views for the table",required:!1}]}],["create_record",{name:"create_record",description:"Create a new record in Dataverse. Inspect schema first to know required fields, then create and verify.",tags:["create","record","write","insert"],steps:[{order:1,tool:"dataverse_get_table_metadata",description:"Check required fields and column types before creating",required:!0,tips:"Pay attention to required fields and lookup columns"},{order:2,tool:"dataverse_create",description:"Create the new record",required:!0},{order:3,tool:"dataverse_query",description:"Verify the record was created with correct values",required:!1,tips:"Query by the returned ID to confirm field values"}]}],["update_record",{name:"update_record",description:"Update an existing record. Read current values, apply changes, then verify the update.",tags:["update","record","write","modify"],steps:[{order:1,tool:"dataverse_get_table_metadata",description:"Confirm column names and types",required:!0},{order:2,tool:"dataverse_get",description:"Read current record values and etag",required:!0,tips:"Capture @odata.etag for optimistic concurrency"},{order:3,tool:"dataverse_update",description:"Apply the update with etag for concurrency control",required:!0},{order:4,tool:"dataverse_get",description:"Verify the update was applied correctly",required:!1}]}],["delete_record",{name:"delete_record",description:"Delete a record from Dataverse. Read the record first to confirm identity, then delete.",tags:["delete","record","remove"],steps:[{order:1,tool:"dataverse_get",description:"Read the record to confirm it is the correct one",required:!0,tips:"Show record details to the user before deletion"},{order:2,tool:"dataverse_delete",description:"Delete the record (irreversible)",required:!0,tips:"Always confirm with the user before executing this step"}]}],["bulk_operations",{name:"bulk_operations",description:"Perform bulk create/update/delete using Dataverse batch API for efficiency.",tags:["bulk","batch","mass","multiple"],steps:[{order:1,tool:"dataverse_get_table_metadata",description:"Inspect schema to build correct request payloads",required:!0},{order:2,tool:"dataverse_batch_execute",description:"Execute batch of operations in a single request",required:!0,tips:"Group up to 1000 operations per batch; use changesets for transactional groups"}]}],["search_data",{name:"search_data",description:"Full-text search across Dataverse tables, then refine results with targeted queries.",tags:["search","find","fulltext","relevance"],steps:[{order:1,tool:"dataverse_search",description:"Execute full-text search across multiple tables",required:!0,tips:"Use entities filter to narrow which tables to search"},{order:2,tool:"dataverse_query",description:"Refine results with a targeted OData query on the relevant table",required:!1}]}],["manage_solution",{name:"manage_solution",description:"Inspect and manage Dataverse solutions and their components.",tags:["solution","customization","deployment","components"],steps:[{order:1,tool:"dataverse_list_solutions",description:"List all solutions in the environment",required:!0},{order:2,tool:"dataverse_solution_components",description:"List components within a specific solution",required:!0},{order:3,tool:"dataverse_publish_customizations",description:"Publish customizations after changes",required:!1,tips:"Required after modifying solution components"}]}],["inspect_audit",{name:"inspect_audit",description:"Review audit history for records or tables to track changes and user activity.",tags:["audit","history","changes","tracking"],steps:[{order:1,tool:"dataverse_get_audit_log",description:"Retrieve audit entries filtered by record, table, user, or date range",required:!0,tips:"Use at least one filter to avoid large result sets; audit must be enabled on the table"}]}],["file_operations",{name:"file_operations",description:"Upload or download files from Dataverse file/image columns.",tags:["file","upload","download","image","attachment"],steps:[{order:1,tool:"dataverse_get_table_metadata",description:"Identify file or image columns on the table",required:!0,tips:"Look for columns of type File or Image"},{order:2,tool:"dataverse_upload_file_column",description:"Upload a file to a file/image column",required:!1},{order:3,tool:"dataverse_download_file_column",description:"Download a file from a file/image column",required:!1,tips:"Returns base64-encoded content"}]}]]);var _t=[{name:"dataverse_list_guides",description:"Lists all available step-by-step guided workflows for common Dataverse tasks (query_data, create_record, manage_solution, etc.). Use this to discover recommended MCP patterns. NOTE: these are MCP-internal task guides, NOT Dataverse automation processes \u2014 use dataverse_list_workflows to list actual Dataverse flows/workflows.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}},{name:"dataverse_get_guide",description:"Returns the full definition of an MCP task guide including ordered steps, tool names, tips, and required flags. Use this to get a step-by-step plan for a common Dataverse task. NOTE: these are MCP-internal guides \u2014 use dataverse_get_workflow to retrieve an actual Dataverse process.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Guide name (e.g. query_data, explore_schema, create_record, update_record, delete_record, bulk_operations, search_data, manage_solution, inspect_audit, file_operations)"}},required:["name"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}},{name:"dataverse_list_workflows",description:"Lists automation processes stored in the Dataverse environment: Power Automate cloud flows, classic workflows, business rules, business process flows, and actions. Optionally filter by category or partial name.",inputSchema:{type:"object",properties:{category:{type:"number",description:"Filter by process category: 0=Classic Workflow, 1=Dialog, 2=Business Rule, 3=Action, 4=Business Process Flow, 6=Power Automate (Cloud Flow). Omit to list all categories."},nameContains:{type:"string",description:"Filter by partial name match (case-insensitive contains)."},top:{type:"number",description:"Maximum number of results to return (default 50)."}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}},{name:"dataverse_get_workflow",description:"Returns full details of a Dataverse automation process (workflow, cloud flow, business rule, or action) by its GUID.",inputSchema:{type:"object",properties:{workflowId:{type:"string",description:"GUID of the workflow/process record"}},required:["workflowId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}}],bt={0:"Classic Workflow",1:"Dialog",2:"Business Rule",3:"Action",4:"Business Process Flow",6:"Power Automate (Cloud Flow)"};async function wt(a,r,o){if(a==="dataverse_list_guides"){let e=Array.from(J.values()).map(t=>({name:t.name,description:t.description,tags:t.tags,stepCount:t.steps.length}));return H("guides",e,["Use dataverse_get_guide with a guide name to see detailed steps"])}if(a==="dataverse_get_guide"){let{name:e}=r,t=J.get(e);if(!t){let n=Array.from(J.keys()).join(", ");throw new Error(`Unknown guide: "${e}". Available guides: ${n}`)}return u(`Guide "${t.name}": ${t.description}`,t,t.steps.map(n=>`Step ${n.order}: ${n.tool} \u2014 ${n.description}`))}if(a==="dataverse_list_workflows"){let e=r,n=(await o.listDataverseWorkflows({...e.category!==void 0?{category:e.category}:{},...e.nameContains!==void 0?{nameContains:e.nameContains}:{},top:Math.min(e.top??50,200)})).map(i=>({workflowId:i.workflowid,name:i.name,category:bt[i.category]??i.category,state:i.statecode===1?"Active":"Inactive",modifiedOn:i.modifiedon}));return H(`Dataverse workflows (${n.length} found)`,n,["Use dataverse_get_workflow with a workflowId GUID for full details","Filter with category: 0=Classic, 2=Business Rule, 4=BPF, 6=Cloud Flow"])}if(a==="dataverse_get_workflow"){let{workflowId:e}=r,t=await o.getDataverseWorkflow(e),n=t.category,i={...t,categoryLabel:bt[n]??`Category ${n}`,stateLabel:t.statecode===1?"Active":"Inactive"};return u(`Workflow: ${t.name}`,i,[])}throw new Error(`Unknown workflow tool: ${a}`)}import{z as f}from"zod";var W=/^[a-z_][a-z0-9_]*$/,de=["String","Memo","Integer","Decimal","Money","DateTime","Boolean","Picklist","MultiSelectPicklist","AutoNumber","Image"],fn={String:"Microsoft.Dynamics.CRM.StringAttributeMetadata",Memo:"Microsoft.Dynamics.CRM.MemoAttributeMetadata",Integer:"Microsoft.Dynamics.CRM.IntegerAttributeMetadata",Decimal:"Microsoft.Dynamics.CRM.DecimalAttributeMetadata",Money:"Microsoft.Dynamics.CRM.MoneyAttributeMetadata",DateTime:"Microsoft.Dynamics.CRM.DateTimeAttributeMetadata",Boolean:"Microsoft.Dynamics.CRM.BooleanAttributeMetadata",Picklist:"Microsoft.Dynamics.CRM.PicklistAttributeMetadata",MultiSelectPicklist:"Microsoft.Dynamics.CRM.MultiSelectPicklistAttributeMetadata",AutoNumber:"Microsoft.Dynamics.CRM.StringAttributeMetadata",Image:"Microsoft.Dynamics.CRM.ImageAttributeMetadata"},Tt=f.object({entityLogicalName:f.string().min(1).regex(W,"Invalid Dataverse logical name"),schemaName:f.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/,"Invalid schema name"),attributeType:f.enum(de),displayName:f.string().min(1),description:f.string().optional(),requiredLevel:f.enum(["None","ApplicationRequired","Recommended"]).optional().default("None"),maxLength:f.number().int().positive().optional(),minValue:f.number().optional(),maxValue:f.number().optional(),precision:f.number().int().min(0).max(10).optional(),dateTimeFormat:f.enum(["DateOnly","DateAndTime"]).optional().default("DateAndTime"),defaultBooleanValue:f.boolean().optional().default(!1),picklistOptions:f.array(f.object({value:f.number().int(),label:f.string().min(1)})).optional(),autoNumberFormat:f.string().optional(),languageCode:f.number().int().optional().default(1033),autoPublish:f.boolean().optional().default(!0),confirm:f.literal(!0,{errorMap:()=>({message:"Set confirm: true to create a column"})})}).refine(a=>a.attributeType!=="Picklist"&&a.attributeType!=="MultiSelectPicklist"||a.picklistOptions&&a.picklistOptions.length>0,{message:"picklistOptions is required for Picklist and MultiSelectPicklist types and must have at least one option"}),St=f.object({entityLogicalName:f.string().min(1).regex(W,"Invalid Dataverse logical name"),attributeLogicalName:f.string().min(1).regex(W,"Invalid Dataverse logical name"),displayName:f.string().min(1).optional(),description:f.string().optional(),requiredLevel:f.enum(["None","ApplicationRequired","Recommended"]).optional(),maxLength:f.number().int().positive().optional(),isSearchable:f.boolean().optional(),languageCode:f.number().int().optional().default(1033),autoPublish:f.boolean().optional().default(!0),confirm:f.literal(!0,{errorMap:()=>({message:"Set confirm: true to update column metadata"})})}).refine(a=>a.displayName!==void 0||a.description!==void 0||a.requiredLevel!==void 0||a.maxLength!==void 0||a.isSearchable!==void 0,{message:"At least one mutable property (displayName, description, requiredLevel, maxLength, isSearchable) must be provided"}),Nt=f.object({entityLogicalName:f.string().min(1).regex(W,"Invalid Dataverse logical name"),attributeLogicalName:f.string().min(1).regex(W,"Invalid Dataverse logical name"),autoPublish:f.boolean().optional().default(!0),confirm:f.literal(!0,{errorMap:()=>({message:"Set confirm: true to delete a column \u2014 this is irreversible"})})});function E(a,r){return{"@odata.type":"Microsoft.Dynamics.CRM.Label",LocalizedLabels:[{"@odata.type":"Microsoft.Dynamics.CRM.LocalizedLabel",Label:a,LanguageCode:r}]}}function Rt(a){let r=a.languageCode,o={"@odata.type":fn[a.attributeType],SchemaName:a.schemaName,DisplayName:E(a.displayName,r),RequiredLevel:{Value:a.requiredLevel}};switch(a.description&&(o.Description=E(a.description,r)),a.attributeType){case"String":o.MaxLength=a.maxLength??100;break;case"Memo":o.MaxLength=a.maxLength??4e3;break;case"Integer":o.Format="None",a.minValue!==void 0&&(o.MinValue=a.minValue),a.maxValue!==void 0&&(o.MaxValue=a.maxValue);break;case"Decimal":a.precision!==void 0&&(o.Precision=a.precision),a.minValue!==void 0&&(o.MinValue=a.minValue),a.maxValue!==void 0&&(o.MaxValue=a.maxValue);break;case"Money":o.PrecisionSource=a.precision!==void 0?0:2,a.precision!==void 0&&(o.Precision=a.precision);break;case"DateTime":o.Format=a.dateTimeFormat;break;case"Boolean":o.DefaultValue=a.defaultBooleanValue,o.OptionSet={TrueOption:{Value:1,Label:E("Yes",r)},FalseOption:{Value:0,Label:E("No",r)}};break;case"Picklist":o.OptionSet={"@odata.type":"Microsoft.Dynamics.CRM.OptionSetMetadata",IsGlobal:!1,OptionSetType:"Picklist",Options:a.picklistOptions.map(e=>({Value:e.value,Label:E(e.label,r)}))};break;case"MultiSelectPicklist":o.OptionSet={"@odata.type":"Microsoft.Dynamics.CRM.OptionSetMetadata",IsGlobal:!1,Options:a.picklistOptions.map(e=>({Value:e.value,Label:E(e.label,r)}))};break;case"AutoNumber":o.MaxLength=a.maxLength??100,a.autoNumberFormat&&(o.AutoNumberFormat=a.autoNumberFormat);break;case"Image":break}return o}var xt=f.object({entityLogicalName:f.string().min(1).regex(W),schemaName:f.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/),displayName:f.string().min(1),description:f.string().optional(),referencedEntity:f.string().min(1).regex(W),requiredLevel:f.enum(["None","ApplicationRequired","Recommended"]).optional().default("None"),cascadeConfiguration:f.enum(["Referential","Parental"]).optional().default("Referential"),languageCode:f.number().int().optional().default(1033),autoPublish:f.boolean().optional().default(!0),confirm:f.literal(!0,{errorMap:()=>({message:"Set confirm: true to create a lookup column"})})});function At(a){let r=a.languageCode,o=a.schemaName.includes("_")?a.schemaName.slice(0,a.schemaName.indexOf("_")):a.schemaName,e=a.schemaName.includes("_")?a.schemaName.slice(a.schemaName.indexOf("_")+1):a.schemaName,t=`${o}_${a.referencedEntity}_${a.entityLogicalName}_${e}`;if(t.length>100)throw new Error(`Auto-generated relationship SchemaName '${t}' is ${t.length} chars, exceeding Dataverse's 100-char limit. Use shorter entity logical names or column schema names.`);let n={"@odata.type":"Microsoft.Dynamics.CRM.LookupAttributeMetadata",AttributeType:"Lookup",AttributeTypeName:{Value:"LookupType"},SchemaName:a.schemaName,DisplayName:E(a.displayName,r),RequiredLevel:{Value:a.requiredLevel}};return a.description&&(n.Description=E(a.description,r)),{"@odata.type":"Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",SchemaName:t,ReferencedEntity:a.referencedEntity,ReferencedAttribute:`${a.referencedEntity}id`,ReferencingEntity:a.entityLogicalName,Lookup:n,CascadeConfiguration:a.cascadeConfiguration==="Parental"?{Assign:"Cascade",Delete:"Cascade",Merge:"Cascade",Reparent:"Cascade",Share:"Cascade",Unshare:"Cascade"}:{Assign:"NoCascade",Delete:"RemoveLink",Merge:"NoCascade",Reparent:"NoCascade",Share:"NoCascade",Unshare:"NoCascade"},AssociatedMenuConfiguration:{Behavior:"UseCollectionName",Group:"Details",Label:E(a.displayName,r),Order:1e4}}}var ce=[{name:"dataverse_create_attribute",description:"Creates a new column (attribute) on an existing Dataverse table. Supports String, Memo, Integer, Decimal, Money, DateTime, Boolean, Picklist, MultiSelectPicklist, AutoNumber, and Image types. IMPORTANT: Column type CANNOT be changed after creation \u2014 choose carefully. Requires System Customizer or System Administrator privileges. WHEN TO USE: Adding a new column to a table. BEST PRACTICES: Use dataverse_get_table_metadata first to check existing columns. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Logical name of the target table (e.g. 'account', 'new_mytable')"},schemaName:{type:"string",description:"Schema name for the new column (e.g. 'new_mycolumn'). Must include publisher prefix."},attributeType:{type:"string",enum:de,description:"Column data type. CANNOT be changed after creation. String=single-line text, Memo=multi-line, Integer=whole number, Decimal=decimal number, Money=currency, DateTime=date/time, Boolean=yes/no, Picklist=choice/option set, MultiSelectPicklist=multi-choice, AutoNumber=auto-generated sequence, Image=image file."},displayName:{type:"string",description:"Display label for the column"},description:{type:"string",description:"Optional description of the column"},requiredLevel:{type:"string",enum:["None","ApplicationRequired","Recommended"],description:"Required level. Default: None"},maxLength:{type:"number",description:"Max length for String (default 100, max 4000) or Memo (default 4000, max 1048576) types"},minValue:{type:"number",description:"Minimum value for Integer or Decimal types"},maxValue:{type:"number",description:"Maximum value for Integer or Decimal types"},precision:{type:"number",description:"Decimal precision for Decimal (0-10) or Money types"},dateTimeFormat:{type:"string",enum:["DateOnly","DateAndTime"],description:"Format for DateTime type. CANNOT be changed after creation. Default: DateAndTime"},defaultBooleanValue:{type:"boolean",description:"Default value for Boolean type. Default: false"},picklistOptions:{type:"array",items:{type:"object",properties:{value:{type:"number",description:"Integer value for the option"},label:{type:"string",description:"Display label for the option"}},required:["value","label"]},description:"Options for Picklist and MultiSelectPicklist types. Each option needs a value (integer) and label (text)."},autoNumberFormat:{type:"string",description:"Auto-number format string for AutoNumber type (e.g. 'INV-{SEQNUM:5}'). Only used when attributeType=AutoNumber."},languageCode:{type:"number",description:"Language code for labels. Default: 1033 (English)"},autoPublish:{type:"boolean",description:"Publish the customization after creation (default: true)."},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional schema modification"}},required:["entityLogicalName","schemaName","attributeType","displayName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_update_attribute",description:"Updates mutable properties of an existing column (attribute): display name, description, required level, max length (increase only for String/Memo), and search indexing. CANNOT change: column type, logical name, DateTime format, or lookup targets \u2014 these are immutable after creation. Requires System Customizer or System Administrator privileges. WHEN TO USE: Changing a column's label, description, or required level. BEST PRACTICES: Use dataverse_get_table_metadata first to see current values. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Logical name of the table"},attributeLogicalName:{type:"string",description:"Logical name of the column to update"},displayName:{type:"string",description:"New display label for the column"},description:{type:"string",description:"New description for the column"},requiredLevel:{type:"string",enum:["None","ApplicationRequired","Recommended"],description:"New required level"},maxLength:{type:"number",description:"New max length for String/Memo columns. Can only INCREASE, never decrease."},isSearchable:{type:"boolean",description:"Enable or disable Dataverse Search indexing on this column"},languageCode:{type:"number",description:"Language code for labels. Default: 1033 (English)"},autoPublish:{type:"boolean",description:"Publish the customization after update (default: true)."},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional schema modification"}},required:["entityLogicalName","attributeLogicalName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_delete_attribute",description:"Deletes a column (attribute) from a Dataverse table. WARNING: This permanently deletes the column AND all its data. Automatically checks dependencies (views, workflows, forms) before deletion \u2014 refuses if dependencies exist unless force=true. Managed solution columns cannot be deleted. WHEN TO USE: Removing an obsolete custom column. BEST PRACTICES: Use dataverse_get_table_metadata to verify the column exists; check dependencies first. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Logical name of the table"},attributeLogicalName:{type:"string",description:"Logical name of the column to delete"},autoPublish:{type:"boolean",description:"Publish the customization after deletion (default: true)."},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional deletion of column and ALL its data"}},required:["entityLogicalName","attributeLogicalName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!0,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_create_lookup_attribute",description:"Creates a Lookup column on a Dataverse table by creating a One-to-Many relationship. Use this for typed relationship columns (e.g. 'Account' field on a custom table pointing to the account table). IMPORTANT: Creates both the relationship AND the lookup column in one operation. cascadeConfiguration defaults to 'Referential' (NoCascade on Assign/Reparent/Share/Unshare, RemoveLink on Delete). Use 'Parental' only when the source table has no existing parental relationship with the target. Requires System Customizer or System Administrator privileges.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Source table logical name (referencing)"},schemaName:{type:"string",description:"Schema name for the lookup column (e.g. 'new_accountid')"},displayName:{type:"string",description:"Display label"},description:{type:"string",description:"Optional description"},referencedEntity:{type:"string",description:"Target table logical name (e.g. 'account')"},requiredLevel:{type:"string",enum:["None","ApplicationRequired","Recommended"],description:"Required level. Default: None"},languageCode:{type:"number",description:"Language code. Default: 1033"},cascadeConfiguration:{type:"string",enum:["Referential","Parental"],description:"Cascade behavior. 'Referential' (default): NoCascade on most actions, RemoveLink on Delete \u2014 works on any table pair. 'Parental': full Cascade \u2014 only if no parental relation exists yet with the target."},autoPublish:{type:"boolean",description:"Publish after creation. Default: true"},confirm:{type:"boolean",description:"Must be true"}},required:["entityLogicalName","schemaName","displayName","referencedEntity","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function Et(a,r,o){switch(a){case"dataverse_create_attribute":{let e=Tt.parse(r),t=L({toolName:"dataverse_create_attribute",entitySetName:e.entityLogicalName}).map(l=>`[${l.severity.toUpperCase()}] ${l.code}: ${l.message}`),n=Rt(e),i=await o.createAttribute(e.entityLogicalName,n),s="autoPublish=false (skipped)";return e.autoPublish&&(await o.publishCustomizations({entities:[e.entityLogicalName]}),s="published successfully"),u(`Column '${e.schemaName}' (${e.attributeType}) created on '${e.entityLogicalName}'. ${s}.`,{entityLogicalName:e.entityLogicalName,schemaName:e.schemaName,attributeType:e.attributeType,metadataId:i,published:e.autoPublish,...t.length>0&&{warnings:t}},["Use dataverse_get_table_metadata to verify the new column","Column type CANNOT be changed after creation \u2014 to change type, create a new column and migrate data"])}case"dataverse_update_attribute":{let e=St.parse(r),t=L({toolName:"dataverse_update_attribute",entitySetName:e.entityLogicalName}).map(c=>`[${c.severity.toUpperCase()}] ${c.code}: ${c.message}`),n=e.languageCode,i={},s={};e.displayName!==void 0&&(i.DisplayName=E(e.displayName,n),s.DisplayName=e.displayName),e.description!==void 0&&(i.Description=E(e.description,n),s.Description=e.description),e.requiredLevel!==void 0&&(i.RequiredLevel={Value:e.requiredLevel},s.RequiredLevel=e.requiredLevel),e.maxLength!==void 0&&(i.MaxLength=e.maxLength,s.MaxLength=e.maxLength),e.isSearchable!==void 0&&(i.IsSearchable=e.isSearchable,s.IsSearchable=e.isSearchable),await o.updateAttribute(e.entityLogicalName,e.attributeLogicalName,i);let l=Object.entries(s).map(([c,m])=>`${c}=${String(m)}`).join(", "),d="autoPublish=false (skipped)";return e.autoPublish&&(await o.publishCustomizations({entities:[e.entityLogicalName]}),d="published successfully"),u(`Column '${e.attributeLogicalName}' on '${e.entityLogicalName}' updated: ${l}. ${d}.`,{entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName,changes:s,published:e.autoPublish,...t.length>0&&{warnings:t}},["Use dataverse_get_table_metadata to verify the changes","Column type, logical name, and DateTime format cannot be changed \u2014 these are immutable after creation"])}case"dataverse_delete_attribute":{let e=Nt.parse(r),t=L({toolName:"dataverse_delete_attribute",entitySetName:e.entityLogicalName}).map(i=>`[${i.severity.toUpperCase()}] ${i.code}: ${i.message}`);try{await o.deleteAttribute(e.entityLogicalName,e.attributeLogicalName)}catch(i){let s=i instanceof Error?i.message:String(i);if(s.includes("0x80048405"))return C({summary:`Cannot delete column '${e.attributeLogicalName}': it belongs to a managed solution and cannot be deleted.`,data:{error:"0x80048405",entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName},errorCategory:"SCHEMA_MISMATCH",suggestions:["Managed solution columns can only be removed by uninstalling the solution"]});if(s.includes("dependency")||s.includes("dependencies")||s.includes("DependencyList"))return C({summary:`Cannot delete column '${e.attributeLogicalName}': it has dependencies (views, workflows, forms, or other components reference it).`,data:{error:"HAS_DEPENDENCIES",entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName,rawError:s},errorCategory:"SCHEMA_MISMATCH",suggestions:["Use dataverse_list_dependencies to identify what references this column","Remove all references before retrying deletion"]});let l=s.match(/0x[0-9a-fA-F]{8}/),d=l?l[0]:"UNKNOWN";return C({summary:`Cannot delete column '${e.attributeLogicalName}': deletion rejected by Dataverse (${d}).`,data:{error:d,entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName,rawError:s},errorCategory:"SCHEMA_MISMATCH",suggestions:["Verify this is a custom (non-managed, non-system) column","Check that no solution dependencies or forms reference this column","Standard system attributes (e.g. accountnumber) cannot be deleted"]})}let n="autoPublish=false (skipped)";return e.autoPublish&&(await o.publishCustomizations({entities:[e.entityLogicalName]}),n="published successfully"),u(`Column '${e.attributeLogicalName}' deleted from '${e.entityLogicalName}'. ${n}. All data in this column has been permanently removed.`,{entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName,deleted:!0,published:e.autoPublish,...t.length>0&&{warnings:t}},["This action is irreversible \u2014 the column and its data cannot be recovered","The column logical name is tombstoned and cannot be reused for ~90 days"])}case"dataverse_create_lookup_attribute":{let e=xt.parse(r),t=L({toolName:"dataverse_create_lookup_attribute",entitySetName:e.entityLogicalName}).map(d=>`[${d.severity.toUpperCase()}] ${d.code}: ${d.message}`),n=At(e),i,s=!1;try{i=await o.createRelationship(n)}catch(d){if((d instanceof Error?d.message:String(d)).includes("Request timed out")){let m=!1;try{m=((await o.getTableMetadata(e.entityLogicalName,!0)).Attributes??[]).some(k=>k.LogicalName===e.schemaName.toLowerCase())}catch{}if(m)s=!0,i="";else throw d}else throw d}let l="autoPublish=false (skipped)";return e.autoPublish&&!s?(await o.publishCustomizations({entities:[e.entityLogicalName,e.referencedEntity]}),l="published successfully"):s&&(l="publish skipped (request timed out \u2014 use dataverse_publish_customizations to publish)"),s&&t.push("REQUEST TIMED OUT but lookup was found on the table \u2014 creation succeeded. MetadataId unavailable."),u(`Lookup column '${e.schemaName}' created on '${e.entityLogicalName}' \u2192 '${e.referencedEntity}'. ${l}.`,{entityLogicalName:e.entityLogicalName,schemaName:e.schemaName,referencedEntity:e.referencedEntity,...i&&{metadataId:i},published:e.autoPublish&&!s,...t.length>0&&{warnings:t}},["Use dataverse_get_table_metadata to verify the new lookup column","Lookup columns cannot be created via the standard attribute API \u2014 this uses the RelationshipDefinitions endpoint"])}default:throw new Error(`Unknown attribute tool: ${a}`)}}var Ot=ge([{tools:ye,handler:he},{tools:Te,handler:Se},{tools:xe,handler:Ae},{tools:Ee,handler:ke},{tools:De,handler:Ce},{tools:Oe,handler:Ie},{tools:Ue,handler:Le},{tools:He,handler:qe},{tools:Pe,handler:$e},{tools:We,handler:je},{tools:Fe,handler:Be},{tools:Ge,handler:ze},{tools:Ve,handler:Ke},{tools:Xe,handler:Qe},{tools:Ye,handler:Ze},{tools:et,handler:tt},{tools:at,handler:nt},{tools:rt,handler:ot},{tools:it,handler:st},{tools:ct,handler:ut},{tools:pt,handler:mt},{tools:_t,handler:wt},{tools:ce,handler:Et},{tools:ft,handler:gt}]),xn=new Set(oe.map(a=>a.name)),It=[...Ot.getAllDefinitions(),...oe],An=Nn(Rn(import.meta.url)),Ut=JSON.parse(Tn(Sn(An,"../package.json"),"utf-8")).version,kt=`You are connected to a Microsoft Dataverse environment via the mcp-dataverse server.
|
|
10
|
+
</fetch>`,d=await r.executeFetchXml(l,s),p=(Array.isArray(d.value)?d.value:[]).map(m=>{let f={};for(let[N,K]of Object.entries(m))N.startsWith("@")||(f[N]=K);return f});return u(`Duplicate detection: ${p.length>0?`${p.length} potential duplicate(s) found`:"no duplicates found"}`,{hasDuplicates:p.length>0,duplicateCount:p.length,duplicates:p,note:"Field exact-match candidates (OR across provided fields). Dataverse duplicate detection rules are not applied via REST API."},["Review candidate records before creating","For rule-based duplicate detection, configure rules in Dataverse admin"])}default:throw new Error(`Unknown quality tool: ${a}`)}}import{z as I}from"zod";var dn=I.object({recordId:I.string().uuid(),includeContent:I.boolean().optional().default(!1),top:I.number().int().positive().max(100).optional().default(20),mimeTypeFilter:I.string().optional()}),cn=I.object({recordId:I.string().uuid(),entitySetName:h,noteText:I.string().optional(),subject:I.string().optional(),fileName:I.string().optional(),mimeType:I.string().optional(),documentBody:I.string().optional()}).strict().refine(a=>!!a.noteText||!!a.documentBody,{message:"At least one of noteText or documentBody is required"});function un(a){return{opportunities:"opportunity",territories:"territory",categories:"category",queues:"queue",activities:"activitypointer"}[a]??a.replace(/s$/,"")}var lt=[{name:"dataverse_get_annotations",description:"Retrieves notes and file attachments (annotations) linked to a Dataverse record. Returns note text, file metadata (name, size, MIME type), owner, and timestamps. Set includeContent=true to also retrieve base64 file content (warning: can be very large). WHEN TO USE: Retrieving notes or file attachments linked to a specific record. BEST PRACTICES: Avoid includeContent=true unless you need file data \u2014 base64 payloads can be very large. WORKFLOW: file_operations.",inputSchema:{type:"object",properties:{recordId:{type:"string",description:"The parent record's GUID"},includeContent:{type:"boolean",description:"If true, include documentbody (base64). WARNING: can be very large.",default:!1},top:{type:"number",description:"Maximum number of annotations to return (default 20, max 100)",default:20},mimeTypeFilter:{type:"string",description:'Filter by MIME type (e.g. "application/pdf")'}},required:["recordId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_create_annotation",description:"Creates a note or file attachment (annotation) linked to a Dataverse record. Provide notetext for a text note, documentbody (base64) for a file attachment, or both. The parent record is identified by entitySetName and recordId. WHEN TO USE: Adding a text note or file attachment to an existing record. BEST PRACTICES: Provide filename and mimetype when attaching files; at least notetext or documentbody is required. WORKFLOW: file_operations.",inputSchema:{type:"object",properties:{recordId:{type:"string",description:"The parent record's GUID"},entitySetName:{type:"string",description:'The OData entity set name of the parent record (e.g., "accounts", "contacts")'},noteText:{type:"string",description:"Text content of the note"},subject:{type:"string",description:"Subject/title of the note"},fileName:{type:"string",description:"File name (required when attaching a file)"},mimeType:{type:"string",description:'MIME type of the file (e.g., "application/pdf")'},documentBody:{type:"string",description:"Base64-encoded file content"}},required:["recordId","entitySetName"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function dt(a,i,r){switch(a){case"dataverse_get_annotations":{let e=dn.parse(i),t=["annotationid","subject","notetext","filename","filesize","mimetype","isdocument","createdon","modifiedon","_ownerid_value"];e.includeContent&&t.push("documentbody");let n=[`_objectid_value eq ${e.recordId}`];e.mimeTypeFilter&&n.push(`mimetype eq '${v(e.mimeTypeFilter)}'`);let s=((await r.query("annotations",{select:t,filter:n.join(" and "),orderby:"createdon desc",top:e.top})).value??[]).map(d=>{let c={id:d.annotationid??"",subject:d.subject??null,noteText:d.notetext??null,isDocument:d.isdocument===!0,createdOn:d.createdon??"",modifiedOn:d.modifiedon??"",owner:d._ownerid_value??null};return d.isdocument===!0&&(c.fileName=d.filename??null,c.fileSize=d.filesize??null,c.mimeType=d.mimetype??null),e.includeContent&&d.documentbody&&(c.documentBody=d.documentbody),c});return u(`${s.length} annotations found for record ${e.recordId}`,{recordId:e.recordId,annotations:s,count:s.length},["Use dataverse_create_annotation to add a note or attachment"])}case"dataverse_create_annotation":{let e=cn.parse(i),t=un(e.entitySetName),n={[`objectid_${t}@odata.bind`]:`/${e.entitySetName}(${e.recordId})`,objecttypecode:t};e.noteText!==void 0&&(n.notetext=e.noteText),e.subject!==void 0&&(n.subject=e.subject),e.fileName!==void 0&&(n.filename=e.fileName),e.mimeType!==void 0&&(n.mimetype=e.mimeType),e.documentBody!==void 0&&(n.documentbody=e.documentBody,n.isdocument=!0);let o;try{o=await r.createRecord("annotations",n)}catch(l){let s=String(l);if(s.includes("0x80048d19")||s.includes("objectid_")&&s.includes("undeclared"))return X({type:"feature_disabled",feature:"Notes (HasNotes)",cannotProceedBecause:`The table '${t}' does not have Notes enabled (HasNotes=false), so annotations cannot be created.`,adminPortal:"Power Apps Maker Portal",steps:["Open Power Apps maker portal (make.powerapps.com)",`Navigate to Tables \u2192 search for '${t}'`,"Open the table \u2192 click Properties or Settings",'Enable "Notes (includes file attachments)"',"Save the table, then publish customizations"],fixableViaToolName:"dataverse_update_entity"});throw l}return u(`Created annotation ${o}`,{created:!0,annotationId:o,parentRecordId:e.recordId,entitySetName:e.entitySetName},["Use dataverse_get_annotations to list all notes for this record"])}default:throw new Error(`Unknown annotation tool: ${a}`)}}import{z as w}from"zod";var pn=w.object({userId:w.string().uuid()}),mn=w.object({search:w.string().optional(),businessUnitId:w.string().optional(),includeDisabled:w.boolean().optional().default(!1),includeApplicationUsers:w.boolean().optional().default(!1),top:w.number().int().positive().max(100).optional().default(20)}),gn=w.object({nameContains:w.string().optional(),businessUnitId:w.string().optional(),top:w.number().int().positive().max(200).optional().default(50)}),fn=w.object({userId:w.string().uuid(),roleId:w.string().uuid(),confirm:w.literal(!0,{errorMap:()=>({message:"confirm must be true to assign a role"})})}),yn=w.object({userId:w.string().uuid(),roleId:w.string().uuid(),confirm:w.literal(!0,{errorMap:()=>({message:"confirm must be true to remove a role"})})}),ct=[{name:"dataverse_get_user_roles",description:"Returns all security roles assigned to a Dataverse system user. Provide the user GUID to retrieve full name, domain name (UPN), and the list of roles with role ID, name, and managed status. WHEN TO USE: Checking what security roles a user has for permission auditing or troubleshooting. BEST PRACTICES: Use the userId from dataverse_whoami or dataverse_list_users. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{userId:{type:"string",description:"The system user GUID"}},required:["userId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_users",description:"Searches Dataverse system users by name or email. Returns user ID, full name, domain name (UPN), email, business unit, and disabled status. Excludes application users and disabled users by default. WHEN TO USE: Finding user GUIDs for impersonation, record assignment, or permission review. BEST PRACTICES: Search by name or email; set includeDisabled=true for former employees. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{search:{type:"string",description:"Full-name or email contains-search"},businessUnitId:{type:"string",description:"Restrict to a business unit (GUID)"},includeDisabled:{type:"boolean",description:"Include disabled users (default false)"},includeApplicationUsers:{type:"boolean",description:"Include application/service users (default false)"},top:{type:"number",description:"Maximum number of results (default 20, max 100)"}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_list_roles",description:"Lists security roles in the Dataverse environment. Returns role ID, name, business unit, and managed status. Use this to discover role GUIDs before assigning roles to users or teams via dataverse_assign_role_to_user or dataverse_assign_role_to_team. WHEN TO USE: Looking up security role GUIDs before RBAC assignment. BEST PRACTICES: Filter by businessUnitId or nameContains to narrow results. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{nameContains:{type:"string",description:"Filter roles by name (case-insensitive substring match)"},businessUnitId:{type:"string",description:"Filter roles to a specific business unit (GUID)"},top:{type:"number",description:"Maximum number of roles to return (default 50, max 200)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_assign_role_to_user",description:"Assigns a security role to a Dataverse system user. Use dataverse_list_roles to find the role GUID and dataverse_list_users to find the user GUID. Requires System Administrator or System Customizer privileges. WARNING: This operation modifies user permissions. Set confirm=true to proceed. WHEN TO USE: Granting a security role to a user during onboarding or permission changes. BEST PRACTICES: Verify role and user GUIDs first; check existing roles with dataverse_get_user_roles. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{userId:{type:"string",description:"GUID of the system user"},roleId:{type:"string",description:"GUID of the security role to assign"},confirm:{type:"boolean",description:"Must be true to proceed with role assignment"}},required:["userId","roleId","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_remove_role_from_user",description:"Removes a security role from a Dataverse system user. Uses the same N:N disassociation pattern as dataverse_disassociate. WARNING: This modifies user permissions. Set confirm=true to proceed. WHEN TO USE: Revoking access by removing a security role from a user. BEST PRACTICES: Verify the role is assigned first with dataverse_get_user_roles. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{userId:{type:"string",description:"GUID of the system user"},roleId:{type:"string",description:"GUID of the security role to remove"},confirm:{type:"boolean",description:"Must be true to proceed with role removal"}},required:["userId","roleId","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function ut(a,i,r){switch(a){case"dataverse_get_user_roles":{let{userId:e}=pn.parse(i),n=(await r.query("systemusers",{filter:`systemuserid eq ${e}`,select:["fullname","domainname"],expand:"systemuserroles_association($select=name,roleid,ismanaged)",top:1})).value??[];if(n.length===0)throw new Error(`User with ID '${e}' not found`);let o=n[0],s=(o.systemuserroles_association??[]).map(d=>({roleId:d.roleid??"",name:d.name??"",isManaged:d.ismanaged===!0}));return u(`${s.length} roles assigned to user`,{userId:e,fullname:o.fullname??"",domainname:o.domainname??"",roles:s,roleCount:s.length},["Use dataverse_impersonate to execute operations as this user"])}case"dataverse_list_users":{let e=mn.parse(i),t=[];if(e.includeDisabled||t.push("isdisabled eq false"),e.includeApplicationUsers||t.push("applicationid eq null"),e.search){let s=v(e.search);t.push(`(contains(fullname,'${s}') or contains(internalemailaddress,'${s}'))`)}e.businessUnitId&&t.push(`_businessunitid_value eq ${e.businessUnitId}`);let l=((await r.query("systemusers",{select:["systemuserid","fullname","domainname","internalemailaddress","applicationid","isdisabled"],filter:t.join(" and "),expand:"businessunitid($select=name)",orderby:"fullname asc",top:e.top})).value??[]).map(s=>({id:s.systemuserid??"",fullName:s.fullname??"",domainName:s.domainname??"",email:s.internalemailaddress??"",businessUnit:s.businessunitid?.name??null,isDisabled:s.isdisabled===!0,isApplicationUser:s.applicationid!=null}));return u(`${l.length} users found`,{users:l,count:l.length},["Use dataverse_get_user_roles to inspect specific user permissions"])}case"dataverse_list_roles":{let{nameContains:e,businessUnitId:t,top:n}=gn.parse(i),o=[];e&&o.push(`contains(name,'${v(e)}')`),t&&o.push(`_businessunitid_value eq ${t}`);let l=o.length?o.join(" and "):void 0,d=((await r.query("roles",{select:["roleid","name","description","ismanaged","_businessunitid_value"],...l!==void 0?{filter:l}:{},orderby:"name asc",top:n})).value??[]).map(c=>({id:c.roleid??"",name:c.name??"",businessUnitId:c._businessunitid_value??null,isManaged:c.ismanaged===!0,description:c.description??""}));return u(`${d.length} security roles found`,{roles:d,count:d.length},["Use dataverse_assign_role_to_user or dataverse_assign_role_to_team with the role ID"])}case"dataverse_assign_role_to_user":{let{userId:e,roleId:t}=fn.parse(i);return(((await r.query("systemusers",{filter:`systemuserid eq ${e}`,select:["systemuserid"],expand:`systemuserroles_association($select=roleid;$filter=roleid eq ${t};$top=1)`,top:1})).value??[])[0]?.systemuserroles_association??[]).length>0?u("Role is already assigned to this user.",{userId:e,roleId:t,status:"already_assigned"},["Use dataverse_get_user_roles to see current role assignments"]):(await r.associate("systemusers",e,"systemuserroles_association","roles",t),u("Role assigned to user successfully.",{userId:e,roleId:t,status:"assigned"},["Use dataverse_get_user_roles to verify the new assignment"]))}case"dataverse_remove_role_from_user":{let{userId:e,roleId:t}=yn.parse(i);return(((await r.query("systemusers",{filter:`systemuserid eq ${e}`,select:["systemuserid"],expand:`systemuserroles_association($select=roleid;$filter=roleid eq ${t};$top=1)`,top:1})).value??[])[0]?.systemuserroles_association??[]).length===0?u("This role is not currently assigned to the user.",{userId:e,roleId:t,status:"not_assigned"},["Use dataverse_get_user_roles to see current role assignments"]):(await r.disassociate("systemusers",e,"systemuserroles_association",t,"roles"),u("Role removed from user successfully.",{userId:e,roleId:t,status:"removed"},["Use dataverse_get_user_roles to verify the updated assignments"]))}default:throw new Error(`Unknown user tool: ${a}`)}}import{z as k}from"zod";var me={ADD_PRIVILEGES_ROLE:"AddPrivilegesRole",REPLACE_PRIVILEGES_ROLE:"ReplacePrivilegesRole"},pt={RETRIEVE_ROLE_PRIVILEGES:"RetrieveRolePrivilegesRole",WHO_AM_I:"WhoAmI"};var vn=k.enum(["None","Basic","Local","Deep","Global"]),hn=k.object({roleId:k.string().uuid()}),gt=k.object({privilegeId:k.string().uuid(),depth:vn,businessUnitId:k.string().uuid().optional()}),bn=k.object({roleId:k.string().uuid(),privileges:k.array(gt).min(1)}),_n=k.object({roleId:k.string().uuid(),privileges:k.array(gt).min(1),confirm:k.literal(!0,{errorMap:()=>({message:"confirm must be true to replace all privileges on the role"})})}),mt={type:"array",description:"Privileges to assign",minItems:1,items:{type:"object",properties:{privilegeId:{type:"string",description:"GUID of the privilege \u2014 use dataverse_query on 'privileges' entity to find by name or entitylogicalname"},depth:{type:"string",enum:["None","Basic","Local","Deep","Global"],description:"Depth level: Basic=user, Local=BU, Deep=parent BU, Global=org. Use Global for org-owned entities (Basic/Local/Deep fail with error 0x8004140b)."},businessUnitId:{type:"string",description:"Business unit GUID (optional; defaults to root BU if omitted)"}},required:["privilegeId","depth"]}},ft=[{name:"dataverse_get_role_privileges",description:`Retrieves all privileges assigned to a security role with their depth levels (None/Basic/Local/Deep/Global). Use to audit a role's current permissions before modifying them, or to verify depth assignments. Combine with dataverse_query on 'privileges' entity to resolve privilege names and entity associations.
|
|
11
|
+
|
|
12
|
+
\u26A0\uFE0F NOTE \u2014 Direct OData query on 'roleprivileges': The entity set name for roleprivileges is 'roleprivilegess' (double 's'). This means OData queries must target /api/data/v9.2/roleprivilegess. For direct query use: dataverse_query with entitySetName='roleprivilegess'. For FetchXML join pattern (role \u2192 privilege depths), use: <fetch><entity name='role'><attribute name='name'/><link-entity name='roleprivileges' from='roleid' to='roleid'><attribute name='privilegedepthmask'/><link-entity name='privilege' from='privilegeid' to='privilegeid'><attribute name='name'/></link-entity></link-entity></entity></fetch>. WHEN TO USE: Auditing which privileges and depths a security role has. BEST PRACTICES: Use dataverse_list_roles to find the role GUID first. Use this tool (RetrieveRolePrivilegesRole) for the clean structured result; use FetchXML for joins with privilege names in one shot. WORKFLOW: inspect_audit.`,inputSchema:{type:"object",properties:{roleId:{type:"string",description:"GUID of the security role"}},required:["roleId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_add_role_privileges",description:"Adds one or more privileges to a security role with specified depth levels using the AddPrivilegesRole action. Supports all depths: None, Basic (user-level), Local (BU-level), Deep (parent-BU), Global (org-level). For org-owned entities only Global is valid \u2014 Basic/Local/Deep return error 0x8004140b. WHEN TO USE: Setting up or extending a role's permissions. BEST PRACTICES: Get privilege GUIDs from dataverse_query on 'privileges' entity; use dataverse_replace_role_privileges to atomically reset all at once. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{roleId:{type:"string",description:"GUID of the security role"},privileges:mt},required:["roleId","privileges"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_replace_role_privileges",description:"Atomically replaces ALL privileges on a security role using the ReplacePrivilegesRole action. The new set completely overrides the existing privileges \u2014 any privilege not in the list is removed. Use for initial setup or full reconfiguration of a role. WHEN TO USE: Complete reconfiguration of a role's privilege set. BEST PRACTICES: Read current privileges with dataverse_get_role_privileges first to avoid accidental removal. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{roleId:{type:"string",description:"GUID of the security role"},privileges:mt,confirm:{type:"boolean",description:"Must be true \u2014 replaces ALL existing privileges on the role"}},required:["roleId","privileges","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!0,idempotentHint:!0,openWorldHint:!0}}];async function yt(a,i,r){switch(a){case"dataverse_get_role_privileges":{let{roleId:e}=hn.parse(i),n=(await r.executeFunction(pt.RETRIEVE_ROLE_PRIVILEGES,{RoleId:e}))?.RolePrivileges??[];return u(`${n.length} privileges on role`,{roleId:e,privileges:n,count:n.length},["Use dataverse_add_role_privileges to modify privileges or depths"])}case"dataverse_add_role_privileges":{let e=bn.parse(i),t=e.privileges.map(n=>({"@odata.type":"Microsoft.Dynamics.CRM.RolePrivilege",Depth:n.depth,PrivilegeId:n.privilegeId,...n.businessUnitId?{BusinessUnitId:n.businessUnitId}:{}}));return await r.executeBoundAction("roles",e.roleId,me.ADD_PRIVILEGES_ROLE,{Privileges:t}),u(`${e.privileges.length} privileges added to role`,{roleId:e.roleId,count:e.privileges.length},["Use dataverse_get_role_privileges to verify the assignment"])}case"dataverse_replace_role_privileges":{let e=_n.parse(i),t=e.privileges.map(n=>({"@odata.type":"Microsoft.Dynamics.CRM.RolePrivilege",Depth:n.depth,PrivilegeId:n.privilegeId,...n.businessUnitId?{BusinessUnitId:n.businessUnitId}:{}}));return await r.executeBoundAction("roles",e.roleId,me.REPLACE_PRIVILEGES_ROLE,{Privileges:t}),u(`All privileges replaced on role (${e.privileges.length} total)`,{roleId:e.roleId,count:e.privileges.length},["Use dataverse_get_role_privileges to verify the new privilege set"])}default:throw new Error(`Unknown role privilege tool: ${a}`)}}import{z as ie}from"zod";var wn=ie.object({entityLogicalName:ie.string().min(1),includePersonal:ie.boolean().optional().default(!1),top:ie.number().int().positive().max(100).optional().default(20)}),vt=[{name:"dataverse_list_views",description:"Lists saved views (system and optionally personal) for a Dataverse table. System views come from savedqueries; personal views come from userqueries. Returns view name, ID, default flag, query type, and description. WHEN TO USE: Discovering saved system or personal views for a table. BEST PRACTICES: Use the view's FetchXML with dataverse_execute_fetchxml to run it. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:'Logical name of the entity to list views for (e.g., "account")'},includePersonal:{type:"boolean",description:"Include personal (user) views in addition to system views (default false)"},top:{type:"number",description:"Maximum number of results per category (default 20, max 100)"}},required:["entityLogicalName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function ht(a,i,r){switch(a){case"dataverse_list_views":{let{entityLogicalName:e,includePersonal:t,top:n}=wn.parse(i),o=v(e),s=(await r.query("savedqueries",{filter:`returnedtypecode eq '${o}' and statecode eq 0`,select:["savedqueryid","name","isdefault","querytype","description"],orderby:"name asc",top:n})).value.map(p=>({id:p.savedqueryid,name:p.name,isDefault:p.isdefault,queryType:p.querytype,description:p.description??null,viewType:"system"})),d=[];t&&(d=(await r.query("userqueries",{filter:`returnedtypecode eq '${o}'`,select:["userqueryid","name","description"],orderby:"name asc",top:n})).value.map(m=>({id:m.userqueryid,name:m.name,description:m.description??null,viewType:"personal"})));let c=s.length+d.length;return u(`${c} views found for ${e}`,{entityLogicalName:e,systemViews:s,systemViewCount:s.length,personalViews:t?d:void 0,personalViewCount:t?d.length:void 0},["Use the view's fetchxml with dataverse_execute_fetchxml to run it"])}default:throw new Error(`Unknown view tool: ${a}`)}}import{z as ge}from"zod";var Sn=ge.object({top:ge.number().int().positive().max(200).optional().default(50),includeDisabled:ge.boolean().optional().default(!1)}),bt=[{name:"dataverse_list_business_units",description:"Lists business units in the Dataverse environment. Returns name, ID, parent business unit ID, disabled status, and creation date. By default only active business units are returned. WHEN TO USE: Finding business unit IDs for user management, team setup, or security role scope. BEST PRACTICES: The root business unit is the parent of all others; filter disabled units by default. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Maximum number of results (default 50, max 200)"},includeDisabled:{type:"boolean",description:"Include disabled business units (default false)"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function _t(a,i,r){switch(a){case"dataverse_list_business_units":{let{top:e,includeDisabled:t}=Sn.parse(i??{}),n=t?void 0:"isdisabled eq false",l=(await r.query("businessunits",{select:["businessunitid","name","parentbusinessunitid","isdisabled","createdon"],...n?{filter:n}:{},orderby:"name asc",top:e})).value.map(s=>({id:s.businessunitid,name:s.name,parentBusinessUnitId:s.parentbusinessunitid??null,isDisabled:s.isdisabled,createdOn:s.createdon}));return u(`${l.length} business units found`,{businessUnits:l,count:l.length},["Use business unit IDs for user management or security role assignment"])}default:throw new Error(`Unknown org tool: ${a}`)}}import{z as P}from"zod";var wt=/^[a-zA-Z0-9_]+$/,St=/\.\.|[/\\]/,Tn=P.object({entitySetName:P.string().min(1).refine(a=>!St.test(a),{message:"entitySetName must not contain path traversal characters"}),recordId:P.string().uuid(),columnName:P.string().min(1).refine(a=>wt.test(a),{message:"columnName must be alphanumeric/underscore only"}),fileContent:P.string().min(1).describe("Base64-encoded file content"),fileName:P.string().min(1)}),Nn=P.object({entitySetName:P.string().min(1).refine(a=>!St.test(a),{message:"entitySetName must not contain path traversal characters"}),recordId:P.string().uuid(),columnName:P.string().min(1).refine(a=>wt.test(a),{message:"columnName must be alphanumeric/underscore only"})}),Tt=[{name:"dataverse_upload_file_column",description:"Uploads a file to a Dataverse file column. Provide the entity set name, record GUID, column name, base64-encoded file content, and file name. The file is stored in the specified file-type column on the record. WHEN TO USE: Uploading a file to a file-type column on a Dataverse record. BEST PRACTICES: Base64-encode the file content; verify the column is a file-type column via dataverse_get_table_metadata. WORKFLOW: file_operations.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name (e.g., "accounts")'},recordId:{type:"string",description:"Record GUID"},columnName:{type:"string",description:"File column logical name"},fileContent:{type:"string",description:"Base64-encoded file content"},fileName:{type:"string",description:'File name including extension (e.g., "report.pdf")'}},required:["entitySetName","recordId","columnName","fileContent","fileName"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_download_file_column",description:"Downloads a file from a Dataverse file column. Returns the file content as a base64-encoded string along with the file name and size. WHEN TO USE: Downloading a file stored in a file-type column on a Dataverse record. BEST PRACTICES: The response is base64-encoded; decode before saving or processing. WORKFLOW: file_operations.",inputSchema:{type:"object",properties:{entitySetName:{type:"string",description:'OData entity set name (e.g., "accounts")'},recordId:{type:"string",description:"Record GUID"},columnName:{type:"string",description:"File column logical name"}},required:["entitySetName","recordId","columnName"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}];async function Nt(a,i,r){let e=r.http;switch(a){case"dataverse_upload_file_column":{let{entitySetName:t,recordId:n,columnName:o,fileContent:l,fileName:s}=Tn.parse(i),d=Buffer.from(l,"base64"),c=`${t}(${n})/${o}`;return await e.patch(c,d,{headers:{"Content-Type":"application/octet-stream","x-ms-file-name":s}}),u(`Uploaded file to ${o} on ${t}(${n})`,{success:!0,entitySetName:t,recordId:n,columnName:o,fileName:s,sizeBytes:d.length},["Use dataverse_download_file_column to retrieve the file"])}case"dataverse_download_file_column":{let{entitySetName:t,recordId:n,columnName:o}=Nn.parse(i),l=`${t}(${n})/${o}/$value`,s=await e.get(l,{responseType:"text"}),d=s.data,c=Buffer.from(d,"binary").toString("base64"),p=s.headers["x-ms-file-name"]??s.headers["content-disposition"]?.match(/filename="?([^";\n]+)"?/)?.[1]??"download",m=parseInt(s.headers["content-length"]??"0",10)||c.length;return u(`Downloaded file from ${o} on ${t}(${n})`,{entitySetName:t,recordId:n,columnName:o,fileName:p,sizeBytes:m,contentBase64:c})}default:throw new Error(`Unknown file tool: ${a}`)}}import{z as C}from"zod";var Rn={0:"Owner",1:"Access",2:"Office",3:"Security"},An=C.object({top:C.number().int().positive().max(200).optional().default(50),teamType:C.union([C.literal(0),C.literal(1),C.literal(2),C.literal(3)]).optional()}),En=C.object({teamId:C.string().uuid(),roleId:C.string().uuid(),confirm:C.literal(!0,{errorMap:()=>({message:"confirm must be true to assign a role to a team"})})}),Rt=[{name:"dataverse_list_teams",description:"Lists Dataverse teams in the environment. Useful for finding team owners for record assignment and sharing. teamtype: 0=Owner, 1=Access, 2=AAD Office Group, 3=AAD Security Group. WHEN TO USE: Finding team IDs for record assignment or sharing. BEST PRACTICES: Filter by teamType to distinguish owner, access, and AAD group teams. WORKFLOW: explore_schema.",inputSchema:{type:"object",properties:{top:{type:"number",description:"Maximum number of teams to return (1\u2013200, default 50)"},teamType:{type:"number",enum:[0,1,2,3],description:"Filter by team type: 0=Owner, 1=Access, 2=Office Group, 3=Security Group"}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_assign_role_to_team",description:"Assigns a security role to a Dataverse team. All team members inherit the role permissions. Use dataverse_list_roles to find the role GUID and dataverse_list_teams to find the team GUID. WARNING: This modifies team permissions for ALL members. Set confirm=true to proceed. WHEN TO USE: Providing role-based permissions to an entire team during configuration. BEST PRACTICES: Prefer team-based RBAC over individual user assignments for maintainability. WORKFLOW: inspect_audit.",inputSchema:{type:"object",properties:{teamId:{type:"string",description:"GUID of the team"},roleId:{type:"string",description:"GUID of the security role to assign"},confirm:{type:"boolean",description:"Must be true to proceed with role assignment"}},required:["teamId","roleId","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function At(a,i,r){switch(a){case"dataverse_list_teams":{let{top:e,teamType:t}=An.parse(i),o={select:["teamid","name","teamtype","description","isdefault","createdon","_businessunitid_value"],top:e,orderby:"name asc"};t!==void 0&&(o.filter=`teamtype eq ${t}`);let s=(await r.query("teams",o)).value.map(d=>({...d,teamTypeName:Rn[d.teamtype]??"Unknown"}));return u(`${s.length} teams found`,{teams:s,count:s.length},["Use dataverse_assign with a team ID to assign records to a team"])}case"dataverse_assign_role_to_team":{let{teamId:e,roleId:t}=En.parse(i);return(((await r.query("teams",{filter:`teamid eq ${e}`,select:["teamid"],expand:`teamroles_association($select=roleid;$filter=roleid eq ${t};$top=1)`,top:1})).value??[])[0]?.teamroles_association??[]).length>0?u("Role is already assigned to this team.",{teamId:e,roleId:t,status:"already_assigned"},["Use dataverse_list_teams to view current team configuration"]):(await r.associate("teams",e,"teamroles_association","roles",t),u("Role assigned to team successfully.",{teamId:e,roleId:t,status:"assigned"},["All members of this team now inherit the assigned role"]))}default:throw new Error(`Unknown team tool: ${a}`)}}var ee={dataverse_query:["query","read","odata"],dataverse_execute_fetchxml:["query","read","fetchxml","aggregate"],dataverse_create:["write","crud","create"],dataverse_update:["write","crud","update"],dataverse_delete:["write","crud","delete","destructive"],dataverse_get:["read","crud","get"],dataverse_upsert:["write","crud","upsert"],dataverse_retrieve_multiple_with_paging:["query","read","paging"],dataverse_search:["search","read","fulltext"],dataverse_list_tables:["metadata","schema","read"],dataverse_get_table_metadata:["metadata","schema","read"],dataverse_get_relationships:["metadata","schema","relations","read"],dataverse_get_option_set:["metadata","schema","read"],dataverse_get_attribute_option_set:["metadata","schema","read"],dataverse_list_global_option_sets:["metadata","schema","read"],dataverse_get_entity_key:["metadata","schema","read"],dataverse_resolve_entity_name:["metadata","schema","read"],dataverse_create_attribute:["metadata","schema","write","attribute"],dataverse_update_attribute:["metadata","schema","write","attribute"],dataverse_delete_attribute:["metadata","schema","write","attribute","destructive"],dataverse_create_lookup_attribute:["metadata","schema","write","attribute","relations"],dataverse_update_entity:["metadata","schema","write"],dataverse_publish_customizations:["customization","write"],dataverse_create_sitemap:["customization","sitemap","write","manage_solution"],dataverse_list_views:["metadata","views","read"],dataverse_execute_action:["actions","write","custom"],dataverse_execute_bound_action:["actions","write","custom"],dataverse_execute_function:["actions","read","custom"],dataverse_execute_bound_function:["actions","read","custom"],dataverse_batch_execute:["write","bulk","batch"],dataverse_whoami:["auth","identity","read"],dataverse_impersonate:["security","admin"],dataverse_associate:["relations","write"],dataverse_disassociate:["relations","write"],dataverse_associate_bulk:["relations","write","bulk"],dataverse_query_associations:["relations","read"],dataverse_list_roles:["admin","security","roles","read"],dataverse_get_role_privileges:["admin","security","roles","read"],dataverse_add_role_privileges:["admin","security","roles","write"],dataverse_replace_role_privileges:["admin","security","roles","write","destructive"],dataverse_assign_role_to_user:["admin","security","users","write"],dataverse_remove_role_from_user:["admin","security","users","write"],dataverse_assign_role_to_team:["admin","security","teams","write"],dataverse_assign:["write","crud"],dataverse_list_users:["admin","users","read"],dataverse_get_user_roles:["admin","users","security","read"],dataverse_list_teams:["admin","teams","read"],dataverse_list_business_units:["admin","teams","read"],dataverse_list_workflows:["workflows","read"],dataverse_get_workflow:["workflows","read"],dataverse_set_workflow_state:["workflows","write"],dataverse_environment_capabilities:["admin","environments","read"],dataverse_get_environment_variable:["admin","environments","read"],dataverse_set_environment_variable:["admin","environments","write"],dataverse_create_environment_variable:["admin","environments","write"],dataverse_get_audit_log:["audit","read"],dataverse_get_plugin_trace_logs:["debug","trace","read"],dataverse_get_workflow_trace_logs:["debug","trace","read"],dataverse_list_plugin_steps:["debug","plugins","read"],dataverse_get_annotations:["notes","read"],dataverse_create_annotation:["notes","write"],dataverse_download_file_column:["files","read","download"],dataverse_upload_file_column:["files","write","upload"],dataverse_change_detection:["sync","delta","read"],dataverse_detect_duplicates:["quality","read","validation"],dataverse_list_dependencies:["metadata","schema","read"],dataverse_retrieve_dependencies_for_delete:["metadata","schema","read"],dataverse_list_connection_references:["metadata","read"],dataverse_list_custom_actions:["actions","metadata","read"],dataverse_get_guide:["guides","help","read"],dataverse_list_guides:["guides","help","read"],dataverse_suggest_tools:["router","help","read"],dataverse_list_tool_tags:["router","help","read"]},fe={dataverse_query:"Query Dataverse tables using OData syntax with filters, select, expand",dataverse_execute_fetchxml:"Execute FetchXML queries with aggregation, groupby, and joins",dataverse_create:"Create a new record in a Dataverse table",dataverse_update:"Update an existing Dataverse record",dataverse_delete:"Delete a Dataverse record permanently",dataverse_get:"Retrieve a single record by GUID",dataverse_upsert:"Create or update a record by alternate key",dataverse_retrieve_multiple_with_paging:"Query with automatic paging support for large datasets",dataverse_search:"Full-text search across multiple Dataverse tables using Relevance Search",dataverse_list_tables:"List available Dataverse tables (entities)",dataverse_get_table_metadata:"Get column definitions and schema for a table",dataverse_get_relationships:"Get one-to-many and many-to-many relationships for a table",dataverse_get_option_set:"Get a global or local option set definition",dataverse_get_attribute_option_set:"Get option values for a specific column (OptionSet/MultiSelectPicklist)",dataverse_list_global_option_sets:"List all global option sets in the environment",dataverse_get_entity_key:"Get alternate key definitions for a table",dataverse_resolve_entity_name:"Resolve a table logical name to its entity set name (OData collection name)",dataverse_create_attribute:"Create a new column on a Dataverse table",dataverse_update_attribute:"Update mutable properties of an existing column",dataverse_delete_attribute:"Delete a column and all its data from a table",dataverse_create_lookup_attribute:"Create a Lookup column via a One-to-Many relationship",dataverse_update_entity:"Update mutable entity-level properties (display name, description, etc.)",dataverse_publish_customizations:"Publish unpublished schema customizations to make them available to users",dataverse_create_sitemap:"Create a model-driven app sitemap (navigation structure) by generating XML and posting to /sitemaps; optionally links it to an app module",dataverse_list_views:"List saved views (saved queries) for a table",dataverse_execute_action:"Execute an unbound custom action",dataverse_execute_bound_action:"Execute a bound custom action on a specific record",dataverse_execute_function:"Execute an unbound function (read-only)",dataverse_execute_bound_function:"Execute a bound function on a specific record (read-only)",dataverse_batch_execute:"Execute multiple read/write operations in a single HTTP batch request",dataverse_whoami:"Get current authenticated user identity and organization context",dataverse_impersonate:"Set impersonation (run subsequent calls on behalf of another user)",dataverse_associate:"Associate two records via a relationship",dataverse_disassociate:"Remove an association between two records",dataverse_associate_bulk:"Associate multiple records in a single batch",dataverse_query_associations:"Query the associated records through a relationship",dataverse_list_roles:"List security roles in the environment",dataverse_get_role_privileges:"Get all privileges and their depth levels assigned to a security role",dataverse_add_role_privileges:"Add privileges to a security role with specified depth",dataverse_replace_role_privileges:"Atomically replace all privileges on a security role",dataverse_assign_role_to_user:"Assign a security role to a user",dataverse_remove_role_from_user:"Remove a security role from a user",dataverse_assign_role_to_team:"Assign a security role to a team",dataverse_assign:"Assign a record to a different owner (user or team)",dataverse_list_users:"List system users in the environment",dataverse_get_user_roles:"Get security roles assigned to a specific user",dataverse_list_teams:"List teams in the environment",dataverse_list_business_units:"List business units in the organization hierarchy",dataverse_list_workflows:"List workflows and Power Automate flows",dataverse_get_workflow:"Get the definition and status of a specific workflow",dataverse_set_workflow_state:"Activate or deactivate a workflow",dataverse_environment_capabilities:"Get environment capabilities: identity, settings, solutions, variable counts",dataverse_get_environment_variable:"Get the value and schema of an environment variable",dataverse_set_environment_variable:"Set the current value of an environment variable",dataverse_create_environment_variable:"Create a new environment variable definition and optionally its value",dataverse_get_audit_log:"Get the audit history for a specific record",dataverse_get_plugin_trace_logs:"Get plugin trace logs for debugging plugin execution errors",dataverse_get_workflow_trace_logs:"Get execution trace logs for a Power Automate workflow run",dataverse_list_plugin_steps:"List registered plugin steps (SDK message processing steps)",dataverse_get_annotations:"Get notes/annotations attached to a record",dataverse_create_annotation:"Create a note (annotation) on a record",dataverse_download_file_column:"Download the binary content of a file-type column",dataverse_upload_file_column:"Upload base64-encoded content to a file-type column",dataverse_change_detection:"Detect new or changed records since a delta token (change tracking)",dataverse_detect_duplicates:"Detect potential duplicate records before creating a new one",dataverse_list_dependencies:"List workflows, flows, and plugins that reference a table",dataverse_retrieve_dependencies_for_delete:"Check which components block deletion of a specific component",dataverse_list_connection_references:"List Power Automate connection references in the environment",dataverse_list_custom_actions:"List registered custom API actions",dataverse_get_guide:"Get a contextual MCP usage guide for a specific workflow",dataverse_list_guides:"List all available MCP usage guides",dataverse_suggest_tools:"Get top-5 tool suggestions for a natural-language intent",dataverse_list_tool_tags:"List all tool tags with tool counts per category"};function xn(a){return a.toLowerCase().replace(/[^a-z0-9_]/g," ").split(/\s+/).filter(i=>i.length>1)}function kn(a,i){let r=ee[a]??[],e=(fe[a]??"").toLowerCase(),t=a.toLowerCase(),n=0;for(let o of i)r.includes(o)&&(n+=3),t.includes(o)&&(n+=2),e.includes(o)&&(n+=1);return n}function In(a){let i=xn(a);if(i.length===0)return["dataverse_whoami","dataverse_list_tables","dataverse_query","dataverse_search","dataverse_get_table_metadata"].map(t=>({name:t,description:fe[t]??"",tags:ee[t]??[],score:1}));let r=[];for(let e of Object.keys(ee)){let t=kn(e,i);t>0&&r.push({name:e,description:fe[e]??"",tags:ee[e]??[],score:t})}return r.sort((e,t)=>t.score-e.score),r.slice(0,5)}function Dn(){let a=new Map;for(let i of Object.values(ee))for(let r of i)a.set(r,(a.get(r)??0)+1);return Array.from(a.entries()).map(([i,r])=>({tag:i,toolCount:r})).sort((i,r)=>r.toolCount-i.toolCount)}var Et=[{name:"dataverse_suggest_tools",description:"Suggests the most relevant Dataverse tools for a given intent. Provide a natural-language description of what you want to do and this tool returns the top 5 matching tools with descriptions and tags.",inputSchema:{type:"object",properties:{intent:{type:"string",description:"Natural language description of the desired action"}},required:["intent"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1}},{name:"dataverse_list_tool_tags",description:"Lists all available tool tags with the number of tools in each category. Use this to discover what kinds of operations are available.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1}}];async function xt(a,i,r){if(a==="dataverse_suggest_tools"){let{intent:e}=i??{},t=In(e??""),n=t.length>0?[`Try: ${t[0].name}`]:["Use dataverse_list_tool_tags to explore categories"];return u(`${t.length} tools match intent "${e??""}"`,t,n)}if(a==="dataverse_list_tool_tags"){let e=Dn();return H("tags",e,["Use dataverse_suggest_tools with an intent to find specific tools"])}throw new Error(`Unknown router tool: ${a}`)}var On=[{uriTemplate:"dataverse://tables/{tableName}/schema",name:"Table Schema",description:"Returns the full schema (columns, types, requirements) for a Dataverse table",mimeType:"application/json"},{uriTemplate:"dataverse://tables/{tableName}/relationships",name:"Table Relationships",description:"Returns all 1:N and N:N relationships for a Dataverse table",mimeType:"application/json"}],Cn=[{uri:"dataverse://tables",name:"Available Tables",description:"Lists all custom tables in the connected Dataverse environment",mimeType:"application/json"},{uri:"dataverse://server/instructions",name:"Server Instructions",description:"Usage guidelines and best practices for interacting with this Dataverse MCP server",mimeType:"text/plain"}];function Un(a){let i="dataverse://";if(!a.startsWith(i))throw new Error(`Unknown resource URI: ${a}`);let r=a.slice(i.length);if(r==="tables")return{type:"tables"};if(r==="server/instructions")return{type:"instructions"};let e=/^tables\/([^/]+)\/schema$/.exec(r);if(e)return{type:"schema",tableName:e[1]};let t=/^tables\/([^/]+)\/relationships$/.exec(r);if(t)return{type:"relationships",tableName:t[1]};throw new Error(`Unknown resource URI: ${a}`)}function kt(){return Cn}function It(){return On}async function Dt(a,i,r){let e=Un(a);switch(e.type){case"tables":{let t=await i.listTables(!0);return{uri:a,mimeType:"application/json",text:JSON.stringify(t,null,2)}}case"schema":{let t=await i.getTableMetadata(e.tableName);return{uri:a,mimeType:"application/json",text:JSON.stringify(t,null,2)}}case"relationships":{let t=await i.getRelationships(e.tableName);return{uri:a,mimeType:"application/json",text:JSON.stringify(t,null,2)}}case"instructions":return{uri:a,mimeType:"text/plain",text:r}}}var oe=new Map([["query_data",{name:"query_data",description:"Query data from Dataverse tables. Authenticate, discover tables, inspect schema, then query with OData or FetchXML.",tags:["query","data","fetchxml","odata","read"],steps:[{order:1,tool:"dataverse_whoami",description:"Verify authentication and get user context",required:!0},{order:2,tool:"dataverse_list_tables",description:"Discover available tables",required:!0,tips:"Use customOnly=true to focus on custom tables"},{order:3,tool:"dataverse_get_table_metadata",description:"Inspect column names, types, and required fields",required:!0,tips:"Note logical names for use in $select and $filter"},{order:4,tool:"dataverse_query",description:"Execute OData query or use dataverse_execute_fetchxml for complex joins",required:!0,tips:"Always use $select to limit columns; use $top to limit rows"}]}],["explore_schema",{name:"explore_schema",description:"Explore the Dataverse schema: tables, columns, relationships, and saved views.",tags:["schema","metadata","tables","relationships","views"],steps:[{order:1,tool:"dataverse_whoami",description:"Verify authentication",required:!0},{order:2,tool:"dataverse_list_tables",description:"List all available tables",required:!0},{order:3,tool:"dataverse_get_table_metadata",description:"Get detailed column metadata for a table",required:!0},{order:4,tool:"dataverse_get_relationships",description:"Discover one-to-many and many-to-many relationships",required:!1,tips:"Useful before building FetchXML joins"},{order:5,tool:"dataverse_list_views",description:"List saved views for the table",required:!1}]}],["create_record",{name:"create_record",description:"Create a new record in Dataverse. Inspect schema first to know required fields, then create and verify.",tags:["create","record","write","insert"],steps:[{order:1,tool:"dataverse_get_table_metadata",description:"Check required fields and column types before creating",required:!0,tips:"Pay attention to required fields and lookup columns"},{order:2,tool:"dataverse_create",description:"Create the new record",required:!0},{order:3,tool:"dataverse_query",description:"Verify the record was created with correct values",required:!1,tips:"Query by the returned ID to confirm field values"}]}],["update_record",{name:"update_record",description:"Update an existing record. Read current values, apply changes, then verify the update.",tags:["update","record","write","modify"],steps:[{order:1,tool:"dataverse_get_table_metadata",description:"Confirm column names and types",required:!0},{order:2,tool:"dataverse_get",description:"Read current record values and etag",required:!0,tips:"Capture @odata.etag for optimistic concurrency"},{order:3,tool:"dataverse_update",description:"Apply the update with etag for concurrency control",required:!0},{order:4,tool:"dataverse_get",description:"Verify the update was applied correctly",required:!1}]}],["delete_record",{name:"delete_record",description:"Delete a record from Dataverse. Read the record first to confirm identity, then delete.",tags:["delete","record","remove"],steps:[{order:1,tool:"dataverse_get",description:"Read the record to confirm it is the correct one",required:!0,tips:"Show record details to the user before deletion"},{order:2,tool:"dataverse_delete",description:"Delete the record (irreversible)",required:!0,tips:"Always confirm with the user before executing this step"}]}],["bulk_operations",{name:"bulk_operations",description:"Perform bulk create/update/delete using Dataverse batch API for efficiency.",tags:["bulk","batch","mass","multiple"],steps:[{order:1,tool:"dataverse_get_table_metadata",description:"Inspect schema to build correct request payloads",required:!0},{order:2,tool:"dataverse_batch_execute",description:"Execute batch of operations in a single request",required:!0,tips:"Group up to 1000 operations per batch; use changesets for transactional groups"}]}],["search_data",{name:"search_data",description:"Full-text search across Dataverse tables, then refine results with targeted queries.",tags:["search","find","fulltext","relevance"],steps:[{order:1,tool:"dataverse_search",description:"Execute full-text search across multiple tables",required:!0,tips:"Use entities filter to narrow which tables to search"},{order:2,tool:"dataverse_query",description:"Refine results with a targeted OData query on the relevant table",required:!1}]}],["manage_solution",{name:"manage_solution",description:"Inspect and manage Dataverse solutions and their components.",tags:["solution","customization","deployment","components"],steps:[{order:1,tool:"dataverse_list_solutions",description:"List all solutions in the environment",required:!0},{order:2,tool:"dataverse_solution_components",description:"List components within a specific solution",required:!0},{order:3,tool:"dataverse_publish_customizations",description:"Publish customizations after changes",required:!1,tips:"Required after modifying solution components"}]}],["inspect_audit",{name:"inspect_audit",description:"Review audit history for records or tables to track changes and user activity.",tags:["audit","history","changes","tracking"],steps:[{order:1,tool:"dataverse_get_audit_log",description:"Retrieve audit entries filtered by record, table, user, or date range",required:!0,tips:"Use at least one filter to avoid large result sets; audit must be enabled on the table"}]}],["file_operations",{name:"file_operations",description:"Upload or download files from Dataverse file/image columns.",tags:["file","upload","download","image","attachment"],steps:[{order:1,tool:"dataverse_get_table_metadata",description:"Identify file or image columns on the table",required:!0,tips:"Look for columns of type File or Image"},{order:2,tool:"dataverse_upload_file_column",description:"Upload a file to a file/image column",required:!1},{order:3,tool:"dataverse_download_file_column",description:"Download a file from a file/image column",required:!1,tips:"Returns base64-encoded content"}]}]]);var Ct=[{name:"dataverse_list_guides",description:"Lists all available step-by-step guided workflows for common Dataverse tasks (query_data, create_record, manage_solution, etc.). Use this to discover recommended MCP patterns. NOTE: these are MCP-internal task guides, NOT Dataverse automation processes \u2014 use dataverse_list_workflows to list actual Dataverse flows/workflows.",inputSchema:{type:"object",properties:{},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}},{name:"dataverse_get_guide",description:"Returns the full definition of an MCP task guide including ordered steps, tool names, tips, and required flags. Use this to get a step-by-step plan for a common Dataverse task. NOTE: these are MCP-internal guides \u2014 use dataverse_get_workflow to retrieve an actual Dataverse process.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Guide name (e.g. query_data, explore_schema, create_record, update_record, delete_record, bulk_operations, search_data, manage_solution, inspect_audit, file_operations)"}},required:["name"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}},{name:"dataverse_list_workflows",description:"Lists automation processes stored in the Dataverse environment: Power Automate cloud flows, classic workflows, business rules, business process flows, and actions. Optionally filter by category or partial name.",inputSchema:{type:"object",properties:{category:{type:"number",description:"Filter by process category: 0=Classic Workflow, 1=Dialog, 2=Business Rule, 3=Action, 4=Business Process Flow, 6=Power Automate (Cloud Flow). Omit to list all categories."},nameContains:{type:"string",description:"Filter by partial name match (case-insensitive contains)."},top:{type:"number",description:"Maximum number of results to return (default 50)."}},required:[]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}},{name:"dataverse_get_workflow",description:"Returns full details of a Dataverse automation process (workflow, cloud flow, business rule, or action) by its GUID.",inputSchema:{type:"object",properties:{workflowId:{type:"string",description:"GUID of the workflow/process record"}},required:["workflowId"]},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}}],Ot={0:"Classic Workflow",1:"Dialog",2:"Business Rule",3:"Action",4:"Business Process Flow",6:"Power Automate (Cloud Flow)"};async function Ut(a,i,r){if(a==="dataverse_list_guides"){let e=Array.from(oe.values()).map(t=>({name:t.name,description:t.description,tags:t.tags,stepCount:t.steps.length}));return H("guides",e,["Use dataverse_get_guide with a guide name to see detailed steps"])}if(a==="dataverse_get_guide"){let{name:e}=i,t=oe.get(e);if(!t){let n=Array.from(oe.keys()).join(", ");throw new Error(`Unknown guide: "${e}". Available guides: ${n}`)}return u(`Guide "${t.name}": ${t.description}`,t,t.steps.map(n=>`Step ${n.order}: ${n.tool} \u2014 ${n.description}`))}if(a==="dataverse_list_workflows"){let e=i,n=(await r.listDataverseWorkflows({...e.category!==void 0?{category:e.category}:{},...e.nameContains!==void 0?{nameContains:e.nameContains}:{},top:Math.min(e.top??50,200)})).map(o=>({workflowId:o.workflowid,name:o.name,category:Ot[o.category]??o.category,state:o.statecode===1?"Active":"Inactive",modifiedOn:o.modifiedon}));return H(`Dataverse workflows (${n.length} found)`,n,["Use dataverse_get_workflow with a workflowId GUID for full details","Filter with category: 0=Classic, 2=Business Rule, 4=BPF, 6=Cloud Flow"])}if(a==="dataverse_get_workflow"){let{workflowId:e}=i,t=await r.getDataverseWorkflow(e),n=t.category,o={...t,categoryLabel:Ot[n]??`Category ${n}`,stateLabel:t.statecode===1?"Active":"Inactive"};return u(`Workflow: ${t.name}`,o,[])}throw new Error(`Unknown workflow tool: ${a}`)}import{z as g}from"zod";var V=/^[a-z_][a-z0-9_]*$/,ye=["String","Memo","Integer","Decimal","Money","DateTime","Boolean","Picklist","MultiSelectPicklist","AutoNumber","Image"],Ln={String:"Microsoft.Dynamics.CRM.StringAttributeMetadata",Memo:"Microsoft.Dynamics.CRM.MemoAttributeMetadata",Integer:"Microsoft.Dynamics.CRM.IntegerAttributeMetadata",Decimal:"Microsoft.Dynamics.CRM.DecimalAttributeMetadata",Money:"Microsoft.Dynamics.CRM.MoneyAttributeMetadata",DateTime:"Microsoft.Dynamics.CRM.DateTimeAttributeMetadata",Boolean:"Microsoft.Dynamics.CRM.BooleanAttributeMetadata",Picklist:"Microsoft.Dynamics.CRM.PicklistAttributeMetadata",MultiSelectPicklist:"Microsoft.Dynamics.CRM.MultiSelectPicklistAttributeMetadata",AutoNumber:"Microsoft.Dynamics.CRM.StringAttributeMetadata",Image:"Microsoft.Dynamics.CRM.ImageAttributeMetadata"},Lt=g.object({entityLogicalName:g.string().min(1).regex(V,"Invalid Dataverse logical name"),schemaName:g.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/,"Invalid schema name"),attributeType:g.enum(ye),displayName:g.string().min(1),description:g.string().optional(),requiredLevel:g.enum(["None","ApplicationRequired","Recommended"]).optional().default("None"),maxLength:g.number().int().positive().optional(),minValue:g.number().optional(),maxValue:g.number().optional(),precision:g.number().int().min(0).max(10).optional(),dateTimeFormat:g.enum(["DateOnly","DateAndTime"]).optional().default("DateAndTime"),defaultBooleanValue:g.boolean().optional().default(!1),picklistOptions:g.array(g.object({value:g.number().int(),label:g.string().min(1)})).optional(),autoNumberFormat:g.string().optional(),languageCode:g.number().int().optional().default(1033),autoPublish:g.boolean().optional().default(!1),confirm:g.literal(!0,{errorMap:()=>({message:"Set confirm: true to create a column"})})}).refine(a=>a.attributeType!=="Picklist"&&a.attributeType!=="MultiSelectPicklist"||a.picklistOptions&&a.picklistOptions.length>0,{message:"picklistOptions is required for Picklist and MultiSelectPicklist types and must have at least one option"}),Pt=g.object({entityLogicalName:g.string().min(1).regex(V,"Invalid Dataverse logical name"),attributeLogicalName:g.string().min(1).regex(V,"Invalid Dataverse logical name"),displayName:g.string().min(1).optional(),description:g.string().optional(),requiredLevel:g.enum(["None","ApplicationRequired","Recommended"]).optional(),maxLength:g.number().int().positive().optional(),isSearchable:g.boolean().optional(),languageCode:g.number().int().optional().default(1033),autoPublish:g.boolean().optional().default(!1),confirm:g.literal(!0,{errorMap:()=>({message:"Set confirm: true to update column metadata"})})}).refine(a=>a.displayName!==void 0||a.description!==void 0||a.requiredLevel!==void 0||a.maxLength!==void 0||a.isSearchable!==void 0,{message:"At least one mutable property (displayName, description, requiredLevel, maxLength, isSearchable) must be provided"}),qt=g.object({entityLogicalName:g.string().min(1).regex(V,"Invalid Dataverse logical name"),attributeLogicalName:g.string().min(1).regex(V,"Invalid Dataverse logical name"),autoPublish:g.boolean().optional().default(!1),confirm:g.literal(!0,{errorMap:()=>({message:"Set confirm: true to delete a column \u2014 this is irreversible"})})});function D(a,i){return{"@odata.type":"Microsoft.Dynamics.CRM.Label",LocalizedLabels:[{"@odata.type":"Microsoft.Dynamics.CRM.LocalizedLabel",Label:a,LanguageCode:i}]}}function Ht(a){let i=a.languageCode,r={"@odata.type":Ln[a.attributeType],SchemaName:a.schemaName,DisplayName:D(a.displayName,i),RequiredLevel:{Value:a.requiredLevel}};switch(a.description&&(r.Description=D(a.description,i)),a.attributeType){case"String":r.MaxLength=a.maxLength??100;break;case"Memo":r.MaxLength=a.maxLength??4e3;break;case"Integer":r.Format="None",a.minValue!==void 0&&(r.MinValue=a.minValue),a.maxValue!==void 0&&(r.MaxValue=a.maxValue);break;case"Decimal":a.precision!==void 0&&(r.Precision=a.precision),a.minValue!==void 0&&(r.MinValue=a.minValue),a.maxValue!==void 0&&(r.MaxValue=a.maxValue);break;case"Money":r.PrecisionSource=a.precision!==void 0?0:2,a.precision!==void 0&&(r.Precision=a.precision);break;case"DateTime":r.Format=a.dateTimeFormat;break;case"Boolean":r.DefaultValue=a.defaultBooleanValue,r.OptionSet={TrueOption:{Value:1,Label:D("Yes",i)},FalseOption:{Value:0,Label:D("No",i)}};break;case"Picklist":r.OptionSet={"@odata.type":"Microsoft.Dynamics.CRM.OptionSetMetadata",IsGlobal:!1,OptionSetType:"Picklist",Options:a.picklistOptions.map(e=>({Value:e.value,Label:D(e.label,i)}))};break;case"MultiSelectPicklist":r.OptionSet={"@odata.type":"Microsoft.Dynamics.CRM.OptionSetMetadata",IsGlobal:!1,Options:a.picklistOptions.map(e=>({Value:e.value,Label:D(e.label,i)}))};break;case"AutoNumber":r.MaxLength=a.maxLength??100,a.autoNumberFormat&&(r.AutoNumberFormat=a.autoNumberFormat);break;case"Image":break}return r}var $t=g.object({entityLogicalName:g.string().min(1).regex(V),schemaName:g.string().min(1).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/),displayName:g.string().min(1),description:g.string().optional(),referencedEntity:g.string().min(1).regex(V),requiredLevel:g.enum(["None","ApplicationRequired","Recommended"]).optional().default("None"),cascadeConfiguration:g.enum(["Referential","Parental"]).optional().default("Referential"),languageCode:g.number().int().optional().default(1033),autoPublish:g.boolean().optional().default(!1),confirm:g.literal(!0,{errorMap:()=>({message:"Set confirm: true to create a lookup column"})})});function Mt(a){let i=a.languageCode,r=a.schemaName.includes("_")?a.schemaName.slice(0,a.schemaName.indexOf("_")):a.schemaName,e=a.schemaName.includes("_")?a.schemaName.slice(a.schemaName.indexOf("_")+1):a.schemaName,t=`${r}_${a.referencedEntity}_${a.entityLogicalName}_${e}`;if(t.length>100)throw new Error(`Auto-generated relationship SchemaName '${t}' is ${t.length} chars, exceeding Dataverse's 100-char limit. Use shorter entity logical names or column schema names.`);let n={"@odata.type":"Microsoft.Dynamics.CRM.LookupAttributeMetadata",AttributeType:"Lookup",AttributeTypeName:{Value:"LookupType"},SchemaName:a.schemaName,DisplayName:D(a.displayName,i),RequiredLevel:{Value:a.requiredLevel}};return a.description&&(n.Description=D(a.description,i)),{"@odata.type":"Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",SchemaName:t,ReferencedEntity:a.referencedEntity,ReferencedAttribute:`${a.referencedEntity}id`,ReferencingEntity:a.entityLogicalName,Lookup:n,CascadeConfiguration:a.cascadeConfiguration==="Parental"?{Assign:"Cascade",Delete:"Cascade",Merge:"Cascade",Reparent:"Cascade",Share:"Cascade",Unshare:"Cascade"}:{Assign:"NoCascade",Delete:"RemoveLink",Merge:"NoCascade",Reparent:"NoCascade",Share:"NoCascade",Unshare:"NoCascade"},AssociatedMenuConfiguration:{Behavior:"UseCollectionName",Group:"Details",Label:D(a.displayName,i),Order:1e4}}}var ve=[{name:"dataverse_create_attribute",description:"Creates a new column (attribute) on an existing Dataverse table. Supports String, Memo, Integer, Decimal, Money, DateTime, Boolean, Picklist, MultiSelectPicklist, AutoNumber, and Image types. IMPORTANT: Column type CANNOT be changed after creation \u2014 choose carefully. Requires System Customizer or System Administrator privileges. WHEN TO USE: Adding a new column to a table. BEST PRACTICES: Use dataverse_get_table_metadata first to check existing columns. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Logical name of the target table (e.g. 'account', 'new_mytable')"},schemaName:{type:"string",description:"Schema name for the new column (e.g. 'new_mycolumn'). Must include publisher prefix."},attributeType:{type:"string",enum:ye,description:"Column data type. CANNOT be changed after creation. String=single-line text, Memo=multi-line, Integer=whole number, Decimal=decimal number, Money=currency, DateTime=date/time, Boolean=yes/no, Picklist=choice/option set, MultiSelectPicklist=multi-choice, AutoNumber=auto-generated sequence, Image=image file."},displayName:{type:"string",description:"Display label for the column"},description:{type:"string",description:"Optional description of the column"},requiredLevel:{type:"string",enum:["None","ApplicationRequired","Recommended"],description:"Required level. Default: None"},maxLength:{type:"number",description:"Max length for String (default 100, max 4000) or Memo (default 4000, max 1048576) types"},minValue:{type:"number",description:"Minimum value for Integer or Decimal types"},maxValue:{type:"number",description:"Maximum value for Integer or Decimal types"},precision:{type:"number",description:"Decimal precision for Decimal (0-10) or Money types"},dateTimeFormat:{type:"string",enum:["DateOnly","DateAndTime"],description:"Format for DateTime type. CANNOT be changed after creation. Default: DateAndTime"},defaultBooleanValue:{type:"boolean",description:"Default value for Boolean type. Default: false"},picklistOptions:{type:"array",items:{type:"object",properties:{value:{type:"number",description:"Integer value for the option"},label:{type:"string",description:"Display label for the option"}},required:["value","label"]},description:"Options for Picklist and MultiSelectPicklist types. Each option needs a value (integer) and label (text)."},autoNumberFormat:{type:"string",description:"Auto-number format string for AutoNumber type (e.g. 'INV-{SEQNUM:5}'). Only used when attributeType=AutoNumber."},languageCode:{type:"number",description:"Language code for labels. Default: 1033 (English)"},autoPublish:{type:"boolean",description:"Publish the customization after creation (default: false). Set true only when creating a single column in isolation. For batch column creation, leave false and call dataverse_publish_customizations once at the end with components.entities=[entityLogicalName]."},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional schema modification"}},required:["entityLogicalName","schemaName","attributeType","displayName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_update_attribute",description:"Updates mutable properties of an existing column (attribute): display name, description, required level, max length (increase only for String/Memo), and search indexing. CANNOT change: column type, logical name, DateTime format, or lookup targets \u2014 these are immutable after creation. Requires System Customizer or System Administrator privileges. WHEN TO USE: Changing a column's label, description, or required level. BEST PRACTICES: Use dataverse_get_table_metadata first to see current values. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Logical name of the table"},attributeLogicalName:{type:"string",description:"Logical name of the column to update"},displayName:{type:"string",description:"New display label for the column"},description:{type:"string",description:"New description for the column"},requiredLevel:{type:"string",enum:["None","ApplicationRequired","Recommended"],description:"New required level"},maxLength:{type:"number",description:"New max length for String/Memo columns. Can only INCREASE, never decrease."},isSearchable:{type:"boolean",description:"Enable or disable Dataverse Search indexing on this column"},languageCode:{type:"number",description:"Language code for labels. Default: 1033 (English)"},autoPublish:{type:"boolean",description:"Publish the customization after update (default: false). Set true only for a single isolated update. For batch updates, leave false and call dataverse_publish_customizations once at the end."},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional schema modification"}},required:["entityLogicalName","attributeLogicalName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}},{name:"dataverse_delete_attribute",description:"Deletes a column (attribute) from a Dataverse table. WARNING: This permanently deletes the column AND all its data. Automatically checks dependencies (views, workflows, forms) before deletion \u2014 refuses if dependencies exist unless force=true. Managed solution columns cannot be deleted. WHEN TO USE: Removing an obsolete custom column. BEST PRACTICES: Use dataverse_get_table_metadata to verify the column exists; check dependencies first. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Logical name of the table"},attributeLogicalName:{type:"string",description:"Logical name of the column to delete"},autoPublish:{type:"boolean",description:"Publish the customization after deletion (default: false). Set true only for a single isolated deletion. For batch operations, leave false and publish once at the end."},confirm:{type:"boolean",description:"Must be true \u2014 confirms intentional deletion of column and ALL its data"}},required:["entityLogicalName","attributeLogicalName","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!0,idempotentHint:!1,openWorldHint:!0}},{name:"dataverse_create_lookup_attribute",description:"Creates a Lookup column on a Dataverse table by creating a One-to-Many relationship. Use this for typed relationship columns (e.g. 'Account' field on a custom table pointing to the account table). IMPORTANT: Creates both the relationship AND the lookup column in one operation. cascadeConfiguration defaults to 'Referential' (NoCascade on Assign/Reparent/Share/Unshare, RemoveLink on Delete). Use 'Parental' only when the source table has no existing parental relationship with the target. Requires System Customizer or System Administrator privileges.",inputSchema:{type:"object",properties:{entityLogicalName:{type:"string",description:"Source table logical name (referencing)"},schemaName:{type:"string",description:"Schema name for the lookup column (e.g. 'new_accountid')"},displayName:{type:"string",description:"Display label"},description:{type:"string",description:"Optional description"},referencedEntity:{type:"string",description:"Target table logical name (e.g. 'account')"},requiredLevel:{type:"string",enum:["None","ApplicationRequired","Recommended"],description:"Required level. Default: None"},languageCode:{type:"number",description:"Language code. Default: 1033"},cascadeConfiguration:{type:"string",enum:["Referential","Parental"],description:"Cascade behavior. 'Referential' (default): NoCascade on most actions, RemoveLink on Delete \u2014 works on any table pair. 'Parental': full Cascade \u2014 only if no parental relation exists yet with the target."},autoPublish:{type:"boolean",description:"Publish after creation (default: false). Set true only for a single isolated lookup. For batch creation leave false and call dataverse_publish_customizations once at the end with components.entities=[entityLogicalName]."},confirm:{type:"boolean",description:"Must be true"}},required:["entityLogicalName","schemaName","displayName","referencedEntity","confirm"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function Wt(a,i,r){switch(a){case"dataverse_create_attribute":{let e=Lt.parse(i),t=q({toolName:"dataverse_create_attribute",entitySetName:e.entityLogicalName}).map(s=>`[${s.severity.toUpperCase()}] ${s.code}: ${s.message}`),n=Ht(e),o=await r.createAttribute(e.entityLogicalName,n),l="autoPublish=false (skipped)";return e.autoPublish&&(await r.publishCustomizations({entities:[e.entityLogicalName]}),l="published successfully"),u(`Column '${e.schemaName}' (${e.attributeType}) created on '${e.entityLogicalName}'. ${l}.`,{entityLogicalName:e.entityLogicalName,schemaName:e.schemaName,attributeType:e.attributeType,metadataId:o,published:e.autoPublish,...t.length>0&&{warnings:t}},["Use dataverse_get_table_metadata to verify the new column","Column type CANNOT be changed after creation \u2014 to change type, create a new column and migrate data"])}case"dataverse_update_attribute":{let e=Pt.parse(i),t=q({toolName:"dataverse_update_attribute",entitySetName:e.entityLogicalName}).map(c=>`[${c.severity.toUpperCase()}] ${c.code}: ${c.message}`),n=e.languageCode,o={},l={};e.displayName!==void 0&&(o.DisplayName=D(e.displayName,n),l.DisplayName=e.displayName),e.description!==void 0&&(o.Description=D(e.description,n),l.Description=e.description),e.requiredLevel!==void 0&&(o.RequiredLevel={Value:e.requiredLevel},l.RequiredLevel=e.requiredLevel),e.maxLength!==void 0&&(o.MaxLength=e.maxLength,l.MaxLength=e.maxLength),e.isSearchable!==void 0&&(o.IsSearchable=e.isSearchable,l.IsSearchable=e.isSearchable),await r.updateAttribute(e.entityLogicalName,e.attributeLogicalName,o);let s=Object.entries(l).map(([c,p])=>`${c}=${String(p)}`).join(", "),d="autoPublish=false (skipped)";return e.autoPublish&&(await r.publishCustomizations({entities:[e.entityLogicalName]}),d="published successfully"),u(`Column '${e.attributeLogicalName}' on '${e.entityLogicalName}' updated: ${s}. ${d}.`,{entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName,changes:l,published:e.autoPublish,...t.length>0&&{warnings:t}},["Use dataverse_get_table_metadata to verify the changes","Column type, logical name, and DateTime format cannot be changed \u2014 these are immutable after creation"])}case"dataverse_delete_attribute":{let e=qt.parse(i),t=q({toolName:"dataverse_delete_attribute",entitySetName:e.entityLogicalName}).map(o=>`[${o.severity.toUpperCase()}] ${o.code}: ${o.message}`);try{await r.deleteAttribute(e.entityLogicalName,e.attributeLogicalName)}catch(o){let l=o instanceof Error?o.message:String(o);if(l.includes("0x80048405"))return O({summary:`Cannot delete column '${e.attributeLogicalName}': it belongs to a managed solution and cannot be deleted.`,data:{error:"0x80048405",entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName},errorCategory:"SCHEMA_MISMATCH",suggestions:["Managed solution columns can only be removed by uninstalling the solution"]});if(l.includes("dependency")||l.includes("dependencies")||l.includes("DependencyList"))return O({summary:`Cannot delete column '${e.attributeLogicalName}': it has dependencies (views, workflows, forms, or other components reference it).`,data:{error:"HAS_DEPENDENCIES",entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName,rawError:l},errorCategory:"SCHEMA_MISMATCH",suggestions:["Use dataverse_list_dependencies to identify what references this column","Remove all references before retrying deletion"]});let s=l.match(/0x[0-9a-fA-F]{8}/),d=s?s[0]:"UNKNOWN";return O({summary:`Cannot delete column '${e.attributeLogicalName}': deletion rejected by Dataverse (${d}).`,data:{error:d,entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName,rawError:l},errorCategory:"SCHEMA_MISMATCH",suggestions:["Verify this is a custom (non-managed, non-system) column","Check that no solution dependencies or forms reference this column","Standard system attributes (e.g. accountnumber) cannot be deleted"]})}let n="autoPublish=false (skipped)";return e.autoPublish&&(await r.publishCustomizations({entities:[e.entityLogicalName]}),n="published successfully"),u(`Column '${e.attributeLogicalName}' deleted from '${e.entityLogicalName}'. ${n}. All data in this column has been permanently removed.`,{entityLogicalName:e.entityLogicalName,attributeLogicalName:e.attributeLogicalName,deleted:!0,published:e.autoPublish,...t.length>0&&{warnings:t}},["This action is irreversible \u2014 the column and its data cannot be recovered","The column logical name is tombstoned and cannot be reused for ~90 days"])}case"dataverse_create_lookup_attribute":{let e=$t.parse(i),t=q({toolName:"dataverse_create_lookup_attribute",entitySetName:e.entityLogicalName}).map(d=>`[${d.severity.toUpperCase()}] ${d.code}: ${d.message}`),n=Mt(e),o,l=!1;try{o=await r.createRelationship(n)}catch(d){if((d instanceof Error?d.message:String(d)).includes("Request timed out")){let p=!1;try{p=((await r.getTableMetadata(e.entityLogicalName,!0)).Attributes??[]).some(N=>N.LogicalName===e.schemaName.toLowerCase())}catch{}if(p)l=!0,o="";else throw d}else throw d}let s="autoPublish=false (skipped)";return e.autoPublish&&!l?(await r.publishCustomizations({entities:[e.entityLogicalName,e.referencedEntity]}),s="published successfully"):l&&(s="publish skipped (request timed out \u2014 use dataverse_publish_customizations to publish)"),l&&t.push("REQUEST TIMED OUT but lookup was found on the table \u2014 creation succeeded. MetadataId unavailable."),u(`Lookup column '${e.schemaName}' created on '${e.entityLogicalName}' \u2192 '${e.referencedEntity}'. ${s}.`,{entityLogicalName:e.entityLogicalName,schemaName:e.schemaName,referencedEntity:e.referencedEntity,...o&&{metadataId:o},published:e.autoPublish&&!l,...t.length>0&&{warnings:t}},["Use dataverse_get_table_metadata to verify the new lookup column","Lookup columns cannot be created via the standard attribute API \u2014 this uses the RelationshipDefinitions endpoint"])}default:throw new Error(`Unknown attribute tool: ${a}`)}}import{z as T}from"zod";function j(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function Pn(a){let i=0,r=0,e=0;return`<SiteMap>
|
|
13
|
+
${a.map(n=>{let o=n.id??`Area_${++i}`,l=n.groups.map(s=>{let d=s.id??`Group_${++r}`,c=s.subareas.map(p=>{let m=p.id??`Sub_${++e}`,f=[`Id="${j(m)}"`];return p.entityLogicalName&&f.push(`Entity="${j(p.entityLogicalName)}"`),p.url&&f.push(`Url="${j(p.url)}"`),p.title&&f.push(`Title="${j(p.title)}"`),` <SubArea ${f.join(" ")}/>`});return` <Group Id="${j(d)}" Title="${j(s.title)}">
|
|
14
|
+
`+c.join(`
|
|
15
|
+
`)+`
|
|
16
|
+
</Group>`});return` <Area Id="${j(o)}" Title="${j(n.title)}" ShowGroups="true">
|
|
17
|
+
`+l.join(`
|
|
18
|
+
`)+`
|
|
19
|
+
</Area>`}).join(`
|
|
20
|
+
`)}
|
|
21
|
+
</SiteMap>`}var qn=T.object({id:T.string().optional(),entityLogicalName:T.string().optional(),url:T.string().optional(),title:T.string().optional()}),Hn=T.object({id:T.string().optional(),title:T.string(),subareas:T.array(qn).min(1)}),$n=T.object({id:T.string().optional(),title:T.string(),groups:T.array(Hn).min(1)}),Mn=T.object({sitemapName:T.string().min(1),appModuleUniqueName:T.string().optional(),areas:T.array($n).min(1)}),jt=[{name:"dataverse_create_sitemap",description:"Creates a model-driven app sitemap (navigation structure) by generating valid sitemap XML and posting it to the Dataverse sitemaps entity set (POST /api/data/v9.2/sitemaps with field sitemapxml). Optionally links the sitemap to an existing model-driven app module by patching the appmodule's sitemapid_sitemap navigation property. WHEN TO USE: Scaffolding a model-driven app that needs a navigation structure (areas, groups, subareas). BEST PRACTICES: Keep area/group/subarea IDs short and URL-safe (e.g. 'nav_accounts', 'grp_sales'). Specify entityLogicalName OR url per SubArea, not both. Call dataverse_publish_customizations after creation to publish the sitemap. To find appModuleUniqueName, query appmodules with $select=uniquename,name. WORKFLOW: manage_solution.",inputSchema:{type:"object",properties:{sitemapName:{type:"string",description:"Display name of the sitemap (stored in sitemapname field)"},appModuleUniqueName:{type:"string",description:"Unique name of the model-driven app to link this sitemap to (optional). Query appmodules entity set for uniquename values."},areas:{type:"array",description:"One or more navigation areas (min 1)",items:{type:"object",properties:{id:{type:"string",description:"Area element ID (auto-generated if omitted, e.g. 'nav_area1')"},title:{type:"string",description:"Area display title"},groups:{type:"array",description:"Groups inside this area (min 1)",items:{type:"object",properties:{id:{type:"string",description:"Group element ID (auto-generated if omitted)"},title:{type:"string",description:"Group display title"},subareas:{type:"array",description:"SubAreas (navigation items) inside this group (min 1)",items:{type:"object",properties:{id:{type:"string",description:"SubArea element ID (auto-generated if omitted)"},entityLogicalName:{type:"string",description:"Entity logical name to navigate to (e.g. 'account')"},url:{type:"string",description:"Custom URL target (alternative to entityLogicalName)"},title:{type:"string",description:"SubArea display title"}},required:[]}}},required:["title","subareas"]}}},required:["title","groups"]}}},required:["sitemapName","areas"]},annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}}];async function Ft(a,i,r){switch(a){case"dataverse_create_sitemap":{let{sitemapName:e,appModuleUniqueName:t,areas:n}=Mn.parse(i),o=Pn(n),l=await r.createRecord("sitemaps",{sitemapname:e,sitemapxml:o}),s=!1,d=null;if(t){let c=await r.query("appmodules",{select:["appmoduleid"],filter:`uniquename eq '${t}'`,top:1});if(c.value.length===0)return u(`Sitemap '${e}' created (id: ${l}) \u2014 app module not found`,{sitemapId:l,sitemapName:e,linked:!1,warning:`App module '${t}' not found. Sitemap was created but not linked.`,sitemapxml:o},["Run dataverse_publish_customizations to publish the new sitemap","Query appmodules ($select=uniquename,name) to verify the app module unique name"]);d=c.value[0].appmoduleid,await r.updateRecord("appmodules",d,{"sitemapid_sitemap@odata.bind":`/sitemaps(${l})`}),s=!0}return u(`Sitemap '${e}' created successfully`,{sitemapId:l,sitemapName:e,linked:s,appModuleUniqueName:t??null,appModuleId:d,areaCount:n.length,sitemapxml:o},["Run dataverse_publish_customizations to publish the sitemap",s?`Sitemap linked to app '${t}' (appmoduleid: ${d})`:"Provide appModuleUniqueName to link this sitemap to a model-driven app"])}default:throw new Error(`Unknown sitemap tool: ${a}`)}}var Vt=Se([{tools:Te,handler:Ne},{tools:Ie,handler:De},{tools:Ue,handler:Le},{tools:Pe,handler:qe},{tools:He,handler:$e},{tools:Me,handler:We},{tools:je,handler:Fe},{tools:Be,handler:Ge},{tools:ze,handler:Ve},{tools:Xe,handler:Qe},{tools:Ye,handler:Je},{tools:Ze,handler:et},{tools:tt,handler:at},{tools:nt,handler:rt},{tools:ot,handler:st},{tools:lt,handler:dt},{tools:ct,handler:ut},{tools:ft,handler:yt},{tools:vt,handler:ht},{tools:bt,handler:_t},{tools:Tt,handler:Nt},{tools:Rt,handler:At},{tools:Ct,handler:Ut},{tools:ve,handler:Wt},{tools:jt,handler:Ft},{tools:Et,handler:xt}]),Jn=new Set(ue.map(a=>a.name)),Kt=[...Vt.getAllDefinitions(),...ue],Zn=Qn(Yn(import.meta.url)),Xt=JSON.parse(Kn(Xn(Zn,"../package.json"),"utf-8")).version,Bt=`You are connected to a Microsoft Dataverse environment via the mcp-dataverse server.
|
|
11
22
|
|
|
12
23
|
## Recommended Workflow
|
|
13
24
|
1. Start with dataverse_whoami to verify authentication.
|
|
@@ -34,11 +45,11 @@ import{a as ue}from"./chunk-SUDI4JM6.js";import{a as pe}from"./chunk-PAX4NW5B.js
|
|
|
34
45
|
- Avoid retrieving more than 5000 records unless explicitly needed (use dataverse_retrieve_multiple_with_paging with maxTotal).
|
|
35
46
|
- Use server-side filtering ($filter / FetchXML conditions) instead of client-side filtering.
|
|
36
47
|
- Cache table metadata \u2014 it rarely changes during a session.
|
|
37
|
-
`;function
|
|
38
|
-
`);try{await
|
|
39
|
-
`)}catch(n){let
|
|
40
|
-
`)}await t(()=>
|
|
41
|
-
`),
|
|
42
|
-
`)}).catch(
|
|
43
|
-
`)})}}async function
|
|
48
|
+
`;function Gt(a,i,r,e){let t=Vt.getHandler(a);if(!t)throw new Error(`Unknown tool: ${a}`);return t(a,i,r,e)}function zt(a){let i=new Wn({name:"mcp-dataverse",version:Xt},{capabilities:{tools:{},resources:{}},instructions:Bt});return i.setRequestHandler(Bn,async()=>({tools:Kt})),i.setRequestHandler(Fn,async r=>{let{name:e,arguments:t}=r.params,n=r.params._meta?.progressToken,o=new J(n!=null?i:void 0,n);try{return Jn.has(e)?Ke(e,t,a,Gt):await Gt(e,t,a,o)}catch(l){return{content:[{type:"text",text:`Error: ${l instanceof Error?l.message:String(l)}`}],isError:!0}}}),i.setRequestHandler(Gn,async()=>({resources:kt()})),i.setRequestHandler(zn,async()=>({resourceTemplates:It()})),i.setRequestHandler(Vn,async r=>({contents:[await Dt(r.params.uri,a,Bt)]})),i}async function er(){let a=he(),i=be(a),r=new _e(i,a.maxRetries,a.requestTimeoutMs),e=we();if(e.transport==="http"){let{startHttpTransport:t}=await import("./http-server.js");process.stderr.write(`Starting HTTP transport on port ${e.port}...
|
|
49
|
+
`);try{await i.getToken(),process.stderr.write(`[mcp-dataverse] Authenticated \u2713
|
|
50
|
+
`)}catch(n){let o=n instanceof Error?n.message:String(n);process.stderr.write(`[mcp-dataverse] Authentication failed: ${o}
|
|
51
|
+
`)}await t(()=>zt(r),e.port,Xt,Kt.length)}else{let t=zt(r),n=new jn;await t.connect(n),process.stderr.write(`MCP Dataverse server started
|
|
52
|
+
`),i.getToken().then(()=>{process.stderr.write(`[mcp-dataverse] Authenticated \u2713
|
|
53
|
+
`)}).catch(o=>{let l=o instanceof Error?o.message:String(o);process.stderr.write(`[mcp-dataverse] Authentication failed: ${l}
|
|
54
|
+
`)})}}async function tr(){if(process.argv.includes("install")){let{runInstall:a}=await import("./install.js");await a(),process.exit(0)}if(process.argv.includes("doctor")){let{runDoctor:a}=await import("./doctor.js");await a()}await er()}tr().catch(a=>{process.stderr.write(`Fatal error: ${a instanceof Error?a.message:String(a)}
|
|
44
55
|
`),process.exit(1)});
|