connectry-architect-mcp 0.1.1 → 0.1.2
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.js +185 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -183,6 +183,33 @@ function loadOrCreateUserConfig() {
|
|
|
183
183
|
// src/tools/submit-answer.ts
|
|
184
184
|
import { z } from "zod";
|
|
185
185
|
|
|
186
|
+
// src/tools/elicit.ts
|
|
187
|
+
async function elicitSingleSelect(mcpServer, message, fieldName, options) {
|
|
188
|
+
try {
|
|
189
|
+
const result = await mcpServer.server.elicitInput({
|
|
190
|
+
mode: "form",
|
|
191
|
+
message,
|
|
192
|
+
requestedSchema: {
|
|
193
|
+
type: "object",
|
|
194
|
+
properties: {
|
|
195
|
+
[fieldName]: {
|
|
196
|
+
type: "string",
|
|
197
|
+
title: fieldName,
|
|
198
|
+
oneOf: options.map((o) => ({ const: o.value, title: o.title }))
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
required: [fieldName]
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
if (result.action === "accept" && result.content) {
|
|
205
|
+
return result.content[fieldName];
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
} catch {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
186
213
|
// src/engine/grading.ts
|
|
187
214
|
function gradeAnswer(question, userAnswer) {
|
|
188
215
|
const normalizedAnswer = userAnswer.toUpperCase();
|
|
@@ -396,6 +423,17 @@ function registerSubmitAnswer(server2, db2, userConfig2) {
|
|
|
396
423
|
{ key: "handout", label: "Show me the handout" },
|
|
397
424
|
{ key: "project", label: "Show me in the reference project" }
|
|
398
425
|
];
|
|
426
|
+
const elicitOptions = followUpOptions.map((opt) => ({
|
|
427
|
+
value: opt.key,
|
|
428
|
+
title: opt.label
|
|
429
|
+
}));
|
|
430
|
+
const elicitMessage = result.isCorrect ? "Nice work! What would you like to do next?" : "What would you like to do next?";
|
|
431
|
+
const selectedFollowUp = await elicitSingleSelect(
|
|
432
|
+
server2,
|
|
433
|
+
elicitMessage,
|
|
434
|
+
"followUp",
|
|
435
|
+
elicitOptions
|
|
436
|
+
);
|
|
399
437
|
const response = {
|
|
400
438
|
questionId: result.questionId,
|
|
401
439
|
isCorrect: result.isCorrect,
|
|
@@ -403,7 +441,8 @@ function registerSubmitAnswer(server2, db2, userConfig2) {
|
|
|
403
441
|
explanation: result.explanation,
|
|
404
442
|
whyYourAnswerWasWrong: result.whyUserWasWrong,
|
|
405
443
|
references: result.references,
|
|
406
|
-
followUpOptions
|
|
444
|
+
followUpOptions,
|
|
445
|
+
...selectedFollowUp != null ? { selectedFollowUp } : {}
|
|
407
446
|
};
|
|
408
447
|
return {
|
|
409
448
|
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
@@ -561,6 +600,23 @@ function findUnansweredForTaskStatement(questions, taskStatement, answeredIds) {
|
|
|
561
600
|
}
|
|
562
601
|
|
|
563
602
|
// src/tools/get-practice-question.ts
|
|
603
|
+
var OPTION_KEYS = ["A", "B", "C", "D"];
|
|
604
|
+
function formatQuestionText(question) {
|
|
605
|
+
const lines = [
|
|
606
|
+
`**Question ${question.id}** (Domain ${question.domainId} | ${question.difficulty})`,
|
|
607
|
+
"",
|
|
608
|
+
`**Task:** ${question.taskStatement}`,
|
|
609
|
+
"",
|
|
610
|
+
"---",
|
|
611
|
+
"",
|
|
612
|
+
question.scenario,
|
|
613
|
+
"",
|
|
614
|
+
`**${question.text}**`,
|
|
615
|
+
"",
|
|
616
|
+
...OPTION_KEYS.map((key) => ` **${key}.** ${question.options[key]}`)
|
|
617
|
+
];
|
|
618
|
+
return lines.join("\n");
|
|
619
|
+
}
|
|
564
620
|
function registerGetPracticeQuestion(server2, db2, userConfig2) {
|
|
565
621
|
server2.tool(
|
|
566
622
|
"get_practice_question",
|
|
@@ -585,16 +641,39 @@ function registerGetPracticeQuestion(server2, db2, userConfig2) {
|
|
|
585
641
|
content: [{ type: "text", text: "No more questions available for the selected criteria. Try a different domain or difficulty." }]
|
|
586
642
|
};
|
|
587
643
|
}
|
|
588
|
-
const
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
644
|
+
const questionText = formatQuestionText(question);
|
|
645
|
+
const elicitOptions = OPTION_KEYS.map((key) => ({
|
|
646
|
+
value: key,
|
|
647
|
+
title: `${key}. ${question.options[key]}`
|
|
648
|
+
}));
|
|
649
|
+
const selectedAnswer = await elicitSingleSelect(
|
|
650
|
+
server2,
|
|
651
|
+
questionText,
|
|
652
|
+
"answer",
|
|
653
|
+
elicitOptions
|
|
654
|
+
);
|
|
655
|
+
if (selectedAnswer) {
|
|
656
|
+
const responseText = [
|
|
657
|
+
questionText,
|
|
658
|
+
"",
|
|
659
|
+
"---",
|
|
660
|
+
"",
|
|
661
|
+
`**Selected answer: ${selectedAnswer}**`,
|
|
662
|
+
"",
|
|
663
|
+
`Use submit_answer with questionId "${question.id}" and answer "${selectedAnswer}" to grade this response.`
|
|
664
|
+
].join("\n");
|
|
665
|
+
return { content: [{ type: "text", text: responseText }] };
|
|
666
|
+
}
|
|
667
|
+
const fallbackText = [
|
|
668
|
+
questionText,
|
|
669
|
+
"",
|
|
670
|
+
"---",
|
|
671
|
+
"",
|
|
672
|
+
`Question ID: ${question.id}`,
|
|
673
|
+
"",
|
|
674
|
+
"Use submit_answer with the question ID and your chosen answer (A, B, C, or D) to check your response."
|
|
675
|
+
].join("\n");
|
|
676
|
+
return { content: [{ type: "text", text: fallbackText }] };
|
|
598
677
|
}
|
|
599
678
|
);
|
|
600
679
|
}
|
|
@@ -1044,38 +1123,48 @@ function registerStartPracticeExam(server2, db2, userConfig2) {
|
|
|
1044
1123
|
return ` D${domainId}: ${title} \u2014 ${count} questions (${domainScores[`d${domainId}`].weight}%)`;
|
|
1045
1124
|
});
|
|
1046
1125
|
const firstQuestion = examQuestions[0];
|
|
1126
|
+
const text = [
|
|
1127
|
+
"\u2550\u2550\u2550 PRACTICE EXAM STARTED \u2550\u2550\u2550",
|
|
1128
|
+
"",
|
|
1129
|
+
"Simulating the Claude Certified Architect \u2014 Foundations exam.",
|
|
1130
|
+
"",
|
|
1131
|
+
`Exam ID: ${examId}`,
|
|
1132
|
+
"Total Questions: 60",
|
|
1133
|
+
"Passing Score: 720/1000",
|
|
1134
|
+
"",
|
|
1135
|
+
"Question Distribution:",
|
|
1136
|
+
...distribution,
|
|
1137
|
+
"",
|
|
1138
|
+
"\u2500\u2500\u2500 Question 1 of 60 \u2500\u2500\u2500",
|
|
1139
|
+
"",
|
|
1140
|
+
`Domain: D${firstQuestion.domainId}`,
|
|
1141
|
+
`Task: ${firstQuestion.taskStatement}`,
|
|
1142
|
+
`Difficulty: ${firstQuestion.difficulty}`,
|
|
1143
|
+
"",
|
|
1144
|
+
`Scenario: ${firstQuestion.scenario}`,
|
|
1145
|
+
"",
|
|
1146
|
+
firstQuestion.text,
|
|
1147
|
+
"",
|
|
1148
|
+
`A) ${firstQuestion.options.A}`,
|
|
1149
|
+
`B) ${firstQuestion.options.B}`,
|
|
1150
|
+
`C) ${firstQuestion.options.C}`,
|
|
1151
|
+
`D) ${firstQuestion.options.D}`,
|
|
1152
|
+
"",
|
|
1153
|
+
`[Submit your answer using submit_exam_answer with examId: ${examId} and questionId: "${firstQuestion.id}"]`
|
|
1154
|
+
].join("\n");
|
|
1155
|
+
const selected = await elicitSingleSelect(server2, "Select your answer:", "answer", [
|
|
1156
|
+
{ value: "A", title: `A) ${firstQuestion.options.A}` },
|
|
1157
|
+
{ value: "B", title: `B) ${firstQuestion.options.B}` },
|
|
1158
|
+
{ value: "C", title: `C) ${firstQuestion.options.C}` },
|
|
1159
|
+
{ value: "D", title: `D) ${firstQuestion.options.D}` }
|
|
1160
|
+
]);
|
|
1161
|
+
const responseText = selected !== null ? `${text}
|
|
1162
|
+
|
|
1163
|
+
User selected: ${selected}` : text;
|
|
1047
1164
|
return {
|
|
1048
1165
|
content: [{
|
|
1049
1166
|
type: "text",
|
|
1050
|
-
text:
|
|
1051
|
-
"\u2550\u2550\u2550 PRACTICE EXAM STARTED \u2550\u2550\u2550",
|
|
1052
|
-
"",
|
|
1053
|
-
"Simulating the Claude Certified Architect \u2014 Foundations exam.",
|
|
1054
|
-
"",
|
|
1055
|
-
`Exam ID: ${examId}`,
|
|
1056
|
-
"Total Questions: 60",
|
|
1057
|
-
"Passing Score: 720/1000",
|
|
1058
|
-
"",
|
|
1059
|
-
"Question Distribution:",
|
|
1060
|
-
...distribution,
|
|
1061
|
-
"",
|
|
1062
|
-
"\u2500\u2500\u2500 Question 1 of 60 \u2500\u2500\u2500",
|
|
1063
|
-
"",
|
|
1064
|
-
`Domain: D${firstQuestion.domainId}`,
|
|
1065
|
-
`Task: ${firstQuestion.taskStatement}`,
|
|
1066
|
-
`Difficulty: ${firstQuestion.difficulty}`,
|
|
1067
|
-
"",
|
|
1068
|
-
`Scenario: ${firstQuestion.scenario}`,
|
|
1069
|
-
"",
|
|
1070
|
-
firstQuestion.text,
|
|
1071
|
-
"",
|
|
1072
|
-
`A) ${firstQuestion.options.A}`,
|
|
1073
|
-
`B) ${firstQuestion.options.B}`,
|
|
1074
|
-
`C) ${firstQuestion.options.C}`,
|
|
1075
|
-
`D) ${firstQuestion.options.D}`,
|
|
1076
|
-
"",
|
|
1077
|
-
`[Submit your answer using submit_exam_answer with examId: ${examId} and questionId: "${firstQuestion.id}"]`
|
|
1078
|
-
].join("\n")
|
|
1167
|
+
text: responseText
|
|
1079
1168
|
}]
|
|
1080
1169
|
};
|
|
1081
1170
|
}
|
|
@@ -1193,6 +1282,15 @@ function registerSubmitExamAnswer(server2, db2, userConfig2) {
|
|
|
1193
1282
|
lines.push(`B) ${nextQuestion.options.B}`);
|
|
1194
1283
|
lines.push(`C) ${nextQuestion.options.C}`);
|
|
1195
1284
|
lines.push(`D) ${nextQuestion.options.D}`);
|
|
1285
|
+
const selected = await elicitSingleSelect(server2, "Select your answer:", "answer", [
|
|
1286
|
+
{ value: "A", title: `A) ${nextQuestion.options.A}` },
|
|
1287
|
+
{ value: "B", title: `B) ${nextQuestion.options.B}` },
|
|
1288
|
+
{ value: "C", title: `C) ${nextQuestion.options.C}` },
|
|
1289
|
+
{ value: "D", title: `D) ${nextQuestion.options.D}` }
|
|
1290
|
+
]);
|
|
1291
|
+
if (selected !== null) {
|
|
1292
|
+
lines.push("", `User selected: ${selected}`);
|
|
1293
|
+
}
|
|
1196
1294
|
}
|
|
1197
1295
|
}
|
|
1198
1296
|
}
|
|
@@ -2214,6 +2312,16 @@ function handleAbandon(db2, userId) {
|
|
|
2214
2312
|
buildId: build.id
|
|
2215
2313
|
});
|
|
2216
2314
|
}
|
|
2315
|
+
function appendSelectedAction(response, selected) {
|
|
2316
|
+
if (!selected) return response;
|
|
2317
|
+
const existingText = response.content[0].text;
|
|
2318
|
+
return {
|
|
2319
|
+
...response,
|
|
2320
|
+
content: [{ type: "text", text: `${existingText}
|
|
2321
|
+
|
|
2322
|
+
User selected next action: ${selected}` }]
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2217
2325
|
function registerCapstoneBuildStep(server2, db2, userConfig2) {
|
|
2218
2326
|
server2.tool(
|
|
2219
2327
|
"capstone_build_step",
|
|
@@ -2225,8 +2333,17 @@ function registerCapstoneBuildStep(server2, db2, userConfig2) {
|
|
|
2225
2333
|
const userId = userConfig2.userId;
|
|
2226
2334
|
ensureUser(db2, userId);
|
|
2227
2335
|
switch (action) {
|
|
2228
|
-
case "confirm":
|
|
2229
|
-
|
|
2336
|
+
case "confirm": {
|
|
2337
|
+
const result = handleConfirm(db2, userId);
|
|
2338
|
+
if ("isError" in result) return result;
|
|
2339
|
+
const selected = await elicitSingleSelect(
|
|
2340
|
+
server2,
|
|
2341
|
+
"Build confirmed! What would you like to do next?",
|
|
2342
|
+
"nextAction",
|
|
2343
|
+
[{ value: "quiz", title: "Start the first quiz" }]
|
|
2344
|
+
);
|
|
2345
|
+
return appendSelectedAction(result, selected);
|
|
2346
|
+
}
|
|
2230
2347
|
case "quiz":
|
|
2231
2348
|
return handleQuiz(db2, userId);
|
|
2232
2349
|
case "build": {
|
|
@@ -2237,10 +2354,33 @@ function registerCapstoneBuildStep(server2, db2, userConfig2) {
|
|
|
2237
2354
|
if (build.status !== "building") {
|
|
2238
2355
|
return errorResponse(`Build must be in "building" status. Current status: "${build.status}".`);
|
|
2239
2356
|
}
|
|
2240
|
-
|
|
2357
|
+
const result = handleBuild(db2, userId, build);
|
|
2358
|
+
if ("isError" in result) return result;
|
|
2359
|
+
const selected = await elicitSingleSelect(
|
|
2360
|
+
server2,
|
|
2361
|
+
"Build instructions generated. What would you like to do next?",
|
|
2362
|
+
"nextAction",
|
|
2363
|
+
[
|
|
2364
|
+
{ value: "next", title: "Advance to the next step" },
|
|
2365
|
+
{ value: "status", title: "Check build progress" }
|
|
2366
|
+
]
|
|
2367
|
+
);
|
|
2368
|
+
return appendSelectedAction(result, selected);
|
|
2369
|
+
}
|
|
2370
|
+
case "next": {
|
|
2371
|
+
const result = handleNext(db2, userId);
|
|
2372
|
+
if ("isError" in result) return result;
|
|
2373
|
+
const selected = await elicitSingleSelect(
|
|
2374
|
+
server2,
|
|
2375
|
+
"Step advanced. What would you like to do next?",
|
|
2376
|
+
"nextAction",
|
|
2377
|
+
[
|
|
2378
|
+
{ value: "quiz", title: "Start this step's quiz" },
|
|
2379
|
+
{ value: "status", title: "Check build progress" }
|
|
2380
|
+
]
|
|
2381
|
+
);
|
|
2382
|
+
return appendSelectedAction(result, selected);
|
|
2241
2383
|
}
|
|
2242
|
-
case "next":
|
|
2243
|
-
return handleNext(db2, userId);
|
|
2244
2384
|
case "status":
|
|
2245
2385
|
return handleStatus(db2, userId);
|
|
2246
2386
|
case "abandon":
|