Skip to main content
Glama
qelos-io

@qelos/better-mcp

by qelos-io

@qelos/better-mcp

A stdio MCP proxy that connects to one or more upstream MCP servers and exposes their tools, resources, and prompts through a single endpoint — with a configurable middleware pipeline (logging, per-tool flow tracing, redaction, oversize-response offloading, and your own before / after hooks) wrapping every call.

┌──────────┐  stdio   ┌────────────┐  stdio   ┌──────────────────┐
│  Client  │ ───────▶ │ better-mcp │ ───────▶ │ fs MCP server    │
│ (Claude, │          │ middleware │          ├──────────────────┤
│  Cursor, │          │  pipeline  │ ───────▶ │ github MCP server│
│  etc.)   │          └────────────┘          ├──────────────────┤
└──────────┘                                  │ …more upstreams  │
                                              └──────────────────┘

Install

You can run better-mcp two ways. Pick whichever fits your host config.

Option A — npm

# One-shot, no install
npx -y @qelos/better-mcp

# Or install globally
npm install -g @qelos/better-mcp
better-mcp

Wire it into Claude Desktop / Cursor:

{
  "mcpServers": {
    "proxy": {
      "command": "npx",
      "args": ["-y", "@qelos/better-mcp", "-c", "/abs/path/to/mcp.json"]
    }
  }
}

Option B — Docker (GHCR)

The image is published to GitHub Container Registry as a public package:

docker pull ghcr.io/qelos/better-mcp:latest

Run it, mounting your mcp.json so the proxy can find it at /app/mcp.json (the default discovery path inside the container). If you use offload, also mount a writable directory and point middleware.offload.dir at it.

docker run --rm -i \
  -v "$PWD/mcp.json:/app/mcp.json:ro" \
  -v "$PWD/exports:/exports" \
  ghcr.io/qelos/better-mcp:latest

Wire it into a host:

{
  "mcpServers": {
    "proxy": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-v", "/abs/path/to/mcp.json:/app/mcp.json:ro",
        "-v", "/abs/path/to/exports:/exports",
        "ghcr.io/qelos/better-mcp:latest"
      ]
    }
  }
}

Notes for Docker:

  • Use -i (no -t) — the proxy speaks MCP over stdio.

  • Any upstream MCP servers listed in mcp.json need to be runnable inside the container. The image has node and npx, so npx -y @modelcontextprotocol/server-* works out of the box. If an upstream needs Python, Docker-in-Docker, or other toolchains, build a derived image.

  • For per-server secrets, pass them through with -e GITHUB_PERSONAL_ACCESS_TOKEN=….

Option C — Build from source

git clone https://github.com/qelos/better-mcp.git
cd better-mcp
npm install
npm run build
node dist/index.js

Related MCP server: mcp-toolmux

Run

The proxy uses the same mcp.json shape as Cursor and Claude Desktop. By default it looks for one automatically; you only need -c to override.

# Auto-discover mcp.json (see "Config location" below)
better-mcp

# Or point at a specific file
better-mcp -c ./examples/mcp.json
better-mcp --config /abs/path/to/mcp.json

# Or pass via env (inline JSON or a path)
MCP_PROXY_CONFIG=./examples/mcp.json better-mcp
MCP_PROXY_CONFIG='{"mcpServers":{"fs":{"command":"npx","args":["-y","@modelcontextprotocol/server-filesystem","/tmp"]}}}' better-mcp

Config location

Resolved in this order — the first hit wins:

  1. -c <path> / --config <path> CLI flag

  2. MCP_PROXY_CONFIG env var (inline JSON, or a path)

  3. mcp.json next to the entry script (e.g. dist/mcp.json, or /app/dist/mcp.json inside Docker)

  4. mcp.json one level up from the entry script (e.g. project root, or /app/mcp.json inside Docker)

  5. mcp.json in the current working directory

In practice: drop your mcp.json next to package.json (or mount it at /app/mcp.json in Docker) and it just works.

Copy-paste configs for filesystem, GitHub, Postgres, Brave Search, Playwright, Context7, memory, and more — plus a ready-made [examples/mcp.popular.json](examples/mcp.popular.json). See docs/popular-mcps.md.

Config

{
  "mcpServers": {
    "<name>": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
      "env": { "FOO": "bar" },   // optional
      "cwd": "./somewhere",       // optional
      "enabled": true              // optional, default true
    }
  },

  // Prefix every tool/prompt with "<serverName>__". Default true.
  // Resources keep their original URIs (they're already namespaced by scheme).
  "namespace": true,

  "middleware": {
    // true = log to stderr, or pass { level, file } for control.
    // level "info" logs name + duration; "debug" also logs params + result.
    "log": { "level": "info" },

    // Field-name substrings (case-insensitive) whose values get replaced with
    // "[REDACTED]" in responses — useful for masking secrets in tool output.
    "redact": ["token", "password", "api_key", "authorization"],

    // Slim down `tools/list` by stripping JSON-Schema noise (`$schema`,
    // `title`, `examples`, `default`, empty `required`/`enum`, …) from
    // every tool's inputSchema. ON by default; set `false` to disable.
    // See "Slimming tools/list" below for the full set of knobs.
    "slim": true,

    // Compact responses: drop null-valued fields and minify JSON-in-text.
    // Affects the WIRE response only — the file written by `offload` keeps
    // full fidelity. ON by default; see "Compacting responses" below.
    "compact": {
      "dropNull": true,                       // default true
      "dropEmptyString": false,                // default false
      "dropEmptyArray": false,                 // default false
      "dropEmptyObject": false,                // default false
      "roundFloats": 0,                        // 0 = off; e.g. 4 → 0.1235
      "exclude": ["server-name", "server__tool"]  // skip per-server or per-tool
    },

    // Clean terminal noise from text blocks: ANSI escape sequences and
    // trailing whitespace per line. ON by default; see "Cleaning text" below.
    "cleantext": {
      "stripAnsi": true,                       // default true
      "trimTrailingWhitespace": true,          // default true
      "collapseBlankLines": false,             // default false (risky for markdown)
      "exclude": []
    },

    // Response dedup cache. When the same `(server, tool)` returns identical
    // bytes within TTL, replace the response with a short pointer. Useful for
    // polling tools that re-emit unchanged data. OPT-IN — see "Dedup" below.
    "dedup": {
      "ttlSeconds": 300,                       // default 300 (5 min)
      "maxEntries": 1000,                       // LRU cap
      "minBytes": 200,                          // skip dedup below this
      "includeResources": false,                // resources opt-in
      "exclude": []
    },

    // Offload oversize responses to a file and return a short pointer.
    // `true` enables defaults; pass an object to tune.
    "offload": {
      "thresholdBytes": 16384,         // default 16 KB
      "dir": "./exports",              // default <os.tmpdir()>/better-mcp
      "includeResources": false,        // default false (tools only)
      "inferArrayShape": true,          // default true
      "previewRows": 3,                 // first-N preview line; 0 disables
      "chapterMarkdown": true,           // split long markdown on H2 into chapters
      "perTool": {                       // per-server / per-tool overrides
        "fs__list_directory": { "thresholdBytes": 0 },   // always offload
        "github":             { "thresholdBytes": 32768 }, // higher cutoff for the whole server
        "weird-server":       false                       // never offload this server
      }
    },

    // Per-tool JSONL trace of the ENTIRE pipeline flow (request → each
    // middleware before → upstream → each middleware after → response).
    // `true` enables defaults; pass an object to tune.
    "trace": {
      "dir": "/abs/path/to/logs",       // default <os.tmpdir()>/better-mcp/trace
      "maxBodyBytes": 0,                 // 0 = full bodies (no cap)
      "redact": ["token", "password"],  // default: the `redact` list above
      "includeResources": false          // default false (tools only)
    },

    // Path to a JS/MJS module exporting `{ before, after }` hooks.
    // Relative paths resolve against the config file's directory.
    "hooks": "./middleware.js"
  }
}

CLI flags:

  • -c <path> / --config <path> — path to mcp.json (overrides discovery + env).

  • --no-namespace — disable the <server>__<tool> prefix at runtime.

  • --offload-resources — also offload resources/read responses (same as setting middleware.offload.includeResources: true, or MCP_PROXY_OFFLOAD_RESOURCES=1).

Middleware

Every upstream call passes through a small stack. Registration order is logger → offloader → redactor → user, so the after-chain runs from inside out:

client ─▶ logger.before ─▶ user.before ─▶ upstream
                                              │
                                              ▼
client ◀─ logger.after ◀─ offloader.after ◀─ redactor.after ◀─ user.after

User hooks see the raw request and the raw upstream response. Redaction cleans that data, the offloader decides whether to write it to disk and replace the response with a pointer, and the logger records what the client will ultimately see.

The **log** middleware is itself a hook at the outermost position, so it only sees the request before anyone touched it and the response after everyone did. The **trace** feature is different: it's wired into the pipeline itself, not into the hook chain, so it can record what each middleware changed. Use log for a light one-line-per-call record; use trace when you need the full
per-tool flow.

Slimming tools/list

tools/list is resent to the model every conversation turn, so trimming the catalog pays out per turn. By default the proxy strips a small set of JSON-Schema annotations that the model doesn't need at call time:

  • $schema, $id, $comment

  • title, examples, default

  • required: [] and enum: [] when empty (always, regardless of strip list)

Set middleware.slim: false to disable, or pass an object to tune:

"middleware": {
  "slim": {
    // Override the default strip list. Walk is recursive (descends into
    // `properties`, `items`, `anyOf`/`oneOf`/`allOf`, `patternProperties`, …).
    "stripSchemaFields": ["$schema", "title", "examples", "default"],

    // Drop a property's `description` when it's a short paraphrase of its name
    // (e.g. property `userId` with description "the user ID"). Off by default.
    "stripPropertyDescriptions": false,

    // Truncate each tool's top-level description to this many chars
    // (trailing `…`). 0 disables. Off by default — descriptions stay full.
    "maxDescriptionLength": 0
  }
}

What's not stripped by default: additionalProperties, format, per-property description, pattern, minimum/maximum. Those carry real semantics that the model can use.

Compacting responses

For every tool/resource/prompt response, the proxy walks content[].text blocks; when a text block holds parseable JSON (object or array), it drops empty-valued fields and re-stringifies minified. Substitution only happens when the result is strictly shorter, so this is idempotent on already-clean payloads. Free-form text (prose, code, offload pointers) is never touched — the parse-as-JSON precondition is the safety rail.

Compact runs after the offloader in the response chain, so the file written to disk keeps the full original payload. Compact only changes what the client receives.

"middleware": {
  "compact": {
    "dropNull": true,         // default true — drop fields whose value is `null`
    "dropEmptyString": false, // `""` vs missing is often meaningful
    "dropEmptyArray": false,  // `[]` usually means "no results", not missing
    "dropEmptyObject": false, // `{}` can be a deliberate empty container

    // Round JSON numbers to N decimal places. `0` (default) disables.
    // Integers and NaN/Infinity are untouched. Useful for floats from ML
    // scores, timestamps, lat/lng — but lossy, so opt in deliberately.
    //   0.123456789 → 0.1235 at precision 4 (≈45% byte saving per number)
    "roundFloats": 0,

    // Skip compaction for noisy servers/tools whose text payloads must
    // round-trip byte-identical (e.g. an html_dump or code_snippet tool).
    // Match by `"<server>"` (whole server) or `"<server>__<tool>"`.
    "exclude": ["weird-server", "weird-server__raw_html"]
  }
}

Set compact: false to disable entirely. The minification step (whitespace stripping) is always on when compact is enabled — even with every drop* knob off, a pretty-printed JSON response will round-trip to its minified form.

Note on array elements: compact never drops elements from arrays — array length is treated as load-bearing. The drop-* knobs apply only to object FIELDS.

Cleaning text

For every tool/resource/prompt response, the proxy walks content[].text blocks (whether or not they hold JSON) and strips terminal-style noise:

  • ANSI / CSI / OSC escape sequences (\x1b[31m…\x1b[0m, terminal-title setters, cursor moves, …). Useless to a model, pure tokens.

  • Trailing whitespace per line[ \t]+$ per line. No semantic value unless you're writing a markdown trailing-double-space line break.

"middleware": {
  "cleantext": {
    "stripAnsi": true,              // default true
    "trimTrailingWhitespace": true, // default true
    "collapseBlankLines": false,    // default false — risky for markdown that
                                    //   uses blank lines structurally
    "exclude": ["weird-server", "weird-server__raw_terminal"]
  }
}

Cleantext runs after compact in the response chain (so minified JSON text — which is already trim — passes through unchanged), and after offload (so the on-disk file keeps the original ANSI codes for forensic value). Set cleantext: false to disable entirely.

Dedup

Hash-based response cache for polling-style tools. When the proxy sees the same (server, tool, response-bytes) within ttlSeconds, it replaces the response with a short pointer instead of re-sending the full payload:

same response as 5s ago (sha:abc12345)

OFF by default — enable explicitly when you know you're polling. The pointer changes what the client receives; most LLMs handle it fine, but it's a behavioral change worth opting into.

"middleware": {
  "dedup": {
    "ttlSeconds": 300,        // default 300 (5 min)
    "maxEntries": 1000,        // LRU cap; oldest evicted on insert
    "minBytes": 200,           // skip dedup when response is smaller than this
    "includeResources": false, // resources opt-in (prompts never deduped)
    "exclude": ["weird-server", "weird-server__sometimes_caches_wrong"]
  }
}

How it works:

  • Runs after compact + cleantext, so the hash covers the bytes the client actually receives (deterministic transforms don't invalidate cache hits).

  • Cache key is <server>__<tool>__<sha256-of-result-prefix> — same content on different tools doesn't collide.

  • Hash is sha256(JSON.stringify(result)), displayed as the first 8 hex chars. 32 bits of entropy is plenty for in-session dedup.

  • TTL is enforced lazily on each access (no background sweep). Entries past TTL are dropped before the lookup; LRU eviction kicks in at maxEntries.

  • A HIT bumps the entry to most-recent in LRU order but does NOT reset its firstSeen timestamp — the pointer's age reflects when the content was first observed.

  • Per-process cache (per-pipeline). Shared across HTTP sessions naturally. Cleared on restart.

Caveat: tools whose responses embed timestamps, request IDs, or any non-deterministic field will never dedup — bytes differ → not the same response. That's correct behavior, but worth knowing before turning dedup on for a tool that "feels like" it should hit and never does.

Offloading oversize responses

When a tool response's JSON-serialized size exceeds thresholdBytes (default 16 KB), the offloader:

  1. Writes the full response to <dir>/<server>__<tool>__<timestamp>.json. If the response is the typical { content: [{ type: "text", text: "<JSON>" }] } shape, the parsed inner JSON is saved instead of the wrapper.

  2. Replaces the response with a short text message like:

 response exported to: /tmp/better-mcp/github__list_issues__2026-05-17T12-34-56-789Z.json
 size: 142.3 KB (145708 bytes)
 length: 1024
 interface: Array<{ id: number; number: number; title: string; state: string; labels: Array<{ name: string; color: string }>; assignee: { login: string } | null }>
 preview: {"cols":["id","number","title","state"],"rows":[[1,1,"First issue","open"],[2,2,"Second","closed"],[3,3,"Third","open"]]}

length, interface, and preview only appear when the saved data is an array. The interface is inferred from a sample of up to 200 elements and depth-capped at 4 to keep it lean. The preview line shows the first previewRows items (default 3): homogeneous object arrays render as {cols, rows}; primitive or mixed arrays render as a JSON sample. Cell values are capped at 80 chars; tables wider than 12 columns are skipped. Set previewRows: 0 to disable.

Tool responses are always considered. Resource reads are skipped by default; flip includeResources: true (or pass --offload-resources) to include them. Prompts are never offloaded.

Per-tool / per-server overrides

Some tools always cross the threshold and never benefit from inline text (fs__list_directory, log dumps); others should never offload (small, format-sensitive tools). Use perTool to override the global behaviour for specific servers or tools without touching anyone else:

"offload": {
  "thresholdBytes": 16384,
  "perTool": {
    "fs__list_directory":  { "thresholdBytes": 0 },         // always offload
    "github__get_repo":    { "chapterMarkdown": false },     // disable chaptering here
    "github":              { "thresholdBytes": 32768 },      // higher cutoff for whole server
    "weird-server":        false,                            // never offload
    "weird-server__keepme": { "thresholdBytes": 0 }          // …except this one tool
  }
}

Rules:

  • Keys use the <server>__<tool> / <server> convention (same as exclude elsewhere).

  • Object value = Partial<{ thresholdBytes, chapterMarkdown, inferArrayShape, previewRows }> merged on top of the global config for matching calls. Unspecified knobs inherit from the global.

  • false sentinel = skip offload entirely for that server/tool. Use this instead of { thresholdBytes: Infinity }.

  • Specificity: <server>__<tool> wins over <server> when both match. This lets you disable a whole server then re-enable one tool inside it.

  • Storage knobs (dir, includeResources) stay global — they're not per-tool concerns.

{ thresholdBytes: 0 } means "every response length is > 0, so every response offloads." Use it for tools whose output is always too large to be useful inline.

Markdown chaptering

When an oversize response is a single text block (didn't parse as JSON) and contains at least one H2 heading (^## ), the offloader switches to markdown mode: it writes the full text to <base>.md AND one <base>__NN_<slug>.md sidecar per chapter, and returns a TOC pointer instead of the standard line:

markdown exported to: /tmp/better-mcp/jira__get_page__2026-05-17T….md
size: 142.3 KB (145708 bytes)
chapters:
 - 00 - page_title: /tmp/…__00_page_title.md
 - 01 - overview:   /tmp/…__01_overview.md
 - 02 - api_reference: /tmp/…__02_api_reference.md

This costs slightly more pointer bytes than the single-file version, but the model can read_file just the chapter it needs on follow-up turns instead of the whole document.

  • The splitter is code-block aware: a ## line inside ``` or ~~~ won't trigger a split.

  • Chapter 00 is the content before the first H2. Its slug comes from the first # H1 line if one exists, else intro. Empty intros are skipped.

  • Each chapter file includes its own heading line for context.

  • Slugs are lowercase, diacritics stripped, non-alphanumeric → _, capped at 40 chars; falls back to chapter when nothing usable remains.

  • Set chapterMarkdown: false to keep today's behavior (full file saved as a .json wrapper for everything that isn't a JSON array).

  • If a chapter write fails mid-flight, the full .md file is still on disk and the pointer simply omits the failed entries — graceful degradation.

Tracing the full pipeline (per-tool logs)

Set middleware.trace and every tool call is recorded to its own append-only JSONL file:

"middleware": {
  "redact": ["token", "password", "api_token"],
  "trace": true                       // or { dir, maxBodyBytes, redact, includeResources }
}
  • One file per tool: <dir>/<server>__<tool>.jsonl (e.g. jira__search_issues.jsonl). Default dir is <os.tmpdir()>/better-mcp/trace.

  • No per-tool setup — it's automatic for every tool that gets called. Resources/prompts are excluded unless includeResources: true.

What a trace looks like

One JSON object per line. Every line carries ts, callId, seq, server, tool, kind, and phase. One call's lifecycle (here: a user hook that mutated the request, then the redact middleware that cleaned the response):

{"ts":"…","callId":"a1f…","seq":0,"server":"jira","tool":"search_issues","kind":"tool","phase":"request","params":{"jql":"project = DEMO"}}
{… "seq":1,"phase":"before","mw":"user","changed":true,"durationMs":0,"params":{"jql":"project = DEMO","injectedByUser":true}}
{… "seq":2,"phase":"upstream","durationMs":214,"ok":true,"result":{"content":[{"type":"text","text":"{…}"}]}}
{… "seq":3,"phase":"after","mw":"user","changed":false,"durationMs":0}
{… "seq":4,"phase":"after","mw":"redact","changed":true,"durationMs":1,"result":{"content":[{"type":"text","text":"{…redacted…}"}]}}
{… "seq":5,"phase":"response","totalMs":216,"result":{…}}

Phases, in order: request → one before per middleware that has a before hook → upstream → one after per middleware that has an after hook → response. Each middleware step reports mw (log/offload/redact/user), changed (did it return a modified request/response), and durationMs. A body is included on a step only when that step changed it; request, upstream, and response always carry the body. If a hook throws, its step is recorded with an error field and the call still aborts as before.

Concurrency

Concurrent calls to the same tool write to the same file. Every event is a self-contained line tagged with callId + a per-call seq, and writes are serialized per file, so lines never tear. Reconstruct one flow with:

grep '"callId":"a1f…"' jira__search_issues.jsonl | jq -s 'sort_by(.seq)'

What to expect — important behaviors

  • Bodies are full by default (maxBodyBytes: 0). Set a byte cap and larger bodies become a { "truncated": true, "bytes", "sha256", "head" } placeholder instead.

  • Trace vs. offload: the trace captures the pre-offload payload at the inner after steps. With full bodies, a response that offload would shrink still lands in the trace file at full size — that's the point (full fidelity for debugging), but it means trace files can grow large. Cap with maxBodyBytes if that matters.

  • Redaction: the tracer sees raw, pre-redaction upstream data, so it scrubs independently using trace.redact (falling back to middleware.redact). Unlike the redact middleware, it also descends into JSON embedded in strings — the common content[].text wrapper — so secrets there are caught. It's still key-based: a secret that isn't the value of a key matching a pattern won't be masked. Set your patterns deliberately, and treat the trace directory as sensitive.

  • No rotation: per-tool files append indefinitely. Rotate/prune them yourself if volume is a concern.

  • Cost: bodies are redacted and serialized on the call path before the async write. It's a debugging/observability feature — leave it off in latency-sensitive setups, or use maxBodyBytes.

  • A config change (including enabling trace) only takes effect when the proxy restarts — restart your MCP host after editing it.

User hooks

// middleware.js
export default {
  async before(req) {
    // req: { server, kind: "tool"|"resource"|"prompt", name, params, meta? }
    if (req.kind === "tool" && req.name === "write_file") {
      if (req.params?.path?.includes("/etc/")) {
        throw new Error("writes under /etc are blocked");
      }
    }
    return req; // or void to leave unchanged
  },

  async after(req, res) {
    // res: { result, durationMs, error? }
    if (res.durationMs > 2000) {
      process.stderr.write(`slow: ${req.server}/${req.name}\n`);
    }
    return res;
  },
};

Both hooks may be sync or async. Return the modified request/response, or nothing to leave it as-is. Throwing inside before cancels the call; throwing inside after surfaces as an MCP error to the client.

What's proxied

  • tools/list — aggregated from every connected server. Names are namespaced as <server>__<tool> unless namespace: false.

  • tools/call — routed to the right upstream based on the namespaced name.

  • resources/list / resources/read — aggregated; URIs are kept as-is.

  • prompts/list / prompts/get — aggregated; names are namespaced.

If two upstreams expose the same name (or resource URI), the proxy logs a collision warning and the later one wins. Use namespace: true (the default) to avoid this.

Notes

  • Logs go to stderr — stdout is reserved for the MCP protocol.

  • A server that fails to start is logged and skipped; the rest still come up.

  • SIGINT / SIGTERM closes every upstream cleanly before exit.

Publishing

npm (manual)

npm version <patch|minor|major>      # bumps + tags + commits
npm publish --access public           # public scoped package
git push --follow-tags

publishConfig.access: "public" is set in package.json, so the --access public flag is just belt-and-suspenders.

Docker (automated)

Every push to main and every v*.*.* tag triggers .github/workflows/docker-publish.yml, which builds a multi-arch image (linux/amd64 + linux/arm64) and pushes to ghcr.io/qelos/better-mcp. Tags pushed:

  • branch pushes → :main, :sha-<short>

  • semver tags → :latest, :vX.Y.Z, :X.Y, :X

The workflow also flips the package to public on first push (no-op afterwards).

License

MIT

Available Tools

14 tools
fs__create_directoryA

Create a new directory or ensure a directory exists. Can create multiple nested directories in one operation. If the directory already exists, this operation will succeed silently. Perfect for setting up directory structures for projects or ensuring required paths exist. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses idempotent behavior (silent if exists), nested creation, and allowed directories. Lacks permission or failure details, which is acceptable for a simple creation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with primary action. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Fully covers tool use case, behavior, and constraints. No output schema needed; return value is implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only parameter 'path' is described in context (nested creation, path within allowed dirs). Adds meaning beyond schema, which only specifies type 'string'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states verb 'create' and resource 'directory', includes details like nested creation and silent success. Distinguishes from file-writing siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit use case ('setting up directory structures') and constraint ('only within allowed directories'). No negative guidance or sibling alternatives, but context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__directory_treeB

Get a recursive tree view of files and directories as a JSON structure. Each entry includes 'name', 'type' (file/directory), and 'children' for directories. Files have no children array, while directories always have a children array (which may be empty). The output is formatted with 2-space indentation for readability. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
excludePatternsNo

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It describes output structure (name, type, children) and formatting (2-space indentation), and mentions directory restriction. However, lacks details on depth limits, symlink handling, or error behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with clear structure: purpose first, then detail on children arrays and formatting. No redundant text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and 0% parameter coverage, the description lacks essential details about parameter usage and limitations. It covers output structure but not enough for a file system tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%. Description does not mention parameters like 'path' (absolute vs relative?) or 'excludePatterns' (pattern syntax?). Adds no meaning beyond schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Get a recursive tree view of files and directories as a JSON structure', specifying a verb and resource. It distinguishes from sibling tools like fs__list_directory (non-recursive) and fs__list_directory_with_sizes (includes sizes).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool vs alternatives. The only context is 'Only works within allowed directories', but no explicit when-to-use or when-not-to-use instructions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__edit_fileA

Make line-based edits to a text file. Each edit replaces exact line sequences with new content. Returns a git-style diff showing the changes made. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
editsYes
dryRunNoPreview changes using git-style diff format

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description must carry the full burden of behavioral disclosure. It conveys that edits are line-based, require exact matches, and return a git-style diff. However, it does not specify whether the operation is atomic, what happens if oldText is not found, or the file must exist, leaving gaps in expected behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise: three sentences that first state the main function, then detail the mechanism and output, and finally note a constraint. Every sentence adds value with no redundancy or unnecessary information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (3 parameters, no output schema), the description covers the key aspects: what it does, how it works, what it returns, and a constraint. It lacks detail on edge cases (e.g., matching failure, file type requirements) but provides sufficient context for typical use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 33% (only dryRun and inner fields have descriptions). The description adds context that edits are line-based and exact, but does not elaborate on the 'path' parameter or provide format constraints. The schema's own description of oldText ('must match exactly') is sufficient, but the overall parameter semantics are minimally reinforced.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool makes 'line-based edits to a text file,' specifying the verb (edit) and resource (text file). It distinguishes from siblings like fs__write_file, which overwrites entire files, by emphasizing line-level changes and exact replacement.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not provide explicit guidance on when to use this tool versus alternatives. It mentions a constraint ('only works within allowed directories') but lacks a direct comparison to sibling tools like fs__write_file or suggestions for when line editing is preferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__get_file_infoA

Retrieve detailed metadata about a file or directory. Returns comprehensive information including size, creation time, last modified time, permissions, and type. This tool is perfect for understanding file characteristics without reading the actual content. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must disclose behavior fully. It states the tool returns metadata like size, times, permissions, and type, implying a read-only operation. It does not explicitly confirm no side effects or discuss authentication/rate limits, but the description is adequate for a simple info retrieval tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences efficiently convey the core action, return data, use case, and constraint. The description is front-loaded with the main verb and resource, and every sentence adds value without wordiness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given a single parameter and no output schema, the description covers purpose, behavior, and constraints adequately. It could mention return format or error states, but the tool is simple enough that the provided information is mostly complete for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has one parameter 'path' with no description (0% coverage). The tool description does not explain the path format, absolute/relative expectations, or examples. It only mentions 'works within allowed directories,' which does not fully compensate for the lack of parameter guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool retrieves detailed metadata for files or directories, using the verb 'Retrieve' and specifying the resource. It differentiates from siblings like fs__read_file (content reading) and fs__list_directory (listing), making the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description indicates when to use: 'perfect for understanding file characteristics without reading the actual content.' It also notes a constraint: 'Only works within allowed directories.' However, it does not explicitly mention when not to use or list alternative tools, but the context implies it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__list_allowed_directoriesA

Returns the list of directories that this server is allowed to access. Subdirectories within these allowed directories are also accessible. Use this to understand which directories and their nested paths are available before trying to access files.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description implies a read-only operation by stating it 'returns' a list, and mentions that subdirectories are accessible. No annotations are provided, so the description carries the full burden. It does not disclose details like authentication or rate limits, but for a simple listing tool, it is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with the core purpose first and additional context second. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the tool's purpose and usage context. The missing output schema means the return format is not specified, but for this simple tool the description is largely complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has no parameters, so the input schema is trivially covered. Per guidelines, 0 parameters yields a baseline of 4. The description adds no parameter information, but none is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns a list of allowed directories, including subdirectories. It does not explicitly differentiate from siblings like fs__list_directory, but the unique resource 'allowed directories' makes the purpose distinct.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description advises using this tool 'before trying to access files' to understand accessible paths. This provides clear context, though it does not mention when not to use it or suggest alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__list_directoryA

Get a detailed listing of all files and directories in a specified path. Results clearly distinguish between files and directories with [FILE] and [DIR] prefixes. This tool is essential for understanding directory structure and finding specific files within a directory. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description must carry burden. Mentions output formatting with prefixes and directory constraint, but omits whether listing is recursive, performance notes, or error behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with main action, no wasted words. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given simple one-parameter tool with no output schema or annotations, description covers purpose, output format, and constraint. Could mention recursion or sorting but not essential.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%. Description only repeats that 'path' specifies the directory to list and adds constraint of allowed directories. No examples, formats, or additional meaning beyond schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States 'Get a detailed listing of all files and directories in a specified path' with specific verb and resource. Distinguishes from siblings like fs__list_directory_with_sizes and fs__directory_tree by noting [FILE] and [DIR] prefixes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage: 'essential for understanding directory structure' and constraint 'Only works within allowed directories.' No explicit when-not-to-use or comparison to alternative listing tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__list_directory_with_sizesA

Get a detailed listing of all files and directories in a specified path, including sizes. Results clearly distinguish between files and directories with [FILE] and [DIR] prefixes. This tool is useful for understanding directory structure and finding specific files within a directory. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
sortByNoSort entries by name or sizename

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden. It states it's a listing operation (read-only) and works only within allowed directories. However, it does not disclose recursion behavior, performance implications, or whether sizes include subdirectories. Adequate but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the main action. No unnecessary words. Each sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the basic purpose and a use case, but given no output schema, it lacks details on return format (beyond prefixes), whether subdirectories are included recursively, and how errors are handled. Adequate but not fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50% (sortBy has description, path does not). The description does not add meaning to parameters: it mentions 'specified path' but no format or constraints, and does not explain sortBy options. It fails to compensate for low schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists files and directories with sizes, using [FILE] and [DIR] prefixes. It distinguishes from siblings like fs__list_directory which likely lacks sizes, fulfilling 'specific verb+resource'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a use case: 'useful for understanding directory structure and finding specific files'. It provides context but does not explicitly exclude alternatives or mention when not to use it, lacking explicit when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__move_fileA

Move or rename files and directories. Can move files between directories and rename them in a single operation. If the destination exists, the operation will fail. Works across different directories and can be used for simple renaming within the same directory. Both source and destination must be within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
sourceYes
destinationYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist; description carries full burden. Discloses failure on existing destination and allowed directory constraint. Does not mention atomization or side effects, but sufficient for a file move tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four concise sentences, no redundancy. Front-loaded with verb and object, each sentence adds distinct value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, constraints, and failure condition. Lacks return value details (no output schema), but acceptable for a simple operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 0% description coverage; description adds meaning by stating 'both source and destination must be within allowed directories.' No format details, but provides necessary constraint.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the tool moves/renames files and directories. Differentiates between move (cross-directory) and rename (same directory). Distinct from sibling tools like read, write, create directory.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides context for when to use: it can move or rename in one operation, fails if destination exists, and requires both paths within allowed directories. Lacks explicit alternatives but implies usage for relocation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__read_fileA

Read the complete contents of a file as text. DEPRECATED: Use read_text_file instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
tailNoIf provided, returns only the last N lines of the file
headNoIf provided, returns only the first N lines of the file

TDQS

A3.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must convey all behavioral traits. It claims to read 'complete contents', yet the input schema includes 'head' and 'tail' parameters that limit output to partial lines. This contradiction misleads the agent about the tool's actual behavior. No mention of encoding, file size limits, or error handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short sentences with no redundant words. It efficiently communicates the core action and deprecation status.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 3 parameters (one required) and no output schema. The description omits crucial context: the ability to read partial lines via head/tail, the file encoding assumed, any size restrictions, or how it differs from read_text_file beyond deprecation. The agent lacks enough information to use it correctly or decide between siblings.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% (path lacks a description; tail and head have descriptions but are not explained in the tool description). The description says 'complete contents', which contradicts the optional head/tail parameters that allow partial reads. The description adds no value beyond the schema and actually undermines parameter understanding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action: 'Read the complete contents of a file as text', and immediately distinguishes it from the sibling tool by marking it as DEPRECATED and pointing to 'read_text_file' as the successor.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs the agent to avoid this tool when possible: 'DEPRECATED: Use read_text_file instead.' This directly tells when not to use it and provides a named alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__read_media_fileB

Read an image or audio file. Returns the base64 encoded data and MIME type. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses the return format (base64 and MIME type) and a restriction (allowed directories), but it does not mention error handling, file size limits, or what happens if the file is not an image/audio. Since no annotations are present, the description carries the full burden, which is partially met.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with two sentences, front-loading the main action and return type. Every word adds value, and it avoids redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with one parameter and no output schema, the description covers the essential aspects: what it reads, what it returns, and a key constraint. Missing details like error behavior and path validation are minor gaps, but overall it is fairly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter 'path' is described implicitly through the constraint 'only works within allowed directories', adding some context beyond the bare schema. However, no details about path format, absolute vs relative, or required extensions are given. With 0% schema coverage, the description should provide more, but for a single parameter it is minimally acceptable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it reads image or audio files and returns base64 and MIME type, distinguishing it from sibling tools like fs__read_text_file. However, it does not explicitly exclude other file types or mention that it only supports media files.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a constraint ('Only works within allowed directories') but offers no guidance on when to use this tool over similar tools like fs__read_file or fs__read_text_file. No alternatives or exclusions are mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__read_multiple_filesA

Read the contents of multiple files simultaneously. This is more efficient than reading files one by one when you need to analyze or compare multiple files. Each file's content is returned with its path as a reference. Failed reads for individual files won't stop the entire operation. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathsYesArray of file paths to read. Each path must be a string pointing to a valid file within allowed directories.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description discloses key behaviors: failure tolerance ('Failed reads... won't stop the entire operation'), return structure ('Each file's content is returned with its path'), and permission constraint ('Only works within allowed directories'). It lacks details on concurrency or max file limits but is otherwise transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is four sentences, front-loaded with the primary action, and each sentence adds distinct value: purpose, efficiency, return format, failure handling, and constraint. No repetition or unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description adequately covers the output format and error handling. It provides usage context and constraints. However, it misses potential limits (max files, max size) and whether reading is sequential or parallel, which would improve completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% as the input schema fully describes the 'paths' parameter. The tool description does not add new parameter-level semantics beyond reiterating 'allowed directories' and failure handling. Per guidelines, baseline is 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it reads multiple files simultaneously, highlights efficiency for analyzing/comparing multiple files, and distinguishes itself from sibling tools like fs__read_file which read single files. The verb 'read' and resource 'multiple files' are specific.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains it is more efficient than reading files one by one and that failed reads won't stop the operation, guiding agents to use it when handling multiple files or tolerance for failures. However, it does not explicitly state when not to use it (e.g., for single file use fs__read_file).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__read_text_fileA

Read the complete contents of a file from the file system as text. Handles various text encodings and provides detailed error messages if the file cannot be read. Use this tool when you need to examine the contents of a single file. Use the 'head' parameter to read only the first N lines of a file, or the 'tail' parameter to read only the last N lines of a file. Operates on the file as text regardless of extension. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
tailNoIf provided, returns only the last N lines of the file
headNoIf provided, returns only the first N lines of the file

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It discloses text encoding handling, detailed error messages, and that it operates on text regardless of extension. Does not mention file size limits or locking, but sufficient for a read-only tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Five sentences, front-loaded with main purpose. Clear and organized, though could be slightly more concise by merging some sentences. No unnecessary fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, so description does not specify return format. However, it mentions 'complete contents' and 'detailed error messages', which is typical for read tools. Additional info on success/error structure would improve completeness, but acceptable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% (head and tail have descriptions, path does not). Description adds meaning: head/tail read first/last N lines. Path description missing but inferred from context. Schema already provides basic info, and description compensates partially.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states 'Read the complete contents of a file from the file system as text', specifying verb, resource, and modality. It distinguishes from siblings like fs__read_file (binary) and fs__read_multiple_files.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use this tool when you need to examine the contents of a single file' and explains head/tail usage. Mentions allowed directories constraint. Could briefly differentiate from fs__read_file or fs__read_media_file, but still clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__search_filesA

Recursively search for files and directories matching a pattern. The patterns should be glob-style patterns that match paths relative to the working directory. Use pattern like '.ext' to match files in current directory, and '**/.ext' to match files in all subdirectories. Returns full paths to all matching items. Great for finding files when you don't know their exact location. Only searches within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
patternYes
excludePatternsNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Describes recursion, full path returns, glob patterns, and allowed directory restriction. No annotations exist, so description carries full burden; missing performance or error handling but adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four focused sentences, front-loaded with main action, no fluff. Efficient and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema or annotations, description covers core search behavior. Could detail return format or limitations, but sufficiently complete for a search tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has no descriptions (0% coverage). Description explains pattern well but does not clarify path (starting directory) or excludePatterns, leaving gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it recursively searches files/directories matching a glob pattern, distinguishing it from sibling tools like reading or listing directories.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides pattern examples and recommends use when exact location unknown. Lacks explicit when-not-to-use or alternatives, but gives sufficient context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fs__write_fileA

Create a new file or completely overwrite an existing file with new content. Use with caution as it will overwrite existing files without warning. Handles text content with proper encoding. Only works within allowed directories.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
contentYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses key behaviors: complete overwrite without warning, text encoding handling, and restriction to allowed directories. This is adequate for a write operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three concise sentences. The first states the core purpose, the second adds a critical caution, and the third specifies constraints. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple write tool, the description covers purpose, caution, encoding, and scope. It lacks details like whether parent directories are created (unlikely given sibling fs__create_directory), but is largely complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description mentions 'text content with proper encoding' for the content parameter, adding some semantics beyond the schema. However, the path parameter is not elaborated, and schema coverage is 0%, so the description partially compensates.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool creates a new file or overwrites an existing one. It implicitly distinguishes from siblings like fs__edit_file (partial modification) and fs__read_file, but does not explicitly differentiate.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description advises caution due to overwriting without warning, implying use cases for file creation/replacement. However, it does not specify when not to use it (e.g., for appending) or mention alternative tools like fs__edit_file.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 14 tool updatesv0.1.0
    • First observedfs__create_directory
    • First observedfs__directory_tree
    • First observedfs__edit_file
    • First observedfs__get_file_info
    • First observedfs__list_allowed_directories
    • First observedfs__list_directory
    • First observedfs__list_directory_with_sizes
    • First observedfs__move_file
    • First observedfs__read_file
    • First observedfs__read_media_file
    • First observedfs__read_multiple_files
    • First observedfs__read_text_file
    • First observedfs__search_files
    • First observedfs__write_file

TDQS

A3.7/5.0
Disambiguation4/5

Most tools have distinct purposes, but 'list_directory' and 'list_directory_with_sizes' overlap significantly. Also, 'read_file' is deprecated and duplicates 'read_text_file', though the deprecation note mitigates confusion.

Naming Consistency5/5

All tools follow a consistent 'fs__' prefix with clear, descriptive snake_case names. No mixing of conventions.

Tool Count5/5

14 tools is a reasonable number for a file system server. Each tool covers a specific operation without excessive fragmentation.

Completeness3/5

Covers essential file system operations but lacks a delete or copy tool, which are common needs. Also missing append functionality. These gaps could hinder some workflows.

Maintenance

ActivityInactive
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    A flexible proxy server that aggregates multiple backend MCP servers into a single interface using STDIO or SSE transports. It supports dynamic server management via an HTTP API and utilizes namespacing to prevent tool conflicts across connected services.
    3
    1
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Proxy-style MCP tool multiplexer that aggregates multiple downstream stdio MCP servers into one, offering meta-tools for status, search, call, parallel, batch, and pipeline operations with concurrency control and caching.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    A flexible MCP proxy server that connects to and routes between multiple backend MCP servers over STDIO or SSE, enabling dynamic management and namespacing of tools.
    110
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/qelos-io/better-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server