Skip to content

[v2] Codemod treats SDK paths in string literals as imports #2760

Description

@Xuxyyy

What happened?

The v1-to-v2 codemod's project-type inference treats any quoted MCP SDK path as an import, even when the path appears only in an ordinary string literal.

In a client-only project with:

  • a real client import in client.ts,
  • a shared type import in shared.ts, and
  • a server SDK path stored as example text in example.ts,

the codemod classifies the project as using both client and server code.

Running:

pnpm --filter @modelcontextprotocol/codemod exec tsx src/cli.ts v1-to-v2 /tmp/fixture --transforms imports --verbose

rewrites the shared import to:

import type { CallToolResult } from '@modelcontextprotocol/server';

It also adds both @modelcontextprotocol/client and @modelcontextprotocol/server to package.json.

The string in example.ts is never imported or executed:

const serverImportExample = '@modelcontextprotocol/sdk/server/mcp.js';

The source scanner uses regular expressions that match quoted paths anywhere in a file. It does not verify that the match belongs to an import, export, dynamic import, or require() call.

I added this focused regression test locally:

it('ignores an SDK subpath that appears only in a string literal', () => {
    const dir = v1Project({
        'a.ts': [
            `import { Client } from '@modelcontextprotocol/sdk/client/index.js';`,
            `const example = '@modelcontextprotocol/sdk/server/mcp.js';`,
            ''
        ].join('\n')
    });
    expect(analyzeProject(dir).projectType).toBe('client');
});

Running:

pnpm --filter @modelcontextprotocol/codemod test -- projectAnalyzer.test.ts

produces one focused failure while the other 629 tests pass:

Expected: "client"
Received: "both"

What did you expect?

Only actual module specifiers should affect project-type inference.

The client-only fixture should remain classified as client. Its shared type import should move to @modelcontextprotocol/client, and the codemod should not add @modelcontextprotocol/server.

Code to reproduce

// client.ts
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
void Client;

// shared.ts
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
declare const result: CallToolResult;
void result;

// example.ts
const serverImportExample = '@modelcontextprotocol/sdk/server/mcp.js';
void serverImportExample;

Use a package.json containing:

{
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0"
  }
}

Then run the v1-to-v2 codemod with the imports transform.

SDK version

@modelcontextprotocol/codemod@2.0.0, tested from main commit 5119ee7fd7790e335a3fb60ef36f85334e2a6326.

Area

Migration / codemod

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions