رتبه بندی کیفیت برای تعریف ابزار MCP Linter در TypeScript

پروتکل بافت مدل (MCP) به عنوان یک پروتکل به طور گسترده پذیرفته شده برای اتصال عوامل مبتنی بر LLM به ابزارهای خارجی، منابع داده و خدمات ظاهر شده است. در حال حاضر هیچ ابزار استاندارد شده برای تعاریف ابزار MCP وجود ندارد. این مقاله یکی را از ابتدا میسازد: یک لنگر TypeScript CLI که تعاریف ابزار MCP را در برابر یک روبریک وزندار تأیید میکند و یک نمره کیفیت عددی را به دست میدهد.
محتوا
پروتکل بافت مدل (MCP) به عنوان یک پروتکل به طور گسترده پذیرفته شده برای اتصال عوامل مبتنی بر LLM به ابزارهای خارجی، منابع داده و خدمات ظاهر شده است. هنگامی که یک عامل فهرستی از ابزارهای موجود را دریافت میکند، کاملاً به فرادادههای ارائهشده توسط هر تعریف ابزار MCP متکی است تا تصمیم بگیرد که کدام ابزار را فراخوانی کند، چه آرگومانهایی را ارائه کند و چه زمانی آن را فراخوانی کند. روی ساز name، description، و inputSchema تنها سیگنال هایی در خود تعریف ابزار هستند که مدل دریافت می کند. در حالی که مدل در تلاش برای تفسیر طرحوارههای مبهم است، تعاریف ضعیف نوشته شده مستقیماً به توهمات عامل، تماسهای ابزار نادرست و توکنهای هدر رفته منجر میشود.
در حالی که مدل در تلاش برای تفسیر طرحوارههای مبهم است، تعاریف ضعیف نوشته شده مستقیماً به توهمات عامل، تماسهای ابزار نادرست و توکنهای هدر رفته منجر میشود.
در حال حاضر هیچ ابزار استاندارد شده برای تعاریف ابزار MCP وجود ندارد. این مقاله یکی را از ابتدا میسازد: یک لنگر TypeScript CLI که تعاریف ابزار MCP را در برابر یک روبریک وزندار تأیید میکند و یک نمره کیفیت عددی را به دست میدهد. موضوعات انجمن های متعدد فقط این نوع پورت با کیفیت را درخواست کرده اند، و آنچه در ادامه می آید آن را پیاده سازی می کند.
آناتومی شی ابزار MCP
هر تعریف ابزار MCP که از طریق پروتکل در معرض دید قرار می گیرد ListToolsResult شامل سه فیلد اصلی است: name، description، و inputSchema. با هم name و description به LLM بگویید کدام ابزار را انتخاب کند و چه زمانی آن را انتخاب کند (توضیحات اختیاری است، اما به شدت توصیه می شود). را inputSchema یک شی طرح JSON است که آرگومان هایی را که ابزار می پذیرد، از جمله انواع، توضیحات، محدودیت ها، و اینکه کدام یک مورد نیاز است، تعریف می کند.
تفاوت بین تعریفی که عامل را به طور قابل اعتماد هدف قرار می دهد و تعریفی که باعث خطای نادرست می شود، اغلب به ویژگی مربوط می شود. تضاد را در نظر بگیرید:
const goodTool = {
name: "get-current-weather",
description: "Retrieve the current weather conditions for a specified city, returning temperature in Celsius and a short forecast summary.",
inputSchema: {
type: "object" as const,
properties: {
city: {
type: "string",
description: "The city name to look up weather for, e.g. 'London'",
minLength: 1
},
units: {
type: "string",
description: "Temperature unit preference",
enum: ["celsius", "fahrenheit"]
}
},
required: ["city"]
}
};
const badTool = {
name: "weather",
description: "Does weather stuff",
inputSchema: {
type: "object" as const,
properties: {
input: { type: "string" }
}
}
};
تعریف اول هر آنچه را که نیاز دارد به مدل می دهد: نام فعل-اسم، توصیفی که فرمت بازگشتی را مشخص می کند، آرگومان های تایپ شده و توصیف شده، محدودیت enum در مجموعه ای از مقادیر نهایی، و صریح required آرایه دومی تقریباً چیزی برای کار کردن به مدل نمی دهد.
ضد الگوهای با کیفیت رایج
چندین الگوی تکراری کیفیت تعریف ابزار را کاهش می دهد. توضیحاتی مانند «کارها را انجام میدهد» یا «درخواستها را پردازش میکند» هیچ سیگنال معنایی ارائه نمیدهند، بنابراین مدل ابزارها را تقریباً خودسرانه انتخاب میکند. زمانی که آرگومان ها فاقد توصیف یا انواع صریح باشند، مدل قصد را حدس می زند. از دست دادن required آرایه زمانی که ویژگیها وجود دارد، مدل را در مورد اینکه کدام آرگومان مورد نیاز است نامشخص میگذارد. نام ابزارهای رایج مانند “اجرا” یا “فرآیند” زمانی که چندین ابزار در دسترس هستند از نظر معنایی با هم برخورد می کنند. در نهایت، یک مجموعه محدود از مقادیر معتبر بدون یک enum محدودیت ظرفیت مدل را هدر می دهد و ورودی نامعتبر ایجاد می کند.
راه اندازی پروژه و وابستگی ها
پیش نیازها: Node.js 18 یا جدیدتر (Node.js 22 LTS برای مطابقت توصیه می شود @types/node@22.x، npm و دسترسی به دایرکتوری کاری را بنویسید.
پروژه TypeScript را راه اندازی کنید
لینتر به حداقل تنظیم TypeScript با فعال بودن حالت سخت و چند وابستگی نیاز دارد.
mkdir mcp-tool-linter && cd mcp-tool-linter
npm init -y
npm install ajv
npm install -D typescript ts-node @types/node
npx tsc --init --strict --target ES2020 --module commonjs --outDir dist --rootDir src
بعد از دویدن tsc --init، بررسی کنید که آیا شما tsconfig.json حداقل شامل این تنظیمات ( tsc --init رفتار پرچم ممکن است بر اساس نسخه TypeScript متفاوت باشد – به صورت دستی تأیید کنید:
{
"compilerOptions": {
"strict": true,
"target": "ES2020",
"module": "commonjs",
"outDir": "dist",
"rootDir": "src",
"esModuleInterop": true
}
}
بخش مربوطه از package.json:
{
"name": "mcp-tool-linter",
"version": "1.0.0",
"scripts": {
"lint-tools": "ts-node src/cli.ts"
},
"dependencies": {
"ajv": "^8.17.1"
},
"devDependencies": {
"typescript": "^5.7.3",
"ts-node": "^10.9.2",
"@types/node": "^22.12.0"
}
}
را @modelcontextprotocol/sdk بسته بندی برای لنتر اصلی مورد نیاز نیست. آن را فقط در صورتی نصب کنید که قصد دارید افزونه حسابرسی زنده را که در بخش افزونه ها توضیح داده شده است، پیاده سازی کنید: npm install @modelcontextprotocol/sdk.
ساختار فایل پروژه
این پروژه از طرح زیر پیروی می کند: src/rules.ts شامل توابع اعتبارسنجی فردی است، src/scorer.ts جمع بندی وزنی را مدیریت می کند، src/cli.ts نقطه ورود است و sample-tools.json (قرار گرفته در ریشه پروژه) داده های آزمایشی را ارائه می دهد.
تعریف روبریک درجه بندی
ابعاد و وزن با کیفیت
لینتر پنج بعد را ارزیابی میکند که هر کدام برای منعکس کردن تأثیر آن بر قابلیت اعتماد نماینده وزن دارند:
- اعتبار طرح (30%): بله
inputSchemaاعتبار سنجی ساختاری طرحواره JSON از طریق Ajv انجام شود؟ طرحواره نامعتبر جدی ترین نقص است زیرا می تواند باعث خطاهای زمان اجرا در هر کلاینت سازگار شود. - از آنجایی که کیفیت توضیحات 25 درصد وزن را به خود اختصاص می دهد، توصیف مبهم یا گم شده به طور قابل توجهی نمره کلی را کاهش می دهد. Linter بررسی می کند که توضیحات به اندازه کافی طولانی، خاص و با یک فعل عمل شروع می شود. این بر دقت انتخاب مدل ابزار تأثیر می گذارد.
- تمامیت استدلال (25%): اینکه آیا هر ملک در
inputSchemaبه صراحت دارندtypeوdescription? استrequiredآرایه در هنگام وجود خواص وجود دارد؟ - قراردادهای نامگذاری 10 درصد وزن را دارند. لینتر بررسی می کند که آیا نام ابزار از kebab-case یا snake_case پیروی می کند و از الگوی فعل-اسم استفاده می کند. MCP رسماً به این کنوانسیون ها نیاز ندارد. این یک اکتشافی با کیفیت است، نه یک محدودیت پروتکل.
- انبوهی از محدودیت ها (10%): آیا محدودیتهای enum، min/max، الگو، یا minLength در صورت لزوم برای آرگومانهای رشتهای استفاده میشوند؟
export interface RuleResult {
ruleName: string;
score: number;
maxScore: number;
feedback: string[];
}
export interface QualityRubric {
schemaValidity: number;
descriptionQuality: number;
argumentCompleteness: number;
namingConventions: number;
constraintRichness: number;
}
export interface QualityScore {
total: number;
status: "PASS" | "WARN" | "FAIL";
ruleResults: RuleResult[];
}
export const DEFAULT_WEIGHTS: QualityRubric = {
schemaValidity: 0.30,
descriptionQuality: 0.25,
argumentCompleteness: 0.25,
namingConventions: 0.10,
constraintRichness: 0.10,
};
مقیاس امتیازدهی
امتیاز نهایی به مقیاس عددی 0 تا 100 تبدیل می شود. امتیاز 75 یا بالاتر به وضعیت PASS اختصاص می یابد که نشان می دهد تعریف آماده برای تولید است. نمرات بین 50 تا 74 باعث ایجاد یک WARN می شود و نشان می دهد که این تعریف احتمالاً کار می کند اما شکاف های قابل توجهی دارد. هر چیزی زیر 50 یک FAIL است، به این معنی که این تعریف خطر واقعی سوء استفاده از عامل را به همراه دارد.
اعمال قوانین اعتبارسنجی
بررسی طرحواره با Ajv
اساسی ترین بررسی تایید می کند که ابزار است inputSchema خود یک سند طرحواره JSON از نظر ساختاری (متا اعتبار سنجی) با استفاده از Ajv v8 است که به طور پیش فرض JSON Schema Draft-2019-09 را هدف قرار می دهد. اگر خود طرحواره از نظر ساختاری نامعتبر باشد، هیچ چیز پایین دستی مهم نیست.
توجه: برای هدف قرار دادن به طور خاص Draft-07، وارد کنید Ajv از ajv-draft-04 یا ajv/dist/2019 و ساب پکیج مناسب را نصب کنید. برهنه ajv@8.x واردات مورد استفاده در اینجا به طور پیشفرض روی Draft-2019-09 است.
import Ajv, { ErrorObject } from "ajv";
const ajv = new Ajv({ allErrors: true, strict: false });
import { RuleResult } from "./scorer";
interface ToolInputSchema {
type?: string;
properties?: Recordstring, any>;
required?: string[];
[key: string]: any;
}
interface Tool {
name: string;
description?: string;
inputSchema?: ToolInputSchema;
}
export function validateSchema(tool: Tool): RuleResult {
const feedback: string[] = [];
let schemaInvalid = false;
let wrongType = false;
if (!tool.inputSchema) {
return {
ruleName: "schemaValidity",
score: 0,
maxScore: 1,
feedback: ["Missing inputSchema entirely"],
};
}
const valid = ajv.validateSchema(tool.inputSchema);
if (!valid && ajv.errors) {
schemaInvalid = true;
ajv.errors.forEach((err: ErrorObject) => {
feedback.push(`Schema error at ${err.instancePath || "root"}: ${err.message}`);
});
}
if (tool.inputSchema.type !== "object") {
wrongType = true;
feedback.push('inputSchema.type should be "object"');
}
let score = 1;
if (schemaInvalid) score -= 1.0;
if (wrongType) score -= 0.5;
return {
ruleName: "schemaValidity",
score: Math.max(0, score),
maxScore: 1,
feedback,
};
}
Ajv با پیکربندی شده است allErrors: true بنابراین هر اعتبار سنجی ناموفق، نه فقط اولی، آشکار می شود. را strict: false گزینه حالت سختگیرانه خود Ajv را غیرفعال می کند، که در غیر این صورت کلمات کلیدی ناشناخته و الگوهای طرحواره ای را که طرحواره JSON معتبر هستند اما بخشی از مجموعه کلمات کلیدی داخلی Ajv نیستند را رد می کند.
به این توجه کنید ajv.validateSchema() متا اعتبار سنجی را انجام می دهد: بررسی می کند که آیا شی داده شده یک سند طرحواره JSON از نظر ساختاری معتبر است یا خیر. در زمان اجرا آرگومان های فراخوانی ابزار را در مقابل طرحواره بررسی نمی کند – این همان چیزی است که شما برای آن استفاده می کنید ajv.compile(schema)(data).
توضیحات تجزیه و تحلیل کیفیت
لینتر کیفیت توصیف را با اکتشافی ارزیابی می کند. محموله حداقل 20 کاراکتر (برای انتقال مقصود کافی است)، بیش از 200 کاراکتر به عنوان طول اکتشافی نیست (هزینه واقعی نشانه بستگی به توکنایزر دارد؛ 200 کاراکتر تقریباً 40 تا 60 نشانه برای نثر معمولی انگلیسی است) و با یک فعل عمل شروع می شود. شکاف های پرکننده مانند “این ابزار” یا “استفاده شده” جریمه می شوند زیرا آنها توکن ها را بدون افزودن ارزش معنایی مصرف می کنند.
const ACTION_VERBS = /^(retrieve|create|update|delete|search|list|get|set|send|fetch|generate|validate|check|convert|calculate|submit|remove|add|find|export|import)/i;
const FILLER_STARTS = /^(this tool|used to|a tool that|it will|tool for)/i;
export function analyzeDescription(description: string | undefined): RuleResult {
const feedback: string[] = [];
let score = 1;
if (!description || description.trim().length === 0) {
return { ruleName: "descriptionQuality", score: 0, maxScore: 1, feedback: ["Description is missing"] };
}
const trimmed = description.trim();
if (trimmed.length 20) {
score -= 0.4;
feedback.push(`Description too short (${trimmed.length} chars, minimum 20)`);
}
if (trimmed.length > 200) {
score -= 0.1;
feedback.push(`Description exceeds 200 chars — consider shortening`);
}
if (!ACTION_VERBS.test(trimmed)) {
score -= 0.3;
feedback.push("Description should start with an action verb (e.g., 'Retrieve', 'Create')");
}
if (FILLER_STARTS.test(trimmed)) {
score -= 0.2;
feedback.push("Description starts with filler phrasing — be direct");
}
return { ruleName: "descriptionQuality", score: Math.max(0, score), maxScore: 1, feedback };
}
بررسی کامل بودن استدلال
قاعده هر ملکی را در نظر می گیرد inputSchema.properties برای اکسپرس type و description زمینه ها را required آرایه باید وجود داشته باشد و در هنگام تعریف خصوصیات خالی نباشد. کسر فیلدهای از دست رفته متناسب با تعداد ویژگیها است، بنابراین ابزاری با بسیاری از ویژگیهای ناقص امتیاز کمتری نسبت به یک با یک شکاف میگیرد، اما مقیاسبندی به جای مقیاس مانند، صاف است.
توجه: کشف رشته نامحدود منحصراً توسط checkConstraintRichness قانون برای جلوگیری از بازخورد تکراری
export function checkArguments(inputSchema: ToolInputSchema | undefined): RuleResult {
const feedback: string[] = [];
let score = 1;
if (!inputSchema || !inputSchema.properties) {
return { ruleName: "argumentCompleteness", score: 0.5, maxScore: 1, feedback: ["No properties defined in inputSchema"] };
}
const props = inputSchema.properties;
const propKeys = Object.keys(props);
if (propKeys.length > 0 && (!inputSchema.required || inputSchema.required.length === 0)) {
score -= 0.3;
feedback.push("Properties exist but no 'required' array is specified");
}
let missingType = 0;
let missingDesc = 0;
for (const key of propKeys) {
const prop = props[key];
if (!prop.type) {
missingType++;
feedback.push(`Property "${key}" is missing a type`);
}
if (!prop.description) {
missingDesc++;
feedback.push(`Property "${key}" is missing a description`);
}
}
const n = propKeys.length;
score -= (missingType / n) * 0.35;
score -= (missingDesc / n) * 0.35;
return { ruleName: "argumentCompleteness", score: Math.max(0, score), maxScore: 1, feedback };
}
قوانین کنوانسیون نامگذاری
این قانون نام ابزار را در برابر عبارت منظم kebab-case یا snake_case بررسی می کند و ساختار فعل-اسم را بررسی می کند. نام تک کلمه ای یا استفاده از camelCase جریمه می شود. هر دو بررسی نام را به حروف کوچک عادی میکنند تا از نتایج متضاد بین قالب عبارت منظم حساس به حروف بزرگ و الگوی فعل-اسم جلوگیری شود.
const KEBAB_OR_SNAKE = /^[a-z]+[-_][a-z]+([_-][a-z]+)*$/;
const VERB_NOUN = /^(get|create|update|delete|search|list|send|fetch|generate|validate|check|convert|calculate|submit|remove|add|find|export|import)[-_]/;
export function checkNaming(name: string): RuleResult {
const feedback: string[] = [];
let score = 1;
const normalized = name.toLowerCase();
if (!KEBAB_OR_SNAKE.test(normalized)) {
score -= 0.5;
feedback.push(`Tool name "${name}" should use kebab-case or snake_case (e.g., "get-user")`);
}
if (!VERB_NOUN.test(normalized)) {
score -= 0.5;
feedback.push(`Tool name "${name}" should follow verb-noun pattern (e.g., "create-invoice")`);
}
return { ruleName: "namingConventions", score: Math.max(0, score) || 0, maxScore: 1, feedback };
}
بررسی غنای محدودیت ها
این قانون ویژگیهایی را که با رشتهای تایپ شدهاند علامتگذاری میکند که کلمه کلیدی محدودیت (enum، الگو، یا minLength) ندارد. در عمل، رشته های نامحدود یکی از رایج ترین منابع ورودی عامل ناقص هستند.
در عمل، رشته های نامحدود یکی از رایج ترین منابع ورودی عامل ناقص هستند.
export function checkConstraintRichness(schema: any): RuleResult {
if (!schema?.properties) {
return { ruleName: "constraintRichness", score: 0.5, maxScore: 1, feedback: ["No properties to evaluate for constraints"] };
}
const props = Object.values(schema.properties) as any[];
if (props.length === 0) {
return { ruleName: "constraintRichness", score: 0.5, maxScore: 1, feedback: ["No properties to evaluate for constraints"] };
}
const feedback: string[] = [];
const constrained = props.filter((p: any) => p.enum || p.pattern || p.minimum !== undefined || p.maximum !== undefined || p.minLength);
const unconstrainedKeys = Object.keys(schema.properties).filter((key: string) => {
const p = schema.properties[key];
return p.type === "string" && !p.enum && !p.pattern && !p.minLength;
});
for (const key of unconstrainedKeys) {
feedback.push(`Property "${key}" is an unconstrained string — consider enum, pattern, or minLength`);
}
const score = constrained.length / props.length;
return { ruleName: "constraintRichness", score, maxScore: 1, feedback };
}
ایجاد امتیاز دهنده و گزارش ساز
قانون تجمیع منجر به نمره کیفیت می شود
امتیازدهنده مجموع وزنی را برای تمام امتیازات قانون اعمال میکند و در مقیاس 0 تا 100 نرمال میکند. [0, 100] محدوده و نام قوانین ناشناخته به عنوان هشدار ثبت می شود.
موارد زیر را به src/scorer.ts (فایل جدید ایجاد نکنید):
export function calculateScore(results: RuleResult[], rubric: QualityRubric): QualityScore {
const weightMap: Recordstring, number> = {
schemaValidity: rubric.schemaValidity,
descriptionQuality: rubric.descriptionQuality,
argumentCompleteness: rubric.argumentCompleteness,
namingConventions: rubric.namingConventions,
constraintRichness: rubric.constraintRichness,
};
let weightedSum = 0;
for (const result of results) {
if (!(result.ruleName in weightMap)) {
console.warn(`[scorer] Unknown rule "${result.ruleName}" — skipped in weighted sum`);
continue;
}
const weight = weightMap[result.ruleName];
weightedSum += (result.score / result.maxScore) * weight;
}
const total = Math.min(100, Math.max(0, Math.round(weightedSum * 100)));
const status = total >= 75 ? "PASS" : total >= 50 ? "WARN" : "FAIL";
return { total, status, ruleResults: results };
}
فرمت خروجی CLI
گزارشگر از کدهای فرار ANSI برای کد رنگی خروجی مستقیماً در ترمینال بدون وابستگی خارجی استفاده می کند.
کدهای فرار ANSI ممکن است در خط فرمان کلاسیک ویندوز به درستی ارائه نشوند. از Windows Terminal، ConEmu یا شبیه ساز ترمینال مدرن مشابه استفاده کنید.
ایجاد کنید src/cli.ts و موارد زیر را به عنوان قسمت 1 از 2 اضافه کنید:
import * as fs from "fs";
import * as path from "path";
import { QualityScore } from "./scorer";
const COLORS = {
green: "\x1b[32m",
yellow: "\x1b[33m",
red: "\x1b[31m",
reset: "\x1b[0m",
bold: "\x1b[1m",
};
function statusColor(status: string): string {
if (status === "PASS") return COLORS.green;
if (status === "WARN") return COLORS.yellow;
return COLORS.red;
}
function printReport(toolName: string, score: QualityScore): void {
const color = statusColor(score.status);
console.log(`
${COLORS.bold}Tool: ${toolName}${COLORS.reset}`);
console.log(` Score: ${color}${score.total}/100 [${score.status}]${COLORS.reset}`);
for (const rule of score.ruleResults) {
const ruleScore = Math.round((rule.score / rule.maxScore) * 100);
console.log(` - ${rule.ruleName}: ${ruleScore}%`);
for (const fb of rule.feedback) {
console.log(` ${COLORS.yellow}! ${fb}${COLORS.reset}`);
}
}
}
نقطه ورودی CLI را وصل کنید
خواندن تعاریف ابزار از یک فایل یا ورودی استاندارد
src/cli.ts نقطه ورود CLI است. این یک مسیر فایل JSON را می خواند process.argv، محتوا را تجزیه می کند، انتظار آرایه ای از اشیاء ابزار را دارد، و هر کدام را از طریق خط لوله پرده ای عبور می دهد. مسیر فایل برای جلوگیری از تجاوز مسیر تأیید می شود و حفاظت از اندازه از شرایط خارج از حافظه برای فایل های غیرمنتظره بزرگ جلوگیری می کند.
موارد زیر را به src/cli.ts به عنوان قسمت 2 از 2 (همان فایل قسمت گزارشگر بالا):
import { validateSchema, analyzeDescription, checkArguments, checkNaming, checkConstraintRichness } from "./rules";
import { calculateScore, DEFAULT_WEIGHTS, RuleResult } from "./scorer";
const MAX_FILE_BYTES = 5 * 1024 * 1024;
function resolveToolFilePath(rawPath: string): string {
const resolved = path.resolve(rawPath);
const cwd = process.cwd();
if (!resolved.startsWith(cwd + path.sep) && resolved !== cwd) {
console.error(`Error: File path must be within the current working directory.`);
process.exit(1);
}
return resolved;
}
function lintTool(tool: any): QualityScore {
const results: RuleResult[] = [
validateSchema(tool),
analyzeDescription(tool.description),
checkArguments(tool.inputSchema),
checkNaming(tool.name || ""),
checkConstraintRichness(tool.inputSchema),
];
return calculateScore(results, DEFAULT_WEIGHTS);
}
function main(): void {
const filePath = process.argv[2];
if (!filePath) {
console.error("Usage: ts-node src/cli.ts " );
process.exit(1);
}
const resolvedPath = resolveToolFilePath(filePath);
let raw: string;
try {
const stat = fs.statSync(resolvedPath);
if (stat.size > MAX_FILE_BYTES) {
console.error(`Error: File exceeds maximum allowed size of ${MAX_FILE_BYTES} bytes.`);
process.exit(1);
}
raw = fs.readFileSync(resolvedPath, "utf-8");
} catch (err: unknown) {
console.error(`Error reading file: ${err instanceof Error ? err.message : String(err)}`);
process.exit(1);
}
let tools: unknown;
try {
tools = JSON.parse(raw);
} catch (err: unknown) {
console.error(`Error parsing JSON: ${err instanceof Error ? err.message : String(err)}`);
process.exit(1);
}
if (!Array.isArray(tools)) {
console.error("Expected a JSON array of tool definitions");
process.exit(1);
}
let failCount = 0;
for (const tool of tools) {
try {
const score = lintTool(tool);
printReport((tool as any).name || "(unnamed)", score);
if (score.status === "FAIL") failCount++;
} catch (err: unknown) {
console.error(
`Error linting tool "${(tool as any)?.name ?? "(unnamed)"}": ` +
`${err instanceof Error ? err.message : String(err)}`
);
failCount++;
}
}
console.log(
`
${COLORS.bold}Summary: ${tools.length} tools checked, ${failCount} failed${COLORS.reset}`
);
process.exit(failCount > 0 ? 1 : 0);
}
if (require.main === module) {
main();
}
نمونه تعاریف ابزار تست
موارد زیر را به عنوان ذخیره کنید sample-tools.json در ریشه پروژه:
[
{
"name": "get-current-weather",
"description": "Retrieve the current weather conditions for a given city, returning temperature and a short forecast.",
"inputSchema": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "City name, e.g. 'Tokyo'", "minLength": 1 },
"units": { "type": "string", "description": "Temperature unit", "enum": ["celsius", "fahrenheit"] }
},
"required": ["city"]
}
},
{
"name": "send-email",
"description": "Send an email to a recipient with a subject and body.",
"inputSchema": {
"type": "object",
"properties": {
"to": { "type": "string", "description": "Recipient email address" },
"subject": { "type": "string", "description": "Email subject line" },
"body": { "type": "string" }
},
"required": ["to", "subject"]
}
},
{
"name": "doStuff",
"description": "Does stuff",
"inputSchema": {
"type": "object",
"properties": {
"input": { "type": "string" }
}
}
}
]
اجرای Linter و تفسیر نتایج
در حال اجرا npm run lint-tools -- sample-tools.json خروجی تولید می کند شبیه به زیر نتایج دقیق به تعاملات قوانین بستگی دارد و تقریبی است. فرمول امتیاز دهی: total = clamp(round((schemaValidity × 0.30 + descriptionQuality × 0.25 + argumentCompleteness × 0.25 + namingConventions × 0.10 + constraintRichness × 0.10) × 100), 0, 100).
Tool: get-current-weather
Score: 95/100 [PASS]
- schemaValidity: 100%
- descriptionQuality: 100%
- argumentCompleteness: 100%
- namingConventions: 100%
- constraintRichness: 100%
Tool: send-email
Score: 83/100 [PASS]
- schemaValidity: 100%
- descriptionQuality: 100%
- argumentCompleteness: 88%
! Property "body" is missing a description
- namingConventions: 100%
- constraintRichness: 0%
! Property "to" is an unconstrained string — consider enum, pattern, or minLength
! Property "subject" is an unconstrained string — consider enum, pattern, or minLength
! Property "body" is an unconstrained string — consider enum, pattern, or minLength
Tool: doStuff
Score: 18/100 [FAIL]
- schemaValidity: 100%
- descriptionQuality: 10%
! Description too short (10 chars, minimum 20)
! Description should start with an action verb (e.g., 'Retrieve', 'Create')
- argumentCompleteness: 35%
! Properties exist but no 'required' array is specified
! Property "input" is missing a description
- namingConventions: 0%
! Tool name "doStuff" should use kebab-case or snake_case (e.g., "get-user")
! Tool name "doStuff" should follow verb-noun pattern (e.g., "create-invoice")
- constraintRichness: 0%
! Property "input" is an unconstrained string — consider enum, pattern, or minLength
Summary: 3 tools checked, 1 failed
ابزار اول امتیاز بالایی دارد و هر چک را رد می کند. ابزار دوم به این دلیل امتیاز از دست می دهد body ویژگی هیچ توصیفی ندارد و هیچ یک از ویژگی های رشته ای آن دارای محدودیت نیستند. در constraintRichness قانون به صراحت هر رشته نامحدود را علامت گذاری می کند. ابزار سوم به طور قطعی شکست میخورد: نام از camelCase بدون الگوی فعل-اسم استفاده میکند، توضیحات خیلی کوتاه است و از فعل عمل استفاده نمیکند، آرگومانها هیچ توصیفی ندارند، و required آرایه و هیچ محدودیتی وجود ندارد. تغییر نام آن به do-stuff، افزودن یک توضیحات به درستی و پر کردن ابرداده آرگومان بلافاصله آن را از آستانه WARN بالاتر می برد.
گسترش Linter برای استفاده در دنیای واقعی
ایده هایی برای بهبود
را process.exit(1) در صورت شکست، اکنون یک نقطه ادغام اولیه CI/CD را فراهم می کند. تیمها میتوانند لینتر را بهعنوان یک قلاب پیشمتعهد یا مرحله خط لوله اضافه کنند که وقتی هر تعریف ابزاری زیر آستانه PASS قرار میگیرد، استقرار را مسدود میکند. برای ادغام CI قابل تحلیل ماشین، اضافه کردن a را در نظر بگیرید --json پرچم خروجی و هدایت خروجی قابل خواندن توسط انسان به stderr.
برای اعتبارسنجی پویا، MCP SDK Client کلاس یک متد ابزار لیست را نمایش می دهد (نام دقیق روش و نوع برگشت را در برابر جریان بررسی کنید @modelcontextprotocol/sdk مستندات پیش از استقرار) که می تواند تعاریف ابزار را مستقیماً از یک سرور MCP در حال اجرا دانلود کند و امکان ممیزی زنده را بدون نگهداری یک فایل JSON جداگانه فراهم کند. نصب کنید @modelcontextprotocol/sdk فقط هنگام اعمال این پسوند.
قوانین سفارشی را می توان از طریق یک فایل پیکربندی پشتیبانی کرد که الگوهای عبارت منظم اضافی، حداقل امتیازات برای یک بعد یا ویژگی های کاملاً جدید قانون بارگذاری شده در زمان اجرا را مشخص می کند. برای دید، صادرات QualityScore اشیایی مانند JSON امکان ادغام با داشبوردهایی را فراهم می کند که کیفیت تعریف را در طول زمان ردیابی می کنند.
پورت های با کیفیت برای سیستم های عامل
فراخوانی مطمئن ابزارهای عامل با تعاریف ابزاری که به خوبی ساختار یافته اند شروع می شود.
فراخوانی مطمئن ابزارهای عامل با تعاریف ابزاری که به خوبی ساختار یافته اند شروع می شود. لینتر ساخته شده در اینجا کنترل کیفیت خودکار و قابل سنجشی را ارائه میکند که توصیفهای نامشخص، ابردادههای آرگومان از دست رفته، خطاهای طرحواره، و ناسازگاریهای نامگذاری را قبل از رسیدن به یک عامل تولید میگیرد. مستندات کامل MCP SDK در مخزن رسمی پروتکل بافت مدل، جزئیات بیشتری را در مورد مشخصات ارائه میکند، و رشتههای انجمن همچنان مدلها و ضد مدلهایی را نشان میدهند که ارزش کدگذاری در قوانین اضافی را دارند.
Source link


