bc-webclient-mcp-server

I Reverse-Engineered BC's WebSocket Protocol. Then I Rewrote Everything.

npm ·GitHub

What do all the other MCP servers have in common? They don’t speak the same protocol as the BC web client. They use OData, SOAP, Playwright, browser automation, anything but the actual protocol. Slow, unreliable, and not how an AI would talk to BC if it could.

The first version of the BC MCP server was a proof of concept. It worked (ish), but it was held together with duct tape and spaghetti code. I had to do better. So here’s the harder, better, faster, stronger version.

The protocol nobody documented

BC’s web client talks to the server over WebSocket using JSON-RPC. Microsoft never documented the protocol. Never intended anyone else to speak it.

Like getting BC to run on Linux, it just made me want to do it even more. As most of my projects, it is more about how, not why.

So I fired up two BC instances (27 and 28), so I could make sure this one wasn’t tied to a specific version. Then I opened the old repo and typed four prompts into Claude Code:

“What is the state of the MCP server?”

(Insert long, honest answer about the code quality, technical debt, and maintainability issues of the old codebase)

“Think I need to rebuild it from the ground up. If we did, what did we learn from v1 that we would like to do differently if we could?”

(Insert list of improvements, architectural changes, and best practices that we would like to implement in the new version)

“Maybe we should iterate over the reversed engineered codebase to verify our assumptions instead of guessing.”

(Insert detailed plan for reverse engineering the protocol, and ask how many tools I would like to create)

“Don’t care how many. It just needs to be the correct ones, we need the best solution, not the easiest, quickest or fastest. The best.”

That was the starting point. Everything else followed from there.

Get it running

business-central-mcp speaks that same protocol. No OData, no SOAP, no Playwright, no browser automation. The AI connects to BC the way you do.

Small note, I only added NavUserPassword auth for now and only tested bc27 and bc28. If you need something else, open an issue or better yet, a PR.

Add it to Claude Desktop, Copilot, whatever you’re using:

{
  "mcpServers": {
    "business-central": {
      "command": "npx",
      "args": ["-y", "business-central-mcp"],
      "env": {
        "BC_BASE_URL": "http://your-bc-server/BC",
        "BC_USERNAME": "your-user",
        "BC_PASSWORD": "your-password"
      }
    }
  }
}

And then you will see 11 well-picked tools.

ToolWhat it does
bc_open_pageOpen any page by ID
bc_read_dataRead fields, lines, factboxes with filters and paging
bc_write_dataWrite field values, get server-validated results back
bc_execute_actionPost, Release, Delete, any page action
bc_respond_dialogHandle confirmation prompts and request pages
bc_navigateSelect rows, drill down, field lookups
bc_search_pagesFind pages via Tell Me
bc_close_pageFree server resources
bc_switch_companySwitch company mid-session
bc_list_companiesDiscover available companies
bc_run_reportExecute reports, fill request pages

I think these cover 90% of what you can do in the web client, if you want more. Like before, open an issue or better yet, a PR.

How I built it

The whole thing was built with Claude Code across five sessions over three days. Here’s the arc.

Day 1: Foundation. Decompiled 26 BC28 assemblies. Scaffolded v2 from zero, threw away all v1 code. Built the connection layer, protocol layer, and session layer. Every assumption verified against the decompiled source, not v1. Integration tested against both BC27 and BC28 before writing business logic.

Day 1: Services and tools. Built six services (Page, Data, Action, Filter, Navigation, Search) with integration tests against live BC. Added the MCP layer. 7 tools initially. Wired up HTTP and stdio server entry points. Smoke tested the full workflow end to end.

Day 1-2: The document page wall. Sales Orders have headers, lines, and factboxes as separate forms. V1’s flat PageState couldn’t handle this. Had Claude Code design a multi-section architecture. Got child form discovery, factbox data loading, and section-aware routing working. Added paging via ScrollRepeater.

Day 2 Got sidetracked. Not allowed to disclose at this time. More on this in the future.

Day 3: Production readiness. Added session resilience. Added multi-company support. Added report execution. Packaged for npm and published.

128 unit tests. 103 integration tests against live BC. Every protocol pattern verified against decompiled source.

Source on GitHub. Package on npm. MIT licensed.

More than ever, hour after hour. Work is never over.