Skip to content

Advanced Claude Code Techniques

You already use Claude Code daily, but you suspect you are leaving capability on the table. The model seems to “think harder” on some prompts than others and you are not sure why. You have heard MCP servers can give Claude direct database and GitHub access, but the config snippets you copied off a blog post silently failed to load. And you keep running one task at a time when you have four independent things to ship.

This guide covers the techniques that separate a casual Claude Code user from someone who drives it like a power tool: controlling reasoning depth, connecting external tools through MCP, writing your own MCP tool, automating reviews in CI, and running genuinely isolated parallel sessions.

  • A correct mental model of extended thinking and how to actually control its depth (effort levels, not magic keywords)
  • A working .mcp.json that loads on the first try, plus the current way to add the GitHub MCP server
  • A minimal, real custom MCP server using the official SDK — copy-paste runnable
  • A GitHub Actions workflow that runs Claude on every PR, triggered by @claude mentions
  • A worktree-based pattern for true parallel work with zero cross-contamination

Extended thinking is enabled by default. It is not a mode you switch on with a keyword — and this is the single most common misconception. Phrases like “think”, “think hard”, and “ultrathink” are interpreted as ordinary prompt text. They do not allocate a thinking-token budget. If you have been sprinkling “ultrathink” into prompts expecting a 128k-token reasoning pass, it was doing nothing special.

How depth is actually controlled depends on the model:

  • On Opus 4.6 and newer (including Opus 4.8 and Fable 5), thinking uses adaptive reasoning. The model dynamically allocates reasoning based on an effort level: low, medium, or high (default). Fable 5 additionally supports xhigh and max for maximum reasoning depth. Set the level in /model, or with the CLAUDE_CODE_EFFORT_LEVEL environment variable.
  • On other models, thinking uses a fixed budget of up to 31,999 tokens drawn from the output budget. Cap it with the MAX_THINKING_TOKENS environment variable. (This variable is ignored on Opus 4.6+ unless you set it to 0, which disables thinking entirely on any model.)

So the lever is the effort level or the token cap — not the wording of your prompt.

Terminal window
# Inside the REPL, raise reasoning depth for a hard task
/model
# Then select Opus with "high" effort, or set it for the session:
export CLAUDE_CODE_EFFORT_LEVEL=high
claude

What you do control with your prompt is the structure of the reasoning. Asking Claude to work through a problem in explicit stages reliably produces better results than a one-line request, regardless of effort level.

Model Context Protocol (MCP) servers give Claude direct, structured access to external systems — GitHub, a database, a browser — instead of you copy-pasting context. The setup that bites people is the config file format and pointing at archived reference packages.

The GitHub MCP server is now a remote HTTP server, not a global npm install. Add it with one command:

Terminal window
claude mcp add --transport http github https://api.githubcopilot.com/mcp/

For local stdio servers (a database, a browser), you configure them in .mcp.json at your project root. The top-level key is mcpServers — not servers. With the wrong key the file is silently ignored.

{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL}"]
},
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp@latest"]
}
}
}

A few things worth knowing that the snippets you find online usually get wrong:

  • Stdio MCP servers run through npx (or uvx for Python-only servers). There is no npm install -g step — npx fetches and runs them on demand.
  • @modelcontextprotocol/server-postgres is a legacy reference server. It still resolves on npm, but treat it as a starting point; many teams move to a maintained vendor server.
  • For browser automation use @playwright/mcp, not the archived server-puppeteer.

Once a server is loaded, you stop describing context and start asking for outcomes:

# With the GitHub MCP server
Open an issue for the login 500s, tag it "bug" and "auth", and link the
three most recent commits that touched src/auth/.
# With the Postgres MCP server
Show me the schema for the users table, then find accounts with no login
in the last 30 days.

When no off-the-shelf server fits — you want Claude to trigger your deploy script, hit an internal API, or run a proprietary tool — write a small one. Use the official SDK, @modelcontextprotocol/sdk. The API is McpServer with registerTool, connected over a transport.

deploy-mcp-server.ts
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
const server = new McpServer({ name: 'project-tools', version: '1.0.0' });
server.registerTool(
'deploy-staging',
{
description: 'Deploy the given branch to the staging environment',
inputSchema: { branch: z.string() },
},
async ({ branch }) => {
// Call your real deploy pipeline here.
const url = `https://staging.example.com/${branch}`;
return { content: [{ type: 'text', text: `Deployed ${branch} -> ${url}` }] };
}
);
await server.connect(new StdioServerTransport());

Register it in .mcp.json like any other stdio server, then ask Claude to deploy a branch by name. Custom servers shine for deployment automation, internal API access, and any workflow that touches tools only your team has.

You can have Claude review every pull request automatically. This runs through GitHub Actions and the anthropics/claude-code-action, not a YAML config file at .github/claude-code-review.yml (that path does not exist).

  1. Install the GitHub app

    Run this inside the Claude Code REPL. It walks you through installing the app and adding the required secrets:

    /install-github-app
  2. Add the workflow file

    Copy the example workflow into .github/workflows/claude.yml. A minimal automated review looks like this:

    .github/workflows/claude.yml
    name: Claude Review
    on:
    pull_request:
    types: [opened, synchronize]
    jobs:
    review:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v5
    - uses: anthropics/claude-code-action@v1
    with:
    anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
    prompt: |
    Review this PR. Report only real issues, grouped by:
    security, correctness, missing error handling.
    Be concise. Skip style nits.

    The instruction goes in the prompt input. (direct_prompt is the deprecated v0.x name — use prompt on @v1.)

  3. Trigger it on demand from a comment

    With the action installed, mention @claude in any PR or issue comment and it responds:

    @claude review this PR for security issues
    @claude suggest improvements to the error handling in src/api/

The pattern that works well in practice: let the Action post an automated first pass on every PR, and reserve @claude mentions for targeted follow-ups (“explain this resolution”, “check the migration for backwards compatibility”). Claude catches mechanical issues so human reviewers can focus on design and intent.

When you have several independent tasks — a feature, an urgent hotfix, a migration — you want each one isolated so they cannot step on each other. The primitive for that is git worktrees, one per task. A common mistake is reaching for --add-dir: that flag adds extra directories to a single session for context, it does not create isolated parallel instances.

Give each task its own worktree, then run a separate Claude session in each:

Terminal window
# One worktree (and branch) per task
git worktree add ../app-feature -b feature/notifications
git worktree add ../app-hotfix -b hotfix/auth-timeout
# Terminal 1
cd ../app-feature && claude
# Terminal 2
cd ../app-hotfix && claude

Each session has its own context and sees only the files in its worktree, so there is zero cross-contamination. When a task is done, remove its worktree with git worktree remove ../app-feature. For the full worktree workflow, see Version Control.

If you only need a fresh branch off the same starting point (not full file isolation), claude --resume <id> --fork-session gives each terminal a clean session without a second working directory.

Claude Code can help tighten how you use Claude Code. The highest-leverage move is curating your CLAUDE.md so the model stops repeating context you give it manually.

For navigation-heavy editing, enable Vim keybindings with the /vim command (or set it permanently via /config). It gives you hjkl motion, text objects, and . to repeat the last change in the input editor.

Reasoning stays shallow no matter what you type — On Opus 4.6+, depth is set by effort level, not prompt wording. Run /model and select high effort. “Think harder” in the prompt does nothing.

MAX_THINKING_TOKENS seems ignored — It is ignored on Opus 4.6+ (adaptive reasoning controls depth there). Use the effort level instead. The only exception is MAX_THINKING_TOKENS=0, which disables thinking on any model.

MCP server does not load — Check the top-level key in .mcp.json is mcpServers, not servers. Verify the server appears with claude mcp list, and run claude --debug "mcp" to see startup errors. For stdio servers, confirm the npx/uvx command runs on its own in a terminal.

GitHub Action does not respond to @claude — Confirm the app is installed (/install-github-app), the ANTHROPIC_API_KEY secret exists, and the workflow lives at .github/workflows/claude.yml. If you copied an older example, replace the direct_prompt input with prompt.

Parallel sessions interfere — You are probably sharing a directory. Give each task its own worktree; --add-dir does not isolate sessions, it only adds context paths to one session.

With these techniques in hand, learn how to scale them across a team. Continue to Team Collaboration for collaborative AI-assisted development patterns.