Score MBTI-style Likert answers deterministically for AI workflows, matching the same four-dimension logic used by the browser tool.
Import directly into Dify, Coze, Cursor, or any tool-calling agent runtime.
{
"name": "mbti_score_answers",
"description": "Score MBTI-style Likert answers and return a four-letter type with per-dimension percentages.",
"parameters": {
"type": "object",
"properties": {
"answers": {
"type": "array",
"description": "Ordered answers where each item includes a dimension key and a Likert value from 1 to 5.",
"items": {
"type": "object",
"properties": {
"dimension": {
"type": "string",
"enum": ["EI", "SN", "TF", "JP"]
},
"value": {
"type": "integer",
"enum": [1, 2, 3, 4, 5],
"description": "1 strongly agrees with pole A, 5 strongly agrees with pole B."
}
},
"required": ["dimension", "value"]
}
}
},
"required": ["answers"]
}
}Paste this into your system prompt to keep the generated tool implementation aligned with the contract.
# Task Constraints: MBTI-Style Answer Scoring
When scoring MBTI-style answers for AI workflows, you MUST keep the logic deterministic and transparent.
## Core Prohibitions
- NEVER diagnose mental health conditions or claim clinical validity.
- NEVER infer unanswered dimensions from unrelated conversation text.
- NEVER randomize tie-breaking.
## Standard Implementation
1. Treat each answer as a Likert value from 1 to 5.
2. Map values to pole-B weights using: 1 -> 0, 2 -> 0.25, 3 -> 0.5, 4 -> 0.75, 5 -> 1.
3. For each dimension, add the complement to pole A and the mapped weight to pole B.
4. Use these pole pairs:
- EI: E vs I
- SN: S vs N
- TF: T vs F
- JP: J vs P
5. Choose the winning letter per dimension by higher score.
6. If the two poles tie, prefer the second letter: I, N, F, or P.
## Output Rules
- Return the final four-letter type.
- Return percentages per dimension from the winner's share of that dimension total.
- If a dimension has no answers, default its percentage to 50 and still apply the deterministic tie-break toward the second letter.
- Keep question wording and question delivery outside this scoring contract.Pure scoring logic matching the browser implementation. The host can provide question text separately, while this tool focuses only on deterministic answer scoring.
function main(args) {
const { answers } = args;
if (!Array.isArray(answers) || answers.length === 0) {
return { success: false, result: null, error: "answers is required" };
}
const dimensionMap = {
EI: { first: "E", second: "I" },
SN: { first: "S", second: "N" },
TF: { first: "T", second: "F" },
JP: { first: "J", second: "P" },
};
const likertWeights = {
1: 0,
2: 0.25,
3: 0.5,
4: 0.75,
5: 1,
};
const dimensionScores = {
EI: { first: 0, second: 0 },
SN: { first: 0, second: 0 },
TF: { first: 0, second: 0 },
JP: { first: 0, second: 0 },
};
for (const answer of answers) {
const dimension = answer.dimension;
const value = answer.value;
if (!dimensionMap[dimension] || !Object.prototype.hasOwnProperty.call(likertWeights, value)) {
return {
success: false,
result: null,
error: "Each answer must include a valid dimension and Likert value from 1 to 5",
};
}
const weightToSecond = likertWeights[value];
const weightToFirst = 1 - weightToSecond;
dimensionScores[dimension].first += weightToFirst;
dimensionScores[dimension].second += weightToSecond;
}
let type = "";
const percentages = {};
const scores = {};
for (const dimension of ["EI", "SN", "TF", "JP"]) {
const mapping = dimensionMap[dimension];
const firstScore = dimensionScores[dimension].first;
const secondScore = dimensionScores[dimension].second;
const total = firstScore + secondScore;
const winner = firstScore > secondScore ? mapping.first : mapping.second;
const winnerScore = winner === mapping.first ? firstScore : secondScore;
type += winner;
scores[mapping.first] = firstScore;
scores[mapping.second] = secondScore;
percentages[dimension] = total > 0 ? Math.round((winnerScore / total) * 100) : 50;
}
return {
success: true,
result: {
type,
scores,
percentages,
dimensionScores,
},
};
}