Read-only MCP server for Dynamics 365 Business Central. Tools over the BC API v2.0, connectable to Claude Code / Claude Desktop (stdio) or as a remote connector (Streamable HTTP).
Strong foundation with 10 well-named, verb-prefixed tools (list_*, get_*, query). All tools have descriptions (avg 150 chars, within 10-1024 baseline). Input schemas are present and use Zod with type constraints. However, output schemas are undocumented, LLMs cannot predict response structure. Error handling is basic (try/catch → generic error text). Missing tool annotations (readOnlyHint, idempotentHint). Parameter descriptions are good but some lack format guidance (e.g., date strings, OData filter syntax). No batch operations despite common agent patterns.
Get one customer's full record by customer number (e.g. C00120) or GUID id.
Get one sales invoice by invoice number or GUID id, including its lines.
Get one sales order by order number (e.g. S-ORD101001) or GUID id, including its lines.
List the Business Central companies visible to this connection.
List customers in the working company. Use `search` for a name substring match, or `filter` for a raw OData $filter.
List inventory items in the working company. Use `search` for a name substring match, or `filter` for a raw OData $filter (e.g. inventory lt 10).
Output schemas undocumented. LLMs cannot predict response structure (fields, types, nesting). Forces agents to guess at downstream field names and risks context loss.
No tool annotations (readOnlyHint, idempotentHint). All tools are read-only but this is not declared in the tool definition. Agents cannot distinguish safe-to-retry operations from destructive ones.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 64 | 2026-07-28+ | v2 |
List posted/draft sales invoices, optionally filtered by customer number, status (Draft, In Review, Open, Paid, Canceled, Corrective), invoice date range, or unpaid balance.
List sales orders, optionally filtered by customer number, status (Draft, In Review, Open), or order date range.
List vendors in the working company. Use `search` for a name substring match.
Read-only escape hatch: GET any Business Central API entity set or record. Covers standard v2.0 entities not exposed as dedicated tools (salesShipments, purchaseOrders, generalLedgerEntries, ...) and custom APIs via api_route (publisher/group/version, e.g. 'contoso/sales/v1.0'). Example: path='salesShipments', params={'$filter': "customerNumber eq 'C00120'"}.
Error handling is generic. Catch-all try/catch returns 'Error: <message>' with no recovery guidance. LLMs cannot distinguish retryable errors (timeout, rate limit) from user-fixable ones (invalid filter syntax).
OData filter parameter lacks format guidance. Description says 'Raw OData $filter' but does not explain syntax (e.g., 'blocked ne \' \' or balanceDue gt 0'). LLMs will hallucinate invalid filter expressions.
bc_query tool name is generic and ambiguous. 'query' does not convey that it is a read-only escape hatch for arbitrary OData paths. Rename to 'bc_query_odata' or 'bc_read_entity' for clarity.