Microsoft levert vanaf versie 26 een MCP-server mee in elke Business Central-omgeving. Die draait op een endpoint van Microsoft zelf, valideert je OAuth-token en stelt je configuratie beschikbaar als een set tools die een AI-client kan aanroepen. Dat deel is voor je geregeld.
Wat niet voor je geregeld is, is de laatste meter. De MCP-server van Business Central spreekt HTTP — een streamable variant met Server-Sent Events. Claude Desktop, VS Code en Cursor draaien op jouw machine en spreken stdio met hun MCP-servers. Er moet dus iets tussen zitten dat vertaalt, op je laptop, met jouw tokens in handen.
Dat iets is bc-mcp-proxy. Het is een fork van Microsofts eigen voorbeeld, MIT-gelicentieerd, en het staat op 360solutionsbe/bc-mcp-proxy.
Waarom het openbaar is
Lees die omschrijving nog eens: een klein programma dat op jouw machine draait, een token vasthoudt met toegang tot je financiële data, en vragen van een taalmodel doorstuurt naar je ERP. Klanten, leveranciers, facturen, boekingen.
Dat is precies de categorie software waarvan je niemand mag vragen ze op goed vertrouwen te installeren. Als we het als een gesloten binary hadden uitgeleverd, was het eerlijke antwoord op “wat doet dit met mijn gegevens?” geweest: geloof ons maar. En dat antwoord zouden we zelf van geen enkele leverancier accepteren.
De licentie is dus geen marketingkeuze. Het is de enige constructie waarbij wij ons comfortabel voelen om iemand te vragen dit te installeren.
Wat de fork werkelijk toevoegt
Het voorbeeld van Microsoft is een voorbeeld. Het demonstreert het protocol helder, en dat is waar een voorbeeld voor dient. Elke toevoeging hieronder bestaat omdat er in echt gebruik iets stukging.
Opnieuw verbinden bij tijdelijke fouten stroomopwaarts. Het origineel gaf op bij de eerste httpx.ReadTimeout. In de praktijk valt een verbinding met een Microsoft-endpoint om volstrekt alledaagse redenen weg, en als dat gebeurde, ging de MCP-client mee. De fork probeert het opnieuw met exponentiële backoff — 1s, 2s, 4s, 8s, 16s, standaard vijf pogingen — en houdt ondertussen de lokale stdio-pijp naar je client open. Vanaf de clientkant is de hik onzichtbaar. Een detail dat de moeite is als je dit zelf bouwt: anyio verpakt deze fouten in een ExceptionGroup, dus matchen op het kale exceptiontype is niet genoeg.
Tokens vernieuwen vóór ze verlopen. Access tokens verlopen, en het antwoord van Business Central op een verlopen token is Authentication_InvalidCredentials — een foutmelding die leest als een rechtenprobleem en je aan het spitten zet in je app-registratie. De fork houdt de vervaltijd lokaal bij en vraagt MSAL om een nieuw token zodra de resterende geldigheid onder een marge zakt, standaard vijf minuten, in plaats van te wachten tot hij geweigerd wordt.
Fouten zichtbaar maken die zich voordoen als successen. Sommige antwoorden van de BC MCP-server komen terug met isError: false terwijl de inhoud onmiskenbaar een foutmelding is — “Semantic search is not enabled”, of de authenticatiefout hierboven. De client ziet een geslaagde aanroep met een zin erin, en het model geeft die braaf door alsof het data is. De fork herkent die patronen en markeert ze alsnog als echte MCP-fouten. Dit is de wijziging die we het liefst in upstream zouden zien.
Koude start opvangen. De eerste tools/list tegen een koude BC-omgeving kan meer dan dertig seconden duren. De MCP-timeout van Claude Desktop staat hard ingebakken en is korter dan dat, dus het allereerste wat een nieuwe gebruiker deed, was de integratie zien mislukken. De fork antwoordt uit een cache in drie lagen — schijf, dan een voorverwarmde geheugenkopie, dan pas upstream — zodat de eerste aanroep meteen terugkomt en het trage pad zich buiten beeld afspeelt.
De basis-URL valideren bij het opstarten. BC_BASE_URL wordt gecontroleerd voor hij de netwerklaag bereikt: het schema moet https zijn en de host moet onder businesscentral.dynamics.com vallen. Er is een override voor lokaal testen met een mock, en die staat uit tenzij je hem zelf aanzet.
Vastgezette transitieve afhankelijkheden. Expliciete ondergrenzen voor h11, cryptography, pyjwt, starlette, urllib3 en meer, waarmee zestien CVE-paden dichtgaan die Snyk vond in de afhankelijkheidsbomen van mcp, msal en httpx. Geen van die dingen is onze code. Het blijft ons probleem, want ze komen in ons pakket op jouw machine terecht.
Vijfennegentig tests dekken de onderdelen die het stilst kunnen wegrotten: foutclassificatie, het verloop van de backoff, de grens van de vernieuwingsmarge, de patronen van gemaskeerde fouten, endpointdetectie en de URL-validatie.
Wat we bewust niet deden
De lijst hierboven is de makkelijke helft van dit artikel. Dit is de helft die de moeite is om op te schrijven.
We noemden het niet productieklaar. In de README staat met zoveel woorden dat de geschiktheid voor productie een afweging van jouw organisatie is. Het is MIT-gelicentieerd, actief onderhouden, getest en bewaakt op afhankelijkheden — en het is een proxy die inloggegevens voor je financiële systeem vasthoudt. Die twee feiten tellen niet op tot een algemene garantie, en zo’n garantie afgeven kost ons niets en jou alles als hij niet blijkt te kloppen.
We verstopten het moeilijke stuk niet. De echt lastige stap is niet het installeren van de proxy, maar het aanmaken van een Azure App Registration met de juiste rechten. Tien minuten voor iemand die thuis is in IT, een muur voor de rest. Het zou makkelijk zijn een snelstart te schrijven die daar stilletjes overheen stapt en mensen die muur in eigen tijd te laten ontdekken. De README benoemt het in de eerste sectie als het moeilijke deel.
We schoven de securityscanner niet stil terzijde. Snyk meldt vier bevindingen van lage ernst rond path traversal en één van middelhoge ernst rond SSRF op deze repository. We hebben ze bekeken, geconcludeerd dat het valse positieven zijn, en — in plaats van simpelweg op Negeren te klikken — voor elk de redenering opgeschreven in SECURITY.md, met bestand en regelnummer erbij, zodat de volgende reviewer het met dat argument oneens kan zijn in plaats van alles opnieuw te moeten uitzoeken. Een genegeerde bevinding zonder onderbouwing is niet te onderscheiden van een bevinding waar niemand naar gekeken heeft.
We zwegen niet over het ongemakkelijke deel. De proxy stuurt je Business Central-data naar een AI-aanbieder. Welke aanbieder, en op welk abonnement, bepaalt of die gegevens bewaard mogen worden of gebruikt voor training. Dat is niet het gedrag van onze software maar van de AI-leverancier, en we hadden het met goed fatsoen uit onze README kunnen laten. We hebben het in NOTICE.md gezet, met een aanbeveling: voor productiegebruik tegen een live omgeving een abonnement onder commerciële voorwaarden met een verwerkersovereenkomst — voor wie in de EU gevestigd is, het verschil tussen een verdedigbare constructie en een pijnlijk gesprek.
We leverden geen Intel-macOS-versie. Apple Silicon is sinds 2020 de standaard. Wie nog een Intel-Mac heeft, kan uit de broncode bouwen; het script staat in de repo. Een platformpakket uitleveren en testen voor een krimpend publiek is onderhoud dat weinig oplevert.
Wat we opnieuw zo zouden doen
Forken in plaats van herschrijven. De upstream-code is goed, en de CLI is onveranderd gebleven — elke vlag en elke omgevingsvariabele uit Microsofts versie werkt nog steeds. Wie daar begonnen is, kan overstappen zonder iets af te leren, en net zo makkelijk weer terug.
En de redenering meteen opschrijven. SECURITY.md en NOTICE.md kostten samen één namiddag. Allebei hebben ze inmiddels vragen beantwoord die we anders per e-mail zouden beantwoorden, klant voor klant.