DEV Community

Renato Marinho
Renato Marinho

Posted on

The Problem with AI-Generated 'Shadow' Duplication

AI agents are incredible at writing functions. They're even better at accidentally duplicating your entire business logic without you realizing it.

If you use Claude Code, Cursor, or any LLM-based agent to refactor code, you’ve probably seen the pattern. You ask it to 'extract this logic into a reusable utility,' and while the new function works perfectly, a few days later, there's a slightly different version of that same logic tucked away in another service. The variable names are different, the whitespace is updated for modern formatting, but the underlying complexity—the actual structural implementation—is identical.

This is 'shadow duplication.' It doesn't show up on a standard grep or a simple diff. A human reviewer might miss it during a PR because the surface-level syntax looks fresh. But as the codebase grows, your technical debt isn't just accumulating; it's mutating.

I built the Code Clone Detector MCP server specifically to kill this pattern at the source by giving AI agents a way to 'see' through the syntactic noise.

The Failure of Syntax-Based Detection

Standard duplication detection usually relies on literal string matching. If you change let userCount = 0 to const totalUsers = 0, most basic tools flag that as a new, unique block of code.

For an AI agent, this is the default mode of operation. Agents tend to 'personalize' code—they rename variables to match local context or clean up comments. If your detection strategy only looks for exact character matches, you are essentially blind to 80% of the duplication being introduced in modern agentic workflows.

To solve this, we have to move away from looking at what the code says and start looking at what the code is.

Normalization: Stripping the Noise

The first tool in this MCP is generate_normalized_signature. This is arguably the most important part of the pipeline.

Before we attempt to compare two blocks, we run them through a normalization process. We strip out comments, normalize all whitespace (converting tabs/spaces into a uniform format), and—most critically—we anonymize variables.

By replacing specific variable names with generic tokens, we create what I call a 'structural skeleton.' If you have two functions that both iterate over an array, check a null condition, and increment a counter, their normalized signatures will look nearly identical, regardless of whether the original code called it index, i, or counter.

This allows the agent to perform structural analysis without needing a heavy-duty AST (Abstract Syntax Tree) parser running in its context window. We've reduced the problem from 'semantic understanding' to 'structural matching.'

Detecting Exact vs. Near Matches

The server provides two distinct layers of detection:

  1. Identical Structural Clones (identify_exact_duplicates): This uses deterministic hashing on the normalized signatures. Once we have that stripped-down, anonymized version of the code, a simple hash comparison tells us if the underlying logic is an exact clone. It’s incredibly fast and catches those 'copy-paste' refactors where the dev (or agent) just duplicated a block and changed the function name.

  2. The Levenshtein Gap (identify_near_matches): This is where things get interesting. Sometimes, code isn't an exact clone, but it's functionally 'close enough' that it warrants investigation. We use the Levenshtein distance algorithm to calculate the edit distance between these normalized signatures.

We don't just give you a binary 'yes/no.' You can adjust the similarity threshold between 0 and 1. The default is set at 0.8. If the agent finds a block with a 0.85 similarity, it means there's only a tiny amount of structural difference—likely just one extra conditional or a slightly different loop type. This catches the 'evolved clones' that standard tools ignore.

Why this matters for your Agentic Workflow

When you are working in Cursor or Claude with an MCP connection, the agent shouldn't just be writing code; it should be auditing its own impact on your architecture.

Imagine a workflow like this:

  1. You ask the agent to implement a new feature.
  2. The agent writes the implementation.
  3. You trigger the Code Clone Detector via an MCP tool call.
  4. The agent scans the existing codebase for near-matches using its new capability.
  5. The agent realizes, 'Wait, I've just reinvented the calculateTax logic that already exists in utils/finance.ts. I should refactor this to use the existing function instead.'

This transforms the AI from a code generator into a code steward. It moves the responsibility of maintaining DRY (Don't Repeat Yourself) principles from your manual review process directly into the agent's execution loop.

Getting Started

You don't need to configure complex OAuth callbacks or manage local environments. Since this runs on Vinkius, you just grab a connection token and paste it into your client.

If you want to start auditing your project for these hidden structural duplicates, you can find the server here: https://vinkius.com/mcp/code-clone-detector

Stop letting your agents accumulate shadows in your codebase.


MCPs are the music of AI Agents. We built the catalog. Discover Vinkius MCP Catalog.

Top comments (0)