@bicon/mcp-composer 0.3.2 → 0.3.5
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/dist/index.mjs +60 -20
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
12
12
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
13
13
|
|
|
14
14
|
// src/version.ts
|
|
15
|
-
var COMPOSER_VERSION = true ? "0.3.
|
|
15
|
+
var COMPOSER_VERSION = true ? "0.3.5" : readPackageVersion();
|
|
16
16
|
|
|
17
17
|
// ../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
18
18
|
var external_exports = {};
|
|
@@ -4193,6 +4193,7 @@ var ListSnapshotsResponseItem = objectType({
|
|
|
4193
4193
|
"initiatives": arrayType(objectType({
|
|
4194
4194
|
"id": stringType(),
|
|
4195
4195
|
"name": stringType(),
|
|
4196
|
+
"externalId": stringType().optional().describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026)"),
|
|
4196
4197
|
"businessUnit": stringType(),
|
|
4197
4198
|
"owner": stringType(),
|
|
4198
4199
|
"description": stringType(),
|
|
@@ -4445,6 +4446,7 @@ var CreateSnapshotBody = objectType({
|
|
|
4445
4446
|
"initiatives": arrayType(objectType({
|
|
4446
4447
|
"id": stringType(),
|
|
4447
4448
|
"name": stringType(),
|
|
4449
|
+
"externalId": stringType().optional().describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026)"),
|
|
4448
4450
|
"businessUnit": stringType(),
|
|
4449
4451
|
"owner": stringType(),
|
|
4450
4452
|
"description": stringType(),
|
|
@@ -4702,6 +4704,7 @@ var RenameSnapshotResponse = objectType({
|
|
|
4702
4704
|
"initiatives": arrayType(objectType({
|
|
4703
4705
|
"id": stringType(),
|
|
4704
4706
|
"name": stringType(),
|
|
4707
|
+
"externalId": stringType().optional().describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026)"),
|
|
4705
4708
|
"businessUnit": stringType(),
|
|
4706
4709
|
"owner": stringType(),
|
|
4707
4710
|
"description": stringType(),
|
|
@@ -4950,6 +4953,7 @@ var DeleteSnapshotParams = objectType({
|
|
|
4950
4953
|
var ListInitiativesResponseItem = objectType({
|
|
4951
4954
|
"id": stringType(),
|
|
4952
4955
|
"name": stringType(),
|
|
4956
|
+
"externalId": stringType().optional().describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026)"),
|
|
4953
4957
|
"businessUnit": stringType(),
|
|
4954
4958
|
"owner": stringType(),
|
|
4955
4959
|
"description": stringType(),
|
|
@@ -5194,6 +5198,7 @@ var ListInitiativesResponse = arrayType(ListInitiativesResponseItem);
|
|
|
5194
5198
|
var CreateInitiativeBody = objectType({
|
|
5195
5199
|
"id": stringType(),
|
|
5196
5200
|
"name": stringType(),
|
|
5201
|
+
"externalId": stringType().optional().describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026)"),
|
|
5197
5202
|
"businessUnit": stringType(),
|
|
5198
5203
|
"owner": stringType(),
|
|
5199
5204
|
"description": stringType(),
|
|
@@ -5446,6 +5451,7 @@ var GetInitiativeParams = objectType({
|
|
|
5446
5451
|
var GetInitiativeResponse = objectType({
|
|
5447
5452
|
"id": stringType(),
|
|
5448
5453
|
"name": stringType(),
|
|
5454
|
+
"externalId": stringType().optional().describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026)"),
|
|
5449
5455
|
"businessUnit": stringType(),
|
|
5450
5456
|
"owner": stringType(),
|
|
5451
5457
|
"description": stringType(),
|
|
@@ -5692,6 +5698,7 @@ var UpdateInitiativeParams = objectType({
|
|
|
5692
5698
|
var UpdateInitiativeBody = objectType({
|
|
5693
5699
|
"id": stringType(),
|
|
5694
5700
|
"name": stringType(),
|
|
5701
|
+
"externalId": stringType().optional().describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026)"),
|
|
5695
5702
|
"businessUnit": stringType(),
|
|
5696
5703
|
"owner": stringType(),
|
|
5697
5704
|
"description": stringType(),
|
|
@@ -5941,6 +5948,7 @@ var UpdateInitiativeBody = objectType({
|
|
|
5941
5948
|
var UpdateInitiativeResponse = objectType({
|
|
5942
5949
|
"id": stringType(),
|
|
5943
5950
|
"name": stringType(),
|
|
5951
|
+
"externalId": stringType().optional().describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026)"),
|
|
5944
5952
|
"businessUnit": stringType(),
|
|
5945
5953
|
"owner": stringType(),
|
|
5946
5954
|
"description": stringType(),
|
|
@@ -8602,6 +8610,13 @@ var REQUIRED_FIELDS = [
|
|
|
8602
8610
|
];
|
|
8603
8611
|
var OPTIONAL_SECTIONS = [
|
|
8604
8612
|
{ key: "tags", hint: { en: "Free-text tags", de: "Freie Schlagworte" } },
|
|
8613
|
+
{
|
|
8614
|
+
key: "externalId",
|
|
8615
|
+
hint: {
|
|
8616
|
+
en: "The organisation's own initiative reference (project number, Jira key, IC id) \u2014 the app's 'Initiative ID' field",
|
|
8617
|
+
de: "Eigene Referenz der Organisation (Projektnummer, Jira-Key, IC-Nummer) \u2014 das Feld \u201EInitiativen-ID\u201C der App"
|
|
8618
|
+
}
|
|
8619
|
+
},
|
|
8605
8620
|
{
|
|
8606
8621
|
key: "docsUrl / pmUrl",
|
|
8607
8622
|
hint: {
|
|
@@ -8726,19 +8741,7 @@ function buildSchemaDescriptor(sectionShapes) {
|
|
|
8726
8741
|
};
|
|
8727
8742
|
}
|
|
8728
8743
|
|
|
8729
|
-
// src/
|
|
8730
|
-
function contractObjectShape() {
|
|
8731
|
-
const def = CreateInitiativeBody._def;
|
|
8732
|
-
if (def.typeName === "ZodIntersection" && def.left && def.right) return { ...def.left.shape, ...def.right.shape };
|
|
8733
|
-
return CreateInitiativeBody.shape;
|
|
8734
|
-
}
|
|
8735
|
-
var contractShape = contractObjectShape();
|
|
8736
|
-
function contractSection(key) {
|
|
8737
|
-
const s = contractShape[key];
|
|
8738
|
-
if (!s) throw new Error(`contract has no section ${key}`);
|
|
8739
|
-
return s instanceof external_exports.ZodOptional ? s.unwrap() : s;
|
|
8740
|
-
}
|
|
8741
|
-
var keepDescription = (from, to) => from.description ? to.describe(from.description) : to;
|
|
8744
|
+
// ../../initiative-model/src/dates.ts
|
|
8742
8745
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
8743
8746
|
var DMY = /^(\d{1,2})[./](\d{1,2})[./](\d{4})$/;
|
|
8744
8747
|
function normaliseDateInput(v) {
|
|
@@ -8748,12 +8751,30 @@ function normaliseDateInput(v) {
|
|
|
8748
8751
|
const [, d, mo, y] = m;
|
|
8749
8752
|
return `${y}-${mo.padStart(2, "0")}-${d.padStart(2, "0")}`;
|
|
8750
8753
|
}
|
|
8754
|
+
function isCalendarParts(y, m, d) {
|
|
8755
|
+
const dt = /* @__PURE__ */ new Date(0);
|
|
8756
|
+
dt.setUTCFullYear(y, m - 1, d);
|
|
8757
|
+
return dt.getUTCFullYear() === y && dt.getUTCMonth() === m - 1 && dt.getUTCDate() === d;
|
|
8758
|
+
}
|
|
8751
8759
|
function isCalendarDate(s) {
|
|
8752
8760
|
if (!ISO_DATE.test(s)) return false;
|
|
8753
8761
|
const [y, m, d] = s.split("-").map(Number);
|
|
8754
|
-
|
|
8755
|
-
|
|
8762
|
+
return isCalendarParts(y, m, d);
|
|
8763
|
+
}
|
|
8764
|
+
|
|
8765
|
+
// src/schema.ts
|
|
8766
|
+
function contractObjectShape() {
|
|
8767
|
+
const def = CreateInitiativeBody._def;
|
|
8768
|
+
if (def.typeName === "ZodIntersection" && def.left && def.right) return { ...def.left.shape, ...def.right.shape };
|
|
8769
|
+
return CreateInitiativeBody.shape;
|
|
8756
8770
|
}
|
|
8771
|
+
var contractShape = contractObjectShape();
|
|
8772
|
+
function contractSection(key) {
|
|
8773
|
+
const s = contractShape[key];
|
|
8774
|
+
if (!s) throw new Error(`contract has no section ${key}`);
|
|
8775
|
+
return s instanceof external_exports.ZodOptional ? s.unwrap() : s;
|
|
8776
|
+
}
|
|
8777
|
+
var keepDescription = (from, to) => from.description ? to.describe(from.description) : to;
|
|
8757
8778
|
var dateField = (what) => external_exports.preprocess(normaliseDateInput, external_exports.string().refine(isCalendarDate, { message: `${what} must be a real calendar date \u2014 dd/mm/yyyy or yyyy-mm-dd` })).describe("dd/mm/yyyy (or yyyy-mm-dd)");
|
|
8758
8779
|
var DATE_LIKE_KEY = /^date$|Date$|At$/;
|
|
8759
8780
|
var MINTED_KEYS = /* @__PURE__ */ new Set(["id", "createdAt", "updatedAt"]);
|
|
@@ -8825,6 +8846,7 @@ var compactSpecSchema = external_exports.object({
|
|
|
8825
8846
|
"ONLY to UPDATE an existing initiative: its id (from read_portfolio_context \u2192 lists.initiatives, or the app). The exported file then updates that initiative in place. Omit for a new initiative \u2014 never invent an id."
|
|
8826
8847
|
),
|
|
8827
8848
|
name: requiredText(),
|
|
8849
|
+
externalId: external_exports.preprocess((v) => typeof v === "string" && v.trim() === "" ? void 0 : v, external_exports.string().trim().min(1).optional()).describe("The organisation's own reference for the initiative (project number, Jira key, IC id, \u2026) \u2014 ask for it when the organisation uses such references"),
|
|
8828
8850
|
businessUnit: requiredText().describe("With a portfolio context: one of the organisation's business units (read_portfolio_context \u2192 lists.businessUnits)"),
|
|
8829
8851
|
owner: requiredText(),
|
|
8830
8852
|
description: requiredText(),
|
|
@@ -8944,7 +8966,7 @@ var portfolioContextSchema = external_exports.object({
|
|
|
8944
8966
|
categories: external_exports.array(external_exports.string()),
|
|
8945
8967
|
suggestedTags: external_exports.array(external_exports.string()),
|
|
8946
8968
|
skills: external_exports.array(external_exports.object({ id: external_exports.string().min(1), name: external_exports.string() }).passthrough()),
|
|
8947
|
-
initiatives: external_exports.array(external_exports.object({ id: external_exports.string().min(1), name: external_exports.string(), status: external_exports.enum(STATUS_VALUES) }).passthrough()),
|
|
8969
|
+
initiatives: external_exports.array(external_exports.object({ id: external_exports.string().min(1), externalId: external_exports.string().trim().optional(), name: external_exports.string(), status: external_exports.enum(STATUS_VALUES) }).passthrough()),
|
|
8948
8970
|
sliders: external_exports.array(sliderSchema)
|
|
8949
8971
|
}).passthrough();
|
|
8950
8972
|
var CONTEXT_SUPPORTED_VERSION = PORTFOLIO_CONTEXT_VERSION;
|
|
@@ -9003,6 +9025,15 @@ function checkAgainstContext(spec, ctx) {
|
|
|
9003
9025
|
const warnings = [];
|
|
9004
9026
|
const v = versionNotice(ctx);
|
|
9005
9027
|
if (v) warnings.push(v);
|
|
9028
|
+
const specExt = spec.externalId?.trim().toLowerCase();
|
|
9029
|
+
if (specExt) {
|
|
9030
|
+
const holder = ctx.initiatives.find((x) => (x.externalId ?? "").trim().toLowerCase() === specExt && x.id !== spec.id);
|
|
9031
|
+
if (holder) {
|
|
9032
|
+
warnings.push(
|
|
9033
|
+
spec.id ? `externalId "${spec.externalId.trim()}" already belongs to "${holder.name}" (${holder.id}) \u2014 two initiatives would share the same organisation reference.` : `externalId "${spec.externalId.trim()}" already belongs to "${holder.name}" (${holder.id}) \u2014 pass that id as \`id\` to UPDATE it instead of creating a duplicate.`
|
|
9034
|
+
);
|
|
9035
|
+
}
|
|
9036
|
+
}
|
|
9006
9037
|
const bus = ctx.businessUnits;
|
|
9007
9038
|
let businessUnit = spec.businessUnit;
|
|
9008
9039
|
const buMatch = canonical(spec.businessUnit, bus);
|
|
@@ -9079,7 +9110,7 @@ function buildInterviewPlan(ctx, contextId) {
|
|
|
9079
9110
|
...allOff.length ? [`Dimension(s) with EVERY sub-dimension switched off (${allOff.join(", ")}) still need an entry in evaluation: { subs: {}, confidence } \u2014 the score is 0 there; ask only for the confidence.`] : [],
|
|
9080
9111
|
ctx.businessUnits.length && ctx.categories.length ? "businessUnit MUST be one of lists.businessUnits and aiCategory one of lists.categories (matched case-insensitively, normalised to the organisation's spelling) \u2014 the Composer rejects anything else; new ones are created in the app's Settings, not in the interview." : "This organisation has no business units and/or categories configured yet \u2014 they must be added in the app's Settings and the context downloaded again before an initiative can be assembled.",
|
|
9081
9112
|
"dependsOn entries must be ids from lists.initiatives; requiredSkills[].skillId must be ids from lists.skills. Never invent an id; leave the list empty when unsure.",
|
|
9082
|
-
"To UPDATE an existing initiative instead of creating a new one, pass its id (from lists.initiatives) as `id` in the spec \u2014 the exported file then updates it in the app (Import/Export \u2192 Single initiative \u2192 'Update'). Omit id for a new initiative.",
|
|
9113
|
+
"To UPDATE an existing initiative instead of creating a new one, pass its id (from lists.initiatives) as `id` in the spec \u2014 the exported file then updates it in the app (Import/Export \u2192 Single initiative \u2192 'Update'). Omit id for a new initiative. Entries in lists.initiatives may carry externalId \u2014 the organisation's own reference (e.g. IC-26-118) \u2014 use it to recognise which initiative the user means. An update REPLACES the whole record: any field, section or row you omit is CLEARED \u2014 decision log, status reports and links included \u2014 so re-send everything that must survive. Exception: the organisation's externalId is carried over automatically when omitted.",
|
|
9083
9114
|
...ctx.sliderGranularity ? [`Ratings are in steps of ${ctx.sliderGranularity} (the organisation's slider step \u2014 Settings \u203A Slider granularity): ask for and send only multiples of ${ctx.sliderGranularity} between 0 and 100 (${gridExample(ctx.sliderGranularity)}); any other value is rejected.`] : [],
|
|
9084
9115
|
"Dates: talk to the user in dd/mm/yyyy; you may send dates as dd/mm/yyyy, dd.mm.yyyy or yyyy-mm-dd \u2014 the Composer stores yyyy-mm-dd.",
|
|
9085
9116
|
ctx.aiActEnabled ? "The organisation's EU-AI-Act module is ON: collect the AI-Act block and governance flags." : "The organisation's EU-AI-Act module is OFF: skip the AI-Act block and governance flags (the app would remove them on import).",
|
|
@@ -9103,7 +9134,7 @@ function buildInterviewPlan(ctx, contextId) {
|
|
|
9103
9134
|
categories: ctx.categories,
|
|
9104
9135
|
suggestedTags: ctx.suggestedTags,
|
|
9105
9136
|
skills: ctx.skills.map((s) => ({ id: s.id, name: s.name })),
|
|
9106
|
-
initiatives: ctx.initiatives.map((i) => ({ id: i.id, name: i.name, status: i.status }))
|
|
9137
|
+
initiatives: ctx.initiatives.map((i) => ({ id: i.id, ...i.externalId ? { externalId: i.externalId } : {}, name: i.name, status: i.status }))
|
|
9107
9138
|
},
|
|
9108
9139
|
interview: {
|
|
9109
9140
|
dimensions,
|
|
@@ -9224,11 +9255,20 @@ function assembleInitiative(input, now = /* @__PURE__ */ new Date()) {
|
|
|
9224
9255
|
return [dim, { score: dimensionScore(subs, disabled), confidence: d.confidence, subs }];
|
|
9225
9256
|
})
|
|
9226
9257
|
);
|
|
9258
|
+
let externalId = spec.externalId;
|
|
9259
|
+
if (externalId === void 0 && spec.id && context) {
|
|
9260
|
+
const kept = context.initiatives.find((i) => i.id === spec.id)?.externalId?.trim();
|
|
9261
|
+
if (kept) {
|
|
9262
|
+
externalId = kept;
|
|
9263
|
+
warnings.push(`externalId "${kept}" carried over from the organisation's records \u2014 send externalId explicitly to change or clear it.`);
|
|
9264
|
+
}
|
|
9265
|
+
}
|
|
9227
9266
|
const stamp = now.toISOString();
|
|
9228
9267
|
const aiAct = spec.aiAct;
|
|
9229
9268
|
const candidate = {
|
|
9230
9269
|
...spec,
|
|
9231
9270
|
id: spec.id ?? randomUUID(),
|
|
9271
|
+
...externalId !== void 0 ? { externalId } : {},
|
|
9232
9272
|
businessUnit,
|
|
9233
9273
|
aiCategory,
|
|
9234
9274
|
tags: spec.tags ?? [],
|
|
@@ -9274,7 +9314,7 @@ var IMPORT_INSTRUCTIONS = [
|
|
|
9274
9314
|
"2. In the BICon app (signed in to the target organisation), open Import/Export.",
|
|
9275
9315
|
"3. If the initiative carries EU-AI-Act data, make sure the organisation's EU-AI-Act module is switched on (Settings \u203A AI Act) \u2014 the app strips AI-Act fields while it is off.",
|
|
9276
9316
|
"4. In the 'Single initiative' card, drop the file (or Browse).",
|
|
9277
|
-
"5. Review the preview \u2014 it should show 0 warnings \u2014 then choose 'Add as new' (or 'Update' when the file carries an existing initiative's id
|
|
9317
|
+
"5. Review the preview \u2014 it should show 0 warnings \u2014 then choose 'Add as new' (or 'Update' when the file carries an existing initiative's id, Initiative ID or name \u2014 the app keeps that initiative's id and creation date, and REPLACES everything else with this file, decision log and status reports included) and Confirm.",
|
|
9278
9318
|
"6. The initiative appears in the Inventory with the derived dimension scores."
|
|
9279
9319
|
].join("\n");
|
|
9280
9320
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicon/mcp-composer",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "MCP server that helps an AI client compose a valid BICon portfolio initiative and hand it back as an import file (draft-first, no auth, no API calls).",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "BICon Establishment",
|