TDQStool definition quality scoresign in →

tdqs / cli

Command line

The tdqs package is the reference implementation of the specification: the same code scores the playground, the hosted API and your terminal. Lint needs no model; score needs any OpenAI-compatible endpoint.

Install

npm install --global tdqs
# or run it without installing
npx tdqs --help

Lint

The deterministic checks, no model. Everything in the specification that is computed rather than judged: context signals, the hard gates, the invocation-cost prefilter for shadowing, and the checklist items a definition can fail on its own. It runs offline and is safe on every pull request.

# a tools/list result saved to disk
tdqs lint --file tools.json

# a local stdio server
tdqs lint --command "npx -y @modelcontextprotocol/server-filesystem ."

# a remote Streamable HTTP server
tdqs lint --url https://mcp.example.com/mcp

# fail the build on warnings too
tdqs lint --file tools.json --fail-on warning

Findings link to the flag or dimension they come from. A lint result is not a score: it tells you what will cost you points before a model reads the description.

Score

The full rubric. Runs the four stages of the specification for every tool, then the server coherence evaluation and the rollup. Bring a key for any OpenAI-compatible endpoint. Glama scores its registry with deepseek-v4-flash-0731; scores are calibrated to a rubric+model pair, so use the same model when you want numbers that compare with the registry's.

export TDQS_BASE_URL=https://openrouter.ai/api/v1
export TDQS_API_KEY=sk-...
export TDQS_MODEL=deepseek/deepseek-v4-flash-0731
export TDQS_REQUEST_OVERRIDES='{"reasoning":{"enabled":false}}'

tdqs score --file tools.json --format markdown

# gate a release on the passing tier
tdqs score --url https://mcp.example.com/mcp --fail-under B

Turn extended reasoning off. The reference model reasons before it answers unless told not to, which makes a call take a minute instead of seconds, and the calibration examples reproduce with reasoning off. How to say so is provider-specific, so it is an opaque JSON object merged into every request: --request-overrides '{"reasoning":{"enabled":false}}' on OpenRouter, or TDQS_REQUEST_OVERRIDES in the environment.

Or let this site run the model for you. Hosted mode posts the definitions to the API with a key from your account, waits for the report, and prints the same output — with a shareable report URL. It spends one of the account's daily API calls.

TDQS_API_KEY=tdqs_... tdqs score --file tools.json --hosted https://tdqs.dev

Options

--file, --command, --url
Where the definitions come from. Exactly one. --file - reads stdin, and --header "Name: value" (repeatable) sends credentials to a remote server.
--server-name
The name the coherence prompt sees; defaults to the server's own name when connecting to one.
--format
json, markdown or text. JSON matches the published report schema; markdown is for pull request comments.
--output
Write the report to a file instead of stdout.
--fail-on, --fail-under
--fail-on error | warning | never (lint) and --fail-under A | B | C | D (score): what turns a report into a non-zero exit.
--model, --base-url, --api-key
(score) The model configuration, with --concurrency for how many tools are scored at once. Also read from TDQS_MODEL, TDQS_BASE_URL and TDQS_API_KEY.

Exit codes

0
The report was produced and passed the threshold, or no threshold was set.
1
The threshold failed. The report is still printed.
2
Usage error, unreadable input, or a model call that could not complete. The reason is on stderr.

Continuous integration

.github/workflows/tdqs.yml
name: TDQS
on: [pull_request]
jobs:
  tdqs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npx tdqs lint --command "node ./dist/server.js" --fail-on warning
      - run: npx tdqs score --command "node ./dist/server.js" --fail-under B --format markdown >> "$GITHUB_STEP_SUMMARY"
        env:
          TDQS_BASE_URL: https://openrouter.ai/api/v1
          TDQS_API_KEY: ${{ secrets.TDQS_API_KEY }}
          TDQS_MODEL: deepseek/deepseek-v4-flash-0731
          TDQS_REQUEST_OVERRIDES: '{"reasoning":{"enabled":false}}'

Library

Every stage is exported on its own, so a registry or a gateway can run the deterministic parts, hash definitions the way this site does, or build the prompts and call its own model.

import { createLlmClient, lintServer, parseToolDefinitions, scoreServer } from 'tdqs';

const { serverName, tools } = parseToolDefinitions(await response.json());

const lint = lintServer({ serverName, tools });

const report = await scoreServer({
  llm: createLlmClient({ apiKey, baseUrl, model: 'deepseek/deepseek-v4-flash-0731' }),
  serverName,
  tools,
});

console.log(report.serverScore.overallTier, report.serverScore.overallScore);