Claude Code Skills vs MCP: Which Workflow Approach is Better?
The Problem
When I build Claude Code workflows, my Skills don’t trigger reliably. I create a skill for TDD workflows, but Claude skips it and jumps straight to implementation. I add security rules, but Claude forgets to check them before writing auth code.
A Reddit thread explained the core issue:
“Skills have the same problem as CLAUDE.md rules — Claude has to decide to use them. And it won’t always decide correctly.”
Vercel research shows a 56% tool-skip rate when relying on AI judgment for tool invocation. That means more than half the time, Claude won’t use the skill I created.
What I Tried
I started with Claude Code Skills because they’re easy to create. I made a /tdd skill that enforces test-driven development:
# Test-Driven Development Workflow
When user asks to implement features or fix bugs:1. Write test first (RED)2. Run test - should FAIL3. Implement minimal code (GREEN)4. Run test - should PASS5. Refactor (IMPROVE)
Verify 80%+ coverage with:```bashgo test -coverBut when I asked Claude to "add user authentication," it skipped the TDD skill and wrote implementation code directly. No tests, no coverage check.
I tried adding the skill to my CLAUDE.md file:
```markdown title="/Users/zhaocaiwen/.claude/CLAUDE.md"# Coding Rules
For implementation work, use the TDD workflow.Still inconsistent. Sometimes Claude used it, sometimes not.
The Breakthrough
The Reddit thread mentioned three strategies that work together:
- CLAUDE.md routing table - Explicit mapping of triggers to skills
- MCP servers - External workflows with structured data
- Hooks - Forced invocation for critical workflows
The key insight: MCP servers provide external workflow definitions that can’t be reinterpreted. Each step explicitly names the next skill to invoke.
Strategy 1: CLAUDE.md Routing Table
I added a routing table to my CLAUDE.md:
# Workflow Routing Table
## Feature Development- Trigger: "add feature", "implement", "build new"- Route: /plan skill → creates implementation plan- Then: /tdd skill → writes tests first- Then: implementation → following plan- Finally: /code-review skill → reviews before commit
## Bug Fixes- Trigger: "fix bug", "debug", "not working"- Route: /tdd skill → writes failing test first- Then: minimal fix → to pass test- Finally: /verify skill → ensures fix works
## Code Review- Trigger: "review code", "check this", "code review"- Route: /code-review skill → immediate review- No planning step: review is direct action
## Security Work- Trigger: "auth", "login", "payment", "user data"- Route: /security-review skill → MUST run first- Then: /plan skill → security-focused plan- Then: /tdd skill → security tests firstThis helped because the routing table is always in system context. Claude can see the explicit if-then logic for skill selection.
But I still had the 56% tool-skip problem.
Strategy 2: MCP Server for Workflows
I built an MCP server that returns structured workflows. Here’s the key endpoint:
import { z } from 'zod';
const inputSchema = z.object({ featureType: z.enum(['auth', 'api', 'ui', 'database']), complexity: z.enum(['simple', 'medium', 'complex']),});
export async function getFeatureWorkflow(input: z.infer<typeof inputSchema>) { const workflows = { auth: { steps: [ { step: 1, skill: 'security-review', reason: 'Security-first for auth features' }, { step: 2, skill: 'plan', reason: 'Plan authentication flow' }, { step: 3, skill: 'tdd', reason: 'Write tests for auth logic' }, { step: 4, action: 'implement', checkpoints: ['OWASP compliance', '80% coverage'] }, { step: 5, skill: 'code-review', reason: 'Security review required' } ], pitfalls: [ 'Never implement auth without security review', 'Always use parameterized queries (SQL injection prevention)', 'Test rate limiting and password strength validation' ] }, api: { steps: [ { step: 1, skill: 'plan', reason: 'Plan API endpoints' }, { step: 2, skill: 'tdd', reason: 'Write API tests' }, { step: 3, action: 'implement', checkpoints: ['80% coverage'] }, { step: 4, skill: 'code-review', reason: 'Review implementation' } ], pitfalls: [ 'Don't forget error handling', 'Always validate input with zod', 'Test rate limiting' ] } // ... other workflows };
return workflows[input.featureType];}When I ask Claude to “add authentication,” the MCP server returns this JSON:
{ "workflow": "feature-implementation", "steps": [ { "step": 1, "action": "call_skill", "skill": "security-review", "reason": "Security-first for auth features" }, { "step": 2, "action": "call_skill", "skill": "plan", "reason": "Plan authentication flow" }, { "step": 3, "action": "call_skill", "skill": "tdd", "reason": "Write tests for auth logic" }, { "step": 4, "action": "implement", "checkpoints": ["OWASP compliance", "80% coverage"] }, { "step": 5, "action": "call_skill", "skill": "code-review", "reason": "Security review required" } ], "known_pitfalls": [ "Never implement auth without security review", "Always use parameterized queries (SQL injection prevention)", "Test rate limiting and password strength validation" ]}This works because:
- Workflow is external (not Claude’s interpretation)
- Each step explicitly names the next skill
- Returns structured data (numbered checklist), not prose
- Known pitfalls are baked into the workflow
Strategy 3: Hooks for Forced Invocation
For critical workflows like security, I use hooks:
hooks: SessionStart: - name: security-signal-detection skill: security-review condition: | if message contains any of: - "auth", "authentication", "login" - "payment", "stripe", "checkout" - "user data", "personal information" - "API key", "secret", "token" then: invoke security-review skill immediately
- name: tdd-enforcement skill: tdd condition: | if message indicates: - new feature implementation - bug fix - refactoring and message does NOT contain "test" or "spec" then: invoke tdd skill first, block implementation
Stop: - name: completion-checklist action: verify checkpoints: - all tests pass - 80%+ coverage - no console.log statements - security review passed (if applicable)Hooks fire automatically before Claude can choose anything. The SessionStart hook detects “authentication” and forces the security-review skill to run first.
How It Works Together
Here’s what happens when I ask to “add user authentication to the API”:
- SessionStart hook fires → detects “authentication” keyword
- Hook invokes security-review skill → Claude checks security requirements
- CLAUDE.md routing table consulted → maps “auth” to security-first workflow
- Skill calls MCP server →
getFeatureWorkflow({ featureType: 'auth' }) - MCP returns structured workflow:
{"current_step": 1,"skill_to_invoke": "plan","reason": "Plan authentication flow before implementation","next_step": 2,"next_skill": "tdd"}
- Claude invokes /plan skill → creates authentication implementation plan
- MCP provides step 2 → invoke /tdd skill
- Claude invokes /tdd skill → writes tests for auth endpoints
- MCP provides step 3 → implement with checkpoints
- Claude implements → following plan and test requirements
- MCP provides step 4 → invoke /code-review
- Claude invokes /code-review skill → reviews auth implementation
- Stop hook fires → verifies all checkpoints passed
Result: Workflow completes reliably, no steps skipped, security review enforced.
Skills vs MCP Servers
| Aspect | Skills | MCP Servers |
|---|---|---|
| Best For | Reusable patterns, domain knowledge | Multi-step workflows, guaranteed execution |
| Invocation | Claude’s judgment (56% skip rate) | External workflow definition (0% skip rate) |
| Format | Prose instructions in markdown | Structured data (JSON) |
| Visibility | Requires CLAUDE.md routing table | Workflow steps returned in real-time |
| Reliability | Medium (depends on Claude’s choice) | High (external, can’t be reinterpreted) |
| Use Cases | TDD workflows, security patterns | Feature implementation, dev pipelines |
| Maintenance | Update skill files | Update server endpoints |
| Chain Support | Limited (each step independent) | Built-in (each step names next) |
When to Use Skills
Use Skills for:
- Reusable domain knowledge (e.g., “Spring Boot patterns”)
- Single-step or linear workflows
- Situations where you want Claude to have flexibility
- Building knowledge base, not execution chains
Examples:
/planskill/security-reviewskill/code-reviewskill
When to Use MCP Servers
Use MCP servers for:
- Workflows with 3+ steps that must execute in order
- Guaranteed execution (can’t skip steps)
- Workflows requiring checkpoints and validation
- Tracking progress and reporting status
Examples:
- Feature implementation workflow
- CI/CD pipeline
- Testing workflow
When to Use Both
Use both combined when:
- Complex workflow with domain-specific knowledge
- Need both structure (MCP) and expertise (Skills)
- Critical workflows that must complete reliably
Example: Auth feature → MCP orchestrates steps, Skills provide domain knowledge
Why This Matters
The 56% tool-skip rate means I can’t rely on Skills alone for critical workflows. But MCP servers solve this by:
- External workflow definition - Claude can’t reinterpret the steps
- Structured data - Numbered checklist, not prose
- Explicit chaining - Each step names the next skill
- Built-in pitfalls - Known issues documented in workflow
Skills still have value for domain knowledge and reusable patterns. The key is using both together:
- CLAUDE.md routing tables for visibility
- MCP servers for structured execution chains
- Hooks for forced invocation
Summary
In this post, I showed how Claude Code Skills and MCP servers serve different purposes. Skills provide reusable domain knowledge, while MCP servers provide reliable workflow execution. The key is using both together: CLAUDE.md routing tables for visibility, MCP servers for structured workflows, and hooks for critical paths. Skills handle the “what” (domain knowledge, patterns, best practices), while MCP handles the “how” (step-by-step execution, checkpoints, chain invocation).
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments