Skip to main content
Glama
Connectry-io

Connectry Architect Cert

Official

start_assessment

Initiate the certification assessment: 15 scenario-based questions across five domains. Answer one at a time, get results, and track progress.

Instructions

Start the initial assessment. Returns ONE question at a time (15 total, 3 per domain).

IMPORTANT — follow this flow for EVERY question:

  1. Check if "isNewDomain" is true. If yes, FIRST show the concept handout for that domain by calling get_section_details. Tell the user: "Let's learn about [domain] before testing your knowledge." After showing the handout, proceed to step 2.

  2. Present the question to the user using AskUserQuestion:

    • header: "Q[number]"

    • question: Include the FULL scenario text AND question text from the response

    • options: Use the 4 answer options (A/B/C/D) with label as the letter and description as the option text

    • If the scenario contains code, add a "preview" field on each option showing the relevant code snippet so the user can reference it while choosing

  3. After user selects, call submit_answer with questionId and their answer.

  4. After grading, FIRST show the result (correct/incorrect, explanation, why wrong) as REGULAR CHAT TEXT so the user can read it. THEN present follow-up options using AskUserQuestion. The explanation must NOT be hidden behind the card.

  5. Call start_assessment again for the next question.

EDGE CASES:

  • If user selects "Other" and types a question/comment: Answer their question helpfully, then re-present the SAME quiz question using AskUserQuestion again. Never lose the current question.

  • If user clicks "Skip": Treat it as moving to the next question. Call start_assessment again immediately. The skipped question remains unanswered and will appear again later.

  • NEVER let Other or Skip break the assessment flow. Always continue to the next question or re-ask the current one.

PROGRESS TRACKING:

  • At the START of the assessment, create a TodoWrite checklist with all 15 questions (Q1-Q15) grouped by domain, all set to "pending".

  • After each answer, update the corresponding todo item to "completed" (with correct/incorrect note).

  • This gives the user a visual progress tracker throughout the assessment.

When assessment is complete, present next steps using AskUserQuestion with header "Next step".

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The async handler function that executes the start_assessment tool logic. It builds assessment questions (1 easy/medium/hard per domain), checks the database for already-answered questions, presents the next unanswered question, and when all 15 are answered computes results (overall accuracy, domain breakdown), determines learning path (exam-weighted if >=60% accuracy, beginner-friendly otherwise), and returns next-step options.
        async () => {
          const userId = userConfig.userId;
          ensureUser(db, userId);
    
          const questions = buildAssessmentQuestions();
          if (questions.length === 0) {
            return {
              content: [{ type: 'text' as const, text: JSON.stringify({ error: 'No assessment questions available.' }) }],
            };
          }
    
          const answeredIds = db.prepare(
            `SELECT questionId FROM answers WHERE userId = ? AND questionId IN (${questions.map(() => '?').join(',')})`,
          ).all(userId, ...questions.map(q => q.id)) as readonly { questionId: string }[];
    
          const answeredSet = new Set(answeredIds.map(r => r.questionId));
          const nextQuestion = questions.find(q => !answeredSet.has(q.id));
    
          // All done — compute results
          if (!nextQuestion) {
            const results = db.prepare(
              `SELECT domainId, COUNT(*) as total, SUM(CASE WHEN isCorrect THEN 1 ELSE 0 END) as correct
               FROM answers WHERE userId = ? AND questionId IN (${questions.map(() => '?').join(',')})
               GROUP BY domainId`,
            ).all(userId, ...questions.map(q => q.id)) as readonly { domainId: number; total: number; correct: number }[];
    
            const totalCorrect = results.reduce((sum, r) => sum + r.correct, 0);
            const totalQuestions = results.reduce((sum, r) => sum + r.total, 0);
            const overallAccuracy = totalQuestions > 0 ? Math.round((totalCorrect / totalQuestions) * 100) : 0;
            const path = overallAccuracy >= 60 ? 'exam-weighted' : 'beginner-friendly';
    
            db.prepare('UPDATE users SET assessmentCompleted = TRUE, learningPath = ? WHERE id = ?').run(path, userId);
    
            const response = {
              status: 'complete',
              overall: { correct: totalCorrect, total: totalQuestions, accuracy: overallAccuracy },
              learningPath: path === 'exam-weighted' ? 'Exam-Weighted' : 'Beginner-Friendly',
              domainResults: results.map(r => ({
                domain: r.domainId,
                name: DOMAIN_NAMES[r.domainId] ?? '',
                correct: r.correct,
                total: r.total,
                accuracy: Math.round((r.correct / r.total) * 100),
              })),
              nextStepOptions: [
                { label: 'Study Plan', description: 'Get personalized study recommendations based on your results' },
                { label: 'Practice Questions', description: 'Start adaptive practice targeting your weak areas' },
                { label: 'Capstone Build', description: 'Build your own project while learning all 30 task statements' },
                { label: 'Reference Projects', description: 'Explore runnable code examples for each domain' },
              ],
              instruction: 'Present nextStepOptions using AskUserQuestion with header "Next step".',
            };
    
            return {
              content: [{ type: 'text' as const, text: JSON.stringify(response, null, 2) }],
            };
          }
    
          // Determine if this is the first question for a new domain
          const questionIndex = answeredSet.size;
          const previousDomainIds = questions
            .filter(q => answeredSet.has(q.id))
            .map(q => q.domainId);
          const isNewDomain = !previousDomainIds.includes(nextQuestion.domainId);
    
          const response = {
            status: 'question',
            questionNumber: questionIndex + 1,
            totalQuestions: questions.length,
            questionId: nextQuestion.id,
            domainId: nextQuestion.domainId,
            domainName: DOMAIN_NAMES[nextQuestion.domainId] ?? 'Unknown',
            difficulty: nextQuestion.difficulty,
            taskStatement: nextQuestion.taskStatement,
            isNewDomain,
            scenario: nextQuestion.scenario,
            questionText: nextQuestion.text,
            options: {
              A: nextQuestion.options.A,
              B: nextQuestion.options.B,
              C: nextQuestion.options.C,
              D: nextQuestion.options.D,
            },
            instruction: isNewDomain
              ? `This is a NEW domain (${DOMAIN_NAMES[nextQuestion.domainId]}). Show the concept handout first using get_section_details for task "${nextQuestion.taskStatement}", then present this question using AskUserQuestion. Put the scenario + question in the "question" field. Use options with label "A"/"B"/"C"/"D" and description as the option text.`
              : `Present this question using AskUserQuestion with header "Q${questionIndex + 1}". Put the scenario + question text in the "question" field. Use options with label "A"/"B"/"C"/"D" and description as the option text.`,
          };
    
          return {
            content: [{ type: 'text' as const, text: JSON.stringify(response, null, 2) }],
          };
        }
      );
    }
  • The tool registration using server.tool() which includes the tool name 'start_assessment', the description/prompt for the LLM, empty schema object (no parameters), and the handler callback.
    export function registerStartAssessment(server: McpServer, db: Database.Database, userConfig: UserConfig): void {
      server.tool(
        'start_assessment',
        `Start the initial assessment. Returns ONE question at a time (15 total, 3 per domain).
    
    IMPORTANT — follow this flow for EVERY question:
    
    1. Check if "isNewDomain" is true. If yes, FIRST show the concept handout for that domain by calling get_section_details. Tell the user: "Let's learn about [domain] before testing your knowledge." After showing the handout, proceed to step 2.
    
    2. Present the question to the user using AskUserQuestion:
       - header: "Q[number]"
       - question: Include the FULL scenario text AND question text from the response
       - options: Use the 4 answer options (A/B/C/D) with label as the letter and description as the option text
       - If the scenario contains code, add a "preview" field on each option showing the relevant code snippet so the user can reference it while choosing
    
    3. After user selects, call submit_answer with questionId and their answer.
    
    4. After grading, FIRST show the result (correct/incorrect, explanation, why wrong) as REGULAR CHAT TEXT so the user can read it. THEN present follow-up options using AskUserQuestion. The explanation must NOT be hidden behind the card.
    
    5. Call start_assessment again for the next question.
    
    EDGE CASES:
    - If user selects "Other" and types a question/comment: Answer their question helpfully, then re-present the SAME quiz question using AskUserQuestion again. Never lose the current question.
    - If user clicks "Skip": Treat it as moving to the next question. Call start_assessment again immediately. The skipped question remains unanswered and will appear again later.
    - NEVER let Other or Skip break the assessment flow. Always continue to the next question or re-ask the current one.
    
    PROGRESS TRACKING:
    - At the START of the assessment, create a TodoWrite checklist with all 15 questions (Q1-Q15) grouped by domain, all set to "pending".
    - After each answer, update the corresponding todo item to "completed" (with correct/incorrect note).
    - This gives the user a visual progress tracker throughout the assessment.
    
    When assessment is complete, present next steps using AskUserQuestion with header "Next step".`,
        {},
        async () => {
          const userId = userConfig.userId;
          ensureUser(db, userId);
    
          const questions = buildAssessmentQuestions();
          if (questions.length === 0) {
            return {
              content: [{ type: 'text' as const, text: JSON.stringify({ error: 'No assessment questions available.' }) }],
            };
          }
    
          const answeredIds = db.prepare(
            `SELECT questionId FROM answers WHERE userId = ? AND questionId IN (${questions.map(() => '?').join(',')})`,
          ).all(userId, ...questions.map(q => q.id)) as readonly { questionId: string }[];
    
          const answeredSet = new Set(answeredIds.map(r => r.questionId));
          const nextQuestion = questions.find(q => !answeredSet.has(q.id));
    
          // All done — compute results
          if (!nextQuestion) {
            const results = db.prepare(
              `SELECT domainId, COUNT(*) as total, SUM(CASE WHEN isCorrect THEN 1 ELSE 0 END) as correct
               FROM answers WHERE userId = ? AND questionId IN (${questions.map(() => '?').join(',')})
               GROUP BY domainId`,
            ).all(userId, ...questions.map(q => q.id)) as readonly { domainId: number; total: number; correct: number }[];
    
            const totalCorrect = results.reduce((sum, r) => sum + r.correct, 0);
            const totalQuestions = results.reduce((sum, r) => sum + r.total, 0);
            const overallAccuracy = totalQuestions > 0 ? Math.round((totalCorrect / totalQuestions) * 100) : 0;
            const path = overallAccuracy >= 60 ? 'exam-weighted' : 'beginner-friendly';
    
            db.prepare('UPDATE users SET assessmentCompleted = TRUE, learningPath = ? WHERE id = ?').run(path, userId);
    
            const response = {
              status: 'complete',
              overall: { correct: totalCorrect, total: totalQuestions, accuracy: overallAccuracy },
              learningPath: path === 'exam-weighted' ? 'Exam-Weighted' : 'Beginner-Friendly',
              domainResults: results.map(r => ({
                domain: r.domainId,
                name: DOMAIN_NAMES[r.domainId] ?? '',
                correct: r.correct,
                total: r.total,
                accuracy: Math.round((r.correct / r.total) * 100),
              })),
              nextStepOptions: [
                { label: 'Study Plan', description: 'Get personalized study recommendations based on your results' },
                { label: 'Practice Questions', description: 'Start adaptive practice targeting your weak areas' },
                { label: 'Capstone Build', description: 'Build your own project while learning all 30 task statements' },
                { label: 'Reference Projects', description: 'Explore runnable code examples for each domain' },
              ],
              instruction: 'Present nextStepOptions using AskUserQuestion with header "Next step".',
            };
    
            return {
              content: [{ type: 'text' as const, text: JSON.stringify(response, null, 2) }],
            };
          }
    
          // Determine if this is the first question for a new domain
          const questionIndex = answeredSet.size;
          const previousDomainIds = questions
            .filter(q => answeredSet.has(q.id))
            .map(q => q.domainId);
          const isNewDomain = !previousDomainIds.includes(nextQuestion.domainId);
    
          const response = {
            status: 'question',
            questionNumber: questionIndex + 1,
            totalQuestions: questions.length,
            questionId: nextQuestion.id,
            domainId: nextQuestion.domainId,
            domainName: DOMAIN_NAMES[nextQuestion.domainId] ?? 'Unknown',
            difficulty: nextQuestion.difficulty,
            taskStatement: nextQuestion.taskStatement,
            isNewDomain,
            scenario: nextQuestion.scenario,
            questionText: nextQuestion.text,
            options: {
              A: nextQuestion.options.A,
              B: nextQuestion.options.B,
              C: nextQuestion.options.C,
              D: nextQuestion.options.D,
            },
            instruction: isNewDomain
              ? `This is a NEW domain (${DOMAIN_NAMES[nextQuestion.domainId]}). Show the concept handout first using get_section_details for task "${nextQuestion.taskStatement}", then present this question using AskUserQuestion. Put the scenario + question in the "question" field. Use options with label "A"/"B"/"C"/"D" and description as the option text.`
              : `Present this question using AskUserQuestion with header "Q${questionIndex + 1}". Put the scenario + question text in the "question" field. Use options with label "A"/"B"/"C"/"D" and description as the option text.`,
          };
    
          return {
            content: [{ type: 'text' as const, text: JSON.stringify(response, null, 2) }],
          };
        }
      );
    }
  • Registration call that wires up start_assessment into the main tool registry. Imported in line 9 from './start-assessment.js'.
    registerStartAssessment(server, db, userConfig);
  • Helper function buildAssessmentQuestions() that constructs the 15-question assessment by picking one easy, one medium, and one hard question from each of the 5 domains using loadQuestions().
    function buildAssessmentQuestions(): readonly Question[] {
      const questions: Question[] = [];
      for (let d = 1; d <= 5; d++) {
        const domainQuestions = loadQuestions(d);
        const easy = domainQuestions.find(q => q.difficulty === 'easy');
        const medium = domainQuestions.find(q => q.difficulty === 'medium');
        const hard = domainQuestions.find(q => q.difficulty === 'hard');
        if (easy) questions.push(easy);
        if (medium) questions.push(medium);
        if (hard) questions.push(hard);
      }
      return questions;
    }
  • Constant mapping of domain IDs (1-5) to their human-readable names (Agentic Architecture, Tool Design & MCP, etc.) used in the response.
    const DOMAIN_NAMES: Readonly<Record<number, string>> = {
      1: 'Agentic Architecture',
      2: 'Tool Design & MCP',
      3: 'Claude Code Config',
      4: 'Prompt Engineering',
      5: 'Context & Reliability',
    };
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided; description carries full burden. It discloses that it returns one question, requires a flow with domain handouts, handles user interactions, and updates progress. No destructive actions implied, and no contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Long but well-structured with sections for flow, edge cases, progress tracking. Front-loaded with core purpose. Could be more concise but every sentence adds necessary detail for correct usage.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the interactive complexity and lack of output schema, description fully explains expected response format, step-by-step flow, edge cases, and progress tracking. Leaves no ambiguity for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has 0 parameters with 100% coverage, so description need not add param info. Baseline 4 is appropriate; description does not need to explain parameters but adds value through behavioral instructions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states 'Start the initial assessment' and specifies it returns one question at a time (15 total, 3 per domain). Distinguishes from sibling tools like start_practice_exam or get_practice_question.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides detailed step-by-step instructions including when to call other tools (get_section_details, submit_answer), how to present questions, handle edge cases (Other, Skip), and progress tracking. Explicitly covers when to use and what to avoid.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Connectry-io/connectrylab-architect-cert-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server