Tether MCP

Prevents AI coding agents from drifting off your architecture — blocks wrong dependencies, enforces file structure, and gives agents persistent memory of your project's rules.


AI agents like Cursor and Claude write code fast — but they suffer from Agent Drift: hallucinating dependencies, violating architectural boundaries, and creating spaghetti code. Tether is a persistent Senior Architect that your AI must consult before making structural changes.

Table of Contents

The Problem

You've been there. You ask an AI agent to add a feature and it:

  • 🎲 Installs moment.js when your project already uses date-fns
  • 🏗️ Creates an Express server inside your Next.js app
  • 🧩 Adds Riverpod when your Flutter team agreed on BLoC
  • 📝 Forgets the entire architecture after a few messages

Every session starts from zero. The AI has no memory of your rules, your stack decisions, or your architectural boundaries. This is Agent Drift, and it turns AI-assisted coding into a technical debt factory.

Quick Start

1. Initialize in Your Project

npx tether-mcp init

Tether scans your project manifest (package.json, pubspec.yaml, .csproj, pyproject.toml, go.mod, Cargo.toml, build.gradle, pom.xml, or Package.swift), auto-detects your framework across 8 ecosystems and 90 frameworks, and generates a tailored tether.config.json with smart defaults.

2. Connect to Your AI Agent

Add to ~/.claude/claude_desktop_config.json:

{
  "mcpServers": {
    "tether": {
      "command": "npx",
      "args": ["-y", "tether-mcp"]
    }
  }
}

Add to .cursor/mcp.json in your project root:

{
  "mcpServers": {
    "tether": {
      "command": "npx",
      "args": ["-y", "tether-mcp"]
    }
  }
}

Add to your Windsurf MCP configuration:

{
  "mcpServers": {
    "tether": {
      "command": "npx",
      "args": ["-y", "tether-mcp"]
    }
  }
}

3. Done. Your AI Agent Now Has Guardrails ⚓

Every time the AI starts working, it consults Tether first — reading your invariants, checking dependency policies, validating file placements, and logging structural decisions. No more drift.

How It Works

┌──────────────┐     MCP Tools     ┌──────────────┐     Local Files     ┌──────────────────┐
│  AI Agent    │ ◄──────────────► │  Tether MCP  │ ◄─────────────────► │ tether.config.json│
│ (Claude,     │                  │  Server      │                     │ ARCHITECTURE.md   │
│  Cursor)     │                  │              │                     │ DECISIONS.md      │
└──────────────┘                  └──────────────┘                     └──────────────────┘

Tools (6 total)

ToolWhen to CallWhat It Does
get_project_invariantsBefore any structural workFeeds the AI your tech stack, architecture rules, and dependency policies
verify_dependency_additionBefore npm install <pkg>Checks if the package is blocked, warned, allowed, or needs review
log_architectural_decisionAfter creating a component or changing data flowAppends a timestamped entry to DECISIONS.md
check_file_structureBefore creating or moving filesValidates the proposed file path against project conventions
verify_code_patternBefore implementing a featureChecks if the coding approach follows approved patterns and invariants
health_checkDiagnosticsReturns server status, registered tools, and session telemetry

MCP Resources

Tether also exposes project context as MCP Resources that clients can auto-subscribe to:

ResourceURIDescription
Configtether://configThe full tether.config.json — tech stack, invariants, dependency policies
Architecturetether://architectureThe project's ARCHITECTURE.md document
Decisionstether://decisionsThe DECISIONS.md ledger of all logged decisions

Configuration

Edit tether.config.json to match your project:

{
  "projectName": "my-app",
  "techStack": {
    "frontend": ["Next.js", "React"],
    "backend": ["Node.js"],
    "orm": ["Prisma"]
  },
  "invariants": [
    "All API routes must validate input with Zod.",
    "Database access must go through Prisma — no raw SQL.",
    "Use Server Components by default — client components only when needed."
  ],
  "dependencies": {
    "blocked": [
      {
        "name": "moment",
        "reason": "Use date-fns instead.",
        "alternatives": ["date-fns"],
        "severity": "block"
      },
      {
        "name": "lodash",
        "reason": "Tree-shaking issues. Use native JS or lodash-es.",
        "alternatives": ["lodash-es", "remeda"],
        "severity": "warn"
      }
    ]
  },
  "fileStructure": [
    {
      "pattern": "component",
      "allowedPaths": ["src/components/", "src/app/"],
      "reason": "All React components must live in src/components/ or src/app/"
    },
    {
      "pattern": "api-route",
      "allowedPaths": ["src/app/api/"],
      "reason": "API routes must use Next.js Route Handlers in app/api/"
    }
  ],
  "codePatterns": [
    {
      "name": "State Management",
      "rule": "Use React Context + useReducer for complex state — no Redux or Zustand",
      "scope": "frontend/state"
    },
    {
      "name": "Data Fetching",
      "rule": "Use Server Components for data fetching — no client-side fetch in components",
      "scope": "frontend"
    }
  ]
}

CLI Commands

npx tether-mcp init       # Scan project & generate tether.config.json
npx tether-mcp serve      # Start the MCP server (stdio)
npx tether-mcp status     # Show project config summary & health
npx tether-mcp validate   # Validate tether.config.json against schema
npx tether-mcp --version  # Show version
npx tether-mcp --help     # Show all commands

Dependency Severity Levels

Blocked dependencies now support severity levels:

SeverityBehavior
"block" (default)Hard stop — the AI is told the package is forbidden
"warn"Soft warning — the AI is discouraged but not blocked
{
  "dependencies": {
    "blocked": [
      { "name": "moment", "reason": "Deprecated.", "alternatives": ["date-fns"], "severity": "block" },
      { "name": "axios", "reason": "Prefer native fetch.", "alternatives": ["fetch"], "severity": "warn" }
    ]
  }
}

What Gets Generated

When you run npx tether-mcp init in a Next.js + Prisma + Tailwind project, Tether generates:

{
  "projectName": "my-next-app",
  "techStack": {
    "frontend": ["Next.js", "React"],
    "styling": ["Tailwind CSS"],
    "orm": ["Prisma"],
    "language": ["TypeScript"]
  },
  "invariants": [
    "Use Next.js App Router for all new routes — do not use the Pages Router.",
    "All database access must go through Prisma — no raw SQL queries.",
    "Use Tailwind utility classes for styling — no inline styles.",
    "All new code must be written in TypeScript with strict mode enabled."
  ],
  "dependencies": {
    "blocked": [
      { "name": "express", "reason": "Next.js has built-in API routes.", "alternatives": ["Next.js Route Handlers"] },
      { "name": "moment",  "reason": "Deprecated and large bundle size.", "alternatives": ["date-fns"] }
    ]
  }
}

The Decision Ledger

Every structural decision the AI makes is logged in DECISIONS.md:

## Added Redis caching layer

| Field | Value |
|-------|-------|
| **Date** | 2026-03-10T01:30:00.000Z |
| **Scope** | `api/cache` |

### Summary

Added Redis via ioredis for caching frequently accessed product data.
Chose Redis over Memcached for pub/sub support and persistence options.

This creates an immutable audit trail of every architectural choice — visible to the next developer and the next AI session.

Session Telemetry

The health_check tool returns local-only session statistics:

{
  "status": "healthy",
  "session": {
    "sessionStartedAt": "2026-03-12T10:00:00.000Z",
    "totalCalls": 7,
    "toolStats": {
      "get_project_invariants": { "callCount": 3, "lastCalledAt": "...", "errors": 0 },
      "verify_dependency_addition": { "callCount": 2, "lastCalledAt": "...", "errors": 0 }
    }
  }
}

No data leaves your machine. Telemetry resets when the server restarts.

Supported Framework Detection

Tether auto-detects 90 frameworks across 8 ecosystems:

JavaScript / TypeScript (package.json)

CategoryDetected
FrontendNext.js, React, Vue.js, Svelte, Angular, Nuxt, Remix, Astro, SolidJS
BackendExpress, Fastify, NestJS, Hono, Koa, Elysia
ORM / DBPrisma, Drizzle, TypeORM, Sequelize, Mongoose
TestingVitest, Jest, Playwright, Cypress
StylingTailwind CSS, Styled Components, Emotion
StateZustand, Redux Toolkit
AuthNextAuth.js
BuildVite
LanguageTypeScript

Python (pyproject.toml, requirements.txt)

CategoryDetected
BackendDjango, Flask, FastAPI
ORMSQLAlchemy
Testingpytest
ValidationPydantic
Task QueueCelery
Data ScienceNumPy, pandas
MLTensorFlow, PyTorch
FrontendStreamlit

Dart / Flutter (pubspec.yaml)

CategoryDetected
FrameworkFlutter
StateBLoC, Riverpod, GetX, Provider
HTTPDio
BackendFirebase
RoutingGoRouter
CodegenFreezed

C# / .NET (.csproj)

CategoryDetected
BackendASP.NET Core
ORMEntity Framework Core, Dapper
FrontendBlazor
Mobile.NET MAUI
TestingxUnit, NUnit
ArchitectureMediatR
LoggingSerilog
ValidationFluentValidation

Go (go.mod)

CategoryDetected
BackendGin, Echo, Fiber, Chi
ORMGORM
TestingTestify
RoutingGorilla Mux

Rust (Cargo.toml)

CategoryDetected
BackendActix Web, Axum, Rocket
AsyncTokio
ORMDiesel, SeaORM
SerializationSerde
DatabaseSQLx
CLIClap

Java / Kotlin (build.gradle, pom.xml)

CategoryDetected
BackendSpring Boot, Ktor
ORMHibernate
TestingJUnit 5
FrontendJetpack Compose

Swift (Package.swift)

CategoryDetected
BackendVapor
HTTPAlamofire
CLISwift Argument Parser
DatabaseGRDB

Each detection adds targeted invariants and smart blocked-package rules specific to your stack.

Config Reference

FieldTypeDescription
projectNamestringDisplay name for the project
techStackRecord<string, string[]>Your enforced technology stack by category
invariantsstring[]Immutable architectural rules the AI must follow
dependencies.allowedstring[]Pre-approved packages
dependencies.blockedarrayForbidden packages with reason, alternatives, and optional severity
dependencies.reviewRequiredstring[]Packages needing justification
fileStructurearrayFile placement rules with pattern, allowedPaths, and reason
codePatternsarrayCode pattern rules with name, rule, and scope
architectureFilestringPath to architecture doc (default: ARCHITECTURE.md)
decisionsFilestringPath to decision ledger (default: DECISIONS.md)

FAQ

No. Run npx tether-mcp init and it auto-generates tether.config.json by scanning your project. You can customize it afterward, but the defaults are smart enough out of the box.

No. MCP tools are auto-discovered. The AI sees Tether's tools in its toolbox and calls them when making structural changes — just like it uses file_read or terminal.

~500-1,500 tokens per session for guardrails vs. 5,000-20,000 tokens wasted fixing drift mistakes. Tether pays for itself in the first blocked bad dependency.

Smart ≠ omniscient. Claude doesn't know your team decided on date-fns three months ago. It doesn't remember Session #1's decisions in Session #10. And when you close the tab, context is gone. Tether gives the AI persistent, file-based memory of your rules — across every session, every agent.

Each project gets its own tether.config.json in its own directory. Project A's rules never leak into Project B.

No. CLAUDE.md is passive — the AI may or may not read it. Tether is active — it validates dependencies, blocks bad packages with alternatives, checks file structure, verifies code patterns, and maintains an audit trail. It works across Claude, Cursor, Windsurf, and any MCP-compatible agent.

Contributing

Contributions are welcome! Here are some ways to help:

  • Add a framework signature — detect a new framework in src/utils/detect-stack.ts
  • Improve invariants — better defaults for existing frameworks
  • Bug reports — open an issue
  • Feature requests — ideas for new tools or resources
git clone https://github.com/MoayadEsam/tether-mcp.git
cd tether-mcp
npm install
npm run build

License

MIT — built with ♥ for developers who are tired of cleaning up after their AI agents.

Related Servers