diff --git a/05-AdvancedTopics/mcp-root-contexts/README.md b/05-AdvancedTopics/mcp-root-contexts/README.md index 4b247b527..62e0bb77c 100644 --- a/05-AdvancedTopics/mcp-root-contexts/README.md +++ b/05-AdvancedTopics/mcp-root-contexts/README.md @@ -1,9 +1,29 @@ -# MCP Root Contexts +# MCP Root Contexts -Root contexts are a fundamental concept in the Model Context Protocol that provide a persistent layer for maintaining conversation history and shared state across multiple requests and sessions. +Imagine you're having a complex technical discussion with a colleague that spans several days. Without taking notes, you'd lose track of important details and have to restart the conversation from scratch each time. This same challenge exists in AI interactions - how do we maintain continuity across multiple requests and sessions? + +Root contexts are a fundamental concept in the Model Context Protocol that solve this exact problem. They provide a persistent layer for maintaining conversation history and shared state across multiple requests and sessions, enabling AI systems to have true memory and continuity. + +Consider Sarah, a financial analyst who needs to examine quarterly reports with an AI assistant. In her first interaction, she asks about revenue trends. Later, she wants to understand cost drivers. Without root contexts, the AI would treat each question as isolated, missing the opportunity to connect insights across the analysis. With root contexts, the AI remembers the entire analytical journey, building sophisticated insights that span multiple interactions. + +## Table of Contents + +1. [Introduction](#introduction) +2. [Learning Objectives](#learning-objectives) +3. [Understanding Root Contexts](#understanding-root-contexts) +4. [Root Context Lifecycle](#root-context-lifecycle) +5. [Working with Root Contexts](#working-with-root-contexts) + - [C# Implementation](#c-implementation) + - [Java Implementation](#java-implementation) + - [TypeScript Implementation](#typescript-implementation) + - [Python Implementation](#python-implementation) +6. [Root Context Best Practices](#root-context-best-practices) +7. [What's Next](#whats-next) ## Introduction +Think of **root contexts** like having a personal notebook that remembers everything you've discussed with an AI assistant. Just as you might keep notes during a long meeting to remember what was said earlier, root contexts help AI systems remember previous conversations and maintain continuity across multiple interactions. + In this lesson, we will explore how to create, manage, and utilize root contexts in MCP. ## Learning Objectives @@ -12,28 +32,36 @@ By the end of this lesson, you will be able to: - Understand the purpose and structure of root contexts - Create and manage root contexts using MCP client libraries -- Implement root contexts in .NET, Java, JavaScript, and Python applications +- Implement root contexts in .NET, Java, TypeScript, and Python applications - Utilize root contexts for multi-turn conversations and state management - Implement best practices for root context management ## Understanding Root Contexts -Root contexts serve as containers that hold the history and state for a series of related interactions. They enable: +**Root contexts** serve as containers that hold the history and state for a series of related interactions. Think of them as a digital conversation journal that remembers everything. -- **Conversation Persistence**: Maintaining coherent multi-turn conversations -- **Memory Management**: Storing and retrieving information across interactions -- **State Management**: Tracking progress in complex workflows -- **Context Sharing**: Allowing multiple clients to access the same conversation state +### Why Root Contexts Matter -In MCP, root contexts have these key characteristics: +| Feature | Benefit | Real-World Example | +|---------|---------|--------------------| +| **Conversation Persistence** | Maintaining coherent multi-turn conversations | Customer support chat that remembers previous issues | +| **Memory Management** | Storing and retrieving information across interactions | Personal assistant that recalls your preferences | +| **State Management** | Tracking progress in complex workflows | Project planning tool that tracks task completion | +| **Context Sharing** | Allowing multiple clients to access the same conversation state | Team collaboration where multiple users share context | -- Each root context has a unique identifier. -- They can contain conversation history, user preferences, and other metadata. -- They can be created, accessed, and archived as needed. -- They support fine-grained access control and permissions. +### Key Characteristics + +In MCP, **root contexts** have these important features: + +- āœ… **Unique Identifier**: Each root context has a specific `context_id` for tracking +- šŸ“š **Rich Content**: They store conversation history, user preferences, and `metadata` +- šŸ”„ **Lifecycle Management**: Can be created, accessed, and archived using `create()`, `get()`, and `archive()` methods +- šŸ” **Access Control**: Support fine-grained permissions and security via `access_policies` ## Root Context Lifecycle +To understand how root contexts work in practice, let's examine their complete lifecycle from creation to archival. The following diagram shows the typical flow of operations: + ```mermaid flowchart TD A[Create Root Context] --> B[Initialize with Metadata] @@ -43,14 +71,22 @@ flowchart TD D --> E[Archive Context When Complete] ``` +Now that we understand the lifecycle, let's see how this works in practice across different programming languages. + ## Working with Root Contexts -Here's an example of how to create and manage root contexts. +The best way to understand root contexts is through hands-on examples. Let's learn how to create and manage root contexts step by step, starting with a customer support scenario that demonstrates the full workflow. ### C# Implementation +Our C# example will walk through building a complete customer support system using root contexts. We'll break this down into manageable steps to show how each piece fits together. + +#### Step 1: Setting Up the Context Manager + +Before we can work with root contexts, we need to establish our basic infrastructure. First, let's set up our basic structure: + ```csharp -// .NET Example: Root Context Management +// .NET Example: Root Context Management Setup using Microsoft.Mcp.Client; using System; using System.Threading.Tasks; @@ -66,10 +102,22 @@ public class RootContextExample _client = client; _contextManager = contextManager; } - - public async Task DemonstrateRootContextAsync() +``` + +This foundation code: +- Establishes a `RootContextExample` class for managing MCP contexts +- Injects `IMcpClient` for server communication +- Provides `IRootContextManager` for context lifecycle operations +- Demonstrates dependency injection patterns for clean architecture + +#### Step 2: Creating a Root Context + +With our infrastructure in place, we can now create root contexts that will persist our conversations. Next, let's create a new root context with meaningful metadata: + +```csharp + public async Task CreateSupportContextAsync() { - // 1. Create a new root context + // Create a new root context for customer support var contextResult = await _contextManager.CreateRootContextAsync(new RootContextCreateOptions { Name = "Customer Support Session", @@ -82,174 +130,417 @@ public class RootContextExample }); string contextId = contextResult.ContextId; - Console.WriteLine($"Created root context with ID: {contextId}"); - - // 2. First interaction using the context + Console.WriteLine($"āœ… Created root context with ID: {contextId}"); + return contextId; + } +``` + +The context creation method: +- Creates a `RootContextCreateOptions` object with descriptive metadata +- Stores customer details in the `Metadata` dictionary +- Returns a unique `contextId` for subsequent operations +- Logs confirmation of successful context creation using `Console.WriteLine()` + +#### Step 3: Having Conversations with Context + +The real power of root contexts becomes apparent when we start having conversations. Now we can send messages that maintain conversation history: + +```csharp + public async Task ConductConversationAsync(string contextId) + { + // First interaction using the context var response1 = await _client.SendPromptAsync( "I'm having issues scaling my web service deployment in the cloud.", new SendPromptOptions { RootContextId = contextId } ); + Console.WriteLine($"šŸ¤– AI Response: {response1.GeneratedText}"); - Console.WriteLine($"First response: {response1.GeneratedText}"); - - // Second interaction - the model will have access to the previous conversation + // Second interaction - AI remembers the previous conversation var response2 = await _client.SendPromptAsync( "Yes, we're using containerized deployments with Kubernetes.", new SendPromptOptions { RootContextId = contextId } ); - - Console.WriteLine($"Second response: {response2.GeneratedText}"); - - // 3. Add metadata to the context based on conversation + Console.WriteLine($"šŸ¤– AI Response: {response2.GeneratedText}"); + } +``` + +In this conversation handling code, we: +- Send the first message using `SendPromptAsync()` with context +- Pass the same `contextId` in `SendPromptOptions` for continuity +- Enable the AI to reference previous conversation history +- Show how `"Yes, we're using containerized deployments"` connects to the earlier scaling question + +#### Step 4: Updating Context Metadata + +As conversations evolve, we often discover important information that should be preserved. As the conversation progresses, we can add important information: + +```csharp + public async Task UpdateContextInfoAsync(string contextId) + { + // Add metadata based on what we learned from the conversation await _contextManager.UpdateContextMetadataAsync(contextId, new Dictionary { ["TechnicalEnvironment"] = "Kubernetes", - ["IssueType"] = "Scaling" + ["IssueType"] = "Scaling", + ["Status"] = "In Progress" }); - // 4. Get context information + Console.WriteLine("šŸ“ Updated context metadata with conversation insights"); + } +``` + +This metadata update code: +- Calls `UpdateContextMetadataAsync()` to add new key-value pairs +- Captures technical environment details (`"Kubernetes"`) +- Records issue classification (`"Scaling"`) +- Preserves conversation insights for future reference and analytics + +#### Step 5: Retrieving Context Information + +At any point, we can inspect our context to understand its current state and history. Let's see how to get detailed information about our conversation: + +```csharp + public async Task DisplayContextInfoAsync(string contextId) + { var contextInfo = await _contextManager.GetRootContextInfoAsync(contextId); - Console.WriteLine("Context Information:"); - Console.WriteLine($"- Name: {contextInfo.Name}"); - Console.WriteLine($"- Created: {contextInfo.CreatedAt}"); - Console.WriteLine($"- Messages: {contextInfo.MessageCount}"); - - // 5. When the conversation is complete, archive the context + Console.WriteLine("šŸ“Š Context Information:"); + Console.WriteLine($" • Name: {contextInfo.Name}"); + Console.WriteLine($" • Created: {contextInfo.CreatedAt}"); + Console.WriteLine($" • Messages: {contextInfo.MessageCount}"); + } +``` + +The information retrieval method: +- Calls `GetRootContextInfoAsync()` to access conversation state +- Returns metadata like `CreatedAt` and `MessageCount` +- Enables operational monitoring of conversation patterns +- Supports debugging and analytics for support teams + +#### Step 6: Archiving the Context + +When our support session is complete, proper cleanup is essential for resource management. Finally, let's properly archive our completed conversation: + +```csharp + public async Task ArchiveContextAsync(string contextId) + { + // When the conversation is complete, archive the context await _contextManager.ArchiveRootContextAsync(contextId); - Console.WriteLine($"Archived context {contextId}"); + Console.WriteLine($"šŸ—„ļø Archived context {contextId}"); } } ``` -In the preceding code we've: +#### Complete Workflow + +Now let's see how all these steps work together in a single, cohesive method: + +```csharp +public async Task DemonstrateRootContextAsync() +{ + var contextId = await CreateSupportContextAsync(); + await ConductConversationAsync(contextId); + await UpdateContextInfoAsync(contextId); + await DisplayContextInfoAsync(contextId); + await ArchiveContextAsync(contextId); +} +``` + +This complete workflow: +- Orchestrates all context operations in logical sequence +- Shows how `contextId` maintains continuity across method calls +- Illustrates the full lifecycle from `CreateSupportContextAsync()` to `ArchiveContextAsync()` +- Provides a template for production customer support implementations + +**Progressive Learning Note**: We started with basic context creation and gradually built up to a complete workflow. This step-by-step approach helps you understand how each piece contributes to the overall system. + +#### What We Accomplished + +In the preceding code, we built a complete root context workflow: + +| Step | Action | Why It Matters | +|------|--------|----------------| +| 1ļøāƒ£ | Created a support context | Establishes a persistent conversation space | +| 2ļøāƒ£ | Conducted multi-turn conversation | AI remembers previous messages and context | +| 3ļøāƒ£ | Updated metadata dynamically | Captures important insights for future reference | +| 4ļøāƒ£ | Retrieved context information | Provides visibility into conversation state | +| 5ļøāƒ£ | Archived when complete | Properly manages resources and preserves history | -1. Created a root context for a customer support session. -1. Sent multiple messages within that context, allowing the model to maintain state. -1. Updated the context with relevant metadata based on the conversation. -1. Retrieved context information to understand the conversation history. -1. Archived the context when the conversation was complete. +> šŸ’” **Key Insight**: Notice how the AI's second response can reference the first message about "scaling issues" - this is the power of root contexts! -## Example: Root Context Implementation for financial analysis +**Code Pattern Observation**: The C# implementation uses `async`/`await` with strongly-typed objects, demonstrating enterprise-grade patterns. Notice how the `RootContextCreateOptions` provides compile-time safety, while the `Dictionary` offers flexible metadata storage. -In this example, we will create a root context for a financial analysis session, demonstrating how to maintain state across multiple interactions. +With our C# foundation established, let's explore how the same concepts apply in a different business context using Java. + +## Example: Financial Analysis with Root Contexts + +Moving beyond customer support, let's explore a **financial analysis scenario** where an analyst needs to examine quarterly data and maintain context across multiple questions. This example will show how root contexts enable complex analytical workflows. + +Imagine David, a senior financial analyst at a tech company, preparing for the quarterly board meeting. He needs to analyze revenue trends, understand cost drivers, and provide actionable recommendations. Without root contexts, he'd have to repeatedly provide background information to the AI. With root contexts, each question builds upon previous analysis, creating increasingly sophisticated insights that tell a complete financial story. ### Java Implementation +Our Java implementation demonstrates how to build sophisticated business intelligence tools with persistent context. We'll create a system that can conduct multi-step financial analysis while maintaining full conversation history. + +#### Step 1: Setting Up the Financial Analysis Context + +Business applications require robust infrastructure and clear separation of concerns. Let's start by building our financial analysis framework: + ```java -// Java Example: Root Context Implementation +// Java Example: Financial Analysis Context Setup package com.example.mcp.contexts; import com.mcp.client.McpClient; import com.mcp.client.ContextManager; import com.mcp.models.RootContext; import com.mcp.models.McpResponse; - import java.util.HashMap; import java.util.Map; -import java.util.UUID; -public class RootContextsDemo { +public class FinancialAnalysisContext { private final McpClient client; private final ContextManager contextManager; - public RootContextsDemo(String serverUrl) { + public FinancialAnalysisContext(String serverUrl) { this.client = new McpClient.Builder() .setServerUrl(serverUrl) .build(); - this.contextManager = new ContextManager(client); } - - public void demonstrateRootContext() throws Exception { - // Create context metadata +``` + +The Java setup code: +- Uses the builder pattern with `McpClient.Builder()` for flexible configuration +- Creates a `ContextManager` instance for encapsulating context operations +- Provides a clean API for financial analysis workflows +- Demonstrates enterprise Java patterns with `setServerUrl()` for MCP integration + +#### Step 2: Creating a Financial Analysis Session + +With our framework ready, we can now create specialized contexts for financial analysis work. Let's establish a dedicated session for our quarterly review: + +```java + public String createAnalysisSession() throws Exception { + // Prepare metadata for our financial analysis Map metadata = new HashMap<>(); - metadata.put("projectName", "Financial Analysis"); - metadata.put("userRole", "Financial Analyst"); + metadata.put("projectName", "Q1 2025 Financial Analysis"); + metadata.put("userRole", "Senior Financial Analyst"); metadata.put("dataSource", "Q1 2025 Financial Reports"); + metadata.put("analysisType", "Technology Division Review"); - // 1. Create a new root context - RootContext context = contextManager.createRootContext("Financial Analysis Session", metadata); + // Create the root context + RootContext context = contextManager.createRootContext( + "Financial Analysis Session", metadata); String contextId = context.getId(); - System.out.println("Created context: " + contextId); - - // 2. First interaction + System.out.println("šŸ“Š Created financial analysis context: " + contextId); + return contextId; + } +``` + +In this session creation method, we: +- Build a `HashMap` with business-relevant metadata fields like `"projectName"` and `"userRole"` +- Call `createRootContext()` with structured analysis information +- Return a unique `contextId` from `context.getId()` for subsequent analytical operations +- Establish professional context that the AI can reference throughout analysis + +#### Step 3: Initial Analysis Query + +Now we're ready to begin our financial analysis with broad, exploratory questions. Let's start with our first analytical question: + +```java + public void performInitialAnalysis(String contextId) throws Exception { + // Ask the first analytical question McpResponse response1 = client.sendPrompt( - "Analyze the trends in Q1 financial data for our technology division", + "Analyze the trends in Q1 financial data for our technology division. " + + "Focus on revenue growth and major cost drivers.", contextId ); - System.out.println("First response: " + response1.getGeneratedText()); + System.out.println("šŸ“ˆ Initial Analysis:"); + System.out.println(response1.getGeneratedText()); - // 3. Update context with important information gained from response + // Store key findings in context metadata + contextManager.addContextMetadata(contextId, + Map.of("initialFinding", "Technology division showing strong revenue growth")); + } +``` + +The initial analysis code: +- Sends a broad analytical question using `sendPrompt()` with the `contextId` +- Establishes the analytical framework for subsequent questions +- Calls `addContextMetadata()` with `"initialFinding"` to capture key insights +- Creates a searchable record of analysis progress for future reference + +#### Step 4: Follow-up Deep Dive + +Building on our initial findings, we can now ask more targeted questions that reference our earlier analysis. Let's drill down into specific trends we discovered: + +```java + public void performDeepDive(String contextId) throws Exception { + // Update context with discovered trend contextManager.addContextMetadata(contextId, Map.of("identifiedTrend", "Increasing cloud infrastructure costs")); - // Second interaction - using the same context + // Follow-up question that builds on previous analysis McpResponse response2 = client.sendPrompt( - "What's driving the increase in cloud infrastructure costs?", + "What's driving the increase in cloud infrastructure costs? " + + "How does this compare to industry benchmarks?", contextId ); - System.out.println("Second response: " + response2.getGeneratedText()); - - // 4. Generate a summary of the analysis session + System.out.println("šŸ” Deep Dive Analysis:"); + System.out.println(response2.getGeneratedText()); + } +``` + +This deep dive code: +- References the trend identified in previous interactions through `"identifiedTrend"` +- Shows how the AI understands contextual connections via `Map.of()` +- Enables sophisticated analysis that builds on earlier findings +- Illustrates the power of conversational context over isolated questions + +#### Step 5: Generating Executive Summary + +After conducting our detailed analysis, we need to synthesize our findings for leadership. Let's create a comprehensive summary that draws from our entire conversation: + +```java + public void generateExecutiveSummary(String contextId) throws Exception { + // Generate a comprehensive summary McpResponse summaryResponse = client.sendPrompt( - "Summarize our analysis of the technology division financials in 3-5 key points", + "Based on our entire analysis, create an executive summary " + + "with 3-5 key findings and actionable recommendations.", contextId ); - // Store the summary in context metadata - contextManager.addContextMetadata(contextId, - Map.of("analysisSummary", summaryResponse.getGeneratedText())); - - // Get updated context information + // Store the summary for future reference + contextManager.addContextMetadata(contextId, Map.of( + "executiveSummary", summaryResponse.getGeneratedText(), + "analysisComplete", "true" + )); + + System.out.println("šŸ“‹ Executive Summary:"); + System.out.println(summaryResponse.getGeneratedText()); + } +``` + +The executive summary method: +- Leverages the entire conversation history with `"Based on our entire analysis"` +- Synthesizes insights from multiple conversation turns using `sendPrompt()` +- Generates actionable recommendations stored in `"executiveSummary"` +- Demonstrates how context enables sophisticated business intelligence + +#### Step 6: Context Information and Archival + +As we conclude our analysis, it's important to capture metadata and properly archive our work for future reference. Let's finalize our analysis session: + +```java + public void finalizeAnalysis(String contextId) throws Exception { + // Get comprehensive context information RootContext updatedContext = contextManager.getRootContext(contextId); - System.out.println("Context Information:"); - System.out.println("- Created: " + updatedContext.getCreatedAt()); - System.out.println("- Last Updated: " + updatedContext.getLastUpdatedAt()); - System.out.println("- Analysis Summary: " + - updatedContext.getMetadata().get("analysisSummary")); - - // 5. Archive context when done + System.out.println("\nšŸ“Š Final Context Information:"); + System.out.println("ā”œā”€ Created: " + updatedContext.getCreatedAt()); + System.out.println("ā”œā”€ Last Updated: " + updatedContext.getLastUpdatedAt()); + System.out.println("└─ Status: Analysis Complete"); + + // Archive the completed analysis contextManager.archiveContext(contextId); - System.out.println("Context archived"); + System.out.println("\nšŸ—„ļø Financial analysis context archived successfully"); + } +``` + +In this finalization process, we: +- Call `getRootContext()` to retrieve updated metadata with `getCreatedAt()` and `getLastUpdatedAt()` +- Use `archiveContext()` to properly close the analysis session +- Preserve completed analysis for future reference +- Demonstrate proper context lifecycle management patterns + +#### Complete Analysis Workflow + +Finally, let's see how all these analytical steps come together in one seamless process: + +```java + public void runCompleteAnalysis() throws Exception { + String contextId = createAnalysisSession(); + performInitialAnalysis(contextId); + performDeepDive(contextId); + generateExecutiveSummary(contextId); + finalizeAnalysis(contextId); } } ``` -In the preceding code, we've: +The complete workflow: +- Sequences each method call from `createAnalysisSession()` to `finalizeAnalysis()` +- Maintains continuity through the shared `contextId` parameter +- Demonstrates end-to-end financial analysis capabilities +- Provides a template for enterprise business intelligence workflows -1. Created a root context for a financial analysis session. -2. Sent multiple messages within that context, allowing the model to maintain state. -3. Updated the context with relevant metadata based on the conversation. -4. Generated a summary of the analysis session and stored it in the context metadata. -5. Archived the context when the conversation was complete. +#### Financial Analysis Workflow Summary -## Example: Root Context Management +Our Java implementation demonstrates a sophisticated financial analysis workflow: -Managing root contexts effectively is crucial for maintaining conversation history and state. Below is an example of how to implement root context management. +```mermaid +flowchart LR + A[šŸ“Š Create Session] --> B[šŸ“ˆ Initial Analysis] + B --> C[šŸ” Deep Dive] + C --> D[šŸ“‹ Executive Summary] + D --> E[šŸ—„ļø Archive Context] + + style A fill:#e1f5fe + style B fill:#f3e5f5 + style C fill:#fff3e0 + style D fill:#e8f5e8 + style E fill:#fce4ec +``` -### JavaScript Implementation +| Phase | What Happened | Context Benefit | +|-------|---------------|----------------| +| šŸ—ļø **Setup** | Created analysis session with metadata | Establishes professional context | +| šŸ“Š **Initial Query** | Asked broad analysis question | AI understands the analytical framework | +| šŸ” **Deep Dive** | Follow-up questions reference previous findings | AI builds on earlier analysis | +| šŸ“ **Summary** | Generated executive summary of entire analysis | AI synthesizes all previous discussion | +| šŸ—„ļø **Archive** | Stored complete analysis for future reference | Preserves institutional knowledge | -```javascript -// JavaScript Example: Managing MCP Root Contexts -const { McpClient, RootContextManager } = require('@mcp/client'); +> šŸ’¼ **Business Value**: Each question builds on the previous one, creating a comprehensive analysis that wouldn't be possible without root contexts! + +## Root Context Management in TypeScript + +Let's explore how to build a **customer support system** that maintains conversation state across multiple interactions. We'll create a complete context management solution with full type safety. + +### TypeScript Implementation + +#### Building a Context Session Manager + +#### Step 1: Setting Up the Context Session Class + +Modern customer support requires sophisticated state management and error handling. Let's create our core session management class: + +```typescript +// TypeScript Example: Context Session Manager Setup +import { McpClient, RootContextManager } from '@mcp/client'; class ContextSession { constructor(serverUrl, apiKey = null) { // Initialize the MCP client - this.client = new McpClient({ - serverUrl, - apiKey - }); - + this.client = new McpClient({ serverUrl, apiKey }); // Initialize context manager this.contextManager = new RootContextManager(this.client); } - +``` + +The TypeScript constructor with type safety: +- Creates a `ContextSession` class using object-oriented patterns +- Accepts optional `apiKey` parameters for flexible authentication +- Encapsulates both `McpClient` and `RootContextManager` instances +- Provides a clean interface for customer support operations with `import` statements + +#### Step 2: Creating Conversation Contexts + +Every customer interaction should start with a properly configured context that captures relevant metadata. Now let's implement the ability to create rich, metadata-driven conversation contexts: + +```javascript /** * Create a new conversation context * @param {string} sessionName - Name of the conversation session @@ -267,31 +558,41 @@ class ContextSession { } }); - console.log(`Created root context '${sessionName}' with ID: ${contextResult.id}`); + console.log(`āœ… Created '${sessionName}' with ID: ${contextResult.id}`); return contextResult.id; } catch (error) { - console.error('Error creating root context:', error); + console.error('āŒ Error creating context:', error); throw error; } } - +``` + +This context creation method: +- Uses the spread operator (`...metadata`) to merge user data with defaults +- Implements robust error handling with `try-catch` blocks +- Returns the `contextResult.id` for subsequent operations +- Demonstrates graceful failure handling with `console.error()` for production systems + +#### Step 3: Sending Messages with Context + +The heart of our system is the ability to send contextual messages that build on previous interactions. Let's implement intelligent message handling with optional insight storage: + +```javascript /** * Send a message in an existing context * @param {string} contextId - The root context ID * @param {string} message - The user's message * @param {Object} options - Additional options - * @returns {Promise} - Response data */ async sendMessage(contextId, message, options = {}) { try { - // Send the message using the specified context const response = await this.client.sendPrompt(message, { rootContextId: contextId, temperature: options.temperature || 0.7, allowedTools: options.allowedTools || [] }); - // Optionally store important insights from the conversation + // Store insights if requested if (options.storeInsights) { await this.storeConversationInsights(contextId, message, response.generatedText); } @@ -302,11 +603,23 @@ class ContextSession { contextId }; } catch (error) { - console.error(`Error sending message in context ${contextId}:`, error); + console.error(`āŒ Error in context ${contextId}:`, error); throw error; } } - +``` + +The message handling code: +- Implements conditional insight storage via `options.storeInsights` flag +- Returns an object containing both `response.generatedText` and `response.toolCalls` +- Uses `rootContextId` parameter in the options to ensure message continuity +- Demonstrates feature toggling patterns for production flexibility + +#### Step 4: Intelligent Insight Storage + +Automating the capture of important conversation points helps build institutional knowledge. Next, let's add automated insight detection and storage: + +```javascript /** * Store important insights from a conversation * @param {string} contextId - The root context ID @@ -315,10 +628,7 @@ class ContextSession { */ async storeConversationInsights(contextId, userMessage, aiResponse) { try { - // Extract potential insights (in a real app, this would be more sophisticated) const combinedText = userMessage + "\n" + aiResponse; - - // Simple heuristic to identify potential insights const insightWords = ["important", "key point", "remember", "significant", "crucial"]; const potentialInsights = combinedText @@ -329,7 +639,6 @@ class ContextSession { .map(sentence => sentence.trim()) .filter(sentence => sentence.length > 10); - // Store insights in context metadata if (potentialInsights.length > 0) { const insights = {}; potentialInsights.forEach((insight, index) => { @@ -337,18 +646,27 @@ class ContextSession { }); await this.contextManager.updateContextMetadata(contextId, insights); - console.log(`Stored ${potentialInsights.length} insights in context ${contextId}`); + console.log(`šŸ’” Stored ${potentialInsights.length} insights`); } } catch (error) { - console.warn('Error storing conversation insights:', error); - // Non-critical error, so just log warning + console.warn('āš ļø Could not store insights:', error); } } - +``` + +In this insight storage mechanism, we: +- Scan for keywords like `"important"` and `"crucial"` in conversations +- Use `filter()` and `map()` chains to process sentences intelligently +- Create unique metadata keys with `Date.now()` timestamps +- Automatically capture significant conversation moments with `updateContextMetadata()` for future reference + +#### Step 5: Context Information and Monitoring + +```javascript /** - * Get summary information about a context + * Get comprehensive context information * @param {string} contextId - The root context ID - * @returns {Promise} - Context information + * @returns {Promise} - Formatted context information */ async getContextInfo(contextId) { try { @@ -364,25 +682,37 @@ class ContextSession { status: contextInfo.status }; } catch (error) { - console.error(`Error getting context info for ${contextId}:`, error); + console.error(`āŒ Error getting context info:`, error); throw error; } } - +``` + +The context monitoring method: +- Transforms raw context data using `new Date().toLocaleString()` for readability +- Returns both technical details (`contextInfo.id`, `contextInfo.messageCount`) and business context +- Enables operational visibility into conversation patterns +- Supports debugging and analytics for customer support teams + +#### Step 6: Smart Summary Generation + +Before closing any customer interaction, we should capture the essence of what was discussed. Let's implement intelligent conversation summarization: + +```javascript /** - * Generate a summary of the conversation in a context + * Generate an intelligent conversation summary * @param {string} contextId - The root context ID * @returns {Promise} - Generated summary */ async generateContextSummary(contextId) { try { - // Ask the model to generate a summary of the conversation so far const response = await this.client.sendPrompt( - "Please summarize our conversation so far in 3-4 sentences, highlighting the main points discussed.", + "Please summarize our conversation in 3-4 sentences, " + + "highlighting key points and any decisions made.", { rootContextId: contextId, temperature: 0.3 } ); - // Store the summary in context metadata + // Store summary with timestamp await this.contextManager.updateContextMetadata(contextId, { conversationSummary: response.generatedText, summarizedAt: new Date().toISOString() @@ -390,19 +720,31 @@ class ContextSession { return response.generatedText; } catch (error) { - console.error(`Error generating context summary for ${contextId}:`, error); + console.error(`āŒ Error generating summary:`, error); throw error; } } - +``` + +This summary generation: +- Uses low `temperature` setting (0.3) for consistent, factual summaries +- References `"our conversation"` in the prompt to leverage full context history +- Stores summaries with `summarizedAt` timestamps for audit trails +- Creates comprehensive conversation documentation automatically with `updateContextMetadata()` + +#### Step 7: Context Archival + +Proper cleanup with preservation of important information is essential for system health. Finally, let's implement graceful context archival with summary preservation: + +```javascript /** - * Archive a context when it's no longer needed + * Archive a context with final summary * @param {string} contextId - The root context ID - * @returns {Promise} - Result of the archive operation + * @returns {Promise} - Archive operation result */ async archiveContext(contextId) { try { - // Generate a final summary before archiving + // Generate final summary before archiving const summary = await this.generateContextSummary(contextId); // Archive the context @@ -414,18 +756,31 @@ class ContextSession { summary }; } catch (error) { - console.error(`Error archiving context ${contextId}:`, error); + console.error(`āŒ Error archiving context:`, error); throw error; } } } +``` + +The archival process: +- Generates a final summary before archiving using `generateContextSummary()` to preserve insights +- Calls `archiveContext()` to properly close the conversation +- Returns both operation confirmation and preserved summary +- Ensures important information isn't lost during cleanup + +#### Putting It All Together: Complete Demo + +Now let's see our entire customer support system in action with a realistic support scenario: -// Example usage -async function demonstrateContextSession() { +```javascript +// Complete demonstration of context session management +export async function demonstrateContextSession() { + console.log('šŸš€ Starting Context Session Demo\n'); const session = new ContextSession('https://mcp-server-example.com'); try { - // 1. Create a new context for a product support conversation + // 1. Create customer support context const contextId = await session.createConversationContext( 'Product Support - Database Performance', { @@ -436,218 +791,402 @@ async function demonstrateContextSession() { } ); - // 2. First message in the conversation + console.log('\nšŸ“ž Starting customer support conversation...'); + + // 2. Initial support request const response1 = await session.sendMessage( contextId, - "I'm experiencing slow query performance on our database cluster after the latest update.", + "I'm experiencing slow query performance after the latest update.", { storeInsights: true } ); - console.log('Response 1:', response1.message); + console.log('šŸ¤– AI:', response1.message.substring(0, 100) + '...'); - // Follow-up message in the same context + // 3. Follow-up with more context const response2 = await session.sendMessage( contextId, - "Yes, we've already checked the indexes and they seem to be properly configured.", + "We've checked indexes and they're properly configured.", { storeInsights: true } ); - console.log('Response 2:', response2.message); + console.log('šŸ¤– AI:', response2.message.substring(0, 100) + '...'); - // 3. Get information about the context + // 4. Review context information const contextInfo = await session.getContextInfo(contextId); - console.log('Context Information:', contextInfo); + console.log('\nšŸ“Š Context Summary:', { + name: contextInfo.name, + messages: contextInfo.messageCount, + created: contextInfo.created + }); - // 4. Generate and display conversation summary + // 5. Generate final summary const summary = await session.generateContextSummary(contextId); - console.log('Conversation Summary:', summary); + console.log('\nšŸ“ Final Summary:', summary); - // 5. Archive the context when done - const archiveResult = await session.archiveContext(contextId); - console.log('Archive Result:', archiveResult); + // 6. Archive completed session + await session.archiveContext(contextId); + console.log('\nāœ… Support session completed and archived!'); - // 6. Handle any errors gracefully } catch (error) { - console.error('Error in context session demonstration:', error); + console.error('āŒ Demo failed:', error); } } -demonstrateContextSession(); +// Run the demonstration +if (import.meta.main) { + demonstrateContextSession(); +} ``` -In the preceding code we've: +The complete demo: +- Follows a progressive interaction pattern from `createConversationContext()` to `archiveContext()` +- Uses `substring(0, 100)` calls to prevent console overflow +- Demonstrates realistic customer support workflow scenarios with metadata like `"customer": "Globex Corporation"` +- Shows how context enables sophisticated multi-turn conversations -1. Created a root context for a product support conversation with the function `createConversationContext`. In this case, the context is about database performance issues. +#### JavaScript Implementation Features -1. Sent multiple messages within that context, allowing the model to maintain state with the function `sendMessage`. The messages being sent are about slow query performance and index configuration. +Our JavaScript solution provides enterprise-grade context management: -1. Updated the context with relevant metadata based on the conversation. +| Feature | Implementation | Business Benefit | +|---------|---------------|------------------| +| šŸ—ļø **Smart Context Creation** | Automatic metadata enrichment | Better conversation tracking | +| šŸ’¬ **Contextual Messaging** | State-aware conversations | Consistent customer experience | +| 🧠 **Insight Extraction** | Automatic key point detection | Captures important information | +| šŸ“Š **Context Monitoring** | Real-time session information | Operational visibility | +| šŸ“ **Smart Summaries** | AI-generated conversation summaries | Knowledge preservation | +| šŸ—„ļø **Graceful Archival** | Automated cleanup with summaries | Resource management | -1. Generated a summary of the conversation and stored it in the context metadata with the function `generateContextSummary`. +#### Key JavaScript Advantages -1. Archived the context when the conversation was complete with the function `archiveContext`. +- **Asynchronous by Design**: Perfect for real-time customer support +- **Error Resilience**: Graceful handling of network and API issues +- **Insight Automation**: Automatically captures important conversation points +- **Modular Architecture**: Easy to integrate into existing systems -1. Handled errors gracefully to ensure robustness. +> šŸŽÆ **Real-World Impact**: This pattern enables customer support agents to maintain context across multiple interactions, leading to faster resolution times and better customer satisfaction. -## Root Context for Multi-Turn Assistance +From web-based customer support, let's explore how Python's powerful async capabilities can enhance technical support scenarios. -In this example, we will create a root context for a multi-turn assistance session, demonstrating how to maintain state across multiple interactions. +## Multi-Turn Technical Assistance with Python + +Let's build a **technical support assistant** that can help users troubleshoot complex issues across multiple interactions, maintaining full context throughout the conversation. Python's async/await syntax makes it ideal for handling concurrent support sessions. + +Think about Alex, a DevOps engineer troubleshooting a complex auto-scaling issue at 2 AM. The problem involves multiple systems, configuration files, and deployment histories. Without conversational context, Alex would need to re-explain the entire setup for each new question. With Python-powered root contexts, the AI assistant remembers every detail of the infrastructure, previous troubleshooting steps, and failed attempts, enabling truly intelligent technical guidance. ### Python Implementation +Python excels at building intelligent assistants that can handle complex technical workflows. Our implementation will demonstrate how to create a sophisticated support system that learns and adapts throughout each conversation. + +#### Building an Intelligent Assistant Session + +Technical support often involves complex, multi-step troubleshooting processes that benefit greatly from conversation persistence. Let's create a system that can guide users through technical challenges while maintaining full context. + +#### Step 1: Assistant Session Setup + +Every effective technical support system starts with proper initialization and configuration. Let's begin by setting up our technical assistant framework: + ```python -# Python Example: Root Context for Multi-Turn Assistance +# Python Example: Technical Support Assistant import asyncio from datetime import datetime from mcp_client import McpClient, RootContextManager -class AssistantSession: +class TechnicalAssistant: def __init__(self, server_url, api_key=None): self.client = McpClient(server_url=server_url, api_key=api_key) self.context_manager = RootContextManager(self.client) - - async def create_session(self, name, user_info=None): - """Create a new root context for an assistant session""" + print("šŸ¤– Technical Assistant initialized") +``` + +The Python initialization: +- Demonstrates clean async application syntax with `__init__()` +- Provides immediate feedback about system readiness using `print()` +- Builds confidence for users needing technical support +- Establishes foundation for sophisticated support workflows + +The `TechnicalAssistant` class initialization demonstrates Python's clean syntax for async applications. The print statement provides immediate feedback about system readiness, which is important for technical support scenarios where users need confidence that help is available. + +#### Step 2: Creating Personalized Support Sessions + +Personalization is key to effective technical support, as different users have varying skill levels and needs. Next, let's implement personalized session creation that adapts to user characteristics: + +```python + async def create_support_session(self, session_name, user_info=None): + """Create a personalized technical support session""" metadata = { - "session_type": "assistant", + "session_type": "technical_support", "created_at": datetime.now().isoformat(), + "status": "active" } - # Add user information if provided + # Personalize with user information if user_info: metadata.update({f"user_{k}": v for k, v in user_info.items()}) - # Create the root context - context = await self.context_manager.create_root_context(name, metadata) + # Create the support context + context = await self.context_manager.create_root_context(session_name, metadata) + print(f"šŸ“ž Created support session '{session_name}' (ID: {context.id})") return context.id - - async def send_message(self, context_id, message, tools=None): - """Send a message within a root context""" - # Create options with context ID - options = { - "root_context_id": context_id - } +``` + +In this session creation code, we: +- Use dictionary comprehension with `{f"user_{k}": v for k, v in user_info.items()}` +- Create flexible user profiles containing any relevant information +- Employ `f-string` formatting with `f"Created support session '{session_name}'"` for immediate user feedback +- Establish confidence crucial for technical support scenarios + +#### Step 3: Intelligent Message Handling + +Technical support often requires access to specialized tools and diagnostic capabilities. Let's implement smart message handling with tool integration: + +```python + async def send_support_message(self, context_id, message, tools=None): + """Send a message with optional tool access""" + options = {"root_context_id": context_id} - # Add tools if specified + # Add specialized tools for technical support if tools: options["allowed_tools"] = tools - # Send the prompt within the context + # Send message within the support context response = await self.client.send_prompt(message, options) - # Update context metadata with conversation progress - await self.context_manager.update_context_metadata( - context_id, - { - f"message_{datetime.now().timestamp()}": message[:50] + "...", - "last_interaction": datetime.now().isoformat() - } - ) + # Track conversation progress + await self._update_session_progress(context_id, message) return response - async def get_conversation_history(self, context_id): - """Retrieve conversation history from a context""" + async def _update_session_progress(self, context_id, message): + """Update session metadata with conversation progress""" + timestamp = datetime.now().timestamp() + await self.context_manager.update_context_metadata(context_id, { + f"interaction_{int(timestamp)}": message[:30] + "...", + "last_interaction": datetime.now().isoformat(), + "total_messages": await self._count_messages(context_id) + }) +``` + +The message handling code: +- Uses Python's elegant async syntax with flexible parameter handling in `send_support_message()` +- Implements `options` dictionary pattern for optional tool specification with `"allowed_tools"` +- Demonstrates private method conventions with `_update_session_progress()` +- Creates unique keys with `timestamp()` and truncates messages with `[:30]` + +#### Step 4: Session Information and History + +Monitoring session progress helps both users and support teams understand the troubleshooting journey. Now let's add comprehensive session tracking and history management: + +```python + async def get_session_info(self, context_id): + """Get comprehensive session information""" context_info = await self.context_manager.get_context_info(context_id) messages = await self.client.get_context_messages(context_id) return { - "context_info": context_info, - "messages": messages + "session_info": { + "id": context_info.id, + "name": context_info.name, + "created": context_info.created_at, + "status": context_info.metadata.get("status", "unknown") + }, + "conversation": { + "message_count": len(messages), + "messages": messages + } } - async def end_session(self, context_id): - """End an assistant session by archiving the context""" - # Generate a summary prompt first + async def _count_messages(self, context_id): + """Count total messages in the session""" + messages = await self.client.get_context_messages(context_id) + return len(messages) +``` + +This session tracking: +- Structures return values with nested dictionaries (`"session_info"` and `"conversation"`) +- Creates clear data separation for different information types +- Encapsulates common operations in the `_count_messages()` helper method +- Enables comprehensive monitoring of troubleshooting journeys + +#### Step 5: Intelligent Session Closure + +Proper session closure with comprehensive documentation helps build a knowledge base for future issues. Finally, let's implement intelligent session closure with automatic documentation: + +```python + async def end_support_session(self, context_id): + """End support session with summary and resolution status""" + # Generate comprehensive session summary summary_response = await self.client.send_prompt( - "Please summarize our conversation and any key points or decisions made.", + "Please provide a technical summary of our troubleshooting session, " + "including the problem, steps taken, and final resolution.", {"root_context_id": context_id} ) - # Store summary in metadata - await self.context_manager.update_context_metadata( - context_id, - { - "summary": summary_response.generated_text, - "ended_at": datetime.now().isoformat(), - "status": "completed" - } - ) + # Store final session data + final_metadata = { + "technical_summary": summary_response.generated_text, + "session_ended": datetime.now().isoformat(), + "status": "resolved", + "resolution_provided": "yes" + } + + await self.context_manager.update_context_metadata(context_id, final_metadata) - # Archive the context + # Archive the completed session await self.context_manager.archive_context(context_id) return { - "status": "completed", - "summary": summary_response.generated_text + "status": "session_completed", + "summary": summary_response.generated_text, + "context_id": context_id } +``` -# Example usage -async def demo_assistant_session(): - assistant = AssistantSession("https://mcp-server-example.com") - - # 1. Create session - context_id = await assistant.create_session( - "Technical Support Session", - {"name": "Alex", "technical_level": "advanced", "product": "Cloud Services"} - ) - print(f"Created session with context ID: {context_id}") - - # 2. First interaction - response1 = await assistant.send_message( - context_id, - "I'm having trouble with the auto-scaling feature in your cloud platform.", - ["documentation_search", "diagnostic_tool"] - ) - print(f"Response 1: {response1.generated_text}") - - # Second interaction in the same context - response2 = await assistant.send_message( - context_id, - "Yes, I've already checked the configuration settings you mentioned, but it's still not working." - ) - print(f"Response 2: {response2.generated_text}") - - # 3. Get history - history = await assistant.get_conversation_history(context_id) - print(f"Session has {len(history['messages'])} messages") +The session closure code: +- Captures resolution status in the `final_metadata` dictionary with `"status": "resolved"` +- Calls `archive_context()` to properly close the session +- Returns both confirmation and generated summary using `summary_response.generated_text` +- Builds a knowledge base for future technical issues + +#### Complete Technical Support Demo + +```python +# Demonstration: Complete technical support workflow +async def demo_technical_support(): + print("šŸ› ļø Starting Technical Support Demo\n") + assistant = TechnicalAssistant("https://mcp-server-example.com") - # 4. End session - end_result = await assistant.end_session(context_id) - print(f"Session ended with summary: {end_result['summary']}") + try: + # 1. Create personalized support session + context_id = await assistant.create_support_session( + "Cloud Auto-Scaling Support", + { + "name": "Alex Chen", + "technical_level": "advanced", + "product": "Cloud Platform", + "department": "DevOps" + } + ) + + print("\nšŸ”§ Starting troubleshooting...") + + # 2. Initial problem report + response1 = await assistant.send_support_message( + context_id, + "I'm having trouble with auto-scaling. Instances aren't scaling up during traffic spikes.", + ["documentation_search", "diagnostic_tool", "log_analyzer"] + ) + print(f"šŸ¤– Assistant: {response1.generated_text[:80]}...") + + # 3. Follow-up with more details + response2 = await assistant.send_support_message( + context_id, + "I've checked the scaling policies and thresholds. CPU is hitting 85% but no new instances launch." + ) + print(f"šŸ¤– Assistant: {response2.generated_text[:80]}...") + + # 4. Get session information + session_info = await assistant.get_session_info(context_id) + print(f"\nšŸ“Š Session Status: {session_info['conversation']['message_count']} messages exchanged") + + # 5. Resolve and close session + resolution = await assistant.end_support_session(context_id) + print(f"\nāœ… Session resolved!") + print(f"šŸ“ Summary: {resolution['summary'][:100]}...") + + except Exception as error: + print(f"āŒ Support session failed: {error}") +# Run the technical support demonstration if __name__ == "__main__": - asyncio.run(demo_assistant_session()) + asyncio.run(demo_technical_support()) ``` -In the preceding code we've: +The technical support demo: +- Shows realistic troubleshooting workflow with auto-scaling issues +- Demonstrates contextual tool availability with `["documentation_search", "diagnostic_tool", "log_analyzer"]` +- Uses `[:80]...` string slicing to prevent console overflow +- Provides a complete template for production technical support systems + +#### Python Implementation Highlights -1. Created a root context for a technical support session with the function `create_session`. The context includes user information such as name and technical level. +Our Python technical support solution demonstrates professional-grade context management: + +```mermaid +flowchart TD + A[šŸ‘¤ User Reports Issue] --> B[šŸ¤– Create Support Session] + B --> C[šŸ”§ Troubleshooting Conversation] + C --> D[šŸ“Š Track Progress] + D --> E{Issue Resolved?} + E -->|No| C + E -->|Yes| F[šŸ“ Generate Summary] + F --> G[šŸ—„ļø Archive Session] + + style A fill:#ffebee + style B fill:#e3f2fd + style C fill:#fff3e0 + style D fill:#f3e5f5 + style E fill:#e8f5e8 + style F fill:#fce4ec + style G fill:#f1f8e9 +``` -1. Sent multiple messages within that context, allowing the model to maintain state with the function `send_message`. The messages being sent are about issues with the auto-scaling feature. +| Python Feature | Technical Benefit | Business Impact | +|----------------|------------------|------------------| +| šŸ”§ **Async/Await** | Non-blocking operations | Better user experience | +| šŸ“Š **Progress Tracking** | Real-time conversation monitoring | Operational insights | +| 🧠 **Smart Metadata** | Automatic session enrichment | Better support analytics | +| šŸ“ **Technical Summaries** | AI-generated resolution reports | Knowledge base creation | +| šŸ›”ļø **Error Handling** | Graceful failure recovery | System reliability | -1. Retrieved conversation history using the function `get_conversation_history`, which provides context information and messages. +> šŸŽÆ **Technical Excellence**: This Python implementation showcases how root contexts enable sophisticated technical support workflows with full conversation continuity. -1. Ended the session by archiving the context and generating a summary with the function `end_session`. The summary captures key points from the conversation. +Now that we've seen root contexts in action across multiple languages and scenarios, let's consolidate our learning with essential best practices for production deployment. ## Root Context Best Practices -Here are some best practices for managing root contexts effectively: +Successful implementation of root contexts requires careful attention to design patterns, operational concerns, and user experience. Master these essential practices for production-ready root context management: + +### šŸ—ļø Design Principles + +Effective root context design starts with clear architectural decisions that will serve your application as it scales. These foundational principles will guide your implementation: + +| Practice | Implementation | Why It Matters | +|----------|----------------|----------------| +| **šŸŽÆ Focused Contexts** | One context per conversation topic | Maintains clarity and relevance | +| **ā° Expiration Policies** | Auto-archive after 30 days of inactivity | Manages storage costs and compliance | +| **šŸ“Š Rich Metadata** | Store user info, preferences, session type | Enables analytics and personalization | +| **šŸ”‘ Consistent IDs** | Use the same context ID throughout | Ensures conversation continuity | + +### šŸ”§ Technical Implementation + +Beyond design principles, specific technical considerations will ensure your root context system performs reliably at scale: -- **Create Focused Contexts**: Create separate root contexts for different conversation purposes or domains to maintain clarity. +- **šŸ“ Generate Summaries**: When conversations grow long (>50 messages), create summaries using `context.generateSummary()` to maintain context efficiency +- **šŸ” Access Control**: Implement user-based permissions for sensitive conversations using `user_permissions` and `context_access_policies` +- **šŸ“ Handle Limitations**: Plan for context size limits with pagination or compression strategies via `context.paginate()` or `context.compress()` +- **šŸ—„ļø Archive Properly**: Always archive completed contexts using `context.archive(preserve_summary=True)` to free resources while preserving history -- **Set Expiration Policies**: Implement policies to archive or delete old contexts to manage storage and comply with data retention policies. +### 🚨 Common Pitfalls to Avoid -- **Store Relevant Metadata**: Use context metadata to store important information about the conversation that might be useful later. +Learning from common mistakes can save significant development time and prevent production issues: -- **Use Context IDs Consistently**: Once a context is created, use its ID consistently for all related requests to maintain continuity. +- āŒ **Don't** create new contexts for every message - use `existing_context_id` instead of `create_new_context()` +- āŒ **Don't** forget to clean up archived contexts - implement `cleanup_archived_contexts()` policies +- āŒ **Don't** store sensitive data in metadata without encryption - use `encrypt_metadata()` for PII +- āŒ **Don't** ignore context size limitations in long conversations - monitor `context.size()` and implement `context.summarize()` when needed -- **Generate Summaries**: When a context grows large, consider generating summaries to capture essential information while managing context size. +### āœ… Production Checklist -- **Implement Access Control**: For multi-user systems, implement proper access controls to ensure privacy and security of conversation contexts. +Before deploying your root context implementation, ensure you've addressed these critical requirements: -- **Handle Context Limitations**: Be aware of context size limitations and implement strategies for handling very long conversations. +- [ ] Context creation includes meaningful `metadata` with business-relevant fields +- [ ] Error handling covers network failures and API limits with `try-catch` blocks +- [ ] Automatic archival policies are configured via `context.auto_archive_after(days=30)` +- [ ] User permissions and privacy controls are implemented using `context.set_permissions(user_id, permissions)` +- [ ] Context size monitoring and management is in place with `context.monitor_size()` alerts +- [ ] Conversation summaries are generated for long sessions using `context.generate_summary()` when `message_count > 50` -- **Archive When Complete**: Archive contexts when conversations are complete to free resources while preserving the conversation history. +With a solid understanding of root contexts and their best practices, you're ready to explore how MCP handles complex request routing scenarios. ## What's next -- [5.5 Routing](../mcp-routing/README.md) \ No newline at end of file +- [5.5 Routing](../mcp-routing/README.md) diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/csharp/README.md b/05-AdvancedTopics/mcp-root-contexts/solution/csharp/README.md new file mode 100644 index 000000000..af326af92 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/csharp/README.md @@ -0,0 +1,97 @@ +# C# Root Context Example + +This example demonstrates how to implement MCP root contexts in a .NET application for customer support scenarios. + +## Prerequisites + +- .NET 8.0 SDK or later +- MCP .NET Client package +- Visual Studio 2022 or VS Code with C# extension + +## Setup + +1. **Create a new console application:** + ```bash + dotnet new console -n RootContextExample + cd RootContextExample + ``` + +2. **Add the MCP Client package:** + ```bash + dotnet add package Microsoft.Mcp.Client + ``` + +3. **Copy the example code:** + - Replace the contents of `Program.cs` with `RootContextExample.cs` + +4. **Update the project file (`RootContextExample.csproj`):** + ```xml + + + Exe + net8.0 + enable + enable + + + + + + + ``` + +## Configuration + +Update the MCP server URL in the `Main` method: +```csharp +var client = new McpClient("YOUR_MCP_SERVER_URL"); +``` + +## Running the Example + +1. **Build the project:** + ```bash + dotnet build + ``` + +2. **Run the application:** + ```bash + dotnet run + ``` + +## What the Example Demonstrates + +- āœ… **Context Creation**: Creating a new root context with metadata +- šŸ’¬ **Multi-turn Conversations**: Sending multiple messages that reference previous context +- šŸ“ **Metadata Updates**: Adding information discovered during conversations +- šŸ“Š **Context Monitoring**: Retrieving context information and statistics +- šŸ—„ļø **Context Archival**: Properly cleaning up completed conversations + +## Expected Output + +``` +āœ… Created root context with ID: [context-id] +šŸ¤– AI Response: [AI response about scaling issues] +šŸ¤– AI Response: [AI response referencing Kubernetes] +šŸ“ Updated context metadata with conversation insights +šŸ“Š Context Information: + • Name: Customer Support Session + • Created: [timestamp] + • Messages: 2 +šŸ—„ļø Archived context [context-id] +āœ… Root context demonstration completed! +``` + +## Key Features + +- **Enterprise-grade patterns**: Uses dependency injection and async/await +- **Type safety**: Strongly-typed objects with compile-time validation +- **Error handling**: Robust exception handling for production use +- **Metadata management**: Flexible metadata storage and retrieval + +## Next Steps + +- Integrate with your existing .NET application +- Add error handling and logging +- Implement user authentication +- Scale for production workloads \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/csharp/RootContextExample.cs b/05-AdvancedTopics/mcp-root-contexts/solution/csharp/RootContextExample.cs new file mode 100644 index 000000000..e8c7aabf8 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/csharp/RootContextExample.cs @@ -0,0 +1,109 @@ +// .NET Example: Root Context Management Setup +using Microsoft.Mcp.Client; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; + +public class RootContextExample +{ + private readonly IMcpClient _client; + private readonly IRootContextManager _contextManager; + + public RootContextExample(IMcpClient client, IRootContextManager contextManager) + { + _client = client; + _contextManager = contextManager; + } + + public async Task CreateSupportContextAsync() + { + // Create a new root context for customer support + var contextResult = await _contextManager.CreateRootContextAsync(new RootContextCreateOptions + { + Name = "Customer Support Session", + Metadata = new Dictionary + { + ["CustomerName"] = "Acme Corporation", + ["PriorityLevel"] = "High", + ["Domain"] = "Cloud Services" + } + }); + + string contextId = contextResult.ContextId; + Console.WriteLine($"āœ… Created root context with ID: {contextId}"); + return contextId; + } + + public async Task ConductConversationAsync(string contextId) + { + // First interaction using the context + var response1 = await _client.SendPromptAsync( + "I'm having issues scaling my web service deployment in the cloud.", + new SendPromptOptions { RootContextId = contextId } + ); + Console.WriteLine($"šŸ¤– AI Response: {response1.GeneratedText}"); + + // Second interaction - AI remembers the previous conversation + var response2 = await _client.SendPromptAsync( + "Yes, we're using containerized deployments with Kubernetes.", + new SendPromptOptions { RootContextId = contextId } + ); + Console.WriteLine($"šŸ¤– AI Response: {response2.GeneratedText}"); + } + + public async Task UpdateContextInfoAsync(string contextId) + { + // Add metadata based on what we learned from the conversation + await _contextManager.UpdateContextMetadataAsync(contextId, new Dictionary + { + ["TechnicalEnvironment"] = "Kubernetes", + ["IssueType"] = "Scaling", + ["Status"] = "In Progress" + }); + + Console.WriteLine("šŸ“ Updated context metadata with conversation insights"); + } + + public async Task DisplayContextInfoAsync(string contextId) + { + var contextInfo = await _contextManager.GetRootContextInfoAsync(contextId); + + Console.WriteLine("šŸ“Š Context Information:"); + Console.WriteLine($" • Name: {contextInfo.Name}"); + Console.WriteLine($" • Created: {contextInfo.CreatedAt}"); + Console.WriteLine($" • Messages: {contextInfo.MessageCount}"); + } + + public async Task ArchiveContextAsync(string contextId) + { + // When the conversation is complete, archive the context + await _contextManager.ArchiveRootContextAsync(contextId); + Console.WriteLine($"šŸ—„ļø Archived context {contextId}"); + } + + public async Task DemonstrateRootContextAsync() + { + var contextId = await CreateSupportContextAsync(); + await ConductConversationAsync(contextId); + await UpdateContextInfoAsync(contextId); + await DisplayContextInfoAsync(contextId); + await ArchiveContextAsync(contextId); + } +} + +// Program entry point +public class Program +{ + public static async Task Main(string[] args) + { + // Initialize MCP client and context manager + var client = new McpClient("https://mcp-server-example.com"); + var contextManager = new RootContextManager(client); + + // Run the demonstration + var example = new RootContextExample(client, contextManager); + await example.DemonstrateRootContextAsync(); + + Console.WriteLine("āœ… Root context demonstration completed!"); + } +} \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/dotnet/README.md b/05-AdvancedTopics/mcp-root-contexts/solution/dotnet/README.md new file mode 100644 index 000000000..5e8e9fbe2 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/dotnet/README.md @@ -0,0 +1,99 @@ +````markdown +# .NET Root Context Example + +This example demonstrates how to implement MCP root contexts in a .NET application for customer support scenarios. + +## Prerequisites + +- .NET 8.0 SDK or later +- MCP .NET Client package +- Visual Studio 2022 or VS Code with C# extension + +## Setup + +1. **Create a new console application:** + ```bash + dotnet new console -n RootContextExample + cd RootContextExample + ``` + +2. **Add the MCP Client package:** + ```bash + dotnet add package Microsoft.Mcp.Client + ``` + +3. **Copy the example code:** + - Replace the contents of `Program.cs` with `RootContextExample.cs` + +4. **Update the project file (`RootContextExample.csproj`):** + ```xml + + + Exe + net8.0 + enable + enable + + + + + + + ``` + +## Configuration + +Update the MCP server URL in the `Main` method: +```csharp +var client = new McpClient("YOUR_MCP_SERVER_URL"); +``` + +## Running the Example + +1. **Build the project:** + ```bash + dotnet build + ``` + +2. **Run the application:** + ```bash + dotnet run + ``` + +## What the Example Demonstrates + +- āœ… **Context Creation**: Creating a new root context with metadata +- šŸ’¬ **Multi-turn Conversations**: Sending multiple messages that reference previous context +- šŸ“ **Metadata Updates**: Adding information discovered during conversations +- šŸ“Š **Context Monitoring**: Retrieving context information and statistics +- šŸ—„ļø **Context Archival**: Properly cleaning up completed conversations + +## Expected Output + +``` +āœ… Created root context with ID: [context-id] +šŸ¤– AI Response: [AI response about scaling issues] +šŸ¤– AI Response: [AI response referencing Kubernetes] +šŸ“ Updated context metadata with conversation insights +šŸ“Š Context Information: + • Name: Customer Support Session + • Created: [timestamp] + • Messages: 2 +šŸ—„ļø Archived context [context-id] +āœ… Root context demonstration completed! +``` + +## Key Features + +- **Enterprise-grade patterns**: Uses dependency injection and async/await +- **Type safety**: Strongly-typed objects with compile-time validation +- **Error handling**: Robust exception handling for production use +- **Metadata management**: Flexible metadata storage and retrieval + +## Next Steps + +- Integrate with your existing .NET application +- Add error handling and logging +- Implement user authentication +- Scale for production workloads +```` \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/dotnet/RootContextExample.cs b/05-AdvancedTopics/mcp-root-contexts/solution/dotnet/RootContextExample.cs new file mode 100644 index 000000000..e8c7aabf8 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/dotnet/RootContextExample.cs @@ -0,0 +1,109 @@ +// .NET Example: Root Context Management Setup +using Microsoft.Mcp.Client; +using System; +using System.Threading.Tasks; +using System.Collections.Generic; + +public class RootContextExample +{ + private readonly IMcpClient _client; + private readonly IRootContextManager _contextManager; + + public RootContextExample(IMcpClient client, IRootContextManager contextManager) + { + _client = client; + _contextManager = contextManager; + } + + public async Task CreateSupportContextAsync() + { + // Create a new root context for customer support + var contextResult = await _contextManager.CreateRootContextAsync(new RootContextCreateOptions + { + Name = "Customer Support Session", + Metadata = new Dictionary + { + ["CustomerName"] = "Acme Corporation", + ["PriorityLevel"] = "High", + ["Domain"] = "Cloud Services" + } + }); + + string contextId = contextResult.ContextId; + Console.WriteLine($"āœ… Created root context with ID: {contextId}"); + return contextId; + } + + public async Task ConductConversationAsync(string contextId) + { + // First interaction using the context + var response1 = await _client.SendPromptAsync( + "I'm having issues scaling my web service deployment in the cloud.", + new SendPromptOptions { RootContextId = contextId } + ); + Console.WriteLine($"šŸ¤– AI Response: {response1.GeneratedText}"); + + // Second interaction - AI remembers the previous conversation + var response2 = await _client.SendPromptAsync( + "Yes, we're using containerized deployments with Kubernetes.", + new SendPromptOptions { RootContextId = contextId } + ); + Console.WriteLine($"šŸ¤– AI Response: {response2.GeneratedText}"); + } + + public async Task UpdateContextInfoAsync(string contextId) + { + // Add metadata based on what we learned from the conversation + await _contextManager.UpdateContextMetadataAsync(contextId, new Dictionary + { + ["TechnicalEnvironment"] = "Kubernetes", + ["IssueType"] = "Scaling", + ["Status"] = "In Progress" + }); + + Console.WriteLine("šŸ“ Updated context metadata with conversation insights"); + } + + public async Task DisplayContextInfoAsync(string contextId) + { + var contextInfo = await _contextManager.GetRootContextInfoAsync(contextId); + + Console.WriteLine("šŸ“Š Context Information:"); + Console.WriteLine($" • Name: {contextInfo.Name}"); + Console.WriteLine($" • Created: {contextInfo.CreatedAt}"); + Console.WriteLine($" • Messages: {contextInfo.MessageCount}"); + } + + public async Task ArchiveContextAsync(string contextId) + { + // When the conversation is complete, archive the context + await _contextManager.ArchiveRootContextAsync(contextId); + Console.WriteLine($"šŸ—„ļø Archived context {contextId}"); + } + + public async Task DemonstrateRootContextAsync() + { + var contextId = await CreateSupportContextAsync(); + await ConductConversationAsync(contextId); + await UpdateContextInfoAsync(contextId); + await DisplayContextInfoAsync(contextId); + await ArchiveContextAsync(contextId); + } +} + +// Program entry point +public class Program +{ + public static async Task Main(string[] args) + { + // Initialize MCP client and context manager + var client = new McpClient("https://mcp-server-example.com"); + var contextManager = new RootContextManager(client); + + // Run the demonstration + var example = new RootContextExample(client, contextManager); + await example.DemonstrateRootContextAsync(); + + Console.WriteLine("āœ… Root context demonstration completed!"); + } +} \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/java/FinancialAnalysisContext.java b/05-AdvancedTopics/mcp-root-contexts/solution/java/FinancialAnalysisContext.java new file mode 100644 index 000000000..90c6f9818 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/java/FinancialAnalysisContext.java @@ -0,0 +1,121 @@ +// Java Example: Financial Analysis Context Setup +package com.example.mcp.contexts; + +import com.mcp.client.McpClient; +import com.mcp.client.ContextManager; +import com.mcp.models.RootContext; +import com.mcp.models.McpResponse; +import java.util.HashMap; +import java.util.Map; + +public class FinancialAnalysisContext { + private final McpClient client; + private final ContextManager contextManager; + + public FinancialAnalysisContext(String serverUrl) { + this.client = new McpClient.Builder() + .setServerUrl(serverUrl) + .build(); + this.contextManager = new ContextManager(client); + } + + public String createAnalysisSession() throws Exception { + // Prepare metadata for our financial analysis + Map metadata = new HashMap<>(); + metadata.put("projectName", "Q1 2025 Financial Analysis"); + metadata.put("userRole", "Senior Financial Analyst"); + metadata.put("dataSource", "Q1 2025 Financial Reports"); + metadata.put("analysisType", "Technology Division Review"); + + // Create the root context + RootContext context = contextManager.createRootContext( + "Financial Analysis Session", metadata); + String contextId = context.getId(); + + System.out.println("šŸ“Š Created financial analysis context: " + contextId); + return contextId; + } + + public void performInitialAnalysis(String contextId) throws Exception { + // Ask the first analytical question + McpResponse response1 = client.sendPrompt( + "Analyze the trends in Q1 financial data for our technology division. " + + "Focus on revenue growth and major cost drivers.", + contextId + ); + + System.out.println("šŸ“ˆ Initial Analysis:"); + System.out.println(response1.getGeneratedText()); + + // Store key findings in context metadata + contextManager.addContextMetadata(contextId, + Map.of("initialFinding", "Technology division showing strong revenue growth")); + } + + public void performDeepDive(String contextId) throws Exception { + // Update context with discovered trend + contextManager.addContextMetadata(contextId, + Map.of("identifiedTrend", "Increasing cloud infrastructure costs")); + + // Follow-up question that builds on previous analysis + McpResponse response2 = client.sendPrompt( + "What's driving the increase in cloud infrastructure costs? " + + "How does this compare to industry benchmarks?", + contextId + ); + + System.out.println("šŸ” Deep Dive Analysis:"); + System.out.println(response2.getGeneratedText()); + } + + public void generateExecutiveSummary(String contextId) throws Exception { + // Generate a comprehensive summary + McpResponse summaryResponse = client.sendPrompt( + "Based on our entire analysis, create an executive summary " + + "with 3-5 key findings and actionable recommendations.", + contextId + ); + + // Store the summary for future reference + contextManager.addContextMetadata(contextId, Map.of( + "executiveSummary", summaryResponse.getGeneratedText(), + "analysisComplete", "true" + )); + + System.out.println("šŸ“‹ Executive Summary:"); + System.out.println(summaryResponse.getGeneratedText()); + } + + public void finalizeAnalysis(String contextId) throws Exception { + // Get comprehensive context information + RootContext updatedContext = contextManager.getRootContext(contextId); + + System.out.println("\nšŸ“Š Final Context Information:"); + System.out.println("ā”œā”€ Created: " + updatedContext.getCreatedAt()); + System.out.println("ā”œā”€ Last Updated: " + updatedContext.getLastUpdatedAt()); + System.out.println("└─ Status: Analysis Complete"); + + // Archive the completed analysis + contextManager.archiveContext(contextId); + System.out.println("\nšŸ—„ļø Financial analysis context archived successfully"); + } + + public void runCompleteAnalysis() throws Exception { + String contextId = createAnalysisSession(); + performInitialAnalysis(contextId); + performDeepDive(contextId); + generateExecutiveSummary(contextId); + finalizeAnalysis(contextId); + } + + public static void main(String[] args) { + try { + FinancialAnalysisContext example = new FinancialAnalysisContext("https://mcp-server-example.com"); + example.runCompleteAnalysis(); + System.out.println("āœ… Financial analysis demonstration completed!"); + } catch (Exception e) { + System.err.println("āŒ Error running analysis: " + e.getMessage()); + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/java/README.md b/05-AdvancedTopics/mcp-root-contexts/solution/java/README.md new file mode 100644 index 000000000..58b71ffdf --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/java/README.md @@ -0,0 +1,189 @@ +# Java Root Context Example + +This example demonstrates how to implement MCP root contexts in a Java application for financial analysis scenarios. + +## Prerequisites + +- Java 21 or later +- Maven 3.8+ or Gradle 8+ +- IDE (IntelliJ IDEA, Eclipse, or VS Code with Java extensions) + +## Setup with Maven + +1. **Create a new Maven project:** + ```bash + mvn archetype:generate -DgroupId=com.example.mcp \ + -DartifactId=root-context-example \ + -DarchetypeArtifactId=maven-archetype-quickstart \ + -DinteractiveMode=false + cd root-context-example + ``` + +2. **Update `pom.xml`:** + ```xml + + + 4.0.0 + + com.example.mcp + root-context-example + 1.0.0 + jar + + + 21 + 21 + UTF-8 + + + + + com.mcp + mcp-client + 1.0.0 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + + + + ``` + +3. **Copy the example code:** + - Place `FinancialAnalysisContext.java` in `src/main/java/com/example/mcp/contexts/` + +## Setup with Gradle + +1. **Create a new Gradle project:** + ```bash + gradle init --type java-application --dsl groovy + ``` + +2. **Update `build.gradle`:** + ```groovy + plugins { + id 'application' + } + + repositories { + mavenCentral() + } + + dependencies { + implementation 'com.mcp:mcp-client:1.0.0' + } + + java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + application { + mainClass = 'com.example.mcp.contexts.FinancialAnalysisContext' + } + ``` + +## Configuration + +Update the MCP server URL in the constructor: +```java +FinancialAnalysisContext example = new FinancialAnalysisContext("YOUR_MCP_SERVER_URL"); +``` + +## Running the Example + +### With Maven: +```bash +# Compile the project +mvn compile + +# Run the application +mvn exec:java -Dexec.mainClass="com.example.mcp.contexts.FinancialAnalysisContext" +``` + +### With Gradle: +```bash +# Build the project +./gradlew build + +# Run the application +./gradlew run +``` + +### With IDE: +- Open the project in your IDE +- Run the `main` method in `FinancialAnalysisContext.java` + +## What the Example Demonstrates + +- šŸ“Š **Analysis Session Creation**: Setting up a context for financial analysis +- šŸ“ˆ **Progressive Analysis**: Building insights through multiple questions +- šŸ” **Deep Dive Investigations**: Following up on discovered trends +- šŸ“‹ **Executive Summaries**: Synthesizing findings for leadership +- šŸ—„ļø **Context Archival**: Properly preserving analysis results + +## Expected Output + +``` +šŸ“Š Created financial analysis context: [context-id] +šŸ“ˆ Initial Analysis: +[AI analysis of Q1 trends and cost drivers] +šŸ” Deep Dive Analysis: +[AI analysis of cloud infrastructure costs] +šŸ“‹ Executive Summary: +[AI-generated executive summary with recommendations] + +šŸ“Š Final Context Information: +ā”œā”€ Created: [timestamp] +ā”œā”€ Last Updated: [timestamp] +└─ Status: Analysis Complete + +šŸ—„ļø Financial analysis context archived successfully +āœ… Financial analysis demonstration completed! +``` + +## Key Features + +- **Enterprise Java patterns**: Builder pattern, dependency injection ready +- **Exception handling**: Comprehensive error management +- **Business intelligence**: Financial analysis workflow +- **Metadata tracking**: Progressive context enrichment + +## Project Structure + +``` +src/ +ā”œā”€ā”€ main/ +│ └── java/ +│ └── com/ +│ └── example/ +│ └── mcp/ +│ └── contexts/ +│ └── FinancialAnalysisContext.java +└── test/ + └── java/ + └── com/ + └── example/ + └── mcp/ + └── contexts/ + └── FinancialAnalysisContextTest.java +``` + +## Next Steps + +- Add unit tests with JUnit 5 +- Implement Spring Boot integration +- Add logging with SLF4J and Logback +- Create REST API endpoints +- Integrate with existing enterprise systems \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/javascript/README.md b/05-AdvancedTopics/mcp-root-contexts/solution/javascript/README.md new file mode 100644 index 000000000..0aad5b533 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/javascript/README.md @@ -0,0 +1,215 @@ +# JavaScript Root Context Example + +This example demonstrates how to implement MCP root contexts in a JavaScript/Node.js application for customer support scenarios. + +## Prerequisites + +- Node.js 18.0 or later +- npm 9.0 or later +- A modern code editor (VS Code recommended) + +## Setup + +1. **Clone or navigate to the project directory:** + ```bash + cd solution/javascript + ``` + +2. **Install dependencies:** + ```bash + npm install + ``` + +3. **Configure your MCP server URL:** + Edit `contextSession.js` and update the server URL: + ```javascript + const session = new ContextSession('YOUR_MCP_SERVER_URL'); + ``` + +## Running the Example + +### Quick Start: +```bash +npm start +``` + +### Development Mode (with auto-restart): +```bash +npm run dev +``` + +### Run with Node directly: +```bash +node contextSession.js +``` + +## What the Example Demonstrates + +- āœ… **Context Creation**: Creating conversation contexts with rich metadata +- šŸ’¬ **Contextual Messaging**: Sending messages that build on previous interactions +- 🧠 **Insight Storage**: Automatically capturing important conversation points +- šŸ“Š **Context Monitoring**: Real-time session information and statistics +- šŸ“ **Smart Summaries**: AI-generated conversation summaries +- šŸ—„ļø **Graceful Archival**: Proper cleanup with summary preservation + +## Expected Output + +``` +šŸš€ Starting Context Session Demo + +āœ… Created 'Product Support - Database Performance' with ID: [context-id] + +šŸ“ž Starting customer support conversation... +šŸ¤– AI: [AI response about database performance]... +šŸ’” Stored 2 insights +šŸ¤– AI: [AI response about index configuration]... +šŸ’” Stored 1 insights + +šŸ“Š Context Summary: { + name: 'Product Support - Database Performance', + messages: 2, + created: '[timestamp]' +} + +šŸ“ Final Summary: [AI-generated summary of the conversation] + +āœ… Support session completed and archived! +``` + +## Project Structure + +``` +javascript/ +ā”œā”€ā”€ contextSession.js # Main implementation file +ā”œā”€ā”€ package.json # Node.js project configuration +ā”œā”€ā”€ README.md # This file +└── .gitignore # Git ignore patterns +``` + +## Key Features + +### ContextSession Class +- **Modular Design**: Clean class-based architecture +- **Error Handling**: Comprehensive try-catch blocks +- **Async/Await**: Modern JavaScript async patterns +- **ES6 Modules**: Uses import/export syntax + +### Smart Features +- **Automatic Insight Detection**: Scans conversations for important keywords +- **Metadata Enrichment**: Automatically adds timestamps and status information +- **Context Continuity**: Maintains conversation state across multiple interactions +- **Production Ready**: Includes error handling and logging + +## API Reference + +### ContextSession Methods + +#### `createConversationContext(sessionName, metadata)` +Creates a new root context for conversation tracking. + +#### `sendMessage(contextId, message, options)` +Sends a message within an existing context with optional configurations. + +#### `storeConversationInsights(contextId, userMessage, aiResponse)` +Automatically extracts and stores important conversation insights. + +#### `getContextInfo(contextId)` +Retrieves comprehensive context information and statistics. + +#### `generateContextSummary(contextId)` +Generates an AI-powered summary of the entire conversation. + +#### `archiveContext(contextId)` +Archives a completed context with final summary preservation. + +## Configuration Options + +### Client Configuration +```javascript +const session = new ContextSession('server-url', { + apiKey: 'your-api-key', + timeout: 30000, + retries: 3 +}); +``` + +### Message Options +```javascript +await session.sendMessage(contextId, message, { + temperature: 0.7, + allowedTools: ['search', 'calculator'], + storeInsights: true +}); +``` + +## Development + +### Code Formatting: +```bash +npm run format +``` + +### Linting: +```bash +npm run lint +``` + +### Testing: +```bash +npm test +``` + +## Integration Examples + +### Express.js Integration +```javascript +import express from 'express'; +import { ContextSession } from './contextSession.js'; + +const app = express(); +const session = new ContextSession(process.env.MCP_SERVER_URL); + +app.post('/support/message', async (req, res) => { + try { + const { contextId, message } = req.body; + const response = await session.sendMessage(contextId, message); + res.json(response); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); +``` + +### React.js Integration +```javascript +import { ContextSession } from './contextSession.js'; + +const useContextSession = () => { + const session = new ContextSession(process.env.REACT_APP_MCP_SERVER_URL); + + const sendMessage = async (contextId, message) => { + return await session.sendMessage(contextId, message); + }; + + return { sendMessage }; +}; +``` + +## Environment Variables + +Create a `.env` file for configuration: +```bash +MCP_SERVER_URL=https://your-mcp-server.com +API_KEY=your-api-key +NODE_ENV=development +``` + +## Next Steps + +- Add unit tests with Jest or Mocha +- Implement WebSocket support for real-time updates +- Add authentication middleware +- Create a web interface with React or Vue.js +- Deploy to cloud platforms (Vercel, Netlify, AWS) +- Add monitoring and analytics +- Implement rate limiting and security measures \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/javascript/contextSession.js b/05-AdvancedTopics/mcp-root-contexts/solution/javascript/contextSession.js new file mode 100644 index 000000000..9e94807cb --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/javascript/contextSession.js @@ -0,0 +1,236 @@ +// JavaScript Example: Context Session Manager +import { McpClient, RootContextManager } from '@mcp/client'; + +class ContextSession { + constructor(serverUrl, apiKey = null) { + // Initialize the MCP client + this.client = new McpClient({ serverUrl, apiKey }); + // Initialize context manager + this.contextManager = new RootContextManager(this.client); + } + + /** + * Create a new conversation context + * @param {string} sessionName - Name of the conversation session + * @param {Object} metadata - Additional metadata for the context + * @returns {Promise} - Context ID + */ + async createConversationContext(sessionName, metadata = {}) { + try { + const contextResult = await this.contextManager.createRootContext({ + name: sessionName, + metadata: { + ...metadata, + createdAt: new Date().toISOString(), + status: 'active' + } + }); + + console.log(`āœ… Created '${sessionName}' with ID: ${contextResult.id}`); + return contextResult.id; + } catch (error) { + console.error('āŒ Error creating context:', error); + throw error; + } + } + + /** + * Send a message in an existing context + * @param {string} contextId - The root context ID + * @param {string} message - The user's message + * @param {Object} options - Additional options + */ + async sendMessage(contextId, message, options = {}) { + try { + const response = await this.client.sendPrompt(message, { + rootContextId: contextId, + temperature: options.temperature || 0.7, + allowedTools: options.allowedTools || [] + }); + + // Store insights if requested + if (options.storeInsights) { + await this.storeConversationInsights(contextId, message, response.generatedText); + } + + return { + message: response.generatedText, + toolCalls: response.toolCalls || [], + contextId + }; + } catch (error) { + console.error(`āŒ Error in context ${contextId}:`, error); + throw error; + } + } + + /** + * Store important insights from a conversation + * @param {string} contextId - The root context ID + * @param {string} userMessage - User's message + * @param {string} aiResponse - AI's response + */ + async storeConversationInsights(contextId, userMessage, aiResponse) { + try { + const combinedText = userMessage + "\n" + aiResponse; + const insightWords = ["important", "key point", "remember", "significant", "crucial"]; + + const potentialInsights = combinedText + .split(".") + .filter(sentence => + insightWords.some(word => sentence.toLowerCase().includes(word)) + ) + .map(sentence => sentence.trim()) + .filter(sentence => sentence.length > 10); + + if (potentialInsights.length > 0) { + const insights = {}; + potentialInsights.forEach((insight, index) => { + insights[`insight_${Date.now()}_${index}`] = insight; + }); + + await this.contextManager.updateContextMetadata(contextId, insights); + console.log(`šŸ’” Stored ${potentialInsights.length} insights`); + } + } catch (error) { + console.warn('āš ļø Could not store insights:', error); + } + } + + /** + * Get comprehensive context information + * @param {string} contextId - The root context ID + * @returns {Promise} - Formatted context information + */ + async getContextInfo(contextId) { + try { + const contextInfo = await this.contextManager.getContextInfo(contextId); + + return { + id: contextInfo.id, + name: contextInfo.name, + created: new Date(contextInfo.createdAt).toLocaleString(), + lastUpdated: new Date(contextInfo.lastUpdatedAt).toLocaleString(), + messageCount: contextInfo.messageCount, + metadata: contextInfo.metadata, + status: contextInfo.status + }; + } catch (error) { + console.error(`āŒ Error getting context info:`, error); + throw error; + } + } + + /** + * Generate an intelligent conversation summary + * @param {string} contextId - The root context ID + * @returns {Promise} - Generated summary + */ + async generateContextSummary(contextId) { + try { + const response = await this.client.sendPrompt( + "Please summarize our conversation in 3-4 sentences, " + + "highlighting key points and any decisions made.", + { rootContextId: contextId, temperature: 0.3 } + ); + + // Store summary with timestamp + await this.contextManager.updateContextMetadata(contextId, { + conversationSummary: response.generatedText, + summarizedAt: new Date().toISOString() + }); + + return response.generatedText; + } catch (error) { + console.error(`āŒ Error generating summary:`, error); + throw error; + } + } + + /** + * Archive a context with final summary + * @param {string} contextId - The root context ID + * @returns {Promise} - Archive operation result + */ + async archiveContext(contextId) { + try { + // Generate final summary before archiving + const summary = await this.generateContextSummary(contextId); + + // Archive the context + await this.contextManager.archiveContext(contextId); + + return { + status: "archived", + contextId, + summary + }; + } catch (error) { + console.error(`āŒ Error archiving context:`, error); + throw error; + } + } +} + +// Complete demonstration of context session management +export async function demonstrateContextSession() { + console.log('šŸš€ Starting Context Session Demo\n'); + const session = new ContextSession('https://mcp-server-example.com'); + + try { + // 1. Create customer support context + const contextId = await session.createConversationContext( + 'Product Support - Database Performance', + { + customer: 'Globex Corporation', + product: 'Enterprise Database', + severity: 'Medium', + supportAgent: 'AI Assistant' + } + ); + + console.log('\nšŸ“ž Starting customer support conversation...'); + + // 2. Initial support request + const response1 = await session.sendMessage( + contextId, + "I'm experiencing slow query performance after the latest update.", + { storeInsights: true } + ); + console.log('šŸ¤– AI:', response1.message.substring(0, 100) + '...'); + + // 3. Follow-up with more context + const response2 = await session.sendMessage( + contextId, + "We've checked indexes and they're properly configured.", + { storeInsights: true } + ); + console.log('šŸ¤– AI:', response2.message.substring(0, 100) + '...'); + + // 4. Review context information + const contextInfo = await session.getContextInfo(contextId); + console.log('\nšŸ“Š Context Summary:', { + name: contextInfo.name, + messages: contextInfo.messageCount, + created: contextInfo.created + }); + + // 5. Generate final summary + const summary = await session.generateContextSummary(contextId); + console.log('\nšŸ“ Final Summary:', summary); + + // 6. Archive completed session + await session.archiveContext(contextId); + console.log('\nāœ… Support session completed and archived!'); + + } catch (error) { + console.error('āŒ Demo failed:', error); + } +} + +// Run the demonstration +if (import.meta.main) { + demonstrateContextSession(); +} + +export { ContextSession }; \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/javascript/package.json b/05-AdvancedTopics/mcp-root-contexts/solution/javascript/package.json new file mode 100644 index 000000000..0a07e1dc4 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/javascript/package.json @@ -0,0 +1,33 @@ +{ + "name": "mcp-root-context-example", + "version": "1.0.0", + "description": "Example demonstrating MCP root contexts for customer support", + "type": "module", + "main": "contextSession.js", + "scripts": { + "start": "node contextSession.js", + "dev": "node --watch contextSession.js", + "test": "node --test", + "lint": "eslint .", + "format": "prettier --write ." + }, + "dependencies": { + "@mcp/client": "^1.0.0" + }, + "devDependencies": { + "eslint": "^8.57.0", + "prettier": "^3.0.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "keywords": [ + "mcp", + "model-context-protocol", + "root-contexts", + "ai", + "customer-support" + ], + "author": "Microsoft", + "license": "MIT" +} \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/python/requirements.txt b/05-AdvancedTopics/mcp-root-contexts/solution/python/requirements.txt new file mode 100644 index 000000000..0174932f0 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/python/requirements.txt @@ -0,0 +1,2 @@ +mcp-client>=1.0.0 +asyncio \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/python/technical_assistant.py b/05-AdvancedTopics/mcp-root-contexts/solution/python/technical_assistant.py new file mode 100644 index 000000000..1b922006a --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/python/technical_assistant.py @@ -0,0 +1,153 @@ +# Python Example: Technical Support Assistant +import asyncio +from datetime import datetime +from mcp_client import McpClient, RootContextManager + +class TechnicalAssistant: + def __init__(self, server_url, api_key=None): + self.client = McpClient(server_url=server_url, api_key=api_key) + self.context_manager = RootContextManager(self.client) + print("šŸ¤– Technical Assistant initialized") + + async def create_support_session(self, session_name, user_info=None): + """Create a personalized technical support session""" + metadata = { + "session_type": "technical_support", + "created_at": datetime.now().isoformat(), + "status": "active" + } + + # Personalize with user information + if user_info: + metadata.update({f"user_{k}": v for k, v in user_info.items()}) + + # Create the support context + context = await self.context_manager.create_root_context(session_name, metadata) + print(f"šŸ“ž Created support session '{session_name}' (ID: {context.id})") + return context.id + + async def send_support_message(self, context_id, message, tools=None): + """Send a message with optional tool access""" + options = {"root_context_id": context_id} + + # Add specialized tools for technical support + if tools: + options["allowed_tools"] = tools + + # Send message within the support context + response = await self.client.send_prompt(message, options) + + # Track conversation progress + await self._update_session_progress(context_id, message) + + return response + + async def _update_session_progress(self, context_id, message): + """Update session metadata with conversation progress""" + timestamp = datetime.now().timestamp() + await self.context_manager.update_context_metadata(context_id, { + f"interaction_{int(timestamp)}": message[:30] + "...", + "last_interaction": datetime.now().isoformat(), + "total_messages": await self._count_messages(context_id) + }) + + async def get_session_info(self, context_id): + """Get comprehensive session information""" + context_info = await self.context_manager.get_context_info(context_id) + messages = await self.client.get_context_messages(context_id) + + return { + "session_info": { + "id": context_info.id, + "name": context_info.name, + "created": context_info.created_at, + "status": context_info.metadata.get("status", "unknown") + }, + "conversation": { + "message_count": len(messages), + "messages": messages + } + } + + async def _count_messages(self, context_id): + """Count total messages in the session""" + messages = await self.client.get_context_messages(context_id) + return len(messages) + + async def end_support_session(self, context_id): + """End support session with summary and resolution status""" + # Generate comprehensive session summary + summary_response = await self.client.send_prompt( + "Please provide a technical summary of our troubleshooting session, " + "including the problem, steps taken, and final resolution.", + {"root_context_id": context_id} + ) + + # Store final session data + final_metadata = { + "technical_summary": summary_response.generated_text, + "session_ended": datetime.now().isoformat(), + "status": "resolved", + "resolution_provided": "yes" + } + + await self.context_manager.update_context_metadata(context_id, final_metadata) + + # Archive the completed session + await self.context_manager.archive_context(context_id) + + return { + "status": "session_completed", + "summary": summary_response.generated_text, + "context_id": context_id + } + +# Demonstration: Complete technical support workflow +async def demo_technical_support(): + print("šŸ› ļø Starting Technical Support Demo\n") + assistant = TechnicalAssistant("https://mcp-server-example.com") + + try: + # 1. Create personalized support session + context_id = await assistant.create_support_session( + "Cloud Auto-Scaling Support", + { + "name": "Alex Chen", + "technical_level": "advanced", + "product": "Cloud Platform", + "department": "DevOps" + } + ) + + print("\nšŸ”§ Starting troubleshooting...") + + # 2. Initial problem report + response1 = await assistant.send_support_message( + context_id, + "I'm having trouble with auto-scaling. Instances aren't scaling up during traffic spikes.", + ["documentation_search", "diagnostic_tool", "log_analyzer"] + ) + print(f"šŸ¤– Assistant: {response1.generated_text[:80]}...") + + # 3. Follow-up with more details + response2 = await assistant.send_support_message( + context_id, + "I've checked the scaling policies and thresholds. CPU is hitting 85% but no new instances launch." + ) + print(f"šŸ¤– Assistant: {response2.generated_text[:80]}...") + + # 4. Get session information + session_info = await assistant.get_session_info(context_id) + print(f"\nšŸ“Š Session Status: {session_info['conversation']['message_count']} messages exchanged") + + # 5. Resolve and close session + resolution = await assistant.end_support_session(context_id) + print(f"\nāœ… Session resolved!") + print(f"šŸ“ Summary: {resolution['summary'][:100]}...") + + except Exception as error: + print(f"āŒ Support session failed: {error}") + +# Run the technical support demonstration +if __name__ == "__main__": + asyncio.run(demo_technical_support()) \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/typescript/README.md b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/README.md new file mode 100644 index 000000000..8431555d1 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/README.md @@ -0,0 +1,333 @@ +````markdown +# TypeScript Root Context Example + +This example demonstrates how to implement MCP root contexts in a TypeScript/Node.js application with full type safety for customer support scenarios. + +## Prerequisites + +- Node.js 18.0 or later +- npm 9.0 or later +- TypeScript 5.0 or later +- A modern code editor (VS Code recommended) + +## Setup + +1. **Navigate to the project directory:** + ```bash + cd solution/typescript + ``` + +2. **Install dependencies:** + ```bash + npm install + ``` + +3. **Configure your MCP server URL:** + Edit `src/contextSession.ts` and update the server URL: + ```typescript + const session = new ContextSession('YOUR_MCP_SERVER_URL'); + ``` + +## Running the Example + +### Development Mode (recommended): +```bash +npm run dev +``` + +### Build and Run: +```bash +npm run build +npm start +``` + +### Type Checking: +```bash +npm run type-check +``` + +## Project Structure + +``` +typescript/ +ā”œā”€ā”€ src/ +│ ā”œā”€ā”€ index.ts # Main entry point +│ ā”œā”€ā”€ contextSession.ts # Core implementation +│ └── types.d.ts # Type definitions +ā”œā”€ā”€ dist/ # Compiled JavaScript (after build) +ā”œā”€ā”€ package.json # Dependencies and scripts +ā”œā”€ā”€ tsconfig.json # TypeScript configuration +└── README.md # This file +``` + +## What the Example Demonstrates + +- āœ… **Type Safety**: Full TypeScript type coverage with interfaces and generics +- šŸ’¬ **Contextual Messaging**: Strongly-typed message options and responses +- 🧠 **Insight Storage**: Type-safe metadata storage and retrieval +- šŸ“Š **Context Monitoring**: Structured context information with type definitions +- šŸ“ **Smart Summaries**: Promise-based summary generation with error handling +- šŸ—„ļø **Graceful Archival**: Type-safe archival operations with result types + +## Expected Output + +``` +šŸš€ Starting TypeScript Context Session Demo + +āœ… Created 'Product Support - Database Performance' with ID: [context-id] + +šŸ“ž Starting customer support conversation... +šŸ¤– AI: [AI response about database performance]... +šŸ’” Stored 2 insights +šŸ¤– AI: [AI response about index configuration]... +šŸ’” Stored 1 insights + +šŸ“Š Context Summary: { + name: 'Product Support - Database Performance', + messages: 2, + created: '[timestamp]' +} + +šŸ“ Final Summary: [AI-generated summary of the conversation] + +āœ… Support session completed and archived! +šŸ“¦ Archive Status: archived +``` + +## Key TypeScript Features + +### Strong Type Definitions +```typescript +interface ContextMetadata { + [key: string]: string | number | boolean; + createdAt?: string; + status?: 'active' | 'archived' | 'suspended'; +} + +interface MessageOptions { + temperature?: number; + allowedTools?: string[]; + storeInsights?: boolean; +} +``` + +### Type-Safe Error Handling +```typescript +try { + const result = await session.createConversationContext(name, metadata); + return result; +} catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.error('āŒ Error:', errorMessage); + throw error; +} +``` + +### Generic Method Signatures +```typescript +async createConversationContext( + sessionName: string, + metadata: ContextMetadata = {} +): Promise +``` + +### Strict Null Checks +```typescript +const response = await this.client.sendPrompt(message, { + rootContextId: contextId, + temperature: options.temperature ?? 0.7, // Nullish coalescing + allowedTools: options.allowedTools ?? [] // Default values +}); +``` + +## API Reference + +### ContextSession Class + +#### Constructor +```typescript +constructor(serverUrl: string, apiKey?: string) +``` + +#### Methods +```typescript +createConversationContext(sessionName: string, metadata?: ContextMetadata): Promise +sendMessage(contextId: string, message: string, options?: MessageOptions): Promise +getContextInfo(contextId: string): Promise +generateContextSummary(contextId: string): Promise +archiveContext(contextId: string): Promise +``` + +## Development Scripts + +### Build Commands: +```bash +npm run build # Compile TypeScript to JavaScript +npm run clean # Remove compiled files +npm run type-check # Check types without compilation +``` + +### Development Commands: +```bash +npm run dev # Watch mode with automatic restart +npm start # Run compiled JavaScript +``` + +### Code Quality: +```bash +npm run lint # ESLint type checking +npm run format # Prettier code formatting +npm test # Run Jest tests +``` + +## Configuration Files + +### TypeScript Configuration (`tsconfig.json`) +- **Target**: ES2022 for modern JavaScript features +- **Module System**: ESNext with Node resolution +- **Strict Mode**: Full TypeScript strict mode enabled +- **Source Maps**: Enabled for debugging +- **Declaration Files**: Generated for library usage + +### Package Configuration (`package.json`) +- **Type**: Module (ESM) +- **Scripts**: Comprehensive development and build scripts +- **Dependencies**: MCP client with TypeScript support +- **Dev Dependencies**: Full TypeScript toolchain + +## Type Safety Benefits + +1. **Compile-time Error Detection**: Catch errors before runtime +2. **IntelliSense Support**: Rich autocomplete and documentation +3. **Refactoring Safety**: Rename and restructure with confidence +4. **Interface Contracts**: Clear API boundaries and expectations +5. **Generic Type Support**: Flexible yet type-safe implementations + +## Integration Examples + +### Express.js with TypeScript +```typescript +import express, { Request, Response } from 'express'; +import { ContextSession, MessageOptions } from './contextSession.js'; + +interface MessageRequest { + contextId: string; + message: string; + options?: MessageOptions; +} + +const app = express(); +const session = new ContextSession(process.env.MCP_SERVER_URL!); + +app.post('/support/message', async (req: Request<{}, {}, MessageRequest>, res: Response) => { + try { + const { contextId, message, options } = req.body; + const response = await session.sendMessage(contextId, message, options); + res.json(response); + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + res.status(500).json({ error: errorMessage }); + } +}); +``` + +### React Hook with TypeScript +```typescript +import { useState, useCallback } from 'react'; +import { ContextSession, MessageResponse } from './contextSession'; + +interface UseContextSessionReturn { + sendMessage: (contextId: string, message: string) => Promise; + loading: boolean; + error: string | null; +} + +export const useContextSession = (): UseContextSessionReturn => { + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const session = new ContextSession(process.env.REACT_APP_MCP_SERVER_URL!); + + const sendMessage = useCallback(async (contextId: string, message: string): Promise => { + setLoading(true); + setError(null); + + try { + const response = await session.sendMessage(contextId, message); + return response; + } catch (err: unknown) { + const errorMessage = err instanceof Error ? err.message : 'Unknown error'; + setError(errorMessage); + throw err; + } finally { + setLoading(false); + } + }, [session]); + + return { sendMessage, loading, error }; +}; +``` + +## Environment Configuration + +Create a `.env` file for type-safe environment variables: +```bash +MCP_SERVER_URL=https://your-mcp-server.com +API_KEY=your-api-key +NODE_ENV=development +``` + +Add environment type definitions: +```typescript +declare global { + namespace NodeJS { + interface ProcessEnv { + MCP_SERVER_URL: string; + API_KEY?: string; + NODE_ENV: 'development' | 'production' | 'test'; + } + } +} +``` + +## Next Steps + +- Add comprehensive unit tests with Jest and TypeScript +- Implement WebSocket support with typed event handlers +- Create API documentation with TypeDoc +- Add authentication middleware with type-safe JWT handling +- Deploy to cloud platforms with proper TypeScript build pipeline +- Implement monitoring with structured logging types +- Add rate limiting with configurable type-safe options + +## Troubleshooting + +### Common TypeScript Issues + +**Import Errors:** +```bash +# Install missing type definitions +npm install --save-dev @types/node + +# Update tsconfig.json for proper module resolution +``` + +**Build Errors:** +```bash +# Clean and rebuild +npm run clean +npm run build + +# Check for type errors +npm run type-check +``` + +**Runtime Errors:** +```bash +# Ensure compiled JavaScript exists +npm run build + +# Check source maps for debugging +node --enable-source-maps dist/index.js +``` +```` \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/typescript/package.json b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/package.json new file mode 100644 index 000000000..3a1e3c3fa --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/package.json @@ -0,0 +1,44 @@ +{ + "name": "mcp-root-context-typescript-example", + "version": "1.0.0", + "description": "TypeScript example demonstrating MCP root contexts for customer support", + "type": "module", + "main": "dist/index.js", + "scripts": { + "build": "tsc", + "start": "npm run build && node dist/index.js", + "dev": "tsx watch src/index.ts", + "clean": "rimraf dist", + "type-check": "tsc --noEmit", + "lint": "eslint src/**/*.ts", + "format": "prettier --write src/**/*.ts", + "test": "jest" + }, + "dependencies": { + "@mcp/client": "^1.0.0" + }, + "devDependencies": { + "@types/node": "^20.8.0", + "@typescript-eslint/eslint-plugin": "^6.7.0", + "@typescript-eslint/parser": "^6.7.0", + "eslint": "^8.50.0", + "jest": "^29.7.0", + "prettier": "^3.0.3", + "rimraf": "^5.0.5", + "tsx": "^3.14.0", + "typescript": "^5.2.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "keywords": [ + "mcp", + "model-context-protocol", + "root-contexts", + "typescript", + "ai", + "customer-support" + ], + "author": "Microsoft", + "license": "MIT" +} \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/contextSession.ts b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/contextSession.ts new file mode 100644 index 000000000..50c8ba6b8 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/contextSession.ts @@ -0,0 +1,287 @@ +// TypeScript Example: Context Session Manager with Strong Types +import { McpClient, RootContextManager } from '@mcp/client'; + +interface ContextMetadata { + [key: string]: string | number | boolean; + createdAt?: string; + status?: 'active' | 'archived' | 'suspended'; +} + +interface MessageOptions { + temperature?: number; + allowedTools?: string[]; + storeInsights?: boolean; +} + +interface MessageResponse { + message: string; + toolCalls: Array<{ name: string; arguments: Record }>; + contextId: string; +} + +interface ContextInfo { + id: string; + name: string; + created: string; + lastUpdated: string; + messageCount: number; + metadata: ContextMetadata; + status: string; +} + +interface ArchiveResult { + status: 'archived'; + contextId: string; + summary: string; +} + +export class ContextSession { + private readonly client: McpClient; + private readonly contextManager: RootContextManager; + + constructor(serverUrl: string, apiKey?: string) { + // Initialize the MCP client with TypeScript strict types + this.client = new McpClient({ serverUrl, apiKey }); + // Initialize context manager + this.contextManager = new RootContextManager(this.client); + } + + /** + * Create a new conversation context with type safety + * @param sessionName - Name of the conversation session + * @param metadata - Additional metadata for the context + * @returns Promise resolving to context ID + */ + async createConversationContext( + sessionName: string, + metadata: ContextMetadata = {} + ): Promise { + try { + const contextResult = await this.contextManager.createRootContext({ + name: sessionName, + metadata: { + ...metadata, + createdAt: new Date().toISOString(), + status: 'active' as const + } + }); + + console.log(`āœ… Created '${sessionName}' with ID: ${contextResult.id}`); + return contextResult.id; + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.error('āŒ Error creating context:', errorMessage); + throw error; + } + } + + /** + * Send a message in an existing context with full type safety + * @param contextId - The root context ID + * @param message - The user's message + * @param options - Additional options with defaults + */ + async sendMessage( + contextId: string, + message: string, + options: MessageOptions = {} + ): Promise { + try { + const response = await this.client.sendPrompt(message, { + rootContextId: contextId, + temperature: options.temperature ?? 0.7, + allowedTools: options.allowedTools ?? [] + }); + + // Store insights if requested + if (options.storeInsights === true) { + await this.storeConversationInsights(contextId, message, response.generatedText); + } + + return { + message: response.generatedText, + toolCalls: response.toolCalls ?? [], + contextId + }; + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.error(`āŒ Error in context ${contextId}:`, errorMessage); + throw error; + } + } + + /** + * Store important insights from a conversation with intelligent parsing + * @param contextId - The root context ID + * @param userMessage - User's message + * @param aiResponse - AI's response + */ + private async storeConversationInsights( + contextId: string, + userMessage: string, + aiResponse: string + ): Promise { + try { + const combinedText = `${userMessage}\n${aiResponse}`; + const insightKeywords = ['important', 'key point', 'remember', 'significant', 'crucial']; + + const potentialInsights = combinedText + .split('.') + .filter((sentence: string) => + insightKeywords.some((keyword: string) => + sentence.toLowerCase().includes(keyword) + ) + ) + .map((sentence: string) => sentence.trim()) + .filter((sentence: string) => sentence.length > 10); + + if (potentialInsights.length > 0) { + const insights: ContextMetadata = {}; + potentialInsights.forEach((insight: string, index: number) => { + insights[`insight_${Date.now()}_${index}`] = insight; + }); + + await this.contextManager.updateContextMetadata(contextId, insights); + console.log(`šŸ’” Stored ${potentialInsights.length} insights`); + } + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.warn('āš ļø Could not store insights:', errorMessage); + } + } + + /** + * Get comprehensive context information with strong typing + * @param contextId - The root context ID + * @returns Promise resolving to formatted context information + */ + async getContextInfo(contextId: string): Promise { + try { + const contextInfo = await this.contextManager.getContextInfo(contextId); + + return { + id: contextInfo.id, + name: contextInfo.name, + created: new Date(contextInfo.createdAt).toLocaleString(), + lastUpdated: new Date(contextInfo.lastUpdatedAt).toLocaleString(), + messageCount: contextInfo.messageCount, + metadata: contextInfo.metadata, + status: contextInfo.status + }; + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.error('āŒ Error getting context info:', errorMessage); + throw error; + } + } + + /** + * Generate an intelligent conversation summary + * @param contextId - The root context ID + * @returns Promise resolving to generated summary + */ + async generateContextSummary(contextId: string): Promise { + try { + const response = await this.client.sendPrompt( + 'Please summarize our conversation in 3-4 sentences, ' + + 'highlighting key points and any decisions made.', + { rootContextId: contextId, temperature: 0.3 } + ); + + // Store summary with timestamp + await this.contextManager.updateContextMetadata(contextId, { + conversationSummary: response.generatedText, + summarizedAt: new Date().toISOString() + }); + + return response.generatedText; + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.error('āŒ Error generating summary:', errorMessage); + throw error; + } + } + + /** + * Archive a context with final summary + * @param contextId - The root context ID + * @returns Promise resolving to archive operation result + */ + async archiveContext(contextId: string): Promise { + try { + // Generate final summary before archiving + const summary = await this.generateContextSummary(contextId); + + // Archive the context + await this.contextManager.archiveContext(contextId); + + return { + status: 'archived' as const, + contextId, + summary + }; + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + console.error('āŒ Error archiving context:', errorMessage); + throw error; + } + } +} + +// Complete demonstration of context session management with types +export async function demonstrateContextSession(): Promise { + console.log('šŸš€ Starting TypeScript Context Session Demo\n'); + const session = new ContextSession('https://mcp-server-example.com'); + + try { + // 1. Create customer support context with typed metadata + const contextId = await session.createConversationContext( + 'Product Support - Database Performance', + { + customer: 'Globex Corporation', + product: 'Enterprise Database', + severity: 'Medium', + supportAgent: 'AI Assistant' + } + ); + + console.log('\nšŸ“ž Starting customer support conversation...'); + + // 2. Initial support request with options + const response1 = await session.sendMessage( + contextId, + "I'm experiencing slow query performance after the latest update.", + { storeInsights: true, temperature: 0.8 } + ); + console.log('šŸ¤– AI:', response1.message.substring(0, 100) + '...'); + + // 3. Follow-up with more context + const response2 = await session.sendMessage( + contextId, + "We've checked indexes and they're properly configured.", + { storeInsights: true, allowedTools: ['database-analyzer'] } + ); + console.log('šŸ¤– AI:', response2.message.substring(0, 100) + '...'); + + // 4. Review context information with full typing + const contextInfo: ContextInfo = await session.getContextInfo(contextId); + console.log('\nšŸ“Š Context Summary:', { + name: contextInfo.name, + messages: contextInfo.messageCount, + created: contextInfo.created + }); + + // 5. Generate final summary + const summary: string = await session.generateContextSummary(contextId); + console.log('\nšŸ“ Final Summary:', summary); + + // 6. Archive completed session + const archiveResult: ArchiveResult = await session.archiveContext(contextId); + console.log('\nāœ… Support session completed and archived!'); + console.log(`šŸ“¦ Archive Status: ${archiveResult.status}`); + + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; + console.error('āŒ Demo failed:', errorMessage); + } +} \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/index.ts b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/index.ts new file mode 100644 index 000000000..706d5fe94 --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/index.ts @@ -0,0 +1,24 @@ +// TypeScript Example: Main Entry Point +import { demonstrateContextSession } from './contextSession.js'; + +/** + * Main entry point for the TypeScript MCP Root Context demonstration + */ +async function main(): Promise { + try { + await demonstrateContextSession(); + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; + console.error('āŒ Application failed:', errorMessage); + process.exit(1); + } +} + +// Check if this module is being run directly +if (import.meta.url === `file://${process.argv[1]}`) { + main().catch((error: unknown) => { + const errorMessage = error instanceof Error ? error.message : 'Unhandled error'; + console.error('šŸ’„ Unhandled error:', errorMessage); + process.exit(1); + }); +} \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/types.d.ts b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/types.d.ts new file mode 100644 index 000000000..928bb11ef --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/src/types.d.ts @@ -0,0 +1,46 @@ +// TypeScript type definitions for MCP Client (mock types for demonstration) +declare module '@mcp/client' { + export interface McpClientOptions { + serverUrl: string; + apiKey?: string; + } + + export interface RootContextCreateOptions { + name: string; + metadata?: Record; + } + + export interface RootContextResult { + id: string; + name: string; + createdAt: string; + lastUpdatedAt: string; + messageCount: number; + metadata: Record; + status: string; + } + + export interface SendPromptOptions { + rootContextId?: string; + temperature?: number; + allowedTools?: string[]; + } + + export interface PromptResponse { + generatedText: string; + toolCalls?: Array<{ name: string; arguments: Record }>; + } + + export class McpClient { + constructor(options: McpClientOptions); + sendPrompt(message: string, options?: SendPromptOptions): Promise; + } + + export class RootContextManager { + constructor(client: McpClient); + createRootContext(options: RootContextCreateOptions): Promise; + getContextInfo(contextId: string): Promise; + updateContextMetadata(contextId: string, metadata: Record): Promise; + archiveContext(contextId: string): Promise; + } +} \ No newline at end of file diff --git a/05-AdvancedTopics/mcp-root-contexts/solution/typescript/tsconfig.json b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/tsconfig.json new file mode 100644 index 000000000..a3517f2bd --- /dev/null +++ b/05-AdvancedTopics/mcp-root-contexts/solution/typescript/tsconfig.json @@ -0,0 +1,43 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "removeComments": false, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "exactOptionalPropertyTypes": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "resolveJsonModule": true, + "isolatedModules": true, + "verbatimModuleSyntax": false + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist", + "**/*.test.ts", + "**/*.spec.ts" + ], + "ts-node": { + "esm": true, + "experimentalSpecifierResolution": "node" + } +} \ No newline at end of file