Skip to main content
Glama
business-central-mcp

business-central-mcp

by SShadowS

bc_write_data

Destructive

Writes field values on an open Business Central page and returns the server-confirmed values, including line-item edits and stale-state protection.

Instructions

Writes one or more field values on an already-open Business Central page. Pass a fields object keyed by the field names a read lists (the caption, or the AL control name of a caption-less control such as a wizard input) and string values. BC validates each field and returns the server-confirmed value, which may differ from input due to formatting, auto-completion, or lookups (e.g., entering a partial customer name resolves to the full match). Requires a pageContextId from bc_open_page.

A field (or list column) that BC publishes as hidden, disabled or not editable is not written: that result has success:false and an error saying why (a hidden list column is reported as hidden), and nothing is sent for it, because BC silently ignores such a write. Other fields in the same call are still written. A result with echoed:false and a warning means BC raised no error but sent no stored value back (BC echoes only a changed value, so rewriting the current value looks the same): the write is not confirmed, read the field back to verify. Write related fields together in one call (e.g., quantity and unit price), but avoid writing unrelated groups together because BC validation cascades may change dependent fields in unexpected order. Check the returned confirmed values to see what BC actually stored.

For Document page line items (Sales Order lines, Purchase Order lines), specify section: "lines" to write to the lines repeater. Use rowIndex (0-based row position) or bookmark (stable row identifier from bc_read_data results) to target a specific line. Prefer bookmark over rowIndex when rows may have been reordered or inserted since the last read.

Pass expectedStateVersion (from a prior bc_read_data or bc_open_page stateVersion field) to guard against acting on drifted state. If the page has been mutated by async events or a sibling operation since that read, the call is immediately rejected with code STALE_CONTEXT before touching BC. Re-read with bc_read_data to get the current stateVersion, then retry. Omit expectedStateVersion to skip the check.

Do NOT use this for triggering actions like Post, Delete, or Release -- use bc_execute_action instead. Do NOT use this for navigating to records -- use bc_navigate instead.

Examples:

  • Write to Card header: { "pageContextId": "abc", "fields": { "Name": "Contoso Ltd", "Address": "123 Main St" } }

  • Write to Sales Order line: { "pageContextId": "abc", "section": "lines", "rowIndex": 0, "fields": { "Quantity": "5", "Unit Price": "100" } }

  • Write with bookmark targeting: { "pageContextId": "abc", "section": "lines", "bookmark": "XXXX", "fields": { "Description": "Consulting Services" } }

  • Write with staleness guard: { "pageContextId": "abc", "fields": { "Name": "Contoso" }, "expectedStateVersion": 3 }

Input Schema

NameRequiredDescriptionDefault
fieldsYesKey-value pairs of field names (the name a read lists: the caption, or for a caption-less control its AL control name, e.g. "CompanyName") or controlPaths, and string values to write (e.g., { "Name": "Contoso", "City": "London" }).
sectionNoSection to write to (e.g., "lines" for document line items). Omit for header fields.
bookmarkNoStable row identifier from bc_read_data results. Preferred over rowIndex when rows may be reordered.
rowIndexNo0-based row position in the repeater to write to. Use for line items. Prefer bookmark for stability.
operationIdNoOptional idempotency key (e.g. a UUID you generate). Retrying with the same operationId and the same arguments returns the first call's stored result instead of running the change again, so a retry after a dropped connection or timeout cannot double-post. Reusing it with different arguments is rejected (OPERATION_ID_REUSED). If the first call's outcome is unknown, the retry returns OPERATION_IN_DOUBT: check the record's state before acting again under a new operationId. Every result of this tool carries replaySafe: true means BC's response proved that re-running the same call (even under a new operationId, after an unknown outcome) cannot apply the change twice -- the write was echoed as an absolute value, or the form it acted on is closed so BC rejects a re-run; false means a re-run may double-apply or nothing proved otherwise, so read the record back before retrying. Replay is time-limited: a completed entry is kept for BC_OPERATION_TTL (default 24h), after which the same operationId runs the call again; check with bc_get_operation before a late retry. A replayed result carries download metadata (fileName, contentType, sizeBytes, savedPath) but not the file bytes.
pageContextIdYesPage context ID returned by bc_open_page. To fill a dialog or request page, use the pageContextId of its dialogsOpened entry (any tool that returns one) or requestPage (bc_run_report).
expectedStateVersionNoOpt-in staleness guard. Pass the stateVersion from a prior bc_read_data or bc_open_page response. If the page state has changed since that read (async events or sibling writes mutated it), the call is rejected immediately with code STALE_CONTEXT before touching BC. Omit to skip the check.

Output Schema

NameRequiredDescriptionDefault
resultsYes
messagesYes
replaySafeYes
allSucceededYes
dialogsOpenedYes
changedSectionsYes
validationWarningsYes
requiresDialogResponseYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema fields changedv2.4.7
    • changedInput schema / properties / fields / description
      Previous value: -"Key-value pairs of field caption names and string values to write (e.g., { \"Name\": \"Contoso\", \"City\": \"London\" })."New value: +"Key-value pairs of field names (the name a read lists: the caption, or for a caption-less control its AL control name, e.g. \"CompanyName\") or controlPaths, and string values to write (e.g., { \"Name\": \"Contoso\", \"City\": \"London\" })."
    • changedInput schema / properties / pageContextId / description
      Previous value: -"Page context ID returned by bc_open_page. To fill a dialog or request page, use the pageContextId of its dialogsOpened entry (bc_execute_action) or requestPage (bc_run_report)."New value: +"Page context ID returned by bc_open_page. To fill a dialog or request page, use the pageContextId of its dialogsOpened entry (any tool that returns one) or requestPage (bc_run_report)."
    • addedOutput schema / properties / dialogsOpened / items / properties / pageContextId
      Added value: +{
      +  "type": "string"
      +}
    • changedOutput schema / properties / dialogsOpened / items / required
      Previous value: -[
      -  "formId"
      -]New value: +[
      +  "formId",
      +  "pageContextId"
      +]
    • addedOutput schema / properties / messages
      Added value: +{
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "text": {
      +        "type": "string"
      +      },
      +      "type": {
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "text",
      +      "type"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "results",
      -  "allSucceeded",
      -  "changedSections",
      -  "dialogsOpened",
      -  "requiresDialogResponse",
      -  "validationWarnings",
      -  "replaySafe"
      -]New value: +[
      +  "results",
      +  "allSucceeded",
      +  "changedSections",
      +  "dialogsOpened",
      +  "requiresDialogResponse",
      +  "validationWarnings",
      +  "messages",
      +  "replaySafe"
      +]
  2. Changed1 schema field changedv2.3.0
    • changedInput schema / properties / pageContextId / description
      Previous value: -"Page context ID returned by bc_open_page."New value: +"Page context ID returned by bc_open_page. To fill a dialog or request page, use the pageContextId of its dialogsOpened entry (bc_execute_action) or requestPage (bc_run_report)."
  3. Changed2 schema fields changedv2.0.0
    • addedInput schema / properties / operationId
      Added value: +{
      +  "description": "Optional idempotency key (e.g. a UUID you generate). Retrying with the same operationId and the same arguments returns the first call's stored result instead of running the change again, so a retry after a dropped connection or timeout cannot double-post. Reusing it with different arguments is rejected (OPERATION_ID_REUSED). If the first call's outcome is unknown, the retry returns OPERATION_IN_DOUBT: check the record's state before acting again under a new operationId. Every result of this tool carries replaySafe: true means BC's response proved that re-running the same call (even under a new operationId, after an unknown outcome) cannot apply the change twice -- the write was echoed as an absolute value, or the form it acted on is closed so BC rejects a re-run; false means a re-run may double-apply or nothing proved otherwise, so read the record back before retrying. Replay is time-limited: a completed entry is kept for BC_OPERATION_TTL (default 24h), after which the same operationId runs the call again; check with bc_get_operation before a late retry. A replayed result carries download metadata (fileName, contentType, sizeBytes, savedPath) but not the file bytes.",
      +  "maxLength": 200,
      +  "minLength": 1,
      +  "type": "string"
      +}
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "https://json-schema.org/draft/2020-12/schema",
      +  "additionalProperties": false,
      +  "properties": {
      +    "allSucceeded": {
      +      "type": "boolean"
      +    },
      +    "changedSections": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "dialogsOpened": {
      +      "items": {
      +        "additionalProperties": {},
      +        "properties": {
      +          "formId": {
      +            "type": "string"
      +          },
      +          "message": {
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "formId"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "replaySafe": {
      +      "type": "boolean"
      +    },
      +    "requiresDialogResponse": {
      +      "type": "boolean"
      +    },
      +    "results": {
      +      "items": {
      +        "additionalProperties": {},
      +        "properties": {},
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "validationWarnings": {
      +      "items": {
      +        "additionalProperties": {},
      +        "properties": {},
      +        "type": "object"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "results",
      +    "allSucceeded",
      +    "changedSections",
      +    "dialogsOpened",
      +    "requiresDialogResponse",
      +    "validationWarnings",
      +    "replaySafe"
      +  ],
      +  "type": "object"
      +}
  4. First observedv1.5.0

TDQS

A4.9/5.0
Behavior5/5

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

Annotations flag a destructive, non-idempotent write, and the description adds substantial context beyond that: hidden/disabled/read-only fields are silently ignored by BC so nothing is sent and success:false is returned, other fields in the same batch still apply, and echoed:false plus a warning means the write is unconfirmed and must be read back. It also documents STALE_CONTEXT pre-flight rejection, cascade validation ordering, and value normalization (partial customer name resolving to full match), none of which appears in the annotations.

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

Conciseness5/5

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

Long but front-loaded: capability, then write-failure semantics, then targeting, then the staleness guard, then exclusions, then four copy-pasteable examples. Each paragraph carries a distinct decision the agent must make, and the examples compress multiple parameters into concrete calls rather than prose.

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

Completeness5/5

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

For a 7-parameter destructive mutation with a nested fields object and an output schema, the definition covers the risky edges: partial batch success, unconfirmed writes, staleness rejection, and row targeting stability. Return-value explanation is partly redundant with the output schema but the echoed/replaySafe interpretation is essential to acting correctly.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3; the description still adds operational meaning the schema does not, such as preferring bookmark over rowIndex for stability and the cascade/order caution when batching fields. The operationId and expectedStateVersion explanations largely restate the schema text, which keeps this from a 5.

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

Purpose5/5

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

Opens with a precise verb+resource+scope: writing field values on an already-open Business Central page, keyed by field names from a read. It explicitly names the two sibling tools it is not (bc_execute_action for Post/Delete/Release, bc_navigate for record navigation), so an agent can discriminate it without opening any schema.

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

Usage Guidelines5/5

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

Gives positive routing (use bc_execute_action for actions, bc_navigate for navigation), scenario guidance (section: "lines" for document line items), a bookmark-vs-rowIndex preference rule with the reason (rows may be reordered), and an explicit opt-in/opt-out for expectedStateVersion. Guidance about grouping related fields together versus avoiding unrelated groups is a genuine when-to-use rule.

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