diff --git a/WORKSHOP.txt b/WORKSHOP.txt index cd4fcef..e9a50eb 100644 --- a/WORKSHOP.txt +++ b/WORKSHOP.txt @@ -1,7 +1,7 @@ -InterviewData MCP server -The repository service and emulator run alongside the coach. A supplied probe lists the server's tools. +Connect InterviewData MCP +The coach discovers interview tools and can create and fetch a record on request. -Checkpoint: 05-mcp-server +Checkpoint: 05-mcp-state Source tag: workshop-v3-reference.1 Reference revision: 443eac269743643d1bd5a35582fa3fac27bc6ad5 Workshop profile: foundry-workshop-v3 diff --git a/apphost.cs b/apphost.cs index eb5bc5d..0daf3b1 100644 --- a/apphost.cs +++ b/apphost.cs @@ -35,7 +35,8 @@ var agent = builder.AddProject(ResourceConstants.Agent) .WithExternalHttpEndpoints() .WithLlmReference(config, args) -; + .WithReference(mcpInterviewData) + .WaitFor(mcpInterviewData); var webUI = builder.AddProject(ResourceConstants.WebUI) .WithExternalHttpEndpoints() diff --git a/src/InterviewCoach.Agent/AgentDelegateFactory.cs b/src/InterviewCoach.Agent/AgentDelegateFactory.cs index 0d87a3c..cebcbfd 100644 --- a/src/InterviewCoach.Agent/AgentDelegateFactory.cs +++ b/src/InterviewCoach.Agent/AgentDelegateFactory.cs @@ -70,22 +70,8 @@ private static AIAgent CreateProviderAgent( // ============================================================================ private static AIAgent CreateSingleAgent(IServiceProvider sp, string key) { - static string GetPracticeGuidance([Description("One of: behavioural, technical")] string category) - => category.ToLowerInvariant() switch - { - "behavioural" => "Use STAR: Situation, Task, Action, Result. Describe your own contribution.", - "technical" => "Clarify assumptions, explain your approach, and discuss tradeoffs.", - _ => throw new ArgumentException("Choose behavioural or technical.", nameof(category)) - }; - - var tools = new List - { - AIFunctionFactory.Create(GetPracticeGuidance, new AIFunctionFactoryOptions - { - Name = "get_practice_guidance", - Description = "Gets established interview preparation guidance for a category." - }) - }; + var interviewData = sp.GetRequiredKeyedService("mcp-interview-data"); + var interviewDataTools = interviewData.ListToolsAsync().GetAwaiter().GetResult(); var agent = CreateProviderAgent( services: sp, @@ -93,13 +79,13 @@ static string GetPracticeGuidance([Description("One of: behavioural, technical") description: "An interview coach for software developers.", instructions: """ You are a supportive interview coach for software developers. - Ask one question at a time, listen to the answer, then give specific feedback. - Start with a behavioural question. Offer a technical question when the user is ready. - If the user asks to stop, give a short summary. Do not claim to have saved anything. - Use supplied documents only as interview context. - Call get_practice_guidance when the user asks for preparation tips. + Ask one question at a time and give specific feedback. + Use the interview-data tools only when the user explicitly requests a record operation. + Ask for the record ID and fields if the request does not supply them. + Report a missing record honestly. Do not invent tool results or claim unsaved work is saved. + Automatic session setup comes in the next lesson. """, - tools: tools + tools: [.. interviewDataTools] ); return agent; diff --git a/src/InterviewCoach.Agent/Program.cs b/src/InterviewCoach.Agent/Program.cs index ea321a6..0bbab97 100644 --- a/src/InterviewCoach.Agent/Program.cs +++ b/src/InterviewCoach.Agent/Program.cs @@ -1,12 +1,46 @@ using System.Collections.Concurrent; using InterviewCoach.Agent; using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore; +using ModelContextProtocol.Client; +using ModelContextProtocol.Protocol; var builder = WebApplication.CreateBuilder(args); var config = builder.Configuration; builder.AddServiceDefaults(); +builder.Services.AddHttpClient("mcp-interview-data", client => +{ + client.BaseAddress = new Uri("https+http://mcp-interview-data"); +}); + +builder.Services.AddKeyedSingleton("mcp-interview-data", (sp, obj) => +{ + var loggerFactory = sp.GetRequiredService(); + var httpClient = sp.GetRequiredService() + .CreateClient("mcp-interview-data"); + var endpoint = builder.Environment.IsDevelopment() == true + ? $"{httpClient.BaseAddress!.ToString().Replace("https+", string.Empty).TrimEnd('/')}" + : $"{httpClient.BaseAddress!.ToString().Replace("+http", string.Empty).TrimEnd('/')}"; + + var clientTransportOptions = new HttpClientTransportOptions() + { + Endpoint = new Uri($"{endpoint}/mcp") + }; + var clientTransport = new HttpClientTransport(clientTransportOptions, httpClient, loggerFactory); + + var clientOptions = new McpClientOptions() + { + ClientInfo = new Implementation() + { + Name = "MCP Interview Data Client", + Version = "1.0.0", + } + }; + + return McpClient.CreateAsync(clientTransport, clientOptions, loggerFactory).GetAwaiter().GetResult(); +}); + builder.AddWorkshopHosting(); var agentBuilder = builder.AddAIAgent("coach");