A Deliverable Factory, Exposed as an MCP Server
178 tools that compose statements of work, architecture files and client decks from a client manifest. The method stops living in senior heads and becomes executable code.
Project details
- TypeScript
- Model Context Protocol
- Entra OAuth 2.1
- Azure Blob
- Ollama
- OOXML
The thesis
In a consultancy, the quality of a deliverable depends on who is staffed on the engagement. The same statement of work, written by two consultants, does not have the same value. That is a structural problem, and no amount of reviewing fixes it, because the review always happens at the end when there is no time left.
Tooling breaks that dependency. Encode the method into a tool, and the deliverable becomes repeatable: a junior consultant produces a senior document, because the rules live in the tool rather than in someone's head.
What it produces
- Contractual documents. Statements of work, meeting reports, acceptance minutes, governance files.
- Client presentations. Framing, readout, steering committee, architecture. On brand, with no manual formatting.
- Automatic guardrails. Finalisation is blocked if a brand rule is broken, or if an internal slide is about to go into a client deck.
Everything composes from a client manifest, so the substance stays human and the form is guaranteed. There are 50 slide templates and 17 document templates behind it.
One server, two transports
The same code serves a consultant's local machine over stdio and a remote Copilot agent over HTTP. That is what stops you writing the business logic twice.
The HTTP path runs OAuth 2.1 as a resource server: signature validation through JWKS, issuer and audience checks, and no secret stored server-side. This is not an API key in a config file.
MCP clients
|-- Development agent (consultant's machine, stdio)
|-- Declarative agent (inside M365 Copilot, HTTP)
|
v
Transport
|-- stdio local, no auth, the proven mode today
|-- HTTP + Entra OAuth 2.1 JWKS signature, issuer + audience, no server-side secret
|
v
Server core: 178 tools, one registry
|-- pptx_* 78 deck composition, 50 slide templates
|-- jumpstart_* 45 pathways, estimating, contract rules
|-- doc_* 35 17 canonical document templates
|-- client_* 15 living memory and client manifests
|-- rag_* 3 local index and search
|-- blueprint_* 2 deliverable recipe to document
|
v
Outputs: PPTX / DOCX / XLSX, asset resolver, local RAG, validatorsThe part I would defend in front of a security committee
The local RAG computes its embeddings locally, and the code physically refuses to run if the host is not on loopback. HTTP mode disables it entirely.
That is not a promise in a charter. It is a check in the code, placed where someone could otherwise break it by accident. Charters do not block anything; constraints placed at the point of violation do.
The numbers, and where they come from
- 178 tools, counted by querying the compiled server's registry. The repository documentation lags the code, so I do not count from it.
- 36,848 lines of TypeScript across 145 source files.
- 364 test assertions over 6 suites, executed, all green.
- 50 slide templates and 17 document templates.
What is actually inside
The 178 tools group into families, and the family names tell you what a delivery engagement actually consumes:
- Decks and documents. Slide composition is the largest single module in the codebase. Alongside it: canonical document templates, statements of work, proof-of-execution files, and governance workbooks in Excel.
- Client context. A living memory per client plus a manifest, so a deliverable composes from what is known about that account rather than from a blank template.
- Estimating and pathways. Sizing, engagement formats and contract rules, encoded rather than remembered.
- Grounding. A Microsoft Learn lookup, so a technical claim in a client document can be pointed at a real documentation page, plus a local RAG index over the reference material.
- Lifecycle. Deck and document sessions, an audit trail, preflight checks, and a deliverable registry.
It composes from 22 blueprint recipes, 13 real client manifests and 77 asset files. Version 0.3.0.
The guardrails, specifically
“Finalisation is blocked” is an easy thing to claim, so here is what actually blocks it.
The deck validator runs brand and accessibility checks before finalising, against the recorded slide metadata. Violations block finalisation in strict mode; warnings are reported and let you through. An em dash anywhere in the text is a violation, which is how a house style rule stops being a preference.
The accent detector is the one I would show a Swiss client. It flags French words written without their accents, and both the document and the deck validator share it. Deliberately a warning and never a hard block: the language model is the source of the text, so the tool cannot safely put accents back, only report where they went missing.
The UX audit exports a finalised deck to per-slide images for visual review, with an optional PDF render and pixel-diff regression detection. On Windows that runs through PowerPoint COM, wrapped in retry and backoff, because it is the only reliable path here: LibreOffice does not work.
A validator you cannot argue with
Every consultancy has a brand guide, and every brand guide is ignored under deadline. What differs here is where the rule lives: not in a PDF a reviewer is supposed to have read, but inside the function that writes the file, refusing to produce output.
The interesting design decision is the split between violation and warning. A rule the tool can verify absolutely, such as an em dash being present or an internal slide sitting in a client deck, blocks. A rule that needs judgement, such as an accent that may have been stripped where only a human knows the intended word, warns. Blocking on a judgement call is how you train people to bypass the tool.
The asset resolver
The largest utility after slide composition, and the least glamorous. It resolves an asset name to an actual file across Azure Blob storage and a local cache, with aliases, fuzzy matching, and Levenshtein-based type suggestions when a name is close but wrong.
It exists because the failure it prevents is the one that costs a whole afternoon: a deck that finalises perfectly with a missing logo, or with the wrong client's logo, discovered by the client.
Getting it onto a consultant machine
Install scripts for Windows and POSIX, plus a doctor script in both flavours that inspects the environment and says what is missing, rather than failing at first use. Continuous integration runs on Azure DevOps.
The six test suites are named for what they protect: the blueprint engine, client context, meteo history, the RAG index, a smoke run across the whole surface, and unit tests. 364 assertions, executed, all green.
Honest status, before anyone asks
It runs in daily production in stdio mode. The HTTP mode with Entra authentication is written, tested and wired into continuous integration, but the Azure App Service deployment is designed and documented and not yet provisioned.
I would rather say that unprompted than let "deployed in production on Azure" go unchallenged and be caught on it later.
Why MCP and not a REST API
Because the client is a language model. MCP describes the tools, their parameters and their constraints in a format the model can consume directly. A REST API would need a translation layer, and that layer would need maintaining every time a tool changed.
This server is internal to client delivery and its repository is private, so there is no public link. The architecture, the transport model and the guardrail design are all things I can walk through.






