# MCP: Business Central for your agent

The knowledge base this site is built from, as an MCP server your agent can query, and a Claude Code plugin around it. Every answer carries the page, its trust tier (official is Microsoft, community is everyone else) and its evidence. No API key, no account: the server downloads the site's search index once a day and reads pages as markdown.

Server: `bc-observatory` 0.7.1 on npm (Node 20 or newer). Plugin: `bc-observatory` 0.3.0 from the repository's marketplace.

## What to ask

- "What is on table 18, and which fields are obsolete?" (get_object)
- "What changed in codeunit Sales-Post between BC29 and BC30?" (diff_object)
- "What does the Belgian localization change in W1?" (localization)
- "What is new in Business Central since last Monday?" (whats_new)
- "Where is posting preview documented, and who blogged about it?" (search, cat)
- "What does kauffmann-nl write about?" (blog_footprint)
- "Show me the body of Sales-Post.PostInvoice and what it calls." (bc-code-atlas via the plugin)
- "Walk me through setting up intercompany partners." (bc-observatory finds the page and Microsoft Learn MCP reads it)

## The tools

- **search**: Every page by title, AL object name and caption, summary and tags, plus fields, events and procedures, ranked like the site's search (t36, cu 80, plurals, one typo, synonyms); hybrid (keywords plus meaning), so a paraphrase still finds the page. A symbol ranks where its owner ranks; a kind: query that finds nothing says so and names the nearest symbols. Filter by type, tier, galaxy system, country, app, object type or kind. Example: `search('posting preview')`.
- **ls**: Browse the page tree; an empty path lists the sections. Example: `ls('objects/table')`.
- **cat**: A page's markdown: frontmatter with evidence and links, then the body. A long page comes back compact with its section keys; section, offset and limit read one part, and a symbol's path returns just that member. Example: `cat('localizations/be')`.
- **get_object**: An object of W1, a first-party app or a country layer by type and id, reference, name or caption: fields, keys, events, public procedures, obsolete state, versions, countries that replace it, Learn pages; a country layer that replaces a W1 object prints what it adds before the page. A large object comes back compact; read one section with section, offset and limit. counts.procedures in the frontmatter counts every procedure; the summary's 'public procedures' excludes locals and events. Example: `get_object('table', '18')`.
- **diff_object**: Member-level changes of a W1 object between two consecutive versions: fields, events, procedures, keys, properties, obsolete state. Example: `diff_object('codeunit', 'Sales-Post', '29', '30')`.
- **localization**: What a country layer adds to or changes in W1, with its Learn local functionality hub. Large countries come back compact, as with cat. Example: `localization('BE')`.
- **whats_new**: Videos, posts, roadmap features, AL extension releases and code changes (merged pull requests) dated on or after a date and up to today, newest first. Example: `whats_new('2026-10-01')`.
- **blog_footprint**: What a blog or channel covers: its posts or videos and the systems they touch. Example: `blog_footprint('kauffmann-nl')`.
- **feedback**: A prefilled GitHub issue link for a page (wrong fact, missing evidence, broken link). Nothing is sent by the agent. Example: `feedback('objects/table/18', 'field 7 is wrong')`.

## The plugin (Claude Code)

- **bc-lookup**: Business Central facts with evidence: AL objects, Learn documentation, roadmap features, videos and posts. For 'what is table 18', 'where is this documented'.
- **bc-whats-new**: Recent videos, posts and roadmap features with status, and what changed in the code between versions. For 'what's new', 'what changed in BC30'.
- **bc-localization**: Which objects a country layer adds, which W1 objects it changes, added fields and events, and where Learn documents the local functionality.
- **bc-grounding**: The servers together: the observatory for ids, fields, events, versions, callers and evidence, bc-code-atlas for the procedure body and what one procedure calls, Microsoft Learn MCP for the Learn page and AL code samples.

The plugin also connects [bc-code-atlas](https://github.com/StefanMaron/bc-code-atlas) by Stefan Maron (https://bc-code-atlas.stefanmaron.dev/mcp) for procedure bodies and the per-procedure call graph; the observatory keeps the object-level facts. It connects Microsoft's [Learn MCP](https://learn.microsoft.com/training/support/mcp) (https://learn.microsoft.com/api/mcp) too: the observatory finds the Learn page and stores no Learn text, the Learn MCP reads it (`microsoft_docs_fetch`) and finds AL code samples (`microsoft_code_sample_search`).

## What the plugin installs

Three MCP servers and four skills. Nothing needs an account or an API key.

- `bc-observatory` (this project (waldo), the npm package run locally; `npx -y bc-observatory@latest`): Business Central facts with evidence and a trust tier: objects, fields, events, versions, localizations, what changed, roadmap, videos, posts. Not procedure bodies or Learn text. Your queries stay on your machine; it downloads the site's search index and the pages you read.
- `bc-code-atlas` (Stefan Maron, a free hobby server (be a polite client); https://bc-code-atlas.stefanmaron.dev/mcp): AL source: a procedure body, what one procedure calls, semantic code search of one W1 version. The names and search text of your calls go to his server.
- `microsoft-learn` (Microsoft, public endpoint, no authentication; https://learn.microsoft.com/api/mcp): Reading a Learn page the observatory points to and AL code samples. The URLs and search text of your calls go to Microsoft.

Routing: the observatory first; bc-code-atlas for procedure bodies and per-procedure edges; Microsoft Learn MCP to read a Learn page the observatory points to and for AL code samples. Switch one plugin server off with /mcp (Claude Code stops connecting to it without removing the plugin); `claude mcp remove` acts on servers you added yourself, so to take only some servers install them by hand instead. A Learn MCP you already have at the same URL wins over the plugin's: keep one. Details: [plugin/README.md](https://github.com/waldo1001/waldo.BCObservatory/blob/main/plugin/README.md).

## Install

### Claude Code: the plugin (server, four skills, bc-code-atlas, Microsoft Learn MCP)

One command. The plugin registers the MCP server, the bc-code-atlas server and Microsoft's Learn MCP server and ships the four skills.

```bash
claude plugin marketplace add waldo1001/waldo.BCObservatory
```

### Claude Code: the server only

No skills, no atlas: just the nine tools.

```bash
claude mcp add bc-observatory -- npx -y bc-observatory@latest
```

### Claude Desktop, Cursor, Windsurf and other MCP clients

Add the server to the client's MCP configuration (claude_desktop_config.json, .cursor/mcp.json, ...).

```json
{
  "mcpServers": {
    "bc-observatory": {
      "command": "npx",
      "args": [
        "-y",
        "bc-observatory@latest"
      ]
    }
  }
}
```

### VS Code (GitHub Copilot)

In .vscode/mcp.json of the workspace, or the user profile's mcp.json.

```json
{
  "servers": {
    "bc-observatory": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "bc-observatory@latest"
      ]
    },
    "bc-code-atlas": {
      "type": "http",
      "url": "https://bc-code-atlas.stefanmaron.dev/mcp"
    },
    "microsoft-learn": {
      "type": "http",
      "url": "https://learn.microsoft.com/api/mcp"
    }
  }
}
```

### From a checkout of the repository

Reads every page from disk instead of the site; for working on the knowledge base itself.

```bash
git clone https://github.com/waldo1001/waldo.BCObservatory.git && cd waldo.BCObservatory && npm ci
claude mcp add bc-observatory -- env BC_OBSERVATORY_LOCAL=$PWD node --import tsx packages/mcp/src/server.ts
```

### Without any install

[llms.txt](https://waldo1001.github.io/waldo.BCObservatory/llms.txt) lists every section; every page has a markdown twin at its URL plus `.md`; GitMCP and DeepWiki (badges in the [README](https://github.com/waldo1001/waldo.BCObservatory)) read the repository directly.

## How it answers

The server fetches `index/` from the published site over HTTPS and caches it by hash in `~/.cache/bc-observatory/` (refreshed daily), and reads a page's markdown twin when you ask for it; a page over 30,000 characters comes back as a compact view with its section keys. Search ranks like the site's own search and is hybrid: keywords plus a small static embedding model (model2vec potion-base-8M, 30 MB, downloaded once, checked by SHA-256) computed locally; `BC_OBSERVATORY_EMBEDDINGS=0` turns the model off. `BC_OBSERVATORY_LOCAL` reads a checkout instead; `BC_OBSERVATORY_SITE` points at another deployment. Nothing is sent anywhere: `feedback` only returns a link.

Source: [packages/mcp](https://github.com/waldo1001/waldo.BCObservatory/tree/main/packages/mcp) and [plugin](https://github.com/waldo1001/waldo.BCObservatory/tree/main/plugin) in the repository, MIT.
