MCP Tool Descriptor Check
schema.validate_mcp_tool_descriptor
Overview
You send one MCP tool descriptor and name the revision it targets, and we answer two questions separately. Eleven completeness rules decide whether a client can reliably invoke it — a usable name, an object inputSchema that is itself a well-formed schema, required entries that name real properties, annotations inside the published set, no key from a revision later than the one you declared — and failing any of those makes valid false. Ten clarity rules decide whether an agent can choose it correctly — descriptions long enough to mean something, properties that say what to send, a name in namespace.verb shape, a mutating verb backed by a hint — and those come back as warnings, leaving valid true, so a build can gate on invocability without gating on prose.
A descriptor is the only thing standing between an agent and the wrong tool call, and the two ways it fails are different: one stops the call outright, the other quietly makes the tool the wrong choice. Mixing them in one severity column is how a build gate ends up switched off.
Reliability
The same descriptor, dialect and rule settings always produce the same findings in the same order, independent of your machine's locale, time zone and default character set. valid reflects the eleven completeness rules only; the ten clarity rules never change it. Whether an inputSchema is itself a schema is decided by the same engine schema.validate_json uses, so the two cannot disagree. A reference problem inside inputSchema or outputSchema is reported as MCPD-E-011; switch that rule off through rules.enabled and the call is refused with the matching MCPD_REF_ failure instead, because a reference graph we have no rule for is not one we will walk. Eleven refusals stop the call and an unchanged retry will not help. MCPD_DESCRIPTOR_INVALID means descriptor is absent or is not an object; MCPD_DESCRIPTOR_TOO_LARGE means it is over 65536 bytes, so trim it; MCPD_DIALECT_UNSUPPORTED means dialect is not one of the three published names; MCPD_RULE_UNKNOWN means rules.enabled names a code outside MCPD-E-001 to MCPD-E-011 and MCPD-W-001 to MCPD-W-010; MCPD_RULE_PARAMETER_INVALID means a threshold is outside its published range; MCPD_OPTION_UNSUPPORTED_FOR_DIALECT means requireOutputSchema was set on MCP_TOOL_2025_03_26, which has no such key, so declare the newer dialect instead; MCPD_NODE_LIMIT_EXCEEDED means the descriptor has over 20000 nodes, nests deeper than 64 levels, breaks a per-object cap, or its schemas would pass 100000 nodes once local references were expanded; MCPD_REF_REMOTE_REFUSED, MCPD_REF_CYCLE_DETECTED and MCPD_REF_DEPTH_EXCEEDED are the reference refusals above; and MCPD_WORK_REFUSED means the run was projected past the 2000000-unit budget before it started and reports both numbers.
Context footprint
Findings carry codes and pointers rather than descriptor text, so a report stays small; the two lists cap at 500 errors and 200 warnings with truncated set when either is exceeded. A 65536-byte descriptor under those caps cannot reach the platform's 2 MiB inline ceiling, so this skill publishes no output-size refusal. A successful call costs 1 execution credit.
When to use it
Before publishing or changing a tool descriptor, especially when clients on more than one MCP revision will read it.
When you want to validate a caller's arguments, or when the document is a plain JSON Schema rather than a tool descriptor.
Scope
Non-goals
- We never call the tool, or check that it does what it says
- We never validate a document against the descriptor's inputSchema
- We never rewrite the descriptor or suggest replacement text
- We never guess which revision a descriptor targets: you declare it
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
How we handle your data
What this means
This skill may receive sensitive content, but it does not target sensitive data and returns only a structured non-sensitive result.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- This skill does not target sensitive data.
- The response does not contain submitted content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| descriptor | object | Yes | One MCP tool descriptor as a JSON object, 2 through 65536 bytes; extra keys are descriptor fields. — unconstrained RFC 8259 JSON items. |
| dialect | string | No | Revision the descriptor targets; omit it for MCP_TOOL_2025_06_18. |
| rules | object | No | Closed published thresholds and an optional enabled-code list; omit the object to run all 21 rules with documented defaults. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| valid | boolean | Yes | True when the errors list is empty; warnings never change it. |
| errors | array | Yes | Completeness findings that make valid false, 0 through 500 closed objects with code, pointer, optional keyword and message. |
| warnings | array | Yes | Clarity findings that never change valid, 0 through 200 closed objects with code, pointer, optional keyword and message. |
| dialectApplied | string | Yes | Revision the rules actually ran under. |
| ruleProfile | string | Yes | Rule-profile version such as mcp-descriptor-rules-1. |
| summary | object | Yes | Closed unfiltered counts with errorCount, warningCount, propertyCount, rulesEvaluated and truncated. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"schema.validate_mcp_tool_descriptor","input":{"descriptor":{"name":"weather.get_forecast","description":"Returns a forecast for one city.","inputSchema":{"type":"object"}}}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("schema.validate_mcp_tool_descriptor", {"descriptor":{"name":"weather.get_forecast","description":"Weather.","inputSchema":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| MCPD_DESCRIPTOR_INVALID | 400 | No | The request payload failed this skill's input validation. |
| MCPD_DESCRIPTOR_TOO_LARGE | 429 | No | A size, quota, rate, or time limit was exceeded. |
| MCPD_DIALECT_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
| MCPD_RULE_UNKNOWN | 400 | No | The request payload failed this skill's input validation. |
| MCPD_RULE_PARAMETER_INVALID | 400 | No | The request payload failed this skill's input validation. |
| MCPD_OPTION_UNSUPPORTED_FOR_DIALECT | 400 | No | The skill does not support the requested variant. |
| MCPD_NODE_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| MCPD_REF_REMOTE_REFUSED | 400 | No | The request payload failed this skill's input validation. |
| MCPD_REF_CYCLE_DETECTED | 400 | No | The request payload failed this skill's input validation. |
| MCPD_REF_DEPTH_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| MCPD_WORK_REFUSED | 429 | No | A size, quota, rate, or time limit was exceeded. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- We never call the tool, or check that it does what it says
- We never validate a document against the descriptor's inputSchema
- We never rewrite the descriptor or suggest replacement text
- We never guess which revision a descriptor targets: you declare it
- Validating arguments a caller sent against the descriptor's inputSchema
- Judging a plain JSON Schema that is not a tool descriptor
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "schema.validate_mcp_tool_descriptor",
"input": {
"descriptor": {
"name": "weather.get_forecast",
"description": "Weather.",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string"
}
},
"required": [
"city"
]
}
}
}
}Examples
A descriptor a client can invoke but an agent will struggle to choose
{
"descriptor": {
"name": "weather.get_forecast",
"description": "Weather.",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string"
}
},
"required": [
"city"
]
}
}
}{
"dialectApplied": "MCP_TOOL_2025_06_18",
"summary": {
"errorCount": 0,
"warningCount": 3,
"propertyCount": 1,
"rulesEvaluated": [
"MCPD-E-001",
"MCPD-E-002",
"MCPD-E-003",
"MCPD-E-004",
"MCPD-E-005",
"MCPD-E-006",
"MCPD-E-007",
"MCPD-E-008",
"MCPD-E-009",
"MCPD-E-010",
"MCPD-E-011",
"MCPD-W-001",
"MCPD-W-002",
"MCPD-W-003",
"MCPD-W-004",
"MCPD-W-005",
"MCPD-W-006",
"MCPD-W-007",
"MCPD-W-008",
"MCPD-W-009",
"MCPD-W-010"
],
"truncated": false
},
"errors": [],
"valid": true,
"ruleProfile": "mcp-descriptor-rules-1",
"warnings": [
{
"code": "MCPD-W-001",
"pointer": "/description",
"keyword": "description",
"message": "The description is absent or shorter than the declared minimum of 24 characters."
},
{
"code": "MCPD-W-002",
"pointer": "/inputSchema/properties/city/description",
"keyword": "description",
"message": "This property has no description, or one shorter than the declared minimum of 8 characters."
},
{
"code": "MCPD-W-007",
"pointer": "/outputSchema",
"keyword": "outputSchema",
"message": "The declared dialect supports an outputSchema and none is declared, so a caller cannot tell what comes back."
}
]
}A required argument the inputSchema never declares, which stops the call outright
{
"descriptor": {
"name": "weather.get_forecast",
"description": "Returns a five-day forecast for one city.",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name."
}
},
"required": [
"city",
"units"
]
}
},
"rules": {
"enabled": [
"MCPD-E-005"
]
}
}{
"dialectApplied": "MCP_TOOL_2025_06_18",
"summary": {
"errorCount": 1,
"warningCount": 0,
"propertyCount": 1,
"rulesEvaluated": [
"MCPD-E-005"
],
"truncated": false
},
"errors": [
{
"code": "MCPD-E-005",
"pointer": "/inputSchema/required/1",
"keyword": "required",
"message": "A required entry names a property that the inputSchema does not declare."
}
],
"valid": false,
"ruleProfile": "mcp-descriptor-rules-1",
"warnings": []
}Recommended use cases
- Gate a build on whether a tool descriptor can actually be invoked
- Review a descriptor's selectability before publishing it to agents
- Check a descriptor against an older MCP revision before shipping to a client on it
Avoid for
- Validating arguments a caller sent against the descriptor's inputSchema
- Judging a plain JSON Schema that is not a tool descriptor
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.