Skip to content

test(filesystem): add MCP SDK regression coverage for directory_tree#3245

Open
lopopolo-openai wants to merge 2 commits intomodelcontextprotocol:mainfrom
lopopolo-openai:fix/filesystem-directory-tree-structured-content-regression-test
Open

test(filesystem): add MCP SDK regression coverage for directory_tree#3245
lopopolo-openai wants to merge 2 commits intomodelcontextprotocol:mainfrom
lopopolo-openai:fix/filesystem-directory-tree-structured-content-regression-test

Conversation

@lopopolo-openai
Copy link
Copy Markdown

@lopopolo-openai lopopolo-openai commented Jan 24, 2026

Summary

This PR adds regression test coverage only for a directory_tree structured-content validation bug that appears to have already been fixed upstream.

There are no runtime behavior changes in this PR.

Context

The -32602 error reported in:

occurs when a tool declares outputSchema: { content: string } but returns structuredContent.content as an array.

From git history, this appears to have been fixed in:

Note: I opened this PR after seeing the open bug reports and reproducing the issue in an older build, but I did not initially confirm that main already contained the fix. I’m keeping this PR scoped to test coverage in case it’s still useful as a regression guard.

What this PR does

  • Adds src/filesystem/__tests__/directory-tree.mcp-sdk.test.ts
    • Uses @modelcontextprotocol/sdk + StdioClientTransport to call directory_tree end-to-end.
    • Asserts that structuredContent.content is a string and JSON-parseable.
  • Makes structured-content.test.ts slightly more robust on macOS by resolving the temp directory with fs.realpath() so the allowlist path matches /private/... temp paths.

This is intended to help prevent reintroducing the same outputSchema/structuredContent mismatch.

Minimal reproduction snippet (for older builds)

I was able to reproduce the -32602 validation error by running the filesystem server over stdio and calling directory_tree through the MCP SDK client.

Maintainers can run the following snippet directly (Node 20+):

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';

const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'mcp-fs-tree-'));
const root = await fs.realpath(tmp);
await fs.writeFile(path.join(root, 'a.txt'), 'hello');

const transport = new StdioClientTransport({
  command: 'npx',
  args: ['-y', '@modelcontextprotocol/server-filesystem', root],
});

const client = new Client({ name: 'debug-client', version: '1.0.0' }, { capabilities: {} });
await client.connect(transport);

const result = await client.callTool({
  name: 'directory_tree',
  arguments: { path: root },
});

console.log(result.structuredContent);
await client.close();

On buggy builds, this call throws McpError: -32602 ... Expected string, received array at path: ["content"].

Release context

I have not traced the exact release tag for e6933ca, but based on timestamps it looks like the fix (2025-12-11) should be included in npm releases published after that date (for example @modelcontextprotocol/server-filesystem@2025.12.18 and later).

Happy to update this PR with the exact release tag if you'd like me to track it down precisely.

Test plan

  • npm test --workspace @modelcontextprotocol/server-filesystem

Follow-up suggestion (optional)

If you'd like, I can follow up with a small CI-level "functional" test job that runs a tiny MCP SDK client against the built dist/index.js binaries for select servers (filesystem, memory, etc.) to assert that schema validation passes for a few representative tool calls.

I didn't include CI changes in this PR since I wasn't sure how you'd want to scope cross-package functional tests.

Authorship note

This contribution (bug identification, repro, test updates, and PR drafting) was authored with OpenAI Codex.

@cliffhall cliffhall added enhancement New feature or request server-filesystem Reference implementation for the Filesystem MCP server - src/filesystem labels Apr 20, 2026
@cliffhall
Copy link
Copy Markdown
Member

@claude review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 21, 2026

Claude finished @cliffhall's task in 1m 13s —— View job


PR Review: test(filesystem): add MCP SDK regression coverage for directory_tree

Tasks:

  • Gather context and understand request
  • Read changed files
  • Review test implementation quality
  • Check adherence to repo conventions
  • Post comprehensive feedback

Summary

The realpath fix to structured-content.test.ts is a genuine macOS bug fix worth keeping. However, the new directory-tree.mcp-sdk.test.ts duplicates test coverage that already exists in structured-content.test.ts, adding CI overhead without meaningful additional protection.


structured-content.test.ts — macOS realpath fix (Good)

src/filesystem/__tests__/structured-content.test.ts, line 23–26`

-    testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcp-fs-test-'));
+    const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'mcp-fs-test-'));
+    // macOS temp dirs may be symlinked (/var -> /private/var); resolve for server allowlist checks.
+    testDir = await fs.realpath(tmpDir);

This is correct and necessary. On macOS, os.tmpdir() returns /var/folders/... which is a symlink to /private/var/folders/.... The server's allowlist check would see the resolved path and reject it. This fix is valid.


directory-tree.mcp-sdk.test.ts — Duplicate Coverage

The new test file is functionally identical to the describe('directory_tree') block already present in structured-content.test.ts (lines 55–76). Both files:

  1. Spin up the same server via StdioClientTransport pointing at ../dist/index.js
  2. Call directory_tree with the same temp directory argument
  3. Assert result.structuredContent is defined
  4. Assert typeof structuredContent.content === 'string'
  5. Assert the content is JSON-parseable and is an array

The new file adds two minor extras: expect(Array.isArray(structured.content)).toBe(false) (redundant — if typeof x === 'string' passes, this is always true) and expect(parsed.length).toBeGreaterThan(0) (slightly more meaningful, but also covered by the fact that the test fixture always creates files). Neither justifies a second full server spawn per test run.

Recommendation: Drop directory-tree.mcp-sdk.test.ts entirely. If the parsed.length > 0 assertion is considered valuable, add it to the existing directory_tree block in structured-content.test.ts. The realpath fix alone is sufficient and correct as a standalone change.

Alternatively, if the goal is to have a dedicated regression file for this specific issue, then remove the describe('directory_tree') block from structured-content.test.ts to avoid the duplication.

Fix this →


Pre-existing issue (not introduced by this PR)

structured-content.test.ts line 7 has an unused spawn import:

import { spawn } from 'child_process'; // unused

Not blocking, but worth a cleanup pass.


Verdict

Change Assessment
realpath fix in structured-content.test.ts ✅ Correct, fix a real macOS bug
New directory-tree.mcp-sdk.test.ts ❌ Duplicate of existing coverage in structured-content.test.ts

The PR can be merged if the duplicate file is dropped (or if the equivalent block is removed from structured-content.test.ts).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request server-filesystem Reference implementation for the Filesystem MCP server - src/filesystem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants