Skip to content

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:

/Users/zhaocaiwen/.claude/skills/tdd/SKILL.md
# Test-Driven Development Workflow
When user asks to implement features or fix bugs:
1. Write test first (RED)
2. Run test - should FAIL
3. Implement minimal code (GREEN)
4. Run test - should PASS
5. Refactor (IMPROVE)
Verify 80%+ coverage with:
```bash
go test -cover
But 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:

  1. CLAUDE.md routing table - Explicit mapping of triggers to skills
  2. MCP servers - External workflows with structured data
  3. 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:

/Users/zhaocaiwen/.claude/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 first

This 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:

mcp-workflow-server/src/handlers/feature-workflow.ts
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:

/Users/zhaocaiwen/.claude/hooks.yaml
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”:

  1. SessionStart hook fires → detects “authentication” keyword
  2. Hook invokes security-review skill → Claude checks security requirements
  3. CLAUDE.md routing table consulted → maps “auth” to security-first workflow
  4. Skill calls MCP servergetFeatureWorkflow({ featureType: 'auth' })
  5. MCP returns structured workflow:
    {
    "current_step": 1,
    "skill_to_invoke": "plan",
    "reason": "Plan authentication flow before implementation",
    "next_step": 2,
    "next_skill": "tdd"
    }
  6. Claude invokes /plan skill → creates authentication implementation plan
  7. MCP provides step 2 → invoke /tdd skill
  8. Claude invokes /tdd skill → writes tests for auth endpoints
  9. MCP provides step 3 → implement with checkpoints
  10. Claude implements → following plan and test requirements
  11. MCP provides step 4 → invoke /code-review
  12. Claude invokes /code-review skill → reviews auth implementation
  13. Stop hook fires → verifies all checkpoints passed

Result: Workflow completes reliably, no steps skipped, security review enforced.

Skills vs MCP Servers

AspectSkillsMCP Servers
Best ForReusable patterns, domain knowledgeMulti-step workflows, guaranteed execution
InvocationClaude’s judgment (56% skip rate)External workflow definition (0% skip rate)
FormatProse instructions in markdownStructured data (JSON)
VisibilityRequires CLAUDE.md routing tableWorkflow steps returned in real-time
ReliabilityMedium (depends on Claude’s choice)High (external, can’t be reinterpreted)
Use CasesTDD workflows, security patternsFeature implementation, dev pipelines
MaintenanceUpdate skill filesUpdate server endpoints
Chain SupportLimited (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:

  • /plan skill
  • /security-review skill
  • /code-review skill

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:

  1. External workflow definition - Claude can’t reinterpret the steps
  2. Structured data - Numbered checklist, not prose
  3. Explicit chaining - Each step names the next skill
  4. 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