Day 24: MCP in Practice - Real Workflows With GitHub Connected

Real GitHub MCP workflows for Claude Code. Issue-driven development, PR reviews, repo intelligence, cross-context. Complete loop: issue to PR without switching.

Day 24: MCP in Practice - Real Workflows With GitHub Connected

Hey, it's G.

Day 24 of the Claude Code series.

Day 23 was setup — connecting GitHub MCP in 10 minutes.

Day 24 is where it gets real.

Today I learned how to actually use GitHub MCP in production — not just "list my issues" but full workflows where Claude Code reads a GitHub issue, understands the codebase, implements the feature, and creates the PR.

That's a different level from anything in Phase 2.

The connection between live GitHub data and local file context is where MCP becomes genuinely powerful.


The Problem (GitHub and Code Are Separate Worlds)

Here's what used to happen before MCP:

Step 1: Check GitHub

Open browser. Read the issue. Copy the description.

Step 2: Switch to Terminal

Paste issue description to Claude Code. Explain what needs to be built.

Step 3: Build

Claude implements based on your description.

Step 4: Switch Back to Browser

Create the PR manually. Write description. Link to issue.

Step 5: Update Issue

Comment that it's done. Close the issue.


Five context switches.

Three tools: browser, terminal, browser again.

You were the human bridge between your project management and your code.


The Concept (MCP Closes the Loop)

Having GitHub MCP connected gives Claude Code two things it didn't have before:

1. Live Context

Real data from your GitHub.

Issues, PRs, comments, labels, repo metadata.

Not a description of what's in your repo.

The actual data.

2. Actionability

Claude Code can not only read GitHub data but act on it.

Create issues. Comment on PRs. Update labels. Push changes.


The real power isn't either of these alone.

It's combining GitHub context with local file context.


Claude Code can:

  • Read an issue on GitHub
  • Look at your local codebase to understand the relevant files
  • Implement the fix
  • Create a PR
  • Update the issue

All in one session without you doing anything manually in between.


Think of it as closing the loop between your project management and your code.

Before MCP those two worlds were separate.

You'd read an issue in the browser, switch to your terminal, explain what the issue said to Claude Code, then switch back to GitHub to create the PR.

MCP removes every one of those manual switches.


The Four Workflow Categories

There are four workflow categories worth building habits around:

1. Issue-Driven Development

Work directly from GitHub issues

2. PR Workflows

Review, analyze, and respond to PRs

3. Repo Intelligence

Ask questions about your repo state

4. Cross-Context Workflows

Combining GitHub data with local code context


Workflow 1: Issue-Driven Development

Pattern 1: Read and Prioritize Your Backlog

claude
Read all open issues in this repo.

Group them by type (bug, feature, chore) based on labels.

Within each group, suggest a priority order and explain why.

Claude responds:

Reading all open issues...

Found 12 open issues. Here's the breakdown:

BUGS (5 issues):
High Priority:
1. #47 "Mobile layout broken on expense page"
   - Labeled: bug, high-priority
   - Affects paying users
   - Multiple reports in comments

2. #41 "Null user state crashes dashboard"
   - Labeled: bug, critical
   - Blocks new users from onboarding
   - Should fix immediately

Medium Priority:
3. #38 "CSV export missing currency formatting"
   - Labeled: bug
   - Annoying but not blocking

[continues...]

Recommendation: Start with #41 (dashboard crash) 
then #47 (mobile layout). Both affect user experience 
and have been open for 3+ days.

Pattern 2: Implement Directly from an Issue

Read issue #28.

Understand what it's asking for, then look at the 
relevant files in our codebase.

Implement the feature following our CLAUDE.md conventions.

Tell me which files you changed and why before committing.

Claude responds:

Reading issue #28...

Issue requests: "Add CSV export button to expenses page"
Acceptance criteria from issue:
- Button in header next to "Add Expense"
- Exports all user's expenses as CSV
- Includes: date, amount, category, notes
- Filename: expenses_YYYY-MM-DD.csv

Looking at relevant files...
- /app/expenses/page.tsx (where button goes)
- /utils/csv.ts (existing CSV helper)
- /app/api/expenses/route.ts (data source)

Planning implementation...
[/plan output]

Ready to implement. Proceed?

You approve. Claude builds it.

When done:

Implementation complete.

Files changed:
1. /app/expenses/page.tsx
   - Added CSV export button in header
   - Triggers download on click

2. /utils/csv.ts
   - Added exportExpensesToCSV() function
   - Formats data matching issue requirements

3. No API changes needed (existing endpoint works)

Following CLAUDE.md conventions:
- Used existing Button component
- Matches header button pattern from other pages
- Error handling matches utils pattern

Ready to review.

Pattern 3: Create an Issue from a Bug You Found

Create a GitHub issue for the bug we just fixed.

Title: "Null user state on dashboard initial render"
Label it as bug.
Include what caused it and how we fixed it in the body.

Claude responds:

Creating GitHub issue...

Issue created: #52
Title: "Null user state on dashboard initial render"
Labels: bug
URL: https://github.com/yourusername/yourrepo/issues/52

Issue body:
---
## Bug Description
Dashboard crashes on initial render when user state is null.

## What Caused It
The dashboard component accessed user.displayName before 
checking if user exists. New users or logged-out sessions 
trigger this.

## How We Fixed It
Added conditional check in /app/dashboard/page.tsx:
- Check user exists before accessing properties
- Show loading state while user loads
- Handle null case gracefully

## Fixed In
Commit: abc123f
Files: /app/dashboard/page.tsx
---

Issue #52 created successfully.

Workflow 2: PR Workflows

Pattern 1: Review an Incoming PR

claude
Read PR #34.

Review the changes for:
- Bugs or logic errors
- Violations of our CLAUDE.md conventions
- Missing tests
- Anything risky to merge

Give me a summary before I review it myself.

Claude responds:

Reading PR #34 "Add dark mode toggle"...

PR Summary:
- 4 files changed
- Adds theme toggle to settings page
- Uses Tailwind dark mode classes

Review findings:

✓ LOOKS GOOD:
- Follows Tailwind convention from CLAUDE.md
- Component structure matches our pattern
- Dark mode toggle persists to localStorage

⚠️ CONCERNS:
1. Missing tests
   - No test for theme toggle component
   - No test for localStorage persistence

2. Incomplete implementation
   - Settings page has dark mode
   - But other pages don't apply dark classes yet
   - User toggles dark mode, only sees it on settings

3. Convention violation
   - Uses 'let' instead of 'const' in theme.ts
   - CLAUDE.md specifies const by default

RECOMMENDATION: Request changes
- Ask for component tests
- Ask to apply dark mode globally or mark as WIP
- Fix const/let issue

Not safe to merge as-is.

Pattern 2: Check if a PR Is Ready to Merge

Look at PR #34.

Is it safe to merge? Check:
- All review comments addressed
- CI checks passing
- No obvious conflicts with recent changes in main

Claude responds:

Checking PR #34 status...

Review Status:
✓ All review comments addressed
✓ Requested changes implemented
✓ Author responded to all feedback

CI Status:
✓ All checks passing
✓ Build successful
✓ Tests passing (12/12)
✓ Lint passing

Conflict Check:
✓ No conflicts with main
✓ PR branch is up to date
✓ Recent changes in main don't affect this PR

SAFE TO MERGE ✓

Recommendation: Approve and merge.
All concerns addressed, CI green, no conflicts.

Pattern 3: Write a PR Description

Look at the git diff from this session.

Create a GitHub PR with a proper title and description.

Link it to issue #28 that we were working from.

Claude responds:

Creating GitHub PR...

PR created: #53
Title: "Add CSV export to expenses page"
Linked to: #28

PR Description:
---
Closes #28

## What This Adds
CSV export button on expenses page allowing users to 
download all their expenses as a CSV file.

## Changes Made
- Added export button in page header
- Created exportExpensesToCSV() utility function
- Filename format: expenses_YYYY-MM-DD.csv
- Includes: date, amount, category, notes

## Testing
- Tested with 0 expenses (downloads empty CSV)
- Tested with 100+ expenses (all included)
- Verified currency formatting
- Verified date format (YYYY-MM-DD)

## Files Changed
- /app/expenses/page.tsx
- /utils/csv.ts
---

PR #53 created and ready for review.

Workflow 3: Repo Intelligence

Pattern 1: Get a Snapshot of Your Repo State

claude
Give me a status report on this repo:
- How many open issues and their breakdown by label
- Any PRs waiting for review
- Most recently closed issues
- Anything that looks stuck or overdue

Claude responds:

Reading repo status...

OPEN ISSUES (12 total):
- bug: 5 (2 high-priority, 3 medium)
- feature: 4 (1 in-progress)
- chore: 3 (all maintenance tasks)

PRS WAITING FOR REVIEW (3):
1. #51 "Add email notifications" (opened 2 days ago)
   - 2 approvals needed
   - CI passing

2. #49 "Refactor auth flow" (opened 5 days ago)
   - No reviews yet
   - CI passing
   - ⚠️ Getting stale

3. #46 "Update dependencies" (opened 1 week ago)
   - 1 approval, needs 1 more
   - CI passing

RECENTLY CLOSED (last 7 days):
- #48 "Fix mobile layout" (merged 1 day ago)
- #45 "Add loading states" (merged 3 days ago)
- #43 "Improve error handling" (merged 5 days ago)

⚠️ ATTENTION NEEDED:
- PR #49 has been waiting 5 days with no reviews
- Issue #41 (critical bug) has been open 10 days
- 3 issues labeled "help-wanted" with no activity

Recommendation: Review PR #49 and fix issue #41 today.

Before I start building the subscription feature,
search our issues for anything related to 
subscriptions, billing, or Stripe.

I don't want to duplicate something already tracked.

Claude responds:

Searching for related issues...

Found 4 issues related to subscriptions/billing:

OPEN:
1. #35 "Add subscription upgrade flow"
   - Opened 2 weeks ago
   - Labeled: feature
   - Assigned to: @teammate
   - ⚠️ This overlaps with what you're building

2. #29 "Fix Stripe webhook for cancellations"
   - Opened 3 weeks ago
   - Labeled: bug
   - No assignee
   - Might affect subscription feature

CLOSED:
3. #22 "Integrate Stripe checkout" (merged last month)
4. #15 "Add subscription plans page" (merged 2 months ago)

RECOMMENDATION:
Check with teammate on #35 before proceeding — 
possible duplicate work. Fix #29 first — broken 
webhook will affect any subscription work.

Want me to read #35 in detail to check overlap?

Pattern 3: Understand Recent Changes

Read the last 3 merged PRs.

Summarize what changed in each and whether any of them
might affect the feature I'm about to build.

Claude responds:

Reading recent merged PRs...

LAST 3 MERGED:

1. PR #48 "Fix mobile layout on expense page"
   - Merged 1 day ago
   - Fixed: responsive design on expenses
   - Files: /app/expenses/page.tsx, /styles/globals.css
   - Impact: ⚠️ Modified expenses page you're working on
   - Recommendation: Pull latest before continuing

2. PR #45 "Add loading states to all pages"
   - Merged 3 days ago
   - Added: skeleton loaders for 7 pages
   - Pattern: if (!data) return <Skeleton />
   - Impact: ✓ New pattern to follow for loading states

3. PR #43 "Improve error handling in API routes"
   - Merged 5 days ago
   - Changed: standardized error format across APIs
   - Pattern: try/catch with consistent error shape
   - Impact: ✓ Use this pattern for any API work

ACTIONS NEEDED:
1. git pull to get PR #48 changes
2. Follow loading state pattern from #45
3. Follow error handling from #43

Want me to pull latest and continue?

Workflow 4: Cross-Context (The Most Powerful)

Pattern 1: Full Loop — Issue → Code → PR

claude
Read issue #35.

Look at the relevant files in our codebase.

/plan

[approve plan]

[Claude implements]

/review

Create a PR linking to issue #35.

Use the changes from this session as the PR diff.

This is the complete loop:

  1. Claude reads GitHub issue
  2. Claude understands acceptance criteria
  3. Claude looks at local codebase
  4. Claude plans implementation
  5. You approve
  6. Claude implements
  7. You review
  8. Claude creates PR with proper description
  9. Claude links PR to issue

Zero manual steps between issue and PR.


Pattern 2: Debug with GitHub Context

There's a bug report in issue #41.

Read the issue to understand what the user reported.

Then look at the relevant code and find the root cause.

Fix it and add a comment to the issue describing 
what caused it and what we did to fix it.

Claude responds:

Reading issue #41...

User reported: "Dashboard crashes immediately after login"
Steps to reproduce: Login → Dashboard loads → Error screen
Error message: "Cannot read properties of undefined (reading 'displayName')"

Looking at dashboard code...

Root cause found in /app/dashboard/page.tsx:
- Line 23: Accessing user.displayName before checking if user exists
- Race condition: Dashboard renders before user fetch completes
- No null check on user object

Implementing fix...
- Added conditional: if (!user) return <LoadingSkeleton />
- User fetch completes → dashboard renders with data
- No more crashes

Adding comment to issue #41...

Comment added:
---
Found and fixed the root cause:

The dashboard was accessing user.displayName before verifying 
the user object exists. This created a race condition where 
the component would render before the user fetch completed.

Fixed by adding a null check and loading state:
```tsx
if (!user) return <LoadingSkeleton />

This ensures user data is loaded before attempting to access properties. Fix tested and working.

Commit: abc123f

Bug fixed and issue updated.


---

### Pattern 3: Sync Code with Issue Tracker

Look at what we built in this session.

Find the GitHub issue this relates to and close it.

Add a comment explaining what was implemented.


---

**Claude responds:**

Reviewing session changes...

Changes made:

  • Added CSV export to expenses page
  • Created exportExpensesToCSV() utility
  • Added tests for export function

Searching for related issue...

Found: Issue #28 "Add CSV export button to expenses page"

This session fully implements #28.

Closing issue and adding comment...

Comment added to #28:

Implemented in PR #53.

Added CSV export button to expenses page with:

  • Export button in header
  • Downloads expenses_YYYY-MM-DD.csv
  • Includes: date, amount, category, notes
  • Tested with 0 and 100+ expenses
  • Handles currency and date formatting correctly

Ready for review.

Issue #28 closed and linked to PR #53.


---

## Complete Real Session Example

**Let me walk you through a full issue-to-PR workflow in one session.**

---

### The Task

Implement the feature described in issue #42: "Add empty state to subscriptions page"

---

### Step 1: Read and Understand the Issue

```bash
cd ~/projects/my-app
claude
Read issue #42 — "Add empty state to subscriptions page"

Claude responds:

Reading issue #42...

Issue Summary:
User requests empty state component for when they have 
no active subscriptions.

Acceptance Criteria:
- Show empty state when subscriptions array is empty
- Include message: "No active subscriptions"
- Add CTA button: "Upgrade to Pro"
- Match design system style

Labels: feature, good-first-issue
Opened: 3 days ago
Comments: 1 (designer provided mockup link)

Ready to implement?

Step 2: Understand Codebase Context

Look at /app/subscriptions/page.tsx and the existing
empty state pattern in /app/dashboard/page.tsx

Tell me how to implement this consistently.

Claude responds:

Reading files...

Current state in /app/subscriptions/page.tsx:
- Fetches subscriptions
- Maps to subscription cards
- No empty state handling

Existing pattern from /app/dashboard/page.tsx:
- Uses <EmptyState> component from /components/EmptyState.tsx
- Props: icon, title, description, ctaText, ctaHref
- Centered layout with icon + text + button

Recommended implementation:
1. Import EmptyState component
2. Add conditional: if (subscriptions.length === 0)
3. Props:
   - icon: CreditCard (from lucide-react)
   - title: "No active subscriptions"
   - description: "Upgrade to Pro to unlock premium features"
   - ctaText: "Upgrade to Pro"
   - ctaHref: "/billing"

Matches existing pattern. Proceed?

Step 3: Plan

/plan

Claude shows implementation plan. You approve.


Step 4: Execute

Looks good. Go ahead.

Claude implements the empty state.


Step 5: Review

/review

All clear.


Step 6: Create the PR

Create a GitHub PR for these changes.

Title: "Add empty state to subscriptions page"
Link it to issue #42.
Describe what was added and why in the PR body.

Claude responds:

Creating PR...

PR #54 created
Title: "Add empty state to subscriptions page"
Linked to: #42

PR Description:
---
Closes #42

## What This Adds
Empty state component for subscriptions page when user 
has no active subscriptions.

## Implementation
- Uses existing EmptyState component pattern
- Shows when subscriptions.length === 0
- Matches design from dashboard empty state
- CTA links to billing page for upgrade

## Testing
- Tested with 0 subscriptions (shows empty state)
- Tested with 1+ subscriptions (shows subscription cards)
- CTA button navigates to /billing correctly

## Screenshot
[Empty state with credit card icon and upgrade CTA]
---

PR ready for review.

Step 7: Close the Issue

Add a comment to issue #42 saying it's been 
implemented and the PR is ready for review.

Claude responds:

Adding comment to issue #42...

Comment added:
---
Implemented in PR #54 ✓

Added empty state component to subscriptions page using 
the existing EmptyState pattern from dashboard.

Shows when user has no subscriptions with upgrade CTA.

Ready for review.
---

Issue updated successfully.

Done.

Issue read. Feature built. PR created. Issue updated.

Never left the terminal.


Why This Matters

The manual switches between your code editor, GitHub, and Claude Code were invisible friction.

You didn't notice how much time they cost until they disappeared.


MCP in practice isn't about any single workflow.

It's about the cumulative effect of removing that friction from every session.


Issue-driven development becomes automatic.

PR reviews happen in context.

Your repo state is always a prompt away.


The developers shipping fastest right now aren't working harder.

They've removed the friction from their tools.


My Raw Notes (Unfiltered)

The full loop workflow is the one that changed how I work day to day.

Reading the issue inside the session means Claude has the actual acceptance criteria in context — no more me paraphrasing what the issue said.

Creating the PR from inside Claude Code sounds small but it means the PR description actually reflects what was done instead of me writing a lazy one-liner.

The repo intelligence prompts are underrated — asking for a status report at the start of a session instead of clicking around GitHub for 5 minutes is a habit I picked up immediately.

Cross-context is where it gets genuinely powerful — GitHub data plus local file context is a combination that didn't exist before MCP.


Tomorrow (Day 25 Preview)

Topic: Building Your Own MCP Server — when it makes sense to build one and how to get started.

What I'm covering:

  • When to build vs use existing servers
  • Anatomy of an MCP server
  • Simple example: custom project management tool
  • Publishing for others to use

When it's worth it: When you have an internal tool or API that needs Claude Code integration and no public server exists.


Following This Series

Phase 1 (Days 1-7): Foundations

Phase 2 (Days 8-21): Getting Productive

Phase 3 (Days 22-30): Power User ⬅️ You are here

So far in Phase 3:


G

P.S. - The full loop workflow: read issue → understand codebase → implement → create PR → update issue. Zero context switching. All in the terminal.

P.P.S. - Repo intelligence is underrated. "Give me a status report" beats clicking around GitHub for 5 minutes.

P.P.P.S. - Cross-context workflows (GitHub data + local files) are the most powerful. That combination didn't exist before MCP.