@bicon/mcp-composer 0.1.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -75
- package/dist/index.mjs +2821 -241
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -23,110 +23,226 @@ via API keys is a separate, security-reviewed phase.
|
|
|
23
23
|
|
|
24
24
|
| Name | What it does |
|
|
25
25
|
|---|---|
|
|
26
|
-
| resource `initiative://schema` / tool `get_initiative_schema` | The field catalog: required fields, enum values, the four dimensions with their named sub-dimensions (EN/DE labels + help text
|
|
27
|
-
| `assemble_initiative` | Compact spec (metadata + named sub-ratings 0–100 + confidence per dimension) → fully-formed initiative validated against the API contract (`CreateInitiativeBody` from `@workspace/api-zod`). Mints id
|
|
28
|
-
| `export_initiative_file` |
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
(
|
|
26
|
+
| resource `initiative://schema` / tool `get_initiative_schema` | The field catalog: required fields, enum values, the four dimensions with their named sub-dimensions (EN/DE labels + help text, plus the wording the app uses in digital / innovation portfolios), the exact shape of every optional section, the EU-AI-Act vocabularies, and the handoff steps. **Read this first.** |
|
|
27
|
+
| `assemble_initiative` | Compact spec (metadata + named sub-ratings 0–100 + confidence per dimension + optional sections, optionally the organisation's `context`) → fully-formed initiative validated against the API contract (`CreateInitiativeBody` from `@workspace/api-zod`). Mints the initiative id and every nested row id (decision-log entries, status reports, incidents — a client never invents ids), **derives** the four dimension scores (the app's own scoring function), accepts dates as dd/mm/yyyy, dd.mm.yyyy or yyyy-mm-dd, returns `{ok, initiative, derivedScores, warnings, errors, contextId}`. Pass `id` (an existing initiative's) only to **update** that initiative. |
|
|
28
|
+
| `export_initiative_file` | Takes the **same compact spec**, assembles it and wraps the result in the app's single-initiative JSON envelope; returns `{ok, filename, json, importInstructions, derivedScores, warnings}`. There is one pipeline — a hand-edited initiative object is not an input, so client-supplied scores or unknown keys can never bypass assembly. |
|
|
29
|
+
| `read_portfolio_context` | Takes the organisation's **portfolio-context file** (see below) and returns the interview plan for that organisation — its own labels, help texts and rating notes per sub-dimension, which sub-dimensions are switched off, its business units, categories, tags, skills (id + name) and non-archived initiatives (id + name), currency, discount rate, whether the EU-AI-Act module is on — plus a short **contextId** that stands in for the file in the two other tools. |
|
|
30
|
+
| `composer_version` | Returns `{composerVersion, capabilities}`. Every *successful* tool result also carries `composerVersion`. |
|
|
31
|
+
|
|
32
|
+
### The portfolio context — how the Composer learns an organisation's settings
|
|
33
|
+
|
|
34
|
+
The Composer holds no credentials and calls no API, so on its own it cannot
|
|
35
|
+
know how an organisation configured its portfolio. The app therefore exports
|
|
36
|
+
a small **portfolio-context** JSON (Import/Export → the AI-assistant card →
|
|
37
|
+
*Download portfolio context*): the active portfolio mode, which evaluation
|
|
38
|
+
sliders are switched off, the organisation's own slider wording and rating
|
|
39
|
+
notes, business units, categories, tags, the skill roster and the live
|
|
40
|
+
initiatives (id + name), currency, discount rate and the AI-Act module switch.
|
|
41
|
+
The user hands that file to the assistant at the start; the assistant calls
|
|
42
|
+
`read_portfolio_context` once and then passes the returned **contextId**
|
|
43
|
+
(`ctx_<16 hex>`, a content hash — or the whole file again) as `context` to
|
|
44
|
+
`assemble_initiative` / `export_initiative_file`, so a 5–40 KB document is
|
|
45
|
+
not re-emitted three times per initiative. The id resolves against a
|
|
46
|
+
per-process content cache; an unknown id (server restarted) is a clear error
|
|
47
|
+
naming the fix, never a wrong answer. Effects:
|
|
48
|
+
|
|
49
|
+
- the interview uses the organisation's wording (org label › mode overlay ›
|
|
50
|
+
base) and skips switched-off sub-dimensions;
|
|
51
|
+
- switched-off sub-dimensions are optional in the spec, stored as 0 (the app's
|
|
52
|
+
blank default — a value sent anyway is zeroed with a warning) and
|
|
53
|
+
**excluded from the dimension score** — the app's own derivation, so the
|
|
54
|
+
score does not change on the first save in Evaluate; a dimension with every
|
|
55
|
+
sub-dimension off needs only `{ confidence }`;
|
|
56
|
+
- `businessUnit` and `aiCategory` **must be on the organisation's lists** (no
|
|
57
|
+
inventing — matched case-insensitively and normalised to the organisation's
|
|
58
|
+
spelling; new ones are created in the app's Settings); `dependsOn`,
|
|
59
|
+
`requiredSkills[].skillId` and an update `id` must be ids that exist (any
|
|
60
|
+
id format; Retired initiatives count, archived ones do not);
|
|
61
|
+
- every EU-AI-Act field the app strips is warned about while the
|
|
62
|
+
organisation's AI-Act module is off; the export file defaults to the
|
|
63
|
+
context's mode and language; a file newer than the Composer knows is flagged.
|
|
64
|
+
|
|
65
|
+
Without the file everything falls back to the built-in catalog: business unit
|
|
66
|
+
and category are free text, dependency / update ids must at least be UUID-shaped
|
|
67
|
+
(zod's rule, the same the API uses), and scores are derived over all 30
|
|
68
|
+
sub-dimensions. Export the file again after changing settings — the plan
|
|
69
|
+
reports its export date.
|
|
70
|
+
|
|
71
|
+
### How validation works (and why it lives at the wire)
|
|
72
|
+
|
|
73
|
+
The MCP SDK validates every call with the registered schema **and hands the
|
|
74
|
+
handler the parsed value** — whatever the schema strips, the server never sees.
|
|
75
|
+
So the spec schema is registered as a full **strict** object, with every
|
|
76
|
+
optional section a **deep-strict copy of the API contract**: an unknown key
|
|
77
|
+
anywhere is rejected by the SDK with its exact path
|
|
78
|
+
(`Unrecognized key(s) in object: 'literacy' at aiAct`), enum values, dates
|
|
79
|
+
(dd/mm/yyyy, dd.mm.yyyy or yyyy-mm-dd — real calendar dates, normalised to
|
|
80
|
+
yyyy-mm-dd) and blank names are caught with field paths, and the advertised JSON Schema
|
|
81
|
+
(`additionalProperties: false`, no `$ref` pointers) means what it says. A
|
|
82
|
+
section may also be sent as a **JSON string** (clients working from a stale
|
|
83
|
+
tool descriptor did that); it is parsed and validated identically. What a JSON
|
|
84
|
+
Schema cannot express — the 30 named ratings, the AI-Act controlled
|
|
85
|
+
vocabularies (`aiActVocabularies` in the descriptor; the app drops unknown
|
|
86
|
+
obligation keys and never shows unknown artifact keys), the score derivation —
|
|
87
|
+
is checked in the assembler, which reports **all** problems of a call at once
|
|
88
|
+
with the allowed values in the message (id shapes included). Row ids of
|
|
89
|
+
decision-log entries, status reports and incidents are minted by the
|
|
90
|
+
Composer — a client-supplied UUID is kept, anything else replaced — because
|
|
91
|
+
the app keys those rows per initiative and a re-used id from another
|
|
92
|
+
initiative is exactly what collided on import once.
|
|
93
|
+
|
|
94
|
+
Errors the SDK raises before a handler runs (`Input validation error: …`) carry
|
|
95
|
+
no `composerVersion` — that is normal. A *successful* result without it means an
|
|
96
|
+
old build is answering (see next section).
|
|
97
|
+
|
|
98
|
+
### Stale instances (reinstall is not enough — quit the app)
|
|
99
|
+
|
|
100
|
+
Claude Desktop runs an extension in **two** places: a chat-UI instance, which
|
|
101
|
+
every reinstall restarts, and a session-facing instance
|
|
102
|
+
(`LocalMcpServerManager` in Desktop's `main.log`) that serves Claude Code,
|
|
103
|
+
Cowork and remote claude.ai chats reaching the device. The session-facing
|
|
104
|
+
instance is started once at app launch and is only replaced on a **full app
|
|
105
|
+
quit** — reinstalling or disabling/enabling the extension leaves it running
|
|
106
|
+
the old code. Observed on 2026-08-18: five reinstalls, the chat-UI copy was
|
|
107
|
+
current every time, and every session still got the original build.
|
|
108
|
+
|
|
109
|
+
Tell: a successful tool result without `composerVersion`, or
|
|
110
|
+
`composer_version` missing from the tool list. Fix: install the new `.mcpb`,
|
|
111
|
+
then **quit Claude Desktop completely** (tray icon → Quit — closing the window
|
|
112
|
+
is not enough), reopen, and check with `composer_version`.
|
|
113
|
+
|
|
114
|
+
### One source for the domain
|
|
115
|
+
|
|
116
|
+
The Composer imports the app's own domain leaf, `@workspace/initiative-model`
|
|
117
|
+
(types and value lists incl. the AI-Act vocabularies, the score derivation, the
|
|
118
|
+
portfolio-mode wording overlays, the backup-format version) — the same package
|
|
119
|
+
the web app renders and validates with — and derives its enum lists from the
|
|
120
|
+
generated API contract. The 30 sub-dimension keys are the shared leaf's too;
|
|
121
|
+
the only hand-listed part is their base wording, and `catalog-drift.test.ts`
|
|
122
|
+
pins the keys to the contract in both directions. `server.test.ts` drives the real server through
|
|
123
|
+
the real SDK client over an in-memory transport, so what is asserted is what a
|
|
124
|
+
client sees.
|
|
125
|
+
|
|
126
|
+
## Install for users
|
|
127
|
+
|
|
128
|
+
### Claude Desktop — the extension (recommended, no Node needed)
|
|
129
|
+
|
|
130
|
+
Download **`bicon-composer.mcpb`** from the BICon app (Import/Export → *Set
|
|
131
|
+
up initiatives with an AI assistant*, or directly at
|
|
132
|
+
`https://www.bicon.digital/downloads/bicon-composer.mcpb`) and open it —
|
|
133
|
+
double-click, or Claude Desktop → Settings → Extensions → Install. Claude
|
|
134
|
+
Desktop runs the server on its own built-in Node runtime, so there is nothing
|
|
135
|
+
else to install and no configuration file to edit. Then **quit Claude Desktop
|
|
136
|
+
completely and reopen** (see *Stale instances*), start a **new chat** and ask:
|
|
137
|
+
*"Use the BICon Initiative Composer to help me set up a new initiative."*
|
|
138
|
+
|
|
139
|
+
Why the extension is primary: current Claude Desktop builds manage local MCP
|
|
140
|
+
servers as Desktop Extensions and treat `claude_desktop_config.json` as their
|
|
141
|
+
own preferences store — a hand-pasted `mcpServers` block there is silently
|
|
142
|
+
overwritten. There is no supported config-file route for Claude Desktop.
|
|
143
|
+
|
|
144
|
+
### Other MCP clients — the npm package
|
|
145
|
+
|
|
146
|
+
`@bicon/mcp-composer` on npm is a single self-contained bundle whose only
|
|
147
|
+
runtime dependency is the MCP SDK. Any MCP-capable client with Node ≥ 20 can
|
|
148
|
+
run it; for a client that reads a `mcpServers` config, add this and restart
|
|
149
|
+
the client:
|
|
41
150
|
|
|
42
151
|
```json
|
|
43
152
|
{
|
|
44
153
|
"mcpServers": {
|
|
45
154
|
"bicon-composer": {
|
|
46
155
|
"command": "npx",
|
|
47
|
-
"args": ["-y", "@bicon/mcp-composer"]
|
|
156
|
+
"args": ["-y", "@bicon/mcp-composer@latest"]
|
|
48
157
|
}
|
|
49
158
|
}
|
|
50
159
|
}
|
|
51
160
|
```
|
|
52
161
|
|
|
53
|
-
|
|
54
|
-
|
|
162
|
+
`@latest` matters: an unpinned `npx` spec keeps serving whatever it cached
|
|
163
|
+
first. Check what you got with the `composer_version` tool — the registry
|
|
164
|
+
version and the extension version are released together (see *Publishing*);
|
|
165
|
+
if npm is behind, use the extension.
|
|
166
|
+
|
|
167
|
+
**Prerequisite:** Node.js ≥ 20 on the **same operating system as the client**.
|
|
168
|
+
On Windows with Node only inside WSL, launch the server *through* WSL:
|
|
169
|
+
`"command": "wsl.exe", "args": ["-d", "Ubuntu", "--", "/path/to/npx", "-y",
|
|
170
|
+
"@bicon/mcp-composer@latest"]` (replace `/path/to/npx` with the output of
|
|
171
|
+
`which npx` in WSL). Restart the client afterwards.
|
|
55
172
|
|
|
56
173
|
## Build & run from source (contributors)
|
|
57
174
|
|
|
58
175
|
```bash
|
|
59
|
-
pnpm --filter @bicon/mcp-composer run build
|
|
60
|
-
pnpm --filter @bicon/mcp-composer run test
|
|
61
|
-
|
|
176
|
+
pnpm --filter @bicon/mcp-composer run build # → dist/index.mjs (npm bundle) + dist/mcpb/composer-<v>.mjs (extension bundle)
|
|
177
|
+
pnpm --filter @bicon/mcp-composer run test # vitest, incl. the SDK-boundary suite (builds the bundles itself)
|
|
178
|
+
pnpm --filter @bicon/mcp-composer run build:mcpb # → dist/bicon-composer.mcpb, copied to the web app's public/downloads
|
|
179
|
+
node lib/integrations/mcp/dist/index.mjs # stdio server (used by a client, not by hand)
|
|
62
180
|
```
|
|
63
181
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
```json
|
|
81
|
-
{
|
|
82
|
-
"mcpServers": {
|
|
83
|
-
"bicon-composer": {
|
|
84
|
-
"command": "wsl.exe",
|
|
85
|
-
"args": ["-d", "Ubuntu", "--", "/home/<user>/.nvm/versions/node/<version>/bin/node",
|
|
86
|
-
"/home/<user>/projects/ai-portfolio-steering/lib/integrations/mcp/dist/index.mjs"]
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Restart Claude Desktop; the tools appear under the tools menu.
|
|
182
|
+
For a client that reads a `mcpServers` config, point it at the local build
|
|
183
|
+
with an absolute path (`"command": "node", "args": ["/ABSOLUTE/PATH/TO/lib/integrations/mcp/dist/index.mjs"]`;
|
|
184
|
+
on Windows with the repo in WSL, run through `wsl.exe` with the WSL `node`).
|
|
185
|
+
For Claude Desktop, build and install the extension instead.
|
|
186
|
+
|
|
187
|
+
`build:mcpb` stages the manifest (version, entry point and launch args written
|
|
188
|
+
from `package.json` — the checked-in `mcpb/manifest.json` carries
|
|
189
|
+
placeholders), adds the single self-contained bundle, and — before zipping —
|
|
190
|
+
boots the staged server and drives it through the protocol: `initialize`
|
|
191
|
+
(version), `tools/list` (five tools, no `$ref`), `composer_version`,
|
|
192
|
+
`resources/list`, and an `assemble_initiative` call with an unknown AI-Act key
|
|
193
|
+
that must be rejected by name. It then copies the `.mcpb` to
|
|
194
|
+
`artifacts/bicon-portfolio/public/downloads/` and writes
|
|
195
|
+
`src/lib/composer-extension.json` (version + path), which the Import/Export
|
|
196
|
+
card imports. Requires `python3` for the zip container.
|
|
93
197
|
|
|
94
198
|
## Using it (the interview → import flow)
|
|
95
199
|
|
|
96
|
-
1.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
200
|
+
1. (Recommended) In the app, Import/Export → *Download portfolio context*,
|
|
201
|
+
and give that file to Claude first — it then interviews with your
|
|
202
|
+
organisation's own wording, skips switched-off sliders and only accepts
|
|
203
|
+
your business units, categories, skills and initiatives.
|
|
204
|
+
2. Ask Claude: *"Help me set up a new initiative in BICon."* It reads
|
|
205
|
+
`initiative://schema` (and your context) and interviews you — metadata
|
|
206
|
+
first, then the sub-dimensions with the app's help text, then a confidence
|
|
207
|
+
per dimension. Dates are dd/mm/yyyy in conversation.
|
|
208
|
+
3. Claude calls `assemble_initiative` and shows you the **derived scores** and
|
|
209
|
+
any warnings as a sanity check (fix and re-run if anything looks off).
|
|
210
|
+
4. Claude calls `export_initiative_file` with the same spec → save the returned
|
|
211
|
+
JSON under the suggested filename (`initiative-<name>-<date>.json`). To
|
|
212
|
+
**update** an existing initiative, name it — Claude passes its id from the
|
|
213
|
+
context and the app offers "Update"; a re-export without the id is
|
|
214
|
+
recognised by name and offered as an update too.
|
|
215
|
+
5. In the app (signed in to the target organisation): if the initiative carries
|
|
216
|
+
EU-AI-Act data, make sure the organisation's **EU-AI-Act module is switched
|
|
217
|
+
on** (Settings › AI Act — the app strips AI-Act fields on import while it is
|
|
218
|
+
off; the file's `sourceMode` is informational and cannot override that).
|
|
219
|
+
Then **Import/Export → Single initiative** card → drop the file → the
|
|
220
|
+
preview should show **0 warnings** → **Add as new** (or **Update**, which
|
|
221
|
+
keeps the existing initiative's id, creation date and links) → **Confirm**.
|
|
222
|
+
6. The initiative appears in the Inventory with exactly the scores Claude
|
|
107
223
|
reported.
|
|
108
224
|
|
|
109
|
-
`sourceMode` (default `ai`) must match the target portfolio's mode, otherwise the
|
|
110
|
-
importer strips the AI-Act fields.
|
|
111
|
-
|
|
112
225
|
## Publishing (maintainers)
|
|
113
226
|
|
|
114
|
-
|
|
115
|
-
devDependency the registry cannot resolve), so what ships is
|
|
116
|
-
`dist/index.mjs` + this README with `@modelcontextprotocol/sdk` as the sole
|
|
117
|
-
runtime dependency — `publish-shape.test.ts` guards exactly that. Publish under
|
|
118
|
-
the BICon npm account (business identity, 2FA on):
|
|
227
|
+
Release = extension + npm together, from one version:
|
|
119
228
|
|
|
120
229
|
```bash
|
|
121
230
|
cd lib/integrations/mcp
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
npm
|
|
231
|
+
npm version patch|minor # bumps package.json — the ONLY place the version is written
|
|
232
|
+
pnpm run test # incl. the SDK-boundary suite
|
|
233
|
+
pnpm run build:mcpb # bundles, ship-gate smoke, copies the .mcpb + version JSON into the web app
|
|
234
|
+
npm login # once, as the BICon npm account (business identity, 2FA on)
|
|
235
|
+
npm publish # prepack builds; publishConfig.access is public
|
|
126
236
|
```
|
|
127
237
|
|
|
128
|
-
Then
|
|
129
|
-
|
|
238
|
+
Then commit (the `.mcpb` and `composer-extension.json` are part of the
|
|
239
|
+
release commit) and verify from a clean machine:
|
|
240
|
+
`npx -y @bicon/mcp-composer@latest` starts and `composer_version` reports the
|
|
241
|
+
new version. The bundle inlines `zod`, `@workspace/api-zod` and
|
|
242
|
+
`@workspace/initiative-model` (workspace-only packages the registry cannot
|
|
243
|
+
resolve), so what ships is `dist/index.mjs` + this README with
|
|
244
|
+
`@modelcontextprotocol/sdk` as the sole runtime dependency —
|
|
245
|
+
`publish-shape.test.ts` guards exactly that.
|
|
130
246
|
|
|
131
247
|
## Not in scope (Phase 2)
|
|
132
248
|
|