Skip to content

How to Automate Claude Code with Hooks and MCP Servers

Purpose

This post shows how to automate Claude Code using hooks, MCP servers, and the -p flag. The goal is to transform Claude from a reactive tool into a component of repeatable development systems.

The Problem

When I first started using Claude Code, I treated it like a one-shot assistant. I’d open it for individual tasks, manually copy context from various sources, and repeat the same prompts over and over.

Here’s what my workflow looked like:

1. Open Claude Code
2. Copy context from GitHub issue
3. Copy relevant code snippets
4. Paste everything into Claude
5. Ask for code review
6. Manually run prettier on changed files
7. Manually run type checker
8. Commit changes

This worked, but it was tedious. I was spending more time on process than actual development.

The insight that changed my approach came from a Reddit discussion: “The people getting the most value from Claude aren’t using it for individual tasks. They’re building systems where Claude is a component.”

The Solution

Claude Code provides three automation layers that work together:

+------------------+ +------------------+ +------------------+
| HOOKS | | MCP SERVERS | | -p FLAG |
| Event-driven | | External service | | Headless mode |
| automation | | connections | | for scripting |
+------------------+ +------------------+ +------------------+
| | |
v v v
+------------------------------------------------------------------+
| AUTOMATED WORKFLOWS |
| - Auto-format on every edit |
| - Auto-typecheck after changes |
| - Fetch context from GitHub/Slack/databases |
| - Run in CI/CD pipelines |
+------------------------------------------------------------------+

Layer 1: Hooks

Hooks let you run code automatically before or after Claude makes changes. This was the first thing I set up.

I created a hooks configuration in my settings:

~/.claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "prettier --write $FILE_PATH"
},
{
"type": "command",
"command": "npx tsc --noEmit $FILE_PATH"
}
]
}
]
}
}

Now every time Claude edits a file, Prettier formats it and TypeScript checks it. No more manual formatting. No more “forgot to run tsc” errors.

There are three hook types:

PreToolUse - Runs before tool execution (validation, parameter modification)
PostToolUse - Runs after tool execution (linters, formatters, type checkers)
Stop - Runs when sessions end (final verification, cleanup)

Layer 2: MCP Servers

Hooks handle local automation. MCP servers handle external connections.

I was constantly copying information from GitHub issues into Claude. Every session, same thing. Then I discovered MCP servers.

Model Context Protocol servers let Claude connect to external services: Slack, GitHub, databases, APIs. Instead of manual copy-paste, Claude fetches what it needs automatically.

Here’s how I configured GitHub integration:

~/.claude.json
{
"mcpServers": {
"github": {
"command": "mcp-server-github",
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}

Now I can ask Claude to “review the PR at github.com/user/repo/pull/123” and it fetches the PR directly. No manual context gathering.

Other useful MCP servers I’ve configured:

MCP server examples
{
"mcpServers": {
"slack": {
"command": "mcp-server-slack",
"env": { "SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}" }
},
"postgres": {
"command": "mcp-server-postgres",
"args": ["postgresql://user:pass@localhost/mydb"]
},
"fetch": {
"command": "mcp-server-fetch"
}
}
}

The rule of thumb: if you’re constantly copying information into Claude, there’s probably an MCP server that can do it automatically.

Layer 3: The -p Flag

This was the missing piece for CI/CD integration.

The -p flag runs Claude non-interactively. It takes a prompt, executes it, outputs the result, and exits. No interactive interface.

I tried it first with a simple security check:

security-check.sh
#!/bin/bash
# Get changed files in the PR
CHANGED_FILES=$(git diff --name-only origin/main...HEAD)
# Run Claude headless for security review
claude -p "Review these files for security vulnerabilities:
$CHANGED_FILES
Output JSON with:
- file: the file path
- issues: array of security issues
- severity: critical, high, medium, low
- recommendation: how to fix"

The output goes to stdout, so I can pipe it to other tools:

ci-pipeline.sh
# In CI pipeline
claude -p "Review for security issues" | jq '.issues[] | select(.severity == "critical")' | wc -l

If critical issues exist, the CI fails.

Putting It Together

The real power comes from combining all three. Here’s my pre-deploy workflow:

1. Developer pushes code
2. Hook triggers: TypeScript check runs automatically
3. Hook triggers: Prettier formats all changed files
4. CI runs: claude -p "Review for deployment readiness"
5. MCP server: Checks database migration safety via postgres connection
6. MCP server: Posts results to Slack
7. If all checks pass, deployment proceeds

This is what “building systems where Claude is a component” means. Claude isn’t just helping with individual tasks. It’s part of the infrastructure.

Common Mistakes

I made several mistakes while learning this:

1. Over-automating early

I added 12 hooks in my first week. TypeScript broke because Prettier ran before tsc. Then I had circular hook dependencies. Start with one hook, add complexity gradually.

2. Reinventing MCP servers

I spent a day writing a custom GitHub integration before realizing mcp-server-github already existed. Check existing servers first.

3. Forgetting environment variables

My MCP server configs use ${GITHUB_TOKEN} but I forgot to set the environment variable. Claude silently failed. Always test MCP servers with claude mcp list first.

4. Not packaging reusable prompts

I had the same prompt saved in three different places. Then I discovered custom slash commands. Package repeated prompts as commands:

~/.claude/commands/review.md
---
description: Review code for security issues
---
Review the current file for:
1. Security vulnerabilities (OWASP Top 10)
2. Input validation gaps
3. Authentication/authorization issues
4. Sensitive data exposure
Provide severity ratings and specific fix recommendations.

Now I just type /review instead of pasting the full prompt.

Why This Matters

Automation transforms Claude Code from an assistant into infrastructure:

  • Consistency: Every file gets formatted, every edit gets type-checked
  • Efficiency: No manual context gathering - MCP servers fetch what’s needed
  • Scalability: Scriptable workflows work across teams and projects
  • Reliability: Hooks catch issues before they compound

The difference between using Claude Code as a tool versus using it as infrastructure is the difference between a one-time fix and a permanent improvement.

Summary

In this post, I showed how to automate Claude Code using hooks, MCP servers, and the -p flag. Start with a single PostToolUse hook for formatting. Add MCP servers for your most-used external services. Then leverage headless mode for CI/CD integration.

Next steps:

  1. Add one PostToolUse hook for Prettier or ESLint
  2. Install an MCP server for a service you use frequently (GitHub, Slack, your database)
  3. Try the -p flag with a simple code review prompt
  4. Build a workflow that combines all three

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