Gemini Integration Workshop Exercises
workshop claude-code gemini typescript hands-on
Workshop Overview
This workshop teaches TypeScript developers how to integrate Claude Code with Google’s Gemini models to leverage their 1M+ context window capabilities. Through hands-on exercises, you’ll learn to build applications that can process entire codebases, analyze large documents, and orchestrate multiple AI models effectively.
Prerequisites
- Node.js 18+ and npm/pnpm
- Basic TypeScript knowledge
- Claude Code CLI installed
- Google Cloud account with Gemini API access
Setup Instructions
# Clone the workshop repository
git clone https://github.com/your-org/claude-gemini-workshop
cd claude-gemini-workshop
# Install dependencies
pnpm install
# Copy environment template
cp .env.example .env
# Add your API keys to .env:
# CLAUDE_API_KEY=your_claude_key
# GEMINI_API_KEY=your_gemini_keyExercise 1: Basic MCP Server Setup
Objective: Create a basic MCP server that bridges Claude Code with Gemini API.
Exercise 1.1: Create Your First MCP Server
// exercises/01-basic-mcp/server.ts
// TODO: Import required packages
// TODO: Initialize Gemini client
// TODO: Create MCP server with basic configuration
// Your task: Complete this server implementation
export function createBasicMCPServer() {
// Hint: Use McpServer from @modelcontextprotocol/sdk
// Initialize with name, version, and description
}
// Test your implementation
// Run: pnpm test:exercise-1.1Exercise 1.2: Implement a Simple Tool
// exercises/01-basic-mcp/tools.ts
// TODO: Implement a tool that sends text to Gemini and returns the response
// Your task: Complete this tool implementation
export function createAnalysisTool(server: McpServer) {
// Hint: Use server.tool() method
// Define inputSchema with zod
// Call Gemini API in the handler
}
// Expected behavior:
// - Accept 'content' and 'prompt' as inputs
// - Send to Gemini 1.5 Flash
// - Return the responseExercise 1.3: Register and Test
# Register your MCP server with Claude Code
# TODO: Write the command to register your server
# Test the integration
# TODO: Write a query to Claude that uses your new toolSuccess Criteria:
- MCP server starts without errors
- Tool appears in Claude’s available tools
- Can successfully call Gemini through Claude
Exercise 2: Large Context Processing
Objective: Build a system that can analyze entire codebases using Gemini’s 1M token context.
Exercise 2.1: Codebase Loader
// exercises/02-large-context/codebase-loader.ts
import { glob } from 'glob';
import fs from 'fs/promises';
interface CodebaseFile {
path: string;
content: string;
language: string;
}
// TODO: Implement a function that loads an entire codebase
export async function loadCodebase(
rootPath: string,
options?: {
include?: string[];
exclude?: string[];
maxFileSize?: number;
}
): Promise<CodebaseFile[]> {
// Your implementation here
// Hint: Use glob patterns to find files
// Filter by file extensions
// Read file contents
// Detect language from extension
}
// Bonus: Implement token counting
export function estimateTokens(files: CodebaseFile[]): number {
// Implement token estimation
}Exercise 2.2: Context-Aware Analysis Tool
// exercises/02-large-context/analysis-tool.ts
// TODO: Create an MCP tool that analyzes large codebases
export function createCodebaseAnalysisTool(server: McpServer) {
server.tool(
"analyze-codebase",
{
description: "Analyze an entire codebase with Gemini",
inputSchema: z.object({
path: z.string(),
analysisType: z.enum([
"architecture",
"security",
"performance",
"quality"
]),
// TODO: Add more schema fields
})
},
async (inputs) => {
// TODO: Implement the analysis logic
// 1. Load the codebase
// 2. Check token count
// 3. Choose appropriate Gemini model
// 4. Send to Gemini with structured prompt
// 5. Return formatted results
}
);
}Exercise 2.3: Implement Caching
// exercises/02-large-context/cache.ts
// TODO: Implement a caching layer for large context operations
interface CacheEntry {
key: string;
content: string;
timestamp: number;
metadata: Record<string, any>;
}
export class ContextCache {
// TODO: Implement cache methods
async get(key: string): Promise<CacheEntry | null> {
// Your implementation
}
async set(key: string, content: string, metadata?: Record<string, any>): Promise<void> {
// Your implementation
}
async invalidate(pattern: string): Promise<number> {
// Your implementation
}
}
// Bonus: Implement LRU eviction
// Bonus: Add persistent storage optionSuccess Criteria:
- Can load codebases up to 1M tokens
- Correctly chooses Gemini model based on size
- Cache reduces repeated processing time by >50%
Exercise 3: Model Orchestration
Objective: Build an intelligent routing system that uses Claude for reasoning and Gemini for large context processing.
Exercise 3.1: Task Router
// exercises/03-orchestration/router.ts
interface Task {
id: string;
type: 'analysis' | 'generation' | 'question' | 'comparison';
content: string;
context?: string;
requirements: string[];
}
interface RoutingDecision {
primary: 'claude' | 'gemini';
strategy: 'direct' | 'sequential' | 'parallel';
reason: string;
}
// TODO: Implement intelligent task routing
export class TaskRouter {
async route(task: Task): Promise<RoutingDecision> {
// TODO: Implement routing logic based on:
// - Content size (token count)
// - Task type
// - Complexity indicators
// - Performance requirements
}
async execute(task: Task): Promise<any> {
// TODO: Execute based on routing decision
}
}
// Test cases to handle:
// 1. Small reasoning task -> Claude only
// 2. Large document analysis -> Gemini then Claude
// 3. Code generation -> Claude with Gemini contextExercise 3.2: Parallel Processing
// exercises/03-orchestration/parallel.ts
// TODO: Implement parallel model execution
export class ParallelOrchestrator {
async comparativeAnalysis(
content: string,
prompts: string[]
): Promise<Map<string, any>> {
// TODO: Send same content to multiple models/prompts
// Aggregate and compare results
// Handle partial failures
}
async consensusDecision(
question: string,
context: string,
models: string[]
): Promise<{
consensus: string;
confidence: number;
dissent: string[];
}> {
// TODO: Get responses from multiple models
// Find consensus
// Calculate confidence score
}
}Exercise 3.3: Sequential Pipeline
// exercises/03-orchestration/pipeline.ts
// TODO: Build a multi-stage processing pipeline
interface PipelineStage {
name: string;
model: 'claude' | 'gemini';
transform: (input: any) => Promise<any>;
}
export class ProcessingPipeline {
private stages: PipelineStage[] = [];
addStage(stage: PipelineStage): this {
// TODO: Add stage to pipeline
return this;
}
async execute(input: any): Promise<any> {
// TODO: Execute stages sequentially
// Pass output of each stage to next
// Handle errors gracefully
}
}
// Example usage:
// pipeline
// .addStage({ name: 'load', model: 'gemini', transform: loadLargeDoc })
// .addStage({ name: 'analyze', model: 'gemini', transform: analyzeStructure })
// .addStage({ name: 'summarize', model: 'claude', transform: createSummary })Success Criteria:
- Router correctly assigns tasks based on characteristics
- Parallel execution improves performance by >30%
- Pipeline maintains context between stages
Exercise 4: Production Features
Objective: Add production-ready features including monitoring, error handling, and cost optimization.
Exercise 4.1: Comprehensive Error Handling
// exercises/04-production/error-handling.ts
// TODO: Implement production error handling
export class ProductionErrorHandler {
async withRetry<T>(
operation: () => Promise<T>,
options?: {
maxRetries?: number;
backoff?: 'linear' | 'exponential';
onRetry?: (attempt: number, error: Error) => void;
}
): Promise<T> {
// TODO: Implement retry logic with backoff
}
async withFallback<T>(
primary: () => Promise<T>,
fallbacks: Array<() => Promise<T>>
): Promise<T> {
// TODO: Try primary, then fallbacks in order
}
async withCircuitBreaker<T>(
operation: () => Promise<T>,
breakerConfig: {
threshold: number;
timeout: number;
resetTimeout: number;
}
): Promise<T> {
// TODO: Implement circuit breaker pattern
}
}Exercise 4.2: Performance Monitoring
// exercises/04-production/monitoring.ts
// TODO: Build a monitoring system
interface Metric {
timestamp: Date;
operation: string;
duration: number;
tokensIn: number;
tokensOut: number;
model: string;
success: boolean;
error?: string;
}
export class PerformanceMonitor {
private metrics: Metric[] = [];
async track<T>(
operation: string,
fn: () => Promise<T>,
metadata?: Partial<Metric>
): Promise<T> {
// TODO: Track operation performance
}
getStats(timeRange?: { start: Date; end: Date }) {
// TODO: Calculate statistics
// - Average latency by model
// - Success rate
// - Token usage trends
// - Cost analysis
}
async exportMetrics(format: 'json' | 'csv' | 'prometheus') {
// TODO: Export metrics in requested format
}
}Exercise 4.3: Cost Optimization
// exercises/04-production/cost-optimizer.ts
// TODO: Implement cost optimization strategies
interface ModelCosts {
[model: string]: {
inputCost: number; // per 1K tokens
outputCost: number; // per 1K tokens
};
}
export class CostOptimizer {
constructor(private costs: ModelCosts, private budget: number) {}
async optimizeRequest(
content: string,
requirements: {
quality: 'high' | 'medium' | 'low';
speed: 'fast' | 'normal' | 'slow';
accuracy: number; // 0-1
}
): Promise<{
model: string;
strategy: string;
estimatedCost: number;
}> {
// TODO: Choose optimal model and strategy based on requirements
}
async trackSpending(operation: string, tokensIn: number, tokensOut: number, model: string) {
// TODO: Track spending against budget
// Alert when thresholds are reached
}
}Success Criteria:
- Error handling prevents cascade failures
- Monitoring captures all key metrics
- Cost optimization reduces spending by >20%
Exercise 5: Advanced Integration
Objective: Build a complete application that showcases all learned concepts.
Exercise 5.1: Multi-Modal Analysis System
// exercises/05-advanced/multimodal.ts
// TODO: Build a system that can analyze code, docs, and images
export class MultiModalAnalyzer {
async analyzeRepository(
repoPath: string,
options: {
includeImages: boolean;
includeDocs: boolean;
includeCode: boolean;
}
): Promise<{
summary: string;
insights: string[];
recommendations: string[];
visualizations: any[];
}> {
// TODO: Implement comprehensive analysis
// 1. Load all content types
// 2. Route to appropriate models
// 3. Aggregate insights
// 4. Generate visualizations
}
}Exercise 5.2: Intelligent Code Migration Assistant
// exercises/05-advanced/migration-assistant.ts
// TODO: Build an end-to-end migration assistant
export class MigrationAssistant {
async planMigration(
sourcePath: string,
targetFramework: string,
options?: {
preserveStructure: boolean;
modernize: boolean;
testCoverage: number;
}
): Promise<MigrationPlan> {
// TODO: Complete implementation
// Use Gemini for large context understanding
// Use Claude for migration strategy
// Generate step-by-step plan
}
async executeMigration(
plan: MigrationPlan,
options?: {
dryRun: boolean;
parallel: boolean;
validateEachStep: boolean;
}
): Promise<MigrationResult> {
// TODO: Execute the migration plan
}
}Exercise 5.3: Real-time Collaboration System
// exercises/05-advanced/collaboration.ts
// TODO: Build a real-time collaborative analysis system
export class CollaborativeAnalyzer {
private sessions = new Map<string, AnalysisSession>();
async createSession(
projectPath: string,
participants: string[]
): Promise<string> {
// TODO: Create collaborative session
}
async addAnalysis(
sessionId: string,
analysis: {
type: string;
content: string;
author: string;
}
): Promise<void> {
// TODO: Add analysis to session
// Trigger re-analysis if needed
// Notify other participants
}
async generateReport(sessionId: string): Promise<Report> {
// TODO: Aggregate all analyses
// Use both Claude and Gemini
// Create comprehensive report
}
}Success Criteria:
- Can analyze mixed content types effectively
- Migration plans are accurate and executable
- Real-time collaboration works smoothly
Final Project
Objective: Design and build your own application using Claude + Gemini integration.
Requirements:
- Must use both Claude and Gemini appropriately
- Must handle at least 500K tokens of context
- Must include error handling and monitoring
- Must demonstrate cost optimization
- Must solve a real-world problem
Suggested Projects:
- Documentation generator for large codebases
- Security audit system for enterprise applications
- Code review assistant with historical context
- Technical debt analyzer and refactoring planner
- Multi-repository dependency analyzer
Evaluation Criteria:
- Architecture (25%): Clean, scalable design
- Integration (25%): Effective use of both models
- Performance (20%): Efficient processing of large contexts
- Reliability (20%): Error handling and monitoring
- Innovation (10%): Creative problem solving
Workshop Resources
Starter Code Repository
claude-gemini-workshop/
├── exercises/
│ ├── 01-basic-mcp/
│ ├── 02-large-context/
│ ├── 03-orchestration/
│ ├── 04-production/
│ └── 05-advanced/
├── solutions/
├── lib/
│ ├── test-helpers.ts
│ └── common-types.ts
├── tests/
├── package.json
└── README.md
Testing Your Solutions
# Test individual exercises
pnpm test:exercise-1.1
pnpm test:exercise-2.3
# Test all exercises in a section
pnpm test:section-3
# Run all tests
pnpm test
# Run with coverage
pnpm test:coverageDebugging Tips
-
Use Debug Mode:
// Enable debug logging process.env.DEBUG = 'mcp:*,gemini:*'; -
Monitor Token Usage:
// Add to your code console.log(`Tokens used: ${estimateTokens(content)}`); -
Test with Smaller Contexts First:
// Start small, then scale up const testContent = fullContent.slice(0, 1000);
Common Pitfalls to Avoid
- Not checking token limits before sending
- Forgetting to handle rate limits
- Not implementing proper error recovery
- Ignoring cost implications of large contexts
- Not caching expensive operations
Additional Challenges
Challenge 1: Streaming Optimization
Implement true streaming from Gemini through MCP to Claude Code client.
Challenge 2: Distributed Processing
Split large contexts across multiple Gemini instances and aggregate results.
Challenge 3: Smart Caching
Implement intelligent cache invalidation based on file changes.
Challenge 4: Cost Prediction
Build a system that accurately predicts costs before processing.
Challenge 5: Multi-Language Support
Extend the system to handle multiple programming languages with language-specific analysis.
Happy Coding! 🚀
For questions during the workshop, use the #workshop-help channel in our Discord.
Resources: