ToolBox API
The ToolBox API provides access to platform features and utilities.
For complete TypeScript definitions, install the @pptb/types package: bash npm install --save-dev @pptb/types
Tool Lifecycle
Use these methods to prevent a user from accidentally closing a tool that has unsaved work or an operation in progress. The guard applies only to the current tool instance.
toolboxAPI.preventClose()
Prevents the current tool instance from closing. When the user closes its tab or quits Power Platform ToolBox, the host displays a warning and offers an Ignore & Close override.
Returns: Promise<boolean>
toolboxAPI.releasePreventClose()
Releases the prevent-close state previously set for the current tool instance. Call this after saving changes, completing the protected operation, or when the user discards their work.
Returns: Promise<boolean>
async function saveChanges() {
await toolboxAPI.preventClose()
try {
await persistChanges()
} finally {
await toolboxAPI.releasePreventClose()
}
}
Connections
Get information about the active Dataverse connection(s).
In @pptb/types, DataverseConnection is deprecated and has been renamed to Connection.
toolboxAPI.connections.getActiveConnection()
Returns the currently active connection or null if none is selected.
const connection = await toolboxAPI.connections.getActiveConnection()
if (connection) {
console.log('Connected to:', connection.name)
console.log('Environment:', connection.environment)
console.log('URL:', connection.url)
} else {
console.log('No active connection')
}
Returns: Promise<Connection | null>
interface Connection {
id: string // Unique identifier of the connection
name: string // Friendly name of the connection
url: string // Base URL of the Dataverse instance
environment: 'Dev' | 'Test' | 'UAT' | 'Production' // Environment classification
environmentColor?: string // Hex color code associated with the environment (added in 1.2.0)
category?: string // Category label assigned to the connection (added in 1.2.0)
categoryColor?: string // Hex color code for the category badge (added in 1.2.0)
createdAt: string // ISO date string of when the connection was created
lastUsedAt?: string // ISO date string of when the connection was last used
enabledForPowerPlatformAPI?: boolean // True when this connection is enabled for Power Platform API usage
scopesForPowerPlatformAPI?: string[] // Granted scopes for Power Platform API calls
isActive?: boolean // @deprecated legacy field retained for backwards compatibility
}
// Deprecated compatibility alias
type DataverseConnection = Connection
Example values that may appear in scopesForPowerPlatformAPI:
[
'https://api.powerplatform.com/EnvironmentManagement.Environments.Read',
'https://api.powerplatform.com/EnvironmentManagement.Groups.Read',
'https://api.powerplatform.com/EnvironmentManagement.Groups.ReadWrite',
'https://api.powerplatform.com/EnvironmentManagement.Settings.Read',
'https://api.powerplatform.com/EnvironmentManagement.Settings.ReadWrite',
'https://api.powerplatform.com/Governance.CrossTenantConnectionReports.Read',
'https://api.powerplatform.com/Governance.CrossTenantConnectionReports.ReadWrite',
'https://api.powerplatform.com/PowerApps.Apps.Play',
'https://api.powerplatform.com/PowerApps.Apps.Read',
'https://api.powerplatform.com/PowerAutomate.Flows.Read',
'https://api.powerplatform.com/.default',
]
Multiple Connections
As a tool developer, you may require access to more than one Dataverse connection. This can be useful for copying data or configuration between environments.
In Desktop 1.2.7 and later, declare the exact count or range your tool supports using features.connections in package.json.
{
"features": {
"connections": { "min": 2, "max": 2 },
"minAPI": "1.2.7"
}
}
The example requires exactly two connections. Use an integer for an exact count from 0 to 10, or { "min": 0, "max": 3 } to allow launch with no connection and up to three connections. The deprecated multiConnection and connectionRequirement fields remain supported for existing tools, but cannot be used together with connections.
toolboxAPI.connections.getConnection(target)
Returns the connection assigned to the requested slot, or null if that slot is empty. target accepts the legacy aliases 'primary' and 'secondary', or a zero-based numeric slot index (0 is primary, 1 is secondary, 2 and above are additional slots).
const secondaryConnection = await toolboxAPI.connections.getConnection('secondary')
if (secondaryConnection) {
console.log('Secondary environment:', secondaryConnection.name)
} else {
console.log('No connection assigned to the secondary slot')
}
Returns: Promise<Connection | null>
toolboxAPI.connections.getConnections()
Returns all connection slots in slot order. Empty slots are null and are not removed or compacted; use each array index as the slot index (slot 0 is primary, slot 1 is secondary).
const connections = await toolboxAPI.connections.getConnections()
for (const [slotIndex, connection] of connections.entries()) {
if (connection === null) {
console.log(`Slot ${slotIndex} is empty`)
continue
}
console.log(`Slot ${slotIndex}: ${connection.name}`)
}
Returns: Promise<Array<Connection | null>>
toolboxAPI.connections.getSecondaryConnection()
Deprecated: Prefer getConnection('secondary') for the secondary slot, or getConnections() to enumerate all slots. This method remains available and continues to work for backward compatibility; it has not been removed in Desktop 1.2.7.
Returns the currently active secondary connection or null if none is configured.
const secondaryConnection =
await toolboxAPI.connections.getSecondaryConnection()
Returns: Promise<Connection | null>
When interacting with dataverse and you want to use the secondary connection, pass the connectionTarget parameter as 'secondary'. ConnectionTarget is optional and defaults to 'primary'.
// Example usage of dataverseAPI using secondary connection
const myTables = await dataverseAPI.getAllEntitiesMetadata(
['logicalName'],
'secondary',
)
Utils
Utility functions for notifications, clipboard, and more.
Breaking Change: saveFile() and selectPath() have been migrated to the File System API. See File System API for details.
toolboxAPI.utils.showNotification(options)
Display a notification to the user.
await toolboxAPI.utils.showNotification({
title: 'Success',
body: 'Operation completed successfully',
type: 'success', // 'info' | 'success' | 'warning' | 'error'
duration: 3000, // Auto-dismiss after 3 seconds
})
Parameters:
options- Notification configuration object
Types:
type:'info' | 'success' | 'warning' | 'error'duration: Number in milliseconds (0 = persistent)
toolboxAPI.utils.copyToClipboard(text)
Copy text to the system clipboard.
const data = JSON.stringify({ accounts: [], contacts: [] }, null, 2)
await toolboxAPI.utils.copyToClipboard(data)
await toolboxAPI.utils.showNotification({
title: 'Copied',
body: 'Data copied to clipboard',
type: 'success',
})
toolboxAPI.utils.getCurrentTheme()
Get the current application theme.
const theme = await toolboxAPI.utils.getCurrentTheme()
document.body.classList.add(`theme-${theme}`)
Returns: Promise<'light' | 'dark'>
toolboxAPI.utils.executeParallel(...operations)
Execute multiple async operations in parallel. Each operation can be an already-started promise or an async function, which is called when execution begins.
const [account, contact, opportunities] =
await toolboxAPI.utils.executeParallel(
dataverseAPI.retrieve('account', accountId, ['name']),
dataverseAPI.retrieve('contact', contactId, ['fullname']),
() => dataverseAPI.fetchXmlQuery(opportunityFetchXml),
)
console.log('All data fetched:', account, contact, opportunities)
toolboxAPI.utils.openInConnectionBrowser(url, connectionTarget?)
Open a URL in the external browser associated with the tool's active connection. When the connection has a browser profile configured (e.g. a specific Chrome or Edge profile), the URL is opened in that browser and profile so the user is already authenticated. Falls back to the system default browser when no profile is configured.
Only https: and http: URLs are allowed.
// Open a record in the browser using the primary connection's browser profile
await toolboxAPI.utils.openInConnectionBrowser(
'https://contoso.crm.dynamics.com/main.aspx?etn=account&id=guid-here&pagetype=entityrecord',
)
// Open a URL using the secondary connection's browser profile
await toolboxAPI.utils.openInConnectionBrowser(
'https://contoso-dev.crm.dynamics.com/main.aspx?pagetype=entitylist&etn=account',
'secondary',
)
Parameters:
url: string— The URL to open (must usehttps:orhttp:protocol)connectionTarget?: ConnectionTarget— Which connection's browser profile to use. Accepts'primary','secondary', or a zero-based numeric slot index; defaults to'primary'.
Returns: Promise<void>
Terminal
Create and manage terminal sessions (context-aware to your tool).
toolboxAPI.terminal.create(options)
Create a new terminal.
const terminal = await toolboxAPI.terminal.create({
name: 'Build Terminal',
cwd: '/path/to/project',
env: {
NODE_ENV: 'production',
},
})
console.log('Terminal created:', terminal.id)
toolboxAPI.terminal.execute(terminalId, command)
Execute a command in a terminal.
const result = await toolboxAPI.terminal.execute(terminal.id, 'npm install')
if (result.exitCode === 0) {
console.log('Command completed successfully')
} else {
console.error('Command failed:', result.error)
}
toolboxAPI.terminal.setVisibility(terminalId, visible)
Show or hide a terminal's UI panel.
await toolboxAPI.terminal.setVisibility(terminal.id, true)
toolboxAPI.terminal.list()
List all terminals created by your tool.
const terminals = await toolboxAPI.terminal.list()
console.log(`This tool has ${terminals.length} terminals`)
toolboxAPI.terminal.close(terminalId)
Close a terminal.
await toolboxAPI.terminal.close(terminal.id)
Invocation API
The Invocation API enables inter-tool communication — one tool can launch another, pass prefill data, and receive a return value when the callee finishes.
toolboxAPI.invocation.launchTool(targetToolId, prefillData?, options?)
Launch another installed tool from within your tool and optionally pass prefill data. Returns a Promise that resolves with the data the target tool sends back via returnData(), or null if the target tool closes without returning data.
// Tool A: launch an entity-picker tool and wait for the result
const result = await toolboxAPI.invocation.launchTool(
'@my-org/entity-picker',
{ entityName: 'account' },
)
if (result) {
console.log('Selected ID:', result.selectedId)
console.log('Selected name:', result.selectedName)
}
Parameters:
targetToolId: string— npm package name (toolId) of the tool to launchprefillData?: Record<string, unknown>— Data to pre-populate the target tool's stateoptions?: object— Optional connection overrides:{ primaryConnectionId?, secondaryConnectionId?, connectionIds?, noReturn? }.connectionIds?: Array<string | null>assigns IDs positionally by slot; preservenullentries for gaps. Legacy primary and secondary overrides remain available.
Returns: Promise<unknown> — Data returned by the target tool, or null if it closes without returning data
toolboxAPI.invocation.getLaunchContext()
Read the prefill data passed by the tool that launched this tool. Returns null if this tool was not launched via an inter-tool invocation.
// Tool B: read the launch context on startup
const ctx = await toolboxAPI.invocation.getLaunchContext()
if (ctx) {
console.log('Launched with entity:', ctx.entityName)
// Pre-populate UI based on ctx...
}
Returns: Promise<Record<string, unknown> | null>
toolboxAPI.invocation.returnData(returnData)
Return data back to the tool that launched this tool. This resolves the Promise returned by the caller's launchTool() call. If this tool was not launched by another tool, the call is a no-op.
// Tool B: after the user makes a selection, return it to the caller
await toolboxAPI.invocation.returnData({
selectedId: 'guid-here',
selectedName: 'Contoso Ltd',
})
Parameters:
returnData: Record<string, unknown>— Data to pass back to the caller
Returns: Promise<void>
Tool Context
toolboxAPI.getToolContext()
Returns the current tool context used by the framework.
const context = await toolboxAPI.getToolContext()
console.log('Tool ID:', context.toolId)
console.log('Instance ID:', context.instanceId)
console.log('Primary URL:', context.connectionUrl)
console.log('Secondary URL:', context.secondaryConnectionUrl)
Returns: Promise<ToolContext>
interface ToolContext {
toolId: string | null
instanceId?: string | null
connectionUrl: string | null
connectionId?: string | null
secondaryConnectionUrl?: string | null
secondaryConnectionId?: string | null
connectionIds?: Array<string | null>
connectionUrls?: Array<string | null>
invocationContext?: {
source?: 'tool' | 'mcp'
mode?: 'one-way' | 'two-way'
correlationId?: string
timeoutMs?: number
expectsResponse?: boolean
}
}
connectionIds and connectionUrls are aligned arrays indexed by slot and preserve null entries for unassigned slots. invocationContext is optional metadata supplied when another tool or the MCP server launched this tool; branch on its source or mode instead of assuming it is present.
ToolContext intentionally does not contain access tokens. Use dataverseAPI for authenticated Dataverse operations.