Skip to content
Reference

Directory readiness ​

m3 lint --directory checks an MCP server's metadata against the published listing rules of three directories:

  • claude: the Claude connector directory;
  • openai: the OpenAI plugin directory, which ChatGPT and Codex share;
  • muse: the Muse connector directory (Meta).
sh
m3 lint https://example.com/mcp --directory all
m3 lint --directory claude --directory openai -- python server.py
m3 lint --directory claude --harness claude_code -- python server.py

--directory is repeatable and all picks the three. With directories alone, only directory checks run; add --harness to run the Claude Code and Codex checks as well. Without --directory, m3 lint behaves exactly as before. Like every lint check, directory checks only read what the server lists: they never call a tool, never contact a model and never print header values. With directories alone, a tools/list that fails, or that has entries which are not tools with a string name, exits with status 2: nothing could be checked. Run without --directory to see what is wrong with the listing.

Passing does not mean a directory will approve the server. Reviewers also test behaviour, authentication, privacy policies, documentation and use cases, none of which metadata shows. These checks catch the listing rules that the metadata can show, before a reviewer does. For the checks that need judgment, install the preparing-directory-submissions agent skill: your coding agent runs these lint checks, then reads the code, docs and listing, and writes one readiness report.

Reading a finding ​

ERROR   directory-claude-safety-hints  tool 'create_issue' annotations
  detail: readOnlyHint absent, destructiveHint absent
  claude [error]: missing the applicable safety hint. https://claude.com/docs/connectors/building/review-criteria#provide-tool-annotations (policy checked 2026-10-18)
  fix: Set "readOnlyHint": true if this tool only reads; otherwise set "destructiveHint" (true if it modifies or deletes data). Claude's MCP page asks for both hints on every tool.

Each finding names the rule and the field, the observed fact, one line per chosen directory with its severity and the policy section it comes from, and a fix. The JSON report carries the same per directory under directories, including the verbatim policy quote and policy_date. The last line of the human report counts findings per directory. If tools/list failed or stopped early, that line starts with directory readiness: incomplete and covers only the tools that were read.

  • error: the policy states a requirement or a rejection reason, and every tool matching the condition breaks it, whatever the tool does. Errors fail the run under the default --fail-on error.
  • warning: the policy rule is real, but the condition only suggests a breach (for example, a method input that lists both GET and POST, or invisible characters that may hide text). The summary says "may", and the fix says what to check first. Warnings fail the run only with --fail-on warning.

Policy versions ​

The rules were checked against each directory's published pages on 2026-10-18, and every report shows that date. Directories change their rules; when they do, the quotes and the date are updated together. python3 benchmarks/lint-oracle/oracle.py --policies checks every quote against its live section.

Rules ​

Each row is one directory effect: the rule, the directory, the severity, the finding variants it applies to, the verbatim policy text it rests on, and why the condition breaks it.

RuleDirectorySeverityApplies toPolicyWhy
tool-description-not-stringclaudewarningall findings“Instructional Software must define each tool or capability through narrow, unambiguous natural language that specifies what it does and when it should be invoked.”2A asks for a natural-language definition of each tool but does not name the description field; a tool with a clear title may still satisfy it, so this is not proven.
tool-description-not-stringopenaierrorall findings“Each tool must have a nonempty description that explicitly and accurately explains its purpose and behavior, when to use it, and any relevant limitations or side effects.”The sentence names the field and the condition: a missing, blank or non-text description breaks it for every tool.
tool-name-collisionopenaierrorduplicate“Tool names must be unique within your MCP server.”Two tools with the same name break the sentence directly.
description-missingclaudewarningall findings“Instructional Software must define each tool or capability through narrow, unambiguous natural language that specifies what it does and when it should be invoked.”2A asks for a natural-language definition of each tool but does not name the description field; a tool with a clear title may still satisfy it, so this is not proven.
description-missingopenaierrorall findings“Each tool must have a nonempty description that explicitly and accurately explains its purpose and behavior, when to use it, and any relevant limitations or side effects.”The sentence names the field and the condition: a missing, blank or non-text description breaks it for every tool.
directory-tool-title-missingclaudeerrorall findings“Every tool must include a title and the applicable hint: readOnlyHint: true for read-only tools, and destructiveHint: true for tools that modify or delete data.”The sentence requires a title on every tool. Claude does not say which field, so either title or annotations.title satisfies the check; a blank title counts as none.
directory-claude-safety-hintsclaudeerrorno-applicable“Every tool must include a title and the applicable hint: readOnlyHint: true for read-only tools, and destructiveHint: true for tools that modify or delete data.”Claude defines readOnlyHint as 'the tool only reads data' and destructiveHint as 'the tool can modify or delete data', so every tool falls under one of them. This tool is not marked read-only and declares no destructiveHint, so it lacks the applicable hint whichever it is; it also breaks the MCP page's 'must declare both'.
directory-claude-safety-hintsclaudewarningone-declared“All MCP tools must declare both of these annotations: … readOnlyHint: the tool only reads data … destructiveHint: the tool can modify or delete data”Claude's MCP page asks for both hints on every tool, while the review criteria accept the applicable one, which this tool declares (readOnlyHint: true or destructiveHint: true); listed servers ship read-only tools without destructiveHint.
directory-claude-safety-hintsclaudewarningread-only-undeclared“Every tool must include a title and the applicable hint: readOnlyHint: true for read-only tools, and destructiveHint: true for tools that modify or delete data.”destructiveHint is false and readOnlyHint is not declared. If the tool only reads, Claude's applicable hint (readOnlyHint: true) is missing; if it writes, the declared destructiveHint applies.
directory-claude-safety-hintsclaudewarningwrite-not-destructive“Every tool must include a title and the applicable hint: readOnlyHint: true for read-only tools, and destructiveHint: true for tools that modify or delete data.”readOnlyHint false says the tool modifies data, and Claude asks for destructiveHint: true on tools that modify data. Whether an additive write such as creating a record counts is not stated, and readOnlyHint false may itself be wrong for a tool that only returns a link.
directory-hints-not-explicitopenaierrorall findings“Set readOnlyHint, destructiveHint, and openWorldHint to explicit boolean values (true or false) in each tool’s annotations object.”The sentence requires all three hints as booleans on every tool; a missing or non-boolean hint breaks it directly.
directory-hints-contradictopenaierrorall findings“readOnlyHint: Use true for retrieval, computation, or previews that do not modify the environment. Use false for external-state changes … destructiveHint: Use false for read-only tools.”If the tool is read-only, the destructiveHint line requires false; if it changes anything, the readOnlyHint line requires false. Either way one of the two hints breaks a rule.
directory-read-write-toolclaudewarninghttp-methods“A single tool that accepts both safe HTTP methods, such as GET, HEAD, and OPTIONS, and unsafe methods, such as POST, PUT, PATCH, and DELETE, is rejected. Don't ship a catch-all api_request tool with a method parameter.”The method input lists both safe and unsafe methods, which Claude rejects. The schema can't show whether the server refuses some of them at run time.
directory-read-write-toolopenaiwarninghttp-methods“Expose each model-callable operation as a separate tool with a clear description, input schema, and annotations. Do not use discovery, operation selection, or schema fetching with a generic executor to enable operations not individually exposed for review.”OpenAI asks for each operation as a separate tool and forbids operation selection through a generic executor; the allowed values suggest that, which the schema alone cannot confirm.
directory-hidden-contentclaudewarningall findings“Instructional Software must not contain hidden, obfuscated, or encoded instructions. All behavioral guidance must be human-readable and clearly presented.”Invisible characters, encoded text, comments or long blank runs are present; whether they carry instructions is a judgment the check cannot make.
directory-hidden-contentopenaiwarningall findings“Act only within the user-authorized task. Plugin and tool metadata must not seek secrets or protected context, direct unauthorized data transfers or actions, override platform instructions or safeguards, conceal behavior, or impersonate another party. Encoded or obfuscated instructions do not exempt a plugin from these requirements.”Invisible characters, encoded text, comments or long blank runs are present; encoding alone is no breach, and whether they conceal behaviour is a judgment the check cannot make.
directory-tool-name-too-longclaudeerrorascii“Tool names must be 64 characters or fewer.”The name is ASCII and over 64 characters, so every way of counting characters gives more than 64.
directory-tool-name-too-longclaudewarningnon-ascii“Tool names must be 64 characters or fewer.”The name has more than 64 code points; with combining characters it may have 64 or fewer visible characters.

Not checked ​

  • Anything that depends on what text means. This covers steering language in descriptions or server instructions (preferring this tool, avoiding other tools or web search, asking for calls on every turn, overriding instructions), unsupported use cases (moving money, placing trades, generating media with AI), tool names that contradict their hints, free-form API tools that don't name their API, and inputs that ask for credentials, payment data, government IDs, precise location or conversation history. Patterns can't decide these correctly; they need judgment.
  • Muse. Muse classifies tools from your documentation rather than MCP annotations, and its listing rules are about meaning, so no rule checks Muse from metadata yet. --directory muse reports it as not checked, never as passing.
  • Listing names, such as OpenAI's rule against appending "MCP" or "Plugin" to a product name: the listing name isn't in the server's metadata.
  • Empty tool names: no directory addresses them (the Claude Code and Codex checks still do).
  • Anything that needs calling a tool: response size, error messages, authentication, and whether descriptions match behaviour.