Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a new TechPulse (C#) sample that demonstrates a Microsoft 365 Agents SDK + Semantic Kernel agent that retrieves real-time tech news via a local MCP server (NewsAPI-backed), along with Microsoft 365 Agents Toolkit project/configuration files to provision and run/debug it.
Changes:
- Adds a C# agent app (bot) that uses Semantic Kernel function-calling to invoke tech-news tools.
- Adds a C# MCP server (stdio) that implements NewsAPI-backed tools (latest news, search, trending, company news).
- Adds Microsoft 365 Agents Toolkit provisioning/deployment assets (manifest, YAML, bicep, env templates) plus sample metadata/docs.
Reviewed changes
Copilot reviewed 34 out of 37 changed files in this pull request and generated 23 comments.
Show a summary per file
| File | Description |
|---|---|
| samples/cea-techPulse-csharp/README.md | Sample documentation and quickstart instructions. |
| samples/cea-techPulse-csharp/assets/sample.json | Sample catalog metadata (name/urls/dates/thumbnails). |
| samples/cea-techPulse-csharp/M365Agent/m365agents.yml | Cloud provision + deploy workflow for the agent app. |
| samples/cea-techPulse-csharp/M365Agent/m365agents.local.yml | Local provision workflow (Entra app, bot reg, config generation). |
| samples/cea-techPulse-csharp/M365Agent/M365Agent.atkproj | Agents Toolkit project definition. |
| samples/cea-techPulse-csharp/M365Agent/M365Agent.atkproj.user | Local VS debug profile selection (user-specific). |
| samples/cea-techPulse-csharp/M365Agent/launchSettings.json | Launch profiles for Agents Toolkit (Playground/Teams/Copilot). |
| samples/cea-techPulse-csharp/M365Agent/appPackage/manifest.json | Teams app manifest defining the custom engine agent bot. |
| samples/cea-techPulse-csharp/M365Agent/appPackage/color.png | Teams app icon (color). |
| samples/cea-techPulse-csharp/M365Agent/appPackage/outline.png | Teams app icon (outline). |
| samples/cea-techPulse-csharp/M365Agent/env/.env.local | Local env placeholders generated/used by provisioning. |
| samples/cea-techPulse-csharp/M365Agent/env/.env.local.user | Local secret placeholders for dev-time secrets. |
| samples/cea-techPulse-csharp/M365Agent/env/.env.dev | Dev environment placeholders for Azure provisioning/deploy. |
| samples/cea-techPulse-csharp/M365Agent/env/.env.dev.user | Dev secret placeholders. |
| samples/cea-techPulse-csharp/M365Agent/infra/azure.bicep | Azure infra to host the bot (App Service, MSI, bot registration). |
| samples/cea-techPulse-csharp/M365Agent/infra/azure.parameters.json | ARM parameters (resource base, SKU, OpenAI key, display name). |
| samples/cea-techPulse-csharp/M365Agent/infra/botRegistration/azurebot.bicep | Module to create an Azure Bot Service registration. |
| samples/cea-techPulse-csharp/M365Agent/infra/botRegistration/readme.md | Notes for bot registration module usage. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/cea-techPulse-csharp.csproj | Main bot web app project (deps + publish behavior). |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/cea-techPulse-csharp.csproj.user | Local VS debug profile selection (user-specific). |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/Program.cs | ASP.NET Core host setup + agent/bot registration + SK setup. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/Config.cs | Configuration option models for OpenAI + NewsAPI. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/AspNetExtensions.cs | JWT bearer token validation/auth helper for bot endpoints. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/Bot/TechNewsBot.cs | Bot/agent logic: chat loop + SK tool calling + streaming response. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/Bot/Plugins/TechNewsPlugin.cs | SK plugin exposing tech-news functions (MCP-backed). |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/Services/TechNewsMcpService.cs | MCP client that spawns/connects to the MCP server via stdio. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/McpServer/TechNewsMcpServer.csproj | MCP server project definition (ModelContextProtocol server). |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/McpServer/TechNewsMcpServer.csproj.user | Local VS debug profile selection (user-specific). |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/McpServer/Program.cs | MCP server host bootstrap with stdio transport + tool discovery. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/McpServer/TechNewsTools.cs | MCP tools implementation calling NewsAPI and formatting results. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/appsettings.json | Base configuration (agent options, auth, AI keys placeholders). |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/appsettings.Development.json | Dev overrides generated by local provision workflow. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/appsettings.Playground.json | Playground overrides (bot connection + AI keys placeholders). |
| samples/cea-techPulse-csharp/cea-techPulse-csharp/Properties/launchSettings.json | ASP.NET Core launch profiles (Playground vs Development). |
| samples/cea-techPulse-csharp/cea-techPulse-csharp.slnx | Solution definition including bot + MCP server + toolkit project. |
| samples/cea-techPulse-csharp/cea-techPulse-csharp.slnLaunch.user | Multi-project launch configuration (user-specific). |
Comments suppressed due to low confidence (1)
samples/cea-techPulse-csharp/M365Agent/env/.env.dev.user:5
- This dev env template is missing a
SECRET_NEWS_API_KEYentry, but the sample requires a NewsAPI key for tech news. Add it here (and wire it through provisioning/app settings) so dev deployments don’t fail at runtime when calling the news tools.
# This file includes environment variables that will not be committed to git by default. You can set these environment variables in your CI/CD system for your project.
# Secrets. Keys prefixed with `SECRET_` will be masked in Microsoft 365 Agents Toolkit logs.
SECRET_OPENAI_API_KEY=
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| TechPulse is an intelligent tech news companion that delivers the latest technology news, trends, and insights from trusted sources in the industry. Built with Microsoft 365 Agents SDK and Semantic Kernel, this agent provides real-time access to tech news across multiple categories including AI/ML, startups, cybersecurity, mobile technology, and gaming. The agent understands natural language queries and can search for specific topics, provide trending tech news, and deliver company-specific updates from major tech players like Microsoft, Apple, Google, and more. | ||
|
|
||
|  |
There was a problem hiding this comment.
The image reference points to ../assets/techPulse.gif, but this README lives in samples/cea-techPulse-csharp/ and the GIF is in samples/cea-techPulse-csharp/assets/techPulse.gif. As written, the image link is broken; update it to a path relative to this README (e.g., ./assets/techPulse.gif).
|  | |
|  |
| We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues. | ||
|
|
||
| You can try looking at [issues related to this sample](https://github.com/pnp/copilot-pro-dev-samples/issues?q=label%3A%22sample%3A%20cea-techpulse-csharp%22) to see if anybody else is having the same issues. | ||
|
|
There was a problem hiding this comment.
The issue-label and visitor-stats links use cea-techpulse-csharp (lowercase p) but the actual sample folder is cea-techPulse-csharp. These URLs will 404 on GitHub/raw paths unless the casing matches; update the links to the correct folder casing (or rename the folder to match the canonical sample id).
| "name": "pnp-copilot-pro-dev-cea-techpulse-csharp", | ||
| "source": "pnp", | ||
| "title": "TechPulse - Custom Engine Agent for Real-Time Technology News (C#)", | ||
| "shortDescription": "An intelligent tech news companion powered by Microsoft 365 Agents SDK and Semantic Kernel", | ||
| "url": "https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/cea-techpulse-csharp", | ||
| "downloadUrl": "https://pnp.github.io/download-partial/?url=https://github.com/pnp/copilot-pro-dev-samples/tree/main/samples/cea-techpulse-csharp", | ||
| "longDescription": [ |
There was a problem hiding this comment.
The url, downloadUrl, and thumbnail url all point at samples/cea-techpulse-csharp, but the folder committed is samples/cea-techPulse-csharp (different casing). This will break links (GitHub paths are case-sensitive); align the paths (or rename the folder) to a single canonical sample id.
| }, | ||
| "hotReloadProfile": "aspnetcore" | ||
| }, | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Trailing comma after the last profile makes this launchSettings.json invalid JSON. Some tooling is strict about JSON here; remove the trailing comma to avoid launch/profile loading failures.
| <!-- Exclude local settings from publish --> | ||
| <ItemGroup> | ||
| <Content Remove="appsettings.Development.json" /> | ||
| <Content Include="appsettings.Development.json"> | ||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
| <CopyToPublishDirectory>None</CopyToPublishDirectory> | ||
| </Content> | ||
| <Content Remove="appsettings.Playground.json" /> | ||
| <Content Include="appsettings.Playground.json"> | ||
| <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
| <CopyToPublishDirectory>None</CopyToPublishDirectory> | ||
| </Content> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <None Include="appsettings.Development.json" /> | ||
| </ItemGroup> |
There was a problem hiding this comment.
appsettings.Development.json is included both as Content and again as None. This duplication can cause MSBuild warnings/errors about duplicate items. Keep a single item entry (typically the Content entry with the desired copy settings) and remove the redundant include.
| args: publish --configuration Release --runtime win-x86 --self-contained | ||
| cea-techPulse-csharp.csproj |
There was a problem hiding this comment.
In YAML, splitting args: across multiple indented lines relies on YAML scalar continuation rules and can be easy to break. To avoid parsing differences across tools, consider using a single-line string or an explicit folded scalar (>), ensuring the final command is exactly publish ... --self-contained cea-techPulse-csharp.csproj.
| args: publish --configuration Release --runtime win-x86 --self-contained | |
| cea-techPulse-csharp.csproj | |
| args: publish --configuration Release --runtime win-x86 --self-contained cea-techPulse-csharp.csproj |
| ### Debug agent in Microsoft 365 Agents Playground | ||
| 1. Ensure your API keys are filled in `appsettings.Playground.json`: | ||
| ```json | ||
| "OpenAI": { | ||
| "ApiKey": "<your-openai-api-key>" | ||
| }, | ||
| "NewsApi": { | ||
| "ApiKey": "<your-newsapi-key>" | ||
| } | ||
| ``` | ||
| 2. Set `Startup Item` as `Microsoft 365 Agents Playground (browser)`. | ||
| 3. Press F5, or select the Debug > Start Debugging menu in Visual Studio. | ||
| 4. In Microsoft 365 Agents Playground from the launched browser, try asking: | ||
| * "Latest AI news" | ||
| * "What's trending in tech?" | ||
| * "News about Microsoft" | ||
| * "Search for cybersecurity updates" | ||
|
|
||
| ### Debug agent in Teams Web Client | ||
| 1. Ensure your API keys are filled in `env/.env.local.user`: | ||
| ``` | ||
| SECRET_OPENAI_API_KEY="<your-openai-api-key>" | ||
| SECRET_NEWS_API_KEY="<your-newsapi-key>" | ||
| ``` | ||
| 2. In the debug dropdown menu, select Dev Tunnels > Create A Tunnel (set authentication type to Public) or select an existing public dev tunnel. |
There was a problem hiding this comment.
The paths in Quick Start don’t match the repo layout: the secrets file is under M365Agent/env/.env.local.user (not env/.env.local.user), and appsettings.Playground.json lives under cea-techPulse-csharp/appsettings.Playground.json. As written, new users will edit the wrong files; update these paths to be relative to the sample root.
| public class ConfigOptions | ||
| { | ||
| public OpenAIConfigOptions OpenAI { get; set; } | ||
| public NewsApiConfigOptions NewsApi { get; set; } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Options for OpenAI | ||
| /// </summary> | ||
| public class OpenAIConfigOptions | ||
| { | ||
| public string ApiKey { get; set; } | ||
| public string DefaultModel = "gpt-4o"; | ||
| } |
There was a problem hiding this comment.
These options types use non-nullable reference properties without initialization (OpenAI, NewsApi, ApiKey), which can produce nullability warnings and runtime NREs when config is missing. Also DefaultModel is a field, so configuration binding won’t populate it. Prefer required/init properties (or nullable properties) and make DefaultModel a property with a default value so binding/validation behaves predictably.
| "parameters": { | ||
| "resourceBaseName": { | ||
| "value": "bot${{RESOURCE_SUFFIX}}" | ||
| }, | ||
| "openAIApiKey": { | ||
| "value": "${{SECRET_OPENAI_API_KEY}}" | ||
| }, | ||
| "webAppSKU": { | ||
| "value": "B1" | ||
| }, | ||
| "botDisplayName": { | ||
| "value": "cea-techPulse-csharp" | ||
| } | ||
| } |
There was a problem hiding this comment.
azure.bicep doesn’t currently parameterize/set the NewsAPI key; correspondingly this parameters file has no newsApiKey value. Add a secure newsApiKey parameter here and pass it through to the web app’s settings (or Key Vault) so deployments have the required configuration.
|
@AjayJ12-MSFT thanks for your contribution, can you take a look at the review comments and mark the PR as ready for review when you resolved them, thanks. |
No description provided.