How to Set Up MCP Servers and Hooks in Claude Code - Web Search, Scraping, and Automation Rules
Connect Claude Code to Perplexity, Firecrawl, and Notion via MCP servers. Build 3 automation hooks for formatting, safety, and quality checks. Full setup guide.
Claude Code couldn’t search the web, always.
That was the limitation I hit first. I’d built a content system (Lesson 1), organized my claude stack extensions (Lesson 2), and then asked Claude Code to research a competitor’s website pages and content structure. It couldn’t do reliably. It had no way to access or fetch outside my project folder and some public web pages.
Same story with my Notion content calendar. Same with checking a live URL. Claude Code knew everything about my local files but not so much about the outside world.
Then I discovered MCP servers and hooks.
MCP servers connect Claude Code to external tools for abilities like web search, web scraping, databases, anything with an API.
Hooks in Claude Code run shell scripts automatically at specific points in Claude Code’s workflow, enforcing rules that Claude can’t ignore.
👋 Julley, I'm Dheeraj, an AI systems builder.
I build production-grade AI systems at work by day and ship my own products by night, 9 and counting, including SubflowAI and the Content OS Agents Toolkit. This newsletter is the bridge between those two worlds. Every system, every build, documented step by step.
Join 1,800+ builders getting the exact AI setups, prompts, and workflows that actually work in your business.
After 60 minutes of setup, my Claude Code could
search the web through Perplexity,
scrape competitor pages through Firecrawl,
read my Notion calendar, and
automatically enforce formatting and safety rules on every single action.
This is Lesson 3 of the Claude Code Full Course. In Lessons 1 and 2, we built a content multiplication system and learned about the 4-layer Claude code extension stack. Today we connect Claude Code to the outside world and add automation that runs without you asking.
Claude Code Masterclass - Full Course
MCP Servers and Automation Hooks ← You are here
MCP servers give Claude Code external intelligence. Hooks give it internal discipline. One without the other is half a system. Together, they turn Claude Code from a smart assistant into a connected, reliable platform.
The locked room and the checklist
Picture a brilliant assistant locked in an office with no internet, no phone, and no access to your company tools. They can organize everything on their desk. But ask them to check a competitor’s website? Impossible. Ask them to update your project tracker? Can’t reach it.
That’s Claude Code without MCP servers. Powerful within your project folder. Blind to everything else.
Now give that assistant internet access, a company login, and a browser. They can research, check databases, pull live data. But here’s the catch: sometimes they forget your formatting rules. Sometimes they run a command you’ve asked them to avoid.
They’re capable but not consistent.
Hooks are the checklists posted at every door. Before the assistant sends an email, they check the formatting list. Before they run a command, they check the safety list. Not because they choose to, but because the checklist is physically there and they can’t skip it.
MCP connects. Hooks enforce. Let’s set up both for your Claude Code setup.
MCP servers: Claude Code meets the outside world
MCP stands for Model Context Protocol.
You add a server, and Claude Code gains new tools it can call - search the web, query a database, post to Slack, read from Notion. (If you want the deeper technical explanation, I covered what MCP is and why it was created in an earlier post.)
No code required. You add a JSON configuration, restart Claude Code, and the new tools appear.
How MCP servers work in Claude Code?
Every MCP server gives Claude Code one or more tools. When Claude Code needs information from an external service, it calls the appropriate tool through the MCP server. The server handles authentication, formatting, and communication with the external service.
The configuration lives in your project (.mcp.json) or globally ( ~/.claude/settings.json or ~/.claude/settings.local.json).
Here’s what a basic setup looks like:
json
{
"mcpServers": {
"server-name": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@package/server-name"],
"env": {
"API_KEY": "your-key-here"
}
}
}
}That’s it. Three fields:
the command to run the server,
any arguments it needs, and
environment variables like API keys.
1. Setting up Perplexity MCP (web search)
This was the first server I added, and the one that changed everything. With Perplexity, Claude Code can search the web in real-time instead of relying JUST on its outdated training data.
Step 1: Get your API key. Go to perplexity.ai, create an account, and generate an API key from the API settings page.
Step 2: Add the server.
bash
claude mcp add perplexity \
--env PERPLEXITY_API_KEY=your-key-here \
-- npx -y @perplexity-ai/mcp-serverStep 3: Verify it works. Type /mcp inside Claude Code. You should see Perplexity listed with its available tools: search and reason.
What it gives you: Claude Code can now answer questions like “What’s the current pricing for Notion’s API?” or “What articles were published about Claude Code hooks this week?” with live data instead of stale training knowledge.
Setup time: about 5 minutes.
Commercial break: Claude Code Builder cohort
The founding batch of my Claude Code cohort starts in July on Maven. Four weeks, six sessions. Learn to build the AI system with me.
Only 12 Seats. When they’re gone, the founding price ($797) closes and Cohort 2 opens at $1,597.
Use code GENAI20 for 20% off. Expires July 9. Check the Syllabus →
2. Setting up Firecrawl MCP (web scraping)
Perplexity searches. Firecrawl reads full pages. When I need Claude Code to analyze a competitor’s landing page or extract content from a blog post, Firecrawl handles it.
Step 1: Get your API key. Sign up at firecrawl.dev and grab your API key.
Step 2: Add the server.
bash
# Remote hosted URL (recommended)
claude mcp add firecrawl --url https://mcp.firecrawl.dev/your-api-key/v2/mcp
# Or run locally via npx
claude mcp add firecrawl -e FIRECRAWL_API_KEY=your-api-key -- npx -y firecrawl-mcpStep 3: Verify. /mcp again. Firecrawl should appear with tools like firecrawl_scrape, firecrawl_search, and firecrawl_map.
What it gives you: “Scrape this article and summarize the key points.” “Extract all headings from this competitor’s course page.” “Map all the URLs on this website.” These all work now.
Setup time: about 5 minutes.
3. Setting up Notion MCP (your content database)
This is the one that made my content pipeline click. Claude Code can now read my content calendar, check post statuses, and update entries from my Notion database and all from inside the Claude Code conversation.
Step 1: Create a Notion integration. Go to notion.so/my-integrations, create a new integration, and copy the API key. Then share your content calendar database with the integration.
Step 2: Add the server.
bash
claude mcp add --transport http notion https://mcp.notion.com/mcpNote: Notion’s official MCP now uses HTTP transport. If you prefer stdio, use npx -y @notionhq/notion-mcp-server instead.
Step 3: Verify. /mcp to confirm. Then try: “List all posts in my Notion content calendar with status Draft.”
What it gives you: Claude Code becomes aware of your content schedule. It can check what’s due, what’s published, and what needs attention without you switching tabs.
Setup time: about 10 minutes (the Notion permissions step takes a moment).
The combined effect
Before MCP: Claude Code could read and write files in my project. That’s it.
After MCP: Claude Code researches topics live, scrapes competitor pages, checks my content calendar, and pulls real-time data into every task.
Three servers. About 25 minutes of total setup.
The quality difference in output was immediate. The research that used to require me switching between five tabs now happens in the same conversation. (I ended up building a dedicated research agent around this exact MCP stack.)
Getting MCP servers and hooks working from scratch takes 2-3 hours of debugging syntax before you run a single connected session.
PluggedIn ships the pre-tested configs, shell scripts, and a complete hooks reference card so you skip the trial-and-error entirely.
Hooks: the rules Claude Code can’t break
Here’s the part nobody else is covering.
Prerequisites for the hooks section
Before setting up hooks, make sure you have these installed:
jq - for JSON parsing in hook scripts. Install with
brew install jq(macOS) orsudo apt-get install jq(Linux)Node.js + npm - for the
npxcommands used in MCP setup. Install from nodejs.orgprettier - for the format-on-save hook. Install globally with
npm install -g prettieror per-project withnpm install --save-dev prettier
All three hook scripts in this lesson use jq to parse the JSON input Claude Code sends them. Without it, you’ll get a command not found: jq error when hooks fire.
CLAUDE.md v/s Hooks
In Lesson 2 linked above, I mentioned that CLAUDE.md is a living document. You add rules, and Claude Code follows them. Most of the time. But “most of the time” isn’t good enough for rules that matter.
I tested this. I put “Always format code with Prettier before saving” in my CLAUDE.md. Over 10 editing sessions, Claude Code followed the instruction 7 times. Three times it forgot.
Not because it’s unreliable. But because instructions in CLAUDE.md are suggestions, not guarantees. Claude Code uses judgment about when to apply them. (This is the same pattern I ran into when training Claude on my brand voice - suggestions work most of the time, but not all of the time.)
Hooks are different. A hook is a shell script that runs automatically at a specific point in Claude Code’s workflow. It doesn’t ask Claude Code to do something. It does it. Every time. No exceptions.
How Hooks work in Claude Code?
Hooks are configured in your settings.json file (either at ~/.claude/settings.json for global hooks or .claude/settings.json for project hooks). Each hook has three parts:
An event - when does it fire?
A matcher - which tools should trigger it?
A hook definition - what does it do?
Claude Code has 18 hook events, grouped by category:
Tool
Event:
PreToolUseWhen it fires: Before any tool runs (block with exit 2)
Tool
Event:
PostToolUseWhen it fires: After any tool completes
Tool
Event:
PermissionRequestWhen it fires: When a permission dialog appears
Tool
Event:
PostToolUseFailureWhen it fires: After a tool call fails
Subagent
Event:
SubagentStartWhen it fires: When a subagent is spawned
Subagent
Event:
SubagentStopWhen it fires: When a subagent finishes
Session
Event:
SessionStartWhen it fires: When a session begins
Session
Event:
SessionEndWhen it fires: When a session terminates
Lifecycle
Event:
StopWhen it fires: When Claude finishes responding
Notification
Event:
NotificationWhen it fires: When Claude sends a notification
(Key events shown. The full 18 include InstructionsLoaded, UserPromptSubmit, ConfigChange, WorktreeCreate, WorktreeRemove, TeammateIdle, TaskCompleted, and PreCompact.)
The 3 you’ll use most: PreToolUse (block dangerous actions), PostToolUse (check/format after changes), and Stop (run cleanup or reporting when Claude finishes).
4 Types of Hooks in Claude Code
Hooks come in 4 types:
commandWhat it does: Runs a shell script
Best for: File formatting, safety checks, validations
httpWhat it does: Calls a URL endpoint
Best for: Webhooks, external service notifications
promptWhat it does: Asks Claude to evaluate
Best for: Context-aware checks (needs LLM judgment)
agentWhat it does: Delegates to an agent
Best for: Complex multi-step evaluations
Today we will build command hooks, the most common type. The others follow the same configuration pattern.
The script communicates back through exit codes:
Exit 0 - everything’s fine, proceed
Exit 2 - block the action, don’t let it happen
Any other code - warning, but don’t block
That exit code 2 is the key. It gives you a hard stop that Claude Code respects every single time.
Hook 1: Auto-format code after every edit
This was the first hook I built. Every time Claude Code edits or creates a file, this hook runs Prettier on it automatically.
Requires prettier in your project or globally: npm install --save-dev prettier (or npm install -g prettier). Without it, the hook runs but skips formatting silently.
The script - save this as .claude/hooks/format-on-save.sh:
bash
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Only format JS/TS/JSON/MD files
if [[ "$FILE_PATH" =~ \.(js|ts|json|md)$ ]]; then
npx prettier --write "$FILE_PATH" 2>&1
fi
exit 0The configuration - add this to .claude/settings.json:
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-on-save.sh"
}
]
}
]
}
}What happens: Every time Claude Code uses the Edit or Write tool, the hook fires after the edit completes. Prettier formats the file. Claude Code doesn’t need to remember the instruction. The formatting just happens.
Result: 10/10 files formatted correctly. Not 7/10. Ten out of ten.
Hook 2: Block dangerous commands
This one has already saved me twice. It prevents Claude Code from running destructive bash commands like rm -rf, git push --force, or git reset --hard.
The script - save as .claude/hooks/block-dangerous.sh:
bash
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
# Block dangerous patterns
DANGEROUS_PATTERNS=(
"rm -rf"
"git push --force"
"git push -f"
"git reset --hard"
"git clean -fd"
"drop table"
"DROP TABLE"
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -q "$pattern"; then
echo "Blocked dangerous command: $COMMAND" >&2
exit 2
fi
done
exit 0The configuration:
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh"
}
]
}
]
}
}Key difference: This uses PreToolUse, not PostToolUse. The hook fires before the command runs. Exit code 2 blocks the command entirely. Claude Code gets feedback explaining why the command was blocked and tries a safer alternative.
The two times it saved me:
once when Claude Code tried
git push --forceto resolve a merge conflict - it would have overwritten my production SubflowAI changes that 40+ beta users were actively using.And once when it tried
rm -rfon a directory that contained files I hadn’t committed yet.
Hook 3: Quality check on new content files
This hook runs a basic quality check every time Claude Code creates or edits a markdown file in my drafts folder. It checks for forbidden phrases from my brand voice guide.
The script - save as .claude/hooks/quality-check.sh:
bash
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Only check markdown files in drafts/
if [[ "$FILE_PATH" != *"drafts/"* ]] || [[ "$FILE_PATH" != *.md ]]; then
exit 0
fi
# Check for forbidden phrases
FORBIDDEN=("revolutionary" "game-changing" "unlock" "unleash" "supercharge" "paradigm" "next-level")
FOUND=""
for phrase in "${FORBIDDEN[@]}"; do
if grep -qi "$phrase" "$FILE_PATH" 2>/dev/null; then
FOUND="$FOUND\n- Found forbidden phrase: '$phrase'"
fi
done
if [ -n "$FOUND" ]; then
echo -e "Brand voice issues detected:$FOUND" >&2
echo "Please revise to remove these phrases." >&2
exit 0 # Warning, not blocking - Claude sees the feedback
fi
exit 0The configuration:
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/quality-check.sh"
}
]
}
]
}
}Design decision: This hook uses exit 0 even when it finds issues. It provides feedback to Claude Code as a warning instead of blocking the edit.
Why? Because sometimes a draft is intentionally rough. I want Claude to know about the issue and fix it in the next pass, not prevent the initial write entirely.
The format hook blocks nothing (just formats). The safety hook blocks destructive commands. The quality hook warns but doesn’t block. Each hook uses the exit code that matches its purpose.
Putting it all together
If you implement all three hooks, your .claude/settings.json needs to merge them under the correct event keys. Here’s the complete configuration:
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-on-save.sh"
},
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/quality-check.sh"
}
]
}
]
}
}Note the structure: PreToolUse and PostToolUse are separate top-level keys. Multiple hooks under the same event get merged into the same array. If you copy each snippet separately and only keep the last one, only the last hook will apply - a common mistake.
The debugging story: the hook that fired too much
My first attempt at the quality-check hook didn’t have the file path filter. It ran on every single file edit - including package.json, settings.json, and config files. Every edit triggered a grep through the file looking for “revolutionary” in a JSON config.
The result: hooks added about 200ms to every file operation. Across a session with 40+ file edits, that was 8 extra seconds of waiting. Not like end of world, but noticeable and pointless.
The fix was the file path filter at the top of the script. Two lines of bash saved 8 seconds per session.
The lesson: always scope your hooks to the files and tools that actually need them. A matcher of Edit|Write combined with a file path check inside the script gives you precision without waste.
MCP + hooks working together in Claude
Here’s where both systems combine into something neither can do alone.
I ask Claude Code to research a topic for my next article.
It calls the Perplexity MCP server, searches the web, pulls current data.
Then it writes a draft based on that research.
The PostToolUse hook on Write automatically checks the draft for forbidden phrases and feeds any issues back to Claude.
Claude revises the draft in the same conversation.
The format hook then cleans up the final output.
One request. Research, write, quality check, format. No manual steps between them.
The MCP servers provide the intelligence (live data, external tools). The hooks provide the discipline (consistent formatting, brand compliance, safety guardrails). I provide the direction. Claude Code handles the execution.
In a typical content session, this combination saves me about 25-30 minutes per article. About 15-20 minutes from not having to manually research in separate tabs, and 10-15 minutes from not having to manually check formatting and brand voice compliance.
👋 Julley, I’m Dheeraj and I’m an AI systems builder.
I build production-grade AI systems at work by day and ship my own products by night (9+). This newsletter is the bridge between those two worlds. Every system, every build, documented step by step.
Join 1,100+ builders getting the exact AI setups, prompts, and production configs that actually work in your business.
The impact numbers of this setup
Here’s what changed in my content creation workflow in Claude Code after adding MCP servers and hooks:
MCP setup time: N/A before, 20-25 minutes one-time after
Hook setup time: N/A before, 15-20 minutes one-time after
Research quality: Limited to training data before, live web data after
Brand voice compliance: ~70% (CLAUDE.md only) before, ~95% (hooks + CLAUDE.md) after
Formatting consistency: Manual check needed before, 100% automatic after
Dangerous commands blocked: 0 (relied on Claude’s judgment) before, all blocked automatically after
Time saved per article: Baseline before, ~25-30 minutes after
The one-time investment of 35-45 minutes pays back on every single content creation session after that.
Why this matters
In Lesson 2, we taught Claude Code to remember your project. Today we taught it to reach outside your project and follow your rules with zero exceptions.
The practical impact:
MCP servers mean Claude Code works with your actual tools - your content calendar, your research sources, your competitor data. Not generic answers from training data or hallucinations.
Hooks mean your standards are enforced automatically. Code is always formatted. Dangerous commands are always blocked. Brand voice is always checked. You stop being the quality control bottleneck.
Together they create a system where you give direction and Claude Code handles research, writing, formatting, and compliance in one continuous flow.
The hooks system is what separates Claude Code from every other AI coding tool. The Agents Toolkit I built packages these patterns (and more) into a ready-to-use system. But the hooks you built today already put you ahead of most Claude Code users.
For my content business, MCP + hooks cut the time between “I have a topic” and “I have a quality-checked draft” from about 1.5 hours to about 45 minutes.
Not because any single piece is dramatically faster, but because the manual checkpoints between steps disappeared.
Your Connected Intelligence Stack
Here’s the complete system you built in this lesson:
MCP provides the intelligence. Hooks enforce the discipline. Skills from Lesson 2 provide the routines. CLAUDE.md provides the memory. Together, they turn Claude Code from a smart assistant into a connected, self-enforcing system.
In Lesson 4 of my Claude Code Full Course, we add the final layer: Claude AI Agents that split the work across separate context windows, so nothing gets forgotten no matter how complex the task.
Key takeaways
MCP servers are Claude Code’s plugin system. Add a JSON config, get new tools. No code required. Setup time per server: 2-5 minutes. The MCP specification is open source - anyone can build a server.
Start with Perplexity for web search. It’s the highest-impact single MCP server. Live research inside Claude Code changes every task that needs current information.
18 hook events, 4 hook types. Most work happens with 3 events (PreToolUse, PostToolUse, Stop) and 1 type (command). But the full event system covers session lifecycle, subagent spawning, permissions, and notifications.
Hooks are deterministic, not probabilistic. CLAUDE.md instructions are suggestions Claude sometimes ignores. Hooks are scripts that run every time, no exceptions. Use hooks for rules that must be followed.
Exit code 2 blocks actions. PreToolUse hooks with exit code 2 prevent dangerous commands before they execute. PostToolUse hooks with exit 0 provide feedback without blocking.
Scope your hooks precisely. Use matchers (
Bash,Edit|Write) and file path filters inside scripts. Unscoped hooks add latency to every operation.MCP connects, hooks enforce. Use MCP for external intelligence (search, scrape, database access). Use hooks for internal discipline (formatting, safety, quality). Together they’re a Connected Intelligence Stack.
Mini exercise (20 minutes)
Add one MCP server to your Claude Code. Perplexity is the best starting point - get your API key and run the
claude mcp addcommand from this lessonVerify it works: type
/mcpand confirm the server appears, then ask Claude Code a question that requires current informationCreate the dangerous-command-blocking hook from this lesson. Save the script, add the configuration to your
.claude/settings.jsonTest the hook: ask Claude Code to run
rm -rf /tmp/test-directoryand verify it gets blockedCreate one more hook for your own workflow - what rule do you want enforced automatically?
That’s 20 minutes to connect Claude Code to the web and add your first safety guardrails. Every session after this starts with more intelligence and more discipline.
Next lesson
In Lesson 4, we build a team. Not of people by of Claude subagents. Three specialized AI workers that research, write, and review in parallel while you focus on strategy. One Claude Code becomes three, and the speed difference is measured in minutes, not percentages.
Get PluggedIn
Stop spending 2-3 hours rebuilding the same MCP configs every time you set up a new machine.
Next machine you set up, that's another 2-3 hours of syntax debugging on configs you've already figured out once.
Get PluggedIn to go from debugging JSON configs and hook exit codes in trial-and-error sessions to dropping in pre-tested files and running your first connected Claude Code session in 20 minutes
Your PluggedIn assets for this post
What’s inside:
format-on-save.sh - Format On Save
mcp-servers-config.json - Mcp Servers Config (config)
quality-check.sh - Quality Check
mcp-test-prompts.pdf - MCP Server Test Prompts
hooks-reference.pdf - Claude Code Hooks - Complete Reference Card
Related reading: Build a competitive-analysis AI agent









