<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Microsoft Azure</title>
    <description>The latest articles on DEV Community by Microsoft Azure (azure).</description>
    <link>https://dev.to/azure</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F512%2F64ce0b82-730d-4ca0-8359-2c21513a0063.jpg</url>
      <title>DEV Community: Microsoft Azure</title>
      <link>https://dev.to/azure</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/azure"/>
    <language>en</language>
    <item>
      <title>Understanding GitHub Billing and management: from licenses to fair AI credit controls</title>
      <dc:creator>Chris Noring</dc:creator>
      <pubDate>Wed, 12 Aug 2026 13:40:44 +0000</pubDate>
      <link>https://dev.to/azure/understanding-github-billing-and-management-from-licenses-to-fair-ai-credit-controls-1hli</link>
      <guid>https://dev.to/azure/understanding-github-billing-and-management-from-licenses-to-fair-ai-credit-controls-1hli</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/kI8t2ur_Zdc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Buying GitHub Copilot licenses is only the beginning of the governance story. The licenses are purchased centrally, but administrators still need to decide who receives a seat, how usage is attributed to the right part of the business, and what happens when included AI credits run out.&lt;/p&gt;

&lt;p&gt;Those decisions happen through several related controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Copilot seat assignment&lt;/strong&gt; determines which people are licensed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost centers&lt;/strong&gt; group attributable usage around a team or business owner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI credit included usage caps&lt;/strong&gt; create boundaries around included credits associated with a cost center's licenses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-center budgets&lt;/strong&gt; govern paid usage after included credits are exhausted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User-level budgets (ULBs)&lt;/strong&gt; limit how much an individual can consume.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why does this separation matter? Without it, an administrator can easily mistake one control for another. An included usage cap does not set an overage policy, and a cost-center budget does not guarantee every person an equal share. Each control answers a different question.&lt;/p&gt;

&lt;p&gt;This article follows the complete flow, starting before a cost center exists and ending with different policies for Business and Developers, where we place them each in separate cost centers with distinct included-usage boundaries, paid-usage budgets, and ULBs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Series
&lt;/h2&gt;

&lt;p&gt;This is part of a series on GitHub Admin and billing controls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/azure/turning-surprise-ai-bills-into-accountable-growth-4343"&gt;Managing surprise bills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/azure/github-admin-ui-billing-api-better-together-for-smarter-spend-decisions-3lp5"&gt;Better together: GitHub Admin UI + Billing API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Understanding GitHub Billing and management: from licenses to fair AI credit controls, &lt;strong&gt;we're here&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem 1: A central purchase does not identify who is licensed
&lt;/h2&gt;

&lt;p&gt;Our story starts with a purchase, but purchasing seats does not yet tell us who can use Copilot. This is the first problem to solve because cost centers, budgets, and AI credit controls all depend on GitHub knowing which named users actually hold eligible licenses.&lt;/p&gt;

&lt;p&gt;Suppose an enterprise purchases 400 Copilot seats for a workforce that includes 600 employees. The purchase creates a centrally managed pool of seats. It does not automatically license 400 unspecified people, nor does every developer receive a fraction of a license.&lt;/p&gt;

&lt;p&gt;At this point, the enterprise knows how many seats it owns, but it cannot yet connect those seats to people, teams, or cost centers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Assign seats to named users
&lt;/h3&gt;

&lt;p&gt;An administrator assigns those seats to specific users, either directly or through the supported administrative assignment process. At that point, GitHub can distinguish between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A person who belongs to the enterprise but has no Copilot seat.&lt;/li&gt;
&lt;li&gt;A person who has been assigned an eligible Copilot seat.&lt;/li&gt;
&lt;li&gt;A licensed person whose usage is attributable to a particular cost center.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This distinction matters because cost-center included credits are based on attributable eligible licenses, not raw headcount.&lt;/p&gt;

&lt;p&gt;For example, imagine a Developers cost center containing 200 people:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Developers in the cost center&lt;/th&gt;
&lt;th&gt;Developers with eligible Copilot seats&lt;/th&gt;
&lt;th&gt;Licenses that can contribute to the calculation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The cost center does not receive an included-credit boundary based simply on having 200 members. GitHub looks at the eligible licenses attributable to those members and calculates the included amount from those licenses.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The exact included-credit amount is calculated by GitHub according to the applicable licenses and product terms. Administrators do not manually divide the enterprise's included credits by cost-center headcount.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now the enterprise knows who is licensed. That solves entitlement, but it creates the next question: when those users consume AI credits, which part of the business owns that usage?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqce8d9q7jm2dfkmi1in9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqce8d9q7jm2dfkmi1in9.png" alt="A developer cost center" width="799" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 1: A developer cost center&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 2: Licensed usage has no business owner
&lt;/h2&gt;

&lt;p&gt;A list of licensed users is not yet a governance model. Finance and administrators still need to connect usage to the team, program, or financial owner responsible for it.&lt;/p&gt;

&lt;p&gt;Why does this matter? A single enterprise can contain groups with very different usage patterns. Business Operations may have predictable demand, while Developers may run more intensive AI workflows. Treating both groups as one undifferentiated population makes it difficult to protect included usage or govern overage appropriately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Use cost centers to establish ownership
&lt;/h3&gt;

&lt;p&gt;Cost centers provide that attribution boundary around resources such as users, teams, or organizations. They do not purchase licenses or assign Copilot seats. Instead, they connect licensed activity to the part of the business responsible for it.&lt;/p&gt;

&lt;p&gt;For this scenario, create two cost centers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Business&lt;/strong&gt;, containing the relevant Business users or teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developers&lt;/strong&gt;, containing the relevant engineering users or teams.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub can then determine which eligible Copilot licenses are attributable to each cost center. Conceptually, the relationship is:&lt;/p&gt;

&lt;p&gt;Cost-center included credits= ∑(included credits from eligible licenses attributed to that cost center)&lt;/p&gt;

&lt;p&gt;This is accounting attribution, not a second license purchase. The enterprise still owns and manages the seats centrally. The cost center tells GitHub where the associated usage and included-credit entitlement belong for governance purposes.&lt;/p&gt;

&lt;p&gt;With that ownership structure in place, GitHub can tell which licenses are attributable to Business and which are attributable to Developers. Ownership is now clear, but both groups can still participate in the same included-credit pool. That creates the next risk.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhpndhkf9mc0hrs6xzdd9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhpndhkf9mc0hrs6xzdd9.png" alt="Developers and Business cost centers" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 2: Developers and Business cost centers&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 3: One group can consume another group's included credits
&lt;/h2&gt;

&lt;p&gt;By default, included AI credits can function as a shared enterprise resource. That is convenient, but it can produce an uneven outcome: one group may consume included credits funded by licenses associated with another group.&lt;/p&gt;

&lt;p&gt;Imagine Developers has an unusually intensive month. Without a separate boundary, its members may continue drawing from the shared pool, reducing the included credits available to Business. Attribution tells us who owns the usage, but attribution alone does not protect either group's share.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Enable the included usage cap
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;AI credit included usage cap&lt;/strong&gt; changes that behavior for a cost center. When enabled, GitHub calculates an included-credit boundary from the eligible licenses attributable to that cost center.&lt;/p&gt;

&lt;p&gt;For example, enable the checkbox for both Business and Developers. Each cost center can then use the included credits calculated from its attributable licenses without the other cost center consuming beyond its own boundary.&lt;/p&gt;

&lt;p&gt;The safest way to describe this is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The cost center receives a protected included-usage boundary calculated from its attributable eligible licenses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is tempting to call those credits "guaranteed to me," but that wording can imply more than the control provides. The boundary belongs to the cost center, not to an individual, and it does not guarantee that every member receives an equal allocation.&lt;/p&gt;

&lt;p&gt;The shared-pool problem is now addressed, but the checkbox also exposes the next question: what happens after a cost center exhausts its protected included credits? The cap separates included usage; it does not define the paid-usage policy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe89jyoq7s1apqez8o92m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe89jyoq7s1apqez8o92m.png" alt="Included usage cap" width="651" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 3: Included usage cap checked on a cost center&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 4: The included usage cap does not stop overage
&lt;/h2&gt;

&lt;p&gt;Once a cost center reaches its included-credit boundary, additional eligible usage may become paid usage when paid AI credit usage is enabled. A cost-center budget determines how that overage is monitored or stopped.&lt;/p&gt;

&lt;p&gt;Why is a separate budget necessary? The included usage cap says, "Do not continue consuming included credits beyond this cost center's calculated boundary." It does not necessarily say, "Block all subsequent usage." A spending control is required to define that second outcome.&lt;/p&gt;

&lt;p&gt;Our two cost centers need different outcomes. Business should stop before overage, while Developers should be allowed to continue so the enterprise can observe real demand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution for Business: Use a $0 hard budget
&lt;/h3&gt;

&lt;p&gt;Business should use its included credits but create no overage. Configure a &lt;strong&gt;$0 cost-center budget&lt;/strong&gt; and enable &lt;strong&gt;Stop usage when budget limit is reached&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Together, the controls mean:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Business uses the included credits associated with its attributable licenses.&lt;/li&gt;
&lt;li&gt;The included usage cap prevents it from drawing beyond its protected included boundary.&lt;/li&gt;
&lt;li&gt;The $0 hard budget allows no paid usage after included credits are exhausted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The $0 budget does not prevent Business from using included credits. It establishes a zero-dollar allowance specifically for the paid-usage phase.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If paid AI credit usage is disabled for the entire enterprise, a $0 cost-center budget may be redundant. It becomes important in this scenario because Developers must retain access to paid usage under the same enterprise account.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;!Business cost center with a $0 hard budget](&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/fw05ktbkv415rph8jm5u.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/fw05ktbkv415rph8jm5u.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 4: Business cost center with a $0 hard budget&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution for Developers: Start with a soft budget
&lt;/h3&gt;

&lt;p&gt;Developers need more flexibility. Configure a funded cost-center budget, such as &lt;strong&gt;$20,000&lt;/strong&gt;, but leave &lt;strong&gt;Stop usage when budget limit is reached&lt;/strong&gt; disabled.&lt;/p&gt;

&lt;p&gt;This is a soft budget. It provides a target and supports alerts, but it is not a hard ceiling. Usage can continue beyond $20,000 unless another applicable control stops it.&lt;/p&gt;

&lt;p&gt;That behavior is useful while the organization learns the team's real demand. Administrators can monitor spending, review whether the usage produces value, and later decide whether to change the amount or turn on the stop control.&lt;/p&gt;

&lt;p&gt;At this point, Business and Developers have distinct overage policies:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost center&lt;/th&gt;
&lt;th&gt;Included usage&lt;/th&gt;
&lt;th&gt;Paid-usage budget&lt;/th&gt;
&lt;th&gt;Stop usage&lt;/th&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Business&lt;/td&gt;
&lt;td&gt;Protected boundary enabled&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Use included credits, then stop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developers&lt;/td&gt;
&lt;td&gt;Protected boundary enabled&lt;/td&gt;
&lt;td&gt;$20,000&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Use included credits, then allow monitored paid usage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We have now defined what paid usage means for each cost center. However, the Developers budget controls the group total, not the behavior of each person inside the group. One heavy user could still consume a disproportionate amount, which leads to the next problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feqxhkmyldje8lb7nuwep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Feqxhkmyldje8lb7nuwep.png" alt="Developers cost center with a $20,000 soft budget and no stop control" width="530" height="900"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 5: Developers cost center with a $20,000 soft budget and no stop control&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 5: An aggregate budget does not create individual fairness
&lt;/h2&gt;

&lt;p&gt;The $20,000 Developers budget gives administrators visibility into aggregate paid usage, but it does not divide that amount fairly among the people in the cost center. A few heavy users could consume most of the available capacity while everyone else remains far below the group budget.&lt;/p&gt;

&lt;p&gt;Why add a ULB when Developers already has a $20,000 budget? The two controls operate at different levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;$20,000 cost-center budget&lt;/strong&gt; monitors the Developers group's aggregate paid usage.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;cost-center ULB&lt;/strong&gt; gives each person in Developers an individual ceiling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Solution: Add a cost-center ULB
&lt;/h3&gt;

&lt;p&gt;A user-level budget limits one person's total AI credit consumption during the billing cycle. It follows the user across included and paid usage and acts as a hard stop when the applicable limit is reached.&lt;/p&gt;

&lt;p&gt;For example, configure a &lt;strong&gt;$200-per-user cost-center ULB&lt;/strong&gt; for Developers. This prevents a small number of heavy users from consuming a disproportionate amount while other users receive little opportunity to work.&lt;/p&gt;

&lt;p&gt;The $200 value is a maximum, not a reservation. It does not set aside $200 for every person, and unused capacity from one user is not a personal entitlement that another user can claim. It simply says that each covered user stops when their individual consumption reaches $200.&lt;/p&gt;

&lt;p&gt;This makes the policy more predictable and equitable without requiring administrators to create a separate budget for every member of the cost center. The common baseline solves the fairness problem, but a uniform limit can be too restrictive for specialized roles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fedqsjn9nittb9q5av75w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fedqsjn9nittb9q5av75w.png" alt="Developers cost center with a $200 per-user ULB" width="519" height="902"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 6: Developers cost center with a $200 per-user ULB&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem 6: One baseline does not fit every role
&lt;/h2&gt;

&lt;p&gt;A shared baseline will not fit every role. A platform engineer, AI lead, or approved power user may have a legitimate need for more capacity than the Developers baseline permits.&lt;/p&gt;

&lt;p&gt;Raising the $200 limit for the entire cost center would solve that person's problem by giving everyone more capacity. That is broader than necessary and weakens the fairness policy we just established.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution: Add an individual override
&lt;/h3&gt;

&lt;p&gt;For example, create an individual ULB of &lt;strong&gt;$400&lt;/strong&gt; for &lt;code&gt;softchris&lt;/code&gt;. That individual policy takes precedence over the $200 Developers cost-center ULB.&lt;/p&gt;

&lt;p&gt;The precedence is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Individual ULB&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost-center ULB&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Universal ULB&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This lets administrators start with a broad enterprise default, apply a more suitable baseline to a cost center, and reserve individual overrides for documented exceptions.&lt;/p&gt;

&lt;p&gt;An individual override should still be reviewed. More capacity is not automatically better governance; it should correspond to an approved role or business outcome. We have now solved each problem at the narrowest appropriate scope.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyw4tcczmnsgp90t6so9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyw4tcczmnsgp90t6so9m.png" alt="Individual ULB override" width="518" height="896"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 7: Individual ULB override for a specific user in the Developers cost center&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resolution: See the complete control model
&lt;/h2&gt;

&lt;p&gt;Now that each control has been introduced separately, we can connect them into one end-to-end model.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Purchase Copilot seats centrally.&lt;/strong&gt; The enterprise or organization owns the seat pool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assign seats to named users.&lt;/strong&gt; This establishes who holds an eligible Copilot license.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribute users, teams, or organizations to cost centers.&lt;/strong&gt; This connects licensed activity to Business or Developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable the included usage cap.&lt;/strong&gt; GitHub calculates a protected included-credit boundary from eligible licenses attributable to each cost center.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set cost-center budgets.&lt;/strong&gt; Business receives a $0 hard budget; Developers receives a $20,000 soft budget.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set a cost-center ULB.&lt;/strong&gt; Developers users receive a $200 individual ceiling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add approved exceptions.&lt;/strong&gt; &lt;code&gt;softchris&lt;/code&gt; receives a $400 individual ULB.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The resulting &lt;strong&gt;Budgets and alerts&lt;/strong&gt; view tells a coherent story:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost center&lt;/td&gt;
&lt;td&gt;Business&lt;/td&gt;
&lt;td&gt;$0, stop enabled&lt;/td&gt;
&lt;td&gt;Prevent paid overage after included usage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost center&lt;/td&gt;
&lt;td&gt;Developers&lt;/td&gt;
&lt;td&gt;$20,000, stop disabled&lt;/td&gt;
&lt;td&gt;Observe aggregate paid usage without an immediate hard stop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User • Cost Center&lt;/td&gt;
&lt;td&gt;Developers&lt;/td&gt;
&lt;td&gt;$200 per user&lt;/td&gt;
&lt;td&gt;Apply a fair individual baseline across the cost center&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User&lt;/td&gt;
&lt;td&gt;&lt;code&gt;softchris&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$400&lt;/td&gt;
&lt;td&gt;Preserve an approved individual exception&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These four rows do not show the included usage caps themselves; those are configured on the cost-center details. The rows show the controls that govern paid usage and individual consumption after the attribution model has been established.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checkpoint: Avoid the most common misunderstandings
&lt;/h2&gt;

&lt;p&gt;The controls become easier to operate when their boundaries are explicit. Keep these distinctions in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Purchasing 400 seats does not automatically license an unspecified 400 people. Seats must be assigned to users.&lt;/li&gt;
&lt;li&gt;Putting 200 people in a cost center does not mean 200 licenses contribute to its included-credit calculation. Only attributable users with eligible licenses contribute.&lt;/li&gt;
&lt;li&gt;An included usage cap does not assign an equal number of credits to every person.&lt;/li&gt;
&lt;li&gt;An included usage cap does not, by itself, define the cost center's paid-usage policy.&lt;/li&gt;
&lt;li&gt;A soft cost-center budget is an observation and alerting threshold, not a hard ceiling.&lt;/li&gt;
&lt;li&gt;A cost-center ULB is a per-user maximum, not a guaranteed allocation for each person.&lt;/li&gt;
&lt;li&gt;An individual ULB overrides a broader cost-center or universal ULB for that user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The easiest way to remember the model is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Assign the license. Attribute the usage. Protect included credits. Govern paid usage. Limit the individual.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Outcome: Different teams, appropriate controls
&lt;/h2&gt;

&lt;p&gt;Business and Developers now operate under the same enterprise purchase but follow policies suited to their work.&lt;/p&gt;

&lt;p&gt;Business can consume the included credits associated with its attributable licenses and then stops before creating paid usage. Developers can continue into paid usage while administrators observe demand against a soft budget. A cost-center ULB prevents a few users from dominating consumption, while individual overrides preserve approved exceptions.&lt;/p&gt;

&lt;p&gt;No single checkbox provides all of that behavior. The result comes from combining license assignment, cost-center attribution, included-credit boundaries, spending budgets, and ULBs in the right order.&lt;/p&gt;

&lt;p&gt;That order is the practical governance lesson: &lt;strong&gt;protect included usage first, decide how paid usage should behave second, and then add per-user controls where fairness or predictability requires them.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>billing</category>
      <category>ai</category>
    </item>
    <item>
      <title>GitHub Admin UI + Billing API: Better together for smarter spend decisions</title>
      <dc:creator>Chris Noring</dc:creator>
      <pubDate>Mon, 10 Aug 2026 14:42:20 +0000</pubDate>
      <link>https://dev.to/azure/github-admin-ui-billing-api-better-together-for-smarter-spend-decisions-3lp5</link>
      <guid>https://dev.to/azure/github-admin-ui-billing-api-better-together-for-smarter-spend-decisions-3lp5</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/6DrBG4tP2ms"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;As a GitHub administrator, you already have a strong place to start when somebody asks, “Why did our AI spend go up?” In &lt;strong&gt;Metered usage&lt;/strong&gt;, you can see the change, choose the period, and group the data by organization or cost center.&lt;/p&gt;

&lt;p&gt;That first investigation often leads to questions that are specific to your company. Finance may want a month-end report based on its own reporting calendar. An engineering leader may want to see whether an increase is spread across a team or concentrated among a few people. Answering those questions once is useful; answering them repeatedly calls for a reusable approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Series
&lt;/h2&gt;

&lt;p&gt;This is part of a series on GitHub Admin and billing controls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/azure/turning-surprise-ai-bills-into-accountable-growth-4343"&gt;Managing surprise bills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Better together: GitHub Admin UI + Billing, &lt;strong&gt;we're here&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/azure/understanding-github-billing-and-management-from-licenses-to-fair-ai-credit-controls-1hli/"&gt;Understanding GitHub Billing and management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use each surface for what it does best
&lt;/h2&gt;

&lt;p&gt;The GitHub admin UI shows you where to look and gives you the controls to respond. The Billing Usage API helps you answer the recurring questions that are specific to your company. Neither replaces the other.&lt;/p&gt;

&lt;p&gt;Together, they give administrators a practical loop: spot the change in &lt;strong&gt;Metered usage&lt;/strong&gt;, understand it through a reusable API-powered view, and act with a targeted budget. That means better cost control without treating every user or team as the problem.&lt;/p&gt;

&lt;p&gt;Let’s walk through this better-together approach using a common example: AI spend starts to rise, but the reason is not yet clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question: Spend is up, but what is driving it?
&lt;/h2&gt;

&lt;p&gt;Imagine that finance notices an increase in AI spend before the next close. It could be a sign that more developers are getting value from Copilot. It could also be one workload using far more than expected. At this point, nobody knows, and a broad restriction would be premature.&lt;/p&gt;

&lt;p&gt;The GitHub administrator needs to help finance and engineering answer three practical questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which part of the business is driving the increase?&lt;/li&gt;
&lt;li&gt;Is the spend concentrated among a few users or broadly distributed?&lt;/li&gt;
&lt;li&gt;Which control should change without disrupting everyone else?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not simply to reduce a number. It is to understand the increase well enough to protect useful work while addressing anything unexpected.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Start in the admin UI: Find the increase
&lt;/h3&gt;

&lt;p&gt;The admin UI is the natural place to begin because it lets you explore the data before you decide what kind of report or control you need. Open &lt;strong&gt;Billing and licensing &amp;gt; Metered usage&lt;/strong&gt; and select the relevant reporting period.&lt;/p&gt;

&lt;p&gt;This first check matters. It confirms that the increase is real, shows when it happened, and gives you a shared starting point for the conversation with finance and engineering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsh65xqssc6t2qgmwjow9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsh65xqssc6t2qgmwjow9.png" alt="Metered usage establishes the increase and the period that needs investigation." width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 01: Metered usage establishes the increase and the period that needs investigation.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Narrow the increase by organization
&lt;/h4&gt;

&lt;p&gt;An enterprise total tells you that spend changed, but not where to look next. Group the usage by organization to see which part of the enterprise contributed most to the increase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz4p44wy4z6z8fuss7rv2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz4p44wy4z6z8fuss7rv2.png" alt="Organization grouping narrows an enterprise-wide increase to an accountable business area" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 02: Organization grouping narrows an enterprise-wide increase to an accountable business area.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose the &lt;code&gt;octodemo&lt;/code&gt; organization stands out. You now know where to continue the investigation and which leaders can add context. You do not yet know whether the spend is justified, and that distinction matters. The increase could come from successful Copilot adoption, a migration, a seasonal workload, or an automated process that needs attention.&lt;/p&gt;

&lt;h4&gt;
  
  
  Connect the increase to a cost center
&lt;/h4&gt;

&lt;p&gt;An organization can contain several teams, programs, and budgets. Grouping by &lt;strong&gt;cost center&lt;/strong&gt; takes the investigation one step closer to the people who understand the work behind the spend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1eoius8ej9nyriha738v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1eoius8ej9nyriha738v.png" alt="Cost-center grouping identifies the financial owner of the increase" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 03: Cost-center grouping identifies the financial owner of the increase.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this scenario, &lt;code&gt;octodemo-org-cc&lt;/code&gt; has the largest increase. In only a few clicks, the admin UI has taken us from an enterprise-wide signal to the cost center that needs a closer look. For a one-time question, this may be enough.&lt;/p&gt;

&lt;p&gt;Now imagine that finance asks for the same analysis every month, with a fixed reporting period and a ranking of spend by user. That is the point where the API adds value. It does not replace the investigation you just completed; it helps you repeat and extend it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Continue with the API: Answer the repeatable question
&lt;/h3&gt;

&lt;p&gt;The Billing Usage API gives you access to the data behind a more tailored report. You can use filters to match the period finance cares about, focus on the cost center you found in the UI, and build a view that can run again tomorrow or next month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjj8vs3z0ht9qyjwg98h5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjj8vs3z0ht9qyjwg98h5.png" alt="Billing usage endpoints and time filters provide the inputs for a reusable report" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 04: Billing usage endpoints and time filters provide the inputs for a reusable report.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Define the reporting question first
&lt;/h4&gt;

&lt;p&gt;Before writing code, state the question the report needs to answer. In this example, it is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which users in the selected cost center account for the most net spend during this reporting period?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That one question keeps the report focused. It also determines the workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List the organization's members to establish the candidate users.&lt;/li&gt;
&lt;li&gt;Resolve which members belong to the selected cost center.&lt;/li&gt;
&lt;li&gt;Query organization AI credit and premium-request usage for those users and the selected period.&lt;/li&gt;
&lt;li&gt;Combine the results into a per-user total.&lt;/li&gt;
&lt;li&gt;Rank users and aggregate the result by cost center.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The prototype uses &lt;code&gt;year&lt;/code&gt;, &lt;code&gt;month&lt;/code&gt;, and optional &lt;code&gt;day&lt;/code&gt; filters so the output matches the finance period. It also accepts a cost-center filter. Because the admin UI has already pointed us to &lt;code&gt;octodemo-org-cc&lt;/code&gt;, there is no reason to start with every member of the enterprise.&lt;/p&gt;

&lt;h4&gt;
  
  
  Understand the per-user query pattern
&lt;/h4&gt;

&lt;p&gt;There is one API behavior to understand before building the report. The organization billing endpoints return an aggregate when the &lt;code&gt;user&lt;/code&gt; filter is omitted. To create a spend-by-user ranking, the workflow makes a filtered request for each selected user and usage type.&lt;/p&gt;

&lt;p&gt;For example, this request asks for Eve's AI credit usage in July 2026:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: application/vnd.github+json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$GITHUB_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-GitHub-Api-Version: 2026-03-10"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"https://api.github.com/organizations/octodemo/settings/billing/ai_credit/usage?year=2026&amp;amp;month=7&amp;amp;user=eve"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response contains one or more usage items, with amounts such as &lt;code&gt;grossAmount&lt;/code&gt;, &lt;code&gt;discountAmount&lt;/code&gt;, and &lt;code&gt;netAmount&lt;/code&gt;. The prototype adds the &lt;code&gt;netAmount&lt;/code&gt; values to calculate Eve's AI credit total for the period. It then runs the equivalent premium-request query and combines the two totals.&lt;/p&gt;

&lt;p&gt;We can now see one user's contribution during the same period we investigated in the UI. Repeating the request for the members of the selected cost center gives us the ranking that finance asked for.&lt;/p&gt;

&lt;p&gt;For a production workflow, a few practical details matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limit the candidate list to the cost center under investigation.&lt;/li&gt;
&lt;li&gt;Paginate organization membership and cost-center results.&lt;/li&gt;
&lt;li&gt;Use bounded concurrency instead of sending every request at once.&lt;/li&gt;
&lt;li&gt;Record partial failures rather than silently treating them as zero spend.&lt;/li&gt;
&lt;li&gt;Keep an audit record of when the data was pulled and transformed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a daily check, the report can use a narrow period and write a timestamped output. At finance close, the same workflow can produce the month-end rollup. The question stays the same; only the reporting window changes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reveal concentration that totals can hide
&lt;/h4&gt;

&lt;p&gt;The result is a custom &lt;strong&gt;Spend by User&lt;/strong&gt; view that brings the organization, cost center, reporting period, AI credit usage, premium-request usage, and total net spend into one place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fve88hld9bbwqxy37zhok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fve88hld9bbwqxy37zhok.png" alt="Custom Spend by User dashboard" width="799" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 05: A company-specific dashboard exposes per-user concentration inside the selected cost center.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the illustrative data, the &lt;code&gt;octodemo&lt;/code&gt; organization has 22 users and $3,651 in total net spend for July 2026. The &lt;code&gt;octodemo-org-cc&lt;/code&gt; cost center accounts for $2,700 of that amount. Two users stand out:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;User&lt;/th&gt;
&lt;th&gt;AI credit net spend&lt;/th&gt;
&lt;th&gt;Premium-request net spend&lt;/th&gt;
&lt;th&gt;Total net spend&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;eve&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$900&lt;/td&gt;
&lt;td&gt;$600&lt;/td&gt;
&lt;td&gt;$1,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adam&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$600&lt;/td&gt;
&lt;td&gt;$400&lt;/td&gt;
&lt;td&gt;$1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Together, Adam and Eve account for $2,500 of the $2,700 attributed to that cost center. That is approximately 93% of its total in this example.&lt;/p&gt;

&lt;p&gt;These figures are demonstration data, but they show why the extra view is useful. Instead of reacting to a $2,700 cost-center total, the administrator can talk to the owners of two workloads and understand what the spend supported.&lt;/p&gt;

&lt;p&gt;Concentration does not automatically mean waste. Adam and Eve may be doing approved, high-value work. The dashboard tells the business where to ask the next question; the people involved provide the context needed to answer it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Return to the admin UI: Choose the right control
&lt;/h3&gt;

&lt;p&gt;The API has helped us understand the increase, but it does not make the decision for us. Return to &lt;strong&gt;Billing and licensing &amp;gt; Budgets and alerts&lt;/strong&gt; to review the available controls and choose the narrowest one that fits what you learned.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F946qzr0ow83ensccroqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F946qzr0ow83ensccroqe.png" alt="Budget scopes turn the investigation into a targeted governance decision" width="515" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 06: Budget scopes turn the investigation into a targeted governance decision.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Set a cost-center user-level baseline
&lt;/h4&gt;

&lt;p&gt;A cost-center user-level budget applies the same per-user amount to every current and future member of that cost center. This is useful when the group needs a different baseline from the rest of the enterprise.&lt;/p&gt;

&lt;p&gt;For example, the administrator might give &lt;code&gt;octodemo-org-cc&lt;/code&gt; additional per-user headroom because its work legitimately uses more AI credits. This avoids raising the universal user-level budget for everyone.&lt;/p&gt;

&lt;p&gt;A user-level budget counts both included and paid AI credit usage. It is always a hard stop for the individual. It does not reserve part of the shared pool, and it does not replace the cost center's paid-usage budget.&lt;/p&gt;

&lt;h4&gt;
  
  
  Preserve justified exceptions
&lt;/h4&gt;

&lt;p&gt;If Adam or Eve has an approved role that requires more capacity, an individual user-level budget can replace the cost-center baseline for that person. The exception stays limited to the person who needs it instead of increasing the budget for the whole cost center.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd0j8iyq3wikvamk6kme2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd0j8iyq3wikvamk6kme2.png" alt=" " width="525" height="879"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 07: Cost-center baselines and individual overrides preserve useful work without widening access for everyone.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The precedence is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An individual user-level budget overrides the cost-center user-level budget.&lt;/li&gt;
&lt;li&gt;The cost-center user-level budget overrides the universal user-level budget.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In practice, you can set a universal baseline, add more headroom for a cost center with a clear business need, and use individual overrides for documented exceptions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why the UI and API work better together
&lt;/h4&gt;

&lt;p&gt;At this point, the better-together pattern becomes clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Metered usage&lt;/strong&gt; supports interactive discovery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Billing Usage API&lt;/strong&gt; supports repeatable, company-specific analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Budgets and alerts&lt;/strong&gt; supports targeted policy decisions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each surface does the job it is best suited to do. The UI makes it easy to explore and manage GitHub. The API lets you repeat a company-specific analysis without rebuilding it by hand. Used together, they give finance, engineering, and administrators the same evidence before a control changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make it part of the operating rhythm
&lt;/h2&gt;

&lt;p&gt;A useful dashboard should lead to a useful conversation. Decide who receives the report, how often they review it, and what happens when a user or cost center stands out.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run a daily pull to detect unusual changes early.&lt;/li&gt;
&lt;li&gt;Produce a month-end rollup aligned to finance close.&lt;/li&gt;
&lt;li&gt;Route cost-center summaries to the relevant business owner.&lt;/li&gt;
&lt;li&gt;Review high-consumption users with engineering before changing limits.&lt;/li&gt;
&lt;li&gt;Record approved individual overrides and revisit them regularly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over time, the conversation can move from “Who spent this?” to “What outcome did this spend support, and does the current policy still fit?”&lt;/p&gt;

&lt;p&gt;When the same users repeatedly appear at the top, leaders can inspect the workload, remove waste, validate business value, or approve more capacity. When usage becomes broadly distributed, the cost-center baseline may need adjustment instead. The report makes those patterns visible over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The better-together workflow at a glance
&lt;/h3&gt;

&lt;p&gt;The story above introduces each surface when it becomes useful. This table summarizes their roles.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Surface&lt;/th&gt;
&lt;th&gt;Primary role&lt;/th&gt;
&lt;th&gt;Best used for&lt;/th&gt;
&lt;th&gt;Important limitation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metered usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Interactive investigation&lt;/td&gt;
&lt;td&gt;Finding the affected period, organization, and cost center&lt;/td&gt;
&lt;td&gt;Manual exploration is not a reusable company-specific report&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Billing Usage API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Programmatic usage retrieval&lt;/td&gt;
&lt;td&gt;Scheduled reporting, time-sliced analysis, and per-user views&lt;/td&gt;
&lt;td&gt;Per-user attribution requires filtered requests and careful handling of pagination and failures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom Spend by User view&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Company-specific interpretation&lt;/td&gt;
&lt;td&gt;Ranking users and aligning usage to internal ownership&lt;/td&gt;
&lt;td&gt;Concentration is evidence to investigate, not proof of waste&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Budgets and alerts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Governance controls&lt;/td&gt;
&lt;td&gt;Cost-center baselines and individual overrides&lt;/td&gt;
&lt;td&gt;A broader budget cannot override a user who has reached their ULB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The practical takeaway is simple: begin with exploration, automate only the question worth repeating, and adjust policy after the data has context. That sequence keeps governance precise while preserving useful AI work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/rest/billing/usage?apiVersion=2026-03-10" rel="noopener noreferrer"&gt;REST API endpoints for billing usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/rest/orgs/members?apiVersion=2026-03-10#list-organization-members" rel="noopener noreferrer"&gt;List organization members&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/enterprise-cloud@latest/copilot/concepts/billing/budgets-for-usage-based-billing" rel="noopener noreferrer"&gt;Budgets for usage-based billing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/enterprise-cloud@latest/billing/how-tos/products/use-cost-centers" rel="noopener noreferrer"&gt;Using cost centers to allocate costs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>billing</category>
    </item>
    <item>
      <title>Turning surprise AI bills into accountable growth with GitHub Billing Controls</title>
      <dc:creator>Chris Noring</dc:creator>
      <pubDate>Mon, 27 Jul 2026 18:44:11 +0000</pubDate>
      <link>https://dev.to/azure/turning-surprise-ai-bills-into-accountable-growth-4343</link>
      <guid>https://dev.to/azure/turning-surprise-ai-bills-into-accountable-growth-4343</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/4fxSmUQV7qc"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;This is a story of how you receive a higher bill than expected and how GitHub's Billing Controls help clarity and predictability. Let's begin our story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Series
&lt;/h2&gt;

&lt;p&gt;This is part of a series on GitHub Admin and billing controls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing surprise bills, &lt;strong&gt;you're here&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/azure/github-admin-ui-billing-api-better-together-for-smarter-spend-decisions-3lp5"&gt;Better together: GitHub Admin UI + Billing API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/azure/understanding-github-billing-and-management-from-licenses-to-fair-ai-credit-controls-1hli/"&gt;Understanding GitHub Billing and management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Confusion: The bill is higher than expected
&lt;/h2&gt;

&lt;p&gt;The AI bill is higher than expected. Now what?&lt;/p&gt;

&lt;p&gt;Finance wants to understand what is driving the cost. Engineering leaders, on the other hand, want to preserve the productivity gains behind the increased usage. The administrator needs to balance both priorities and put a policy in place that the business can understand.&lt;/p&gt;

&lt;p&gt;One question drives the investigation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where is the increase coming from, and how do we control it without disrupting valuable work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To answer it, we first need to follow the spend. Once we know who owns it, we can apply guardrails at the right level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Investigation: Follow the spend
&lt;/h2&gt;

&lt;p&gt;Setting a limit too early could restrict useful adoption without addressing the main source of cost. So, let's find out what changed and who can act on it.&lt;/p&gt;

&lt;p&gt;The investigation begins in the billing administration portal, where usage and budget settings appear in one place.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fakw88c0tldf9dtip9tws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fakw88c0tldf9dtip9tws.png" alt="GitHub Billing Administration Portal" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 01: A unified billing workspace connects usage evidence to budget controls.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Identify the consumption category
&lt;/h3&gt;

&lt;p&gt;First, we identify which product changed. GitHub reports this by &lt;strong&gt;SKU&lt;/strong&gt;, which simply means the billing category for a product or service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2p3pxtew37qb4jknaxok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2p3pxtew37qb4jknaxok.png" alt="Metered usage" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 02: Grouping metered usage by billing category highlights Copilot Enterprise usage.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Grouping usage by billing category shows which product is driving the increase. In this example, the chart points to Copilot Enterprise usage. Leaders can then ask whether that growth comes from valuable adoption, an unusual workload, or demand that has outgrown its budget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Locate the accountable organization
&lt;/h3&gt;

&lt;p&gt;Once you know which product is driving the cost, find out who owns the usage. An enterprise-wide total can hide a sharp increase in one organization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8hrk3ck5y5rktx2qp1z2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8hrk3ck5y5rktx2qp1z2.png" alt="Usage grouped by organization" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 03: Organization-level grouping identifies the business unit accountable for demand.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The organization view points to the leader who can connect that usage to business results, estimate future demand, and decide what to do next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect usage to a cost center
&lt;/h3&gt;

&lt;p&gt;An organization may still be too broad. A &lt;strong&gt;cost center&lt;/strong&gt; is a billing group that connects usage to the team, program, or function responsible for the cost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0hr1rb7298oaxtvrrz07.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0hr1rb7298oaxtvrrz07.png" alt="Group by cost center" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 04: Cost-center analysis reveals concentrated usage averaging about $20,000 per month.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here, one cost center accounts for most of the AI credit usage and averages about $20,000 per month. That gives leaders a practical starting point. A $20,000 alert may suit normal demand, while a growth team, seasonal workload, or strategic migration may need more &lt;strong&gt;headroom&lt;/strong&gt;, or more room to spend before reaching the limit. The right amount depends on expected usage, financial risk, and the value the work creates.&lt;/p&gt;

&lt;p&gt;The investigation has now produced an answer: most of the increase comes from one cost center spending about $20,000 per month. The next question is what to do about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resolution: Put guardrails in place
&lt;/h2&gt;

&lt;p&gt;Rather than place one restrictive limit on everyone, the administrator can add guardrails at three levels: across the organization, for the cost center driving the increase, and for individual users who need a different limit.&lt;/p&gt;

&lt;p&gt;The Budgets and alerts page is where those decisions become policy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0zdzaxgewn7dq0ow719r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0zdzaxgewn7dq0ow719r.png" alt="Budgets and alerts in Billing and licensing" width="796" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 05: The Budgets and alerts page provides the New budget action.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's start with the broadest guardrail and then make it more specific.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set a boundary for shared paid usage
&lt;/h3&gt;

&lt;p&gt;An organization budget gives finance a clear limit for usage charges. License costs are separate and do not count toward this amount.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsowopktuevrzb54r0k56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsowopktuevrzb54r0k56.png" alt="Organization budget" width="544" height="896"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 06: A $200,000 organization budget establishes a configurable boundary for paid usage.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The $200,000 organization budget shown here is an example. The right amount depends on expected usage, available included credits, growth plans, and what would happen if paid usage stopped. This shared budget applies only to additional paid usage after included credits are used. It does not include license costs.&lt;/p&gt;

&lt;p&gt;There is one timing detail to keep in mind: if you create the budget partway through a billing cycle, GitHub does not count usage from earlier in that cycle. The first bill can therefore exceed the displayed $200,000 limit.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Stop usage when budget limit is reached&lt;/strong&gt; toggle controls what happens next. Leave it off and GitHub sends notifications while usage continues. Turn it on and affected paid usage stops at the limit. GitHub Copilot code completions and next edit suggestions still work because they do not use this paid AI credit allowance. A blocked request also does not automatically switch to a cheaper model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create accountable room for a cost center
&lt;/h3&gt;

&lt;p&gt;The organization budget covers shared paid usage across the organization. A cost-center budget gives a specific team an earlier warning.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fknal0tnmghrqw6m4bkow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fknal0tnmghrqw6m4bkow.png" alt="Cost center budget" width="515" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 07: A $20,000 cost-center threshold monitors current demand without stopping usage.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this example, the administrator sets a $20,000 alert and leaves the stop toggle off. The owner can review the workload, remove waste, or ask for a higher limit before usage is interrupted.&lt;/p&gt;

&lt;p&gt;The same timing rule applies here: if the budget is created partway through the billing cycle, earlier usage is not counted. The first bill can therefore exceed the displayed $20,000 limit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fobyyabok6aoe401usz2u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fobyyabok6aoe401usz2u.png" alt="Budget alert configuration" width="543" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 08: Threshold alerts route emerging cost risk to owners before month-end.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alerts give people time to act. Finance can review expected spending, the cost-center owner can explain the increase, and the administrator can adjust the limit or turn on stopping if needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give different users the right limits
&lt;/h3&gt;

&lt;p&gt;Shared budgets do not control how many AI credits one person can use. Per-user budgets do. They count both included and paid credits, and they always stop further AI-credit use when the person's limit is reached.&lt;/p&gt;

&lt;p&gt;Set these limits from broad to specific:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Establish a universal per-user &lt;strong&gt;baseline&lt;/strong&gt;, the starting limit for every licensed user.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;cost-center exception&lt;/strong&gt; where a group's expected outcomes justify a different limit.&lt;/li&gt;
&lt;li&gt;Add an individual &lt;strong&gt;override&lt;/strong&gt;, a replacement limit for one person, only for a role with a documented need.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftwd2ti7jzjnhyv8wmh3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftwd2ti7jzjnhyv8wmh3z.png" alt="Cost-center per-user budget" width="493" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 09: A $200 per-user cost-center exception adds targeted headroom without raising the enterprise baseline.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The screenshot shows the second step: a $200 per-user limit for one cost center. Start with the universal baseline, then add an individual override only when someone has a clear need for a different amount. This keeps exceptions easy to review and avoids raising the limit for everyone just to support one specialist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explain which user limit takes priority
&lt;/h3&gt;

&lt;p&gt;What happens when several limits cover the same user? &lt;strong&gt;Precedence&lt;/strong&gt; is simply the order GitHub follows to choose the user-level budget that applies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9h7c4id3tqd6e6op9km.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9h7c4id3tqd6e6op9km.png" alt="Precedence" width="493" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fig 10: Policy precedence applies individual overrides before cost-center and universal user limits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Among &lt;strong&gt;user-level budgets&lt;/strong&gt;, the individual override comes first, followed by the cost-center per-user budget and then the universal baseline. For example, imagine a $100 universal baseline, a $200 cost-center limit, and a $500 individual override. The specialist gets $500, colleagues in that cost center get $200 each, and everyone else gets $100 each.&lt;/p&gt;

&lt;p&gt;Shared organization and cost-center limits still apply separately. Whichever relevant limit is reached first blocks further usage. A person may still have money left in an individual budget when the shared limit has already been reached. The reverse can also happen: a person's limit may stop their usage while the shared budget still has room.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aftermath: Keep the policy working
&lt;/h2&gt;

&lt;p&gt;Setting the limits is only the start. Someone still needs to review what happens next.&lt;/p&gt;

&lt;p&gt;Finance can see where paid usage is limited. Business owners can see which costs they own. Engineering leaders can see where exceptions protect important work. Included-pool controls protect shared credits, organization and cost-center budgets limit additional paid usage, and per-user budgets set individual limits.&lt;/p&gt;

&lt;p&gt;Assign someone to review alerts, blocked requests, approved exceptions, and business results on a regular schedule. When a team repeatedly reaches its limit, that owner can look for waste, compare usage with results, and recommend a change. Finance and engineering leaders can then approve the change or step in when cost and delivery needs conflict.&lt;/p&gt;

&lt;p&gt;With those responsibilities clear, finance can see the cost, business leaders can own it, and administrators can adjust the controls before the next surprise bill arrives.&lt;/p&gt;

&lt;h3&gt;
  
  
  A quick reference to the controls
&lt;/h3&gt;

&lt;p&gt;The story above introduces each control when it becomes useful. This table collects the technical differences in one place for reference.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Control&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;What it counts&lt;/th&gt;
&lt;th&gt;What happens at the limit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Organization or cost-center budget&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Monitors or limits shared paid usage&lt;/td&gt;
&lt;td&gt;Additional paid usage after included credits are used; license costs are excluded&lt;/td&gt;
&lt;td&gt;Sends alerts, or stops affected paid usage when stopping is enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Included AI credit pool&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Protects the credits included with licenses assigned to a cost center&lt;/td&gt;
&lt;td&gt;Shared included AI credits calculated by GitHub&lt;/td&gt;
&lt;td&gt;Blocks more AI-credit use, or allows paid usage when paid usage is enabled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Per-user budget&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limits one person's total AI-credit use&lt;/td&gt;
&lt;td&gt;Included and paid AI credits for that user&lt;/td&gt;
&lt;td&gt;Always stops more affected usage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;When an included AI credit pool runs out, administrators can block further AI-credit use or allow it to continue as paid usage, as long as paid usage is enabled. Some reductions to the pool take effect in the next billing cycle, so check the timing before relying on a lower limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-06-25-assign-enterprise-teams-to-cost-centers/" rel="noopener noreferrer"&gt;Assign enterprise teams to cost centers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-06-30-per-user-ai-credit-budgets-available-for-cost-centers/" rel="noopener noreferrer"&gt;Per-user AI credit budgets available for cost centers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-07-02-cost-centers-now-support-included-usage-caps/" rel="noopener noreferrer"&gt;Cost centers now support included usage caps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>billing</category>
    </item>
    <item>
      <title>Getting started with GitHub Copilot part 2, streamable responses</title>
      <dc:creator>Chris Noring</dc:creator>
      <pubDate>Mon, 16 Mar 2026 20:14:28 +0000</pubDate>
      <link>https://dev.to/azure/getting-started-with-github-copilot-part-2-streamable-responses-49a8</link>
      <guid>https://dev.to/azure/getting-started-with-github-copilot-part-2-streamable-responses-49a8</guid>
      <description>&lt;p&gt;I'm sure you've seen many AI apps where you sit tight for 30s or and you wonder if things are stuck? Not a great experience right? Yes, you're right, you deserve better, so how do we fix it?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Type your prompt&amp;gt; Tell me a joke
.
.
.
.
.
.
.
.
Why could I never find the atoms, cause they split..
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/T4p-C2v_0wU"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  Series on Copilot SDK
&lt;/h2&gt;

&lt;p&gt;This series is about Copilot SDK and how you can leverage your existing GitHub Copilot license to integrate AI into your apps&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/azure/get-started-with-github-copilot-sdk-1ijm/"&gt;Part 1 - install and your first app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Part 2 - streamable response, &lt;strong&gt;you're here&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Addressing the problem
&lt;/h2&gt;

&lt;p&gt;By streaming the response, the response now arrives in chunks, pieces that you can show as soon as they arrive. How can we do that though and how can GitHub Copilot SDK help out?&lt;/p&gt;

&lt;p&gt;Well, there's two things you need to do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable streaming. You need to set &lt;code&gt;streaming&lt;/code&gt; to &lt;code&gt;True&lt;/code&gt; when you call &lt;code&gt;create_session&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Listen for events that contains a chunk. Specifically, you need to listen to &lt;code&gt;ASSISTANT_MESSAGE_DELTA&lt;/code&gt; and print out the chunk.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 1. Enable streaming
&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on_permission_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PermissionHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;approve_all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;streaming&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting streamed response:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Listen for response chunks
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SessionEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ASSISTANT_MESSAGE_DELTA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mf"&gt;2.&lt;/span&gt; &lt;span class="n"&gt;Chunk&lt;/span&gt; &lt;span class="n"&gt;arrived&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delta_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SessionEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SESSION_IDLE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# New line when done
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what the full application looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;copilot&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CopilotClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PermissionHandler&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;copilot.generated.session_events&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SessionEventType&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CopilotClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;on_permission_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PermissionHandler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;approve_all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;streaming&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting streamed response:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Listen for response chunks
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SessionEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ASSISTANT_MESSAGE_DELTA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delta_content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SessionEventType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SESSION_IDLE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# New line when done
&lt;/span&gt;
    &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handle_event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending prompt...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_and_wait&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tell me a short joke&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it folks, now go out and build better experiences for your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md#step-3-add-streaming-responses" rel="noopener noreferrer"&gt;Streamed response&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>githubcopilot</category>
      <category>copilotsdk</category>
      <category>python</category>
    </item>
    <item>
      <title>Get started with GitHub Copilot CLI: A free, hands-on course</title>
      <dc:creator>Renee Noble</dc:creator>
      <pubDate>Thu, 05 Mar 2026 04:44:08 +0000</pubDate>
      <link>https://dev.to/azure/get-started-with-github-copilot-cli-a-free-hands-on-course-3beg</link>
      <guid>https://dev.to/azure/get-started-with-github-copilot-cli-a-free-hands-on-course-3beg</guid>
      <description>&lt;p&gt;GitHub Copilot has grown well beyond code completions in your editor. It now lives in your terminal, too. &lt;a href="https://docs.github.com/copilot/how-tos/copilot-cli" rel="noopener noreferrer"&gt;GitHub Copilot CLI&lt;/a&gt; lets you review code, generate tests, debug issues, and ask questions about your projects without ever leaving the command line.&lt;/p&gt;

&lt;p&gt;To help developers get up to speed, we put together a free, open source course: &lt;a href="https://github.com/github/copilot-cli-for-beginners" rel="noopener noreferrer"&gt;GitHub Copilot CLI for Beginners&lt;/a&gt;. It’s 8 chapters, hands-on from the start, and designed so you can go from installation to building real workflows in a few hours. &lt;strong&gt;Already have a GitHub account&lt;/strong&gt;? GitHub Copilot CLI works with &lt;a href="https://github.com/features/copilot/plans" rel="noopener noreferrer"&gt;GitHub Copilot Free&lt;/a&gt;, which is available to all personal GitHub accounts.&lt;/p&gt;

&lt;p&gt;In this post, I’ll walk through what the course covers and how to get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  What GitHub Copilot CLI can do
&lt;/h2&gt;

&lt;p&gt;If you haven’t tried it yet, GitHub Copilot CLI is a conversational AI assistant that runs in your terminal. You point it at files using @ references, and it reads your code and responds with analysis, suggestions, or generated code.&lt;/p&gt;

&lt;p&gt;You can use it to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Review a file and get feedback on code quality&lt;/li&gt;
&lt;li&gt;Generate tests based on existing code&lt;/li&gt;
&lt;li&gt;Debug issues by pointing it at a file and asking what’s wrong&lt;/li&gt;
&lt;li&gt;Explain unfamiliar code or confusing logic&lt;/li&gt;
&lt;li&gt;Generate commit messages, refactor functions, and more&lt;/li&gt;
&lt;li&gt;Write new app features (front-end, APIs, database interactions, and more)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It remembers context within a conversation, so follow-up questions build on what came before.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the course covers
&lt;/h2&gt;

&lt;p&gt;The course is structured as 8 progressive chapters. Each one builds on the last, and you work with the same project throughout: a book collection management app. Instead of jumping between isolated snippets, you keep improving one codebase as you go.&lt;/p&gt;

&lt;p&gt;Here’s what using GitHub Copilot CLI looks like in practice. Say you want to review a Python file for potential issues. Start up Copilot CLI and ask what you’d like done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ copilot
&amp;gt; Review @samples/book-app-project/books.py for potential improvements. Focus on error handling and code quality.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copilot reads the file, analyzes the code, and gives you specific feedback right in your terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68z8p0e37osyv69md339.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68z8p0e37osyv69md339.gif" alt="code review demo gif" width="760" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the chapters covered in the course:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Start&lt;/strong&gt; — Installation and authentication&lt;br&gt;
&lt;strong&gt;First Steps&lt;/strong&gt; — Learn the three interaction modes: interactive, plan, and one-shot (programmatic)&lt;br&gt;
&lt;strong&gt;Context and Conversations&lt;/strong&gt; — Using @ references to point Copilot at files and directories, plus session management with --continue and --resume&lt;br&gt;
&lt;strong&gt;Development Workflows&lt;/strong&gt; — Code review, refactoring, debugging, test generation, and Git integration&lt;br&gt;
&lt;strong&gt;Custom Agents&lt;/strong&gt; — Building specialized AI assistants with .agent.md files (for example, a Python reviewer that always checks for type hints)&lt;br&gt;
&lt;strong&gt;Skills&lt;/strong&gt; — Creating task-specific instructions that auto-trigger based on your prompt&lt;br&gt;
&lt;strong&gt;MCP Servers&lt;/strong&gt; — Connecting Copilot to external services like GitHub repos, file systems, and documentation APIs via the Model Context Protocol&lt;br&gt;
&lt;strong&gt;Putting It All Together&lt;/strong&gt; — Combining agents, skills, and MCP servers into complete development workflows&lt;br&gt;
learning path image&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F381r15kd6bohcuu878jj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F381r15kd6bohcuu878jj.png" alt="learning path image" width="800" height="116"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every command in the course can be copied and run directly. No AI or machine learning background is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;The course is built for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Developers using terminal workflows:&lt;/strong&gt; If you’re already running builds, checking git status, and SSHing into servers from the command line, Copilot CLI fits right into that flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teams looking to standardise AI-assisted practices:&lt;/strong&gt; Custom agents and skills can be shared across a team through a project’s &lt;code&gt;.github/agents&lt;/code&gt; and &lt;code&gt;.github/skills&lt;/code&gt; directories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Students and early-career developers:&lt;/strong&gt; The course explains AI terminology as it comes up, and every chapter includes assignments with clear success criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need prior experience with AI tools. If you can run commands in a terminal, you learn and apply the concepts in this course.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the course teaches
&lt;/h2&gt;

&lt;p&gt;Each chapter follows a consistent pattern: a real-world analogy to ground the concept, then the core technical material, then hands-on exercises. For instance, the three interaction modes are compared to ordering food at a restaurant. Plan mode is more like mapping your route to the restaurant before you start driving. Interactive mode is a back-and-forth conversation with a waiter. And one-shot mode (programmatic mode) is like going through the drive-through.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffsorjdhrhn758c638mps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffsorjdhrhn758c638mps.png" alt="ordering food analogy image" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Later chapters use different comparisons: agents are like hiring specialists, skills work like attachments for a power drill, and MCP servers are compared to browser extensions. The goal is to provide you with a visual and mental model before the technical details land.&lt;/p&gt;

&lt;p&gt;The course also focuses on a question that’s harder than it looks: when should I use which tool? Knowing the difference between reaching for an agent, a skill, or an MCP server takes practice, and the final chapter walks through that decision-making in a realistic workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cfcllljwbgovlf9qfc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cfcllljwbgovlf9qfc6.png" alt="integration pattern image" width="749" height="881"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;The course is free and open source. You can clone the repo, or &lt;a href="https://codespaces.new/github/copilot-cli-for-beginners?hide_repo_select=true&amp;amp;ref=main&amp;amp;quickstart=true" rel="noopener noreferrer"&gt;open it in GitHub Codespaces&lt;/a&gt; for a fully configured environment. Jump right in, get Copilot CLI running, and see if it fits your workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/github/copilot-cli-for-beginners" rel="noopener noreferrer"&gt;GitHub Copilot CLI for Beginners&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a quick reference, see the &lt;a href="https://docs.github.com/copilot/reference/cli-command-reference" rel="noopener noreferrer"&gt;CLI command reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Subscribe to &lt;a href="https://resources.github.com/newsletter/" rel="noopener noreferrer"&gt;GitHub Insider&lt;/a&gt; for more developer tips and guides.&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>cli</category>
      <category>vscode</category>
      <category>terminal</category>
    </item>
    <item>
      <title>Get started with GitHub Copilot SDK, part 1</title>
      <dc:creator>Chris Noring</dc:creator>
      <pubDate>Wed, 04 Mar 2026 20:48:00 +0000</pubDate>
      <link>https://dev.to/azure/get-started-with-github-copilot-sdk-1ijm</link>
      <guid>https://dev.to/azure/get-started-with-github-copilot-sdk-1ijm</guid>
      <description>&lt;p&gt;Did you know GitHub Copilot now has an SDK and that you can leverage your existing license to build AI integrations into your app? No, well I hope I have you attention now.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/hvwGZqS4qF0"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  Series on Copilot SDK
&lt;/h2&gt;

&lt;p&gt;This series is about Copilot SDK and how you can leverage your existing GitHub Copilot license to integrate AI into your apps&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Part 1 - install and your first app, &lt;strong&gt;you're here&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/azure/getting-started-with-github-copilot-part-2-streamable-responses-49a8"&gt;Part 2 - streamable responses&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;You need two pieces here to get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Copilot CLI&lt;/li&gt;
&lt;li&gt;A supported runtime, which at present means either Node.js, .NET, Python or Go&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then you need to install the SDK for your chosen runtime like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;github-copilot-sdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The parts
&lt;/h2&gt;

&lt;p&gt;So what do you need to know to get started? There are three concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client&lt;/strong&gt;, you need to create and instance of it. Additionally you need to start and stop it when you're done with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session&lt;/strong&gt;. The session takes an object where you can set things like model, system prompt and more. Also, the session is what you talk when you  want to carry out a request. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response&lt;/strong&gt;. The response contains your LLM response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is an example program using these three concepts. As you can see we choose "gpt-4.1" as model but this can be changed. See also how we pass the prompt to the function &lt;code&gt;send_and_wait&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;copilot&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CopilotClient&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CopilotClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_and_wait&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is 2 + 2?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, now that we know what a simple program looks like, let's make something interesting, an FAQ responder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your first app
&lt;/h2&gt;

&lt;p&gt;An FAQ for a web page, is often a pretty boring read. A way to make that more interesting for the end user is if they can instead chat with the FAQ, let's make that happen. &lt;/p&gt;

&lt;p&gt;Here's the plan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define a static FAQ&lt;/li&gt;
&lt;li&gt;Add the FAQ as part of the prompt.&lt;/li&gt;
&lt;li&gt;Make a request to to the LLM and print out the response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's build out the code little by little. First, let's define the FAQ information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;-1- FAQ information&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# faq.py
&lt;/span&gt;
&lt;span class="n"&gt;faq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;warranty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Our products come with a 1-year warranty covering manufacturing defects. Please contact our support team for assistance.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;return_policy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;We offer a 30-day return policy for unused products in their original packaging. To initiate a return, please visit our returns page and follow the instructions.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shipping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;We offer free standard shipping on all orders over $50. Expedited shipping options are available at checkout for an additional fee.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let's add the call to the Copilot SDK&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;-2  Adding the LLM call&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;copilot&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CopilotClient&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;faq_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tell me about shipping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CopilotClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Here&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s the FAQ, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;faq_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;User question: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Answer:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;   

    &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_and_wait&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My first app using the GitHub Copilot SDK!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[LOG] Asking the model about shipping information...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tell me about shipping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note how we concatenate the FAQ data with the user's prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Here&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s the FAQ, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;faq_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;User question: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_prompt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Answer:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;-3- Let's run it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run faq.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see output like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;My first app using the GitHub Copilot SDK!
[LOG] Asking the model about shipping information...
We offer free standard shipping on all orders over $50. Expedited shipping options are available at checkout for an additional fee.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>githubcopilot</category>
      <category>python</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>The JavaScript AI Build-a-thon Season 2 starts March 2!</title>
      <dc:creator>Julia Muiruri</dc:creator>
      <pubDate>Wed, 25 Feb 2026 04:09:06 +0000</pubDate>
      <link>https://dev.to/azure/the-javascript-ai-build-a-thon-season-2-starts-march-2-1e92</link>
      <guid>https://dev.to/azure/the-javascript-ai-build-a-thon-season-2-starts-march-2-1e92</guid>
      <description>&lt;p&gt;Most applications used by millions of people every single day are powered by JavaScript/TypeScript. But when it comes to AI, most learning resources and code samples assume you're working in Python and will leave you trying to stitch scattered tutorials together to build AI into your stack.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;JavaScript AI Build-a-thon&lt;/strong&gt; is a free, hands-on program designed to close that gap. Over the course of four weeks &lt;strong&gt;(March 2 - March 31, 2026)&lt;/strong&gt;, you'll move from running AI 100% on-device (Local AI), to designing multi-service, multi-agentic systems, all in JavaScript/ TypeScript and using tools you are already familiar with.&lt;br&gt;
The series will culminate in a &lt;strong&gt;hackathon&lt;/strong&gt;, where you will create, compete and turn what you'll have learnt into working projects you can point to, talk about and extend.&lt;/p&gt;

&lt;p&gt;Register now at &lt;a href="https://aka.ms/JSAIBuildathon" rel="noopener noreferrer"&gt;aka.ms/JSAIBuildathon&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How the program works!
&lt;/h2&gt;

&lt;p&gt;The program is organized around 2 phases: -&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase I: Learn &amp;amp; Skill Up Schedule (Mar 2 - 13)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Self-paced quests that teach core AI patterns,&lt;/li&gt;
&lt;li&gt;Interactive Expert-led sessions on Microsoft Reactor (Livestreams) and Discord (Office hours &amp;amp; QnA)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1779ztlhwqxtoxdxq6d3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1779ztlhwqxtoxdxq6d3.png" alt="JavaScript AI Build-a-thon Roadmap" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Day/Time (PT)&lt;/th&gt;
&lt;th&gt;Topic&lt;/th&gt;
&lt;th&gt;Links to join&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mon 3/2, 8:00 AM PST&lt;/td&gt;
&lt;td&gt;Local AI Development with Foundry Local&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://developer.microsoft.com/en-us/reactor/events/26772/" rel="noopener noreferrer"&gt;Livestream&lt;/a&gt; &lt;br&gt; &lt;a href="https://discord.gg/microsoftfoundry?event=1465380906842853666" rel="noopener noreferrer"&gt;Discord Office Hour&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wed 3/4, 8:00 AM PST&lt;/td&gt;
&lt;td&gt;End-to-End Model Development on Microsoft Foundry&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://developer.microsoft.com/en-us/reactor/events/26773/" rel="noopener noreferrer"&gt;Livestream&lt;/a&gt; &lt;br&gt; &lt;a href="https://discord.gg/microsoftfoundry?event=1470927803888173109" rel="noopener noreferrer"&gt;Discord Office Hour&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fri 3/6, 9:00 AM PST&lt;/td&gt;
&lt;td&gt;Advanced RAG Deep Dive + Guided Project&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://developer.microsoft.com/en-us/reactor/events/26775" rel="noopener noreferrer"&gt;Livestream&lt;/a&gt; &lt;br&gt; &lt;a href="https://discord.gg/microsoftfoundry?event=1465381686362509323" rel="noopener noreferrer"&gt;Discord Office Hour&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mon 3/9, 8:00 AM PST&lt;/td&gt;
&lt;td&gt;Design &amp;amp; Build an Agent E2E with Agent Builder (AITK)&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://developer.microsoft.com/en-us/reactor/events/26776/" rel="noopener noreferrer"&gt;Livestream&lt;/a&gt; &lt;br&gt; &lt;a href="https://discord.gg/microsoftfoundry?event=1465382167894036481" rel="noopener noreferrer"&gt;Discord Office Hour&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wed 3/11, 8:00 AM PST&lt;/td&gt;
&lt;td&gt;Build, Scale &amp;amp; Govern AI Agents + Guided project&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://developer.microsoft.com/en-us/reactor/events/26786/" rel="noopener noreferrer"&gt;Livestream&lt;/a&gt; &lt;br&gt; &lt;a href="https://discord.gg/microsoftfoundry?event=1465382908687814840" rel="noopener noreferrer"&gt;Discord Office Hour&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Build-a-thon prioritizes practical learning, so you'll complete &lt;strong&gt;2 guided projects&lt;/strong&gt; by the end of this phase:-&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. A Local Serverless AI chat with RAG&lt;/strong&gt;&lt;br&gt;
Concepts covered include: -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAG Architecture&lt;/li&gt;
&lt;li&gt;RAG Ingestion pipeline&lt;/li&gt;
&lt;li&gt;Query &amp;amp; Retrieval&lt;/li&gt;
&lt;li&gt;Response Generation (LLM Chains)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc733enuiuhxw2cx3jde7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc733enuiuhxw2cx3jde7.png" alt="Serverless Chat LangChain.js CodeTour" width="800" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A Burger Ordering AI Agent&lt;/strong&gt;&lt;br&gt;
Concepts covered include: -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Designing AI Agents&lt;/li&gt;
&lt;li&gt;Building MCP Tools (Backend API Design)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl74vmkvwp1c3m1k6g08m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl74vmkvwp1c3m1k6g08m.png" alt="Contoso Burger Ordering Agent" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase II: Global Hack! (Mar 13 - 31)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Product demo series to showcase the latest product features that will accelerate your builder experience&lt;/li&gt;
&lt;li&gt;A Global hackathon to apply what you learn into real, working AI solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where you'll build something that matters using everything learnt in the quests, and beyond, to create an AI-powered project that solves a real problem, delights users, or pushes what's possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The hackathon launches on March 13, 2026.&lt;/strong&gt; Full details on registration, submission, judging criteria, award categories, prizes, and the hack phase schedule will be published when the hack goes live. Stay tuned!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But, here's what we can tell you now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🏆 &lt;strong&gt;6 award categories&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;Product demo showcases&lt;/strong&gt; throughout the hack phase to keep you building with the latest tools&lt;/li&gt;
&lt;li&gt;👥 Teams of up to 4 or solo. Your call&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Start Now (Join the Community)
&lt;/h2&gt;

&lt;p&gt;Join our community to connect with other participants and experts from Microsoft &amp;amp;. GitHub to support your builder journey.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Foundry Discord (#js-ai-build-a-thon channel):&lt;/strong&gt; &lt;a href="https://aka.ms/JSAIonDiscord" rel="noopener noreferrer"&gt;Our platform for office hours, live QnA, quick questions, community &amp;amp; expert support&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Discussions:&lt;/strong&gt; &lt;a href="https://aka.ms/JSAI_Discussions" rel="noopener noreferrer"&gt;This is where you'll share ideas, ask questions, find teammates&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social:&lt;/strong&gt; Share your progress online using &lt;strong&gt;#JSAIBuildathon&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Register now at &lt;a href="https://aka.ms/JSAIBuildathon" rel="noopener noreferrer"&gt;aka.ms/JSAIBuildathon&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See you soon!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>langchain</category>
      <category>ai</category>
    </item>
    <item>
      <title>Host Your Node.js MCP Server on Azure Functions in 1 Simple Step</title>
      <dc:creator>Yohan Lasorsa</dc:creator>
      <pubDate>Tue, 09 Dec 2025 15:44:53 +0000</pubDate>
      <link>https://dev.to/azure/host-your-nodejs-mcp-server-on-azure-functions-in-3-simple-steps-3ao8</link>
      <guid>https://dev.to/azure/host-your-nodejs-mcp-server-on-azure-functions-in-3-simple-steps-3ao8</guid>
      <description>&lt;p&gt;Building AI agents with the Model Context Protocol (MCP) is powerful, but when it comes to hosting your MCP server in production, you need a solution that's reliable, scalable, and cost-effective. What if you could deploy your regular Node.js MCP server to a serverless platform that handles scaling automatically while you only pay for what you use?&lt;/p&gt;

&lt;p&gt;Let's explore how Azure Functions now supports hosting MCP servers built with the official Anthropic MCP SDK, giving you serverless scaling with almost no changes in your code.&lt;/p&gt;

&lt;p&gt;Grab your favorite hot beverage, and let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Azure Functions now supports hosting Node.js MCP servers using the official Anthropic SDK&lt;/li&gt;
&lt;li&gt;Only 1 simple configuration needed: adding &lt;code&gt;host.json&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Currently supports HTTP Streaming protocol with stateless servers&lt;/li&gt;
&lt;li&gt;Serverless hosting means automatic scaling and pay-per-use pricing&lt;/li&gt;
&lt;li&gt;Deploy with one command using Infrastructure as Code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What will you learn here?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Understand how MCP servers work on Azure Functions&lt;/li&gt;
&lt;li&gt;Configure a Node.js MCP server for Azure Functions hosting&lt;/li&gt;
&lt;li&gt;Test your MCP server locally and with real AI agents&lt;/li&gt;
&lt;li&gt;Deploy your MCP server with Infrastructure as Code and AZD&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reference links for everything we use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://modelcontextprotocol.io/" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; - Official MCP documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-overview" rel="noopener noreferrer"&gt;Azure Functions&lt;/a&gt; - Serverless compute platform&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/modelcontextprotocol/typescript-sdk" rel="noopener noreferrer"&gt;Anthropic MCP SDK&lt;/a&gt; - Official TypeScript SDK&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/overview" rel="noopener noreferrer"&gt;Azure Developer CLI&lt;/a&gt; - One-command deployment tool&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Azure-Samples/mcp-agent-langchainjs" rel="noopener noreferrer"&gt;Full sample project&lt;/a&gt; - Complete burger ordering system with MCP&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Azure-Samples/mcp-sdk-functions-hosting-node" rel="noopener noreferrer"&gt;Simple example&lt;/a&gt; - Minimal MCP server starter&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/anthonychu/create-functions-mcp-server" rel="noopener noreferrer"&gt;GitHub Copilot prompt helper&lt;/a&gt; - Automated setup by Anthony Chu&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 22 or higher&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://azure.microsoft.com/free" rel="noopener noreferrer"&gt;Azure account&lt;/a&gt; (free signup, or if you're a student, &lt;a href="https://azure.microsoft.com/free/students" rel="noopener noreferrer"&gt;get free credits here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/azure-dev/install" rel="noopener noreferrer"&gt;Azure Developer CLI&lt;/a&gt; (for deployment)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/signup" rel="noopener noreferrer"&gt;GitHub account&lt;/a&gt; (optional, for using Codespaces)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is MCP and why does it matter?
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol is an open standard that enables AI models to securely interact with external tools and data sources. Instead of hardcoding tool integrations, you build an MCP server that exposes capabilities (like browsing a menu, placing orders, or querying a database) as tools that any MCP-compatible AI agent can discover and use. MCP is model-agnostic, meaning it can work with any LLM that supports the protocol, including models from Anthropic, OpenAI, and others. It's also worth noting that MCP supports more than just tool calls, though that's its most common use case.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkujo718hq9m24ouev5zl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkujo718hq9m24ouev5zl.png" alt="Schema showing MCP interfacing with different tool servers" width="722" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The challenge? &lt;strong&gt;Running MCP servers in production requires infrastructure&lt;/strong&gt;. You need to handle scaling, monitoring, and costs. That's where Azure Functions comes in.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🚨 Free course alert!&lt;/strong&gt; If you're new to MCP, check out the &lt;a href="https://github.com/microsoft/mcp-for-beginners" rel="noopener noreferrer"&gt;MCP for Beginners&lt;/a&gt; course to get up to speed quickly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Azure Functions for MCP servers?
&lt;/h2&gt;

&lt;p&gt;Azure Functions is a serverless compute platform that's perfect for MCP servers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero infrastructure management&lt;/strong&gt;: No servers to maintain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic scaling&lt;/strong&gt;: Handles traffic spikes seamlessly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost-effective&lt;/strong&gt;: Pay only for actual execution time (with generous free grant)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in monitoring&lt;/strong&gt;: Application Insights integration out of the box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global distribution&lt;/strong&gt;: Deploy to regions worldwide&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The new Azure Functions support means you can take your existing Node.js MCP server and deploy it to a production-ready serverless environment with minimal changes. This comes up as an additional option for native Node.js MCP hosting, but you can still use the &lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-bindings-mcp?pivots=programming-language-typescript" rel="noopener noreferrer"&gt;Azure Functions MCP bindings&lt;/a&gt; that were available before.&lt;/p&gt;

&lt;h2&gt;
  
  
  1 simple step to enable Functions hosting
&lt;/h2&gt;

&lt;p&gt;Let's break down what you need to add to your existing Node.js MCP server to run it on Azure Functions. I'll use a &lt;a href="https://github.com/Azure-Samples/mcp-agent-langchainjs/tree/main/packages/burger-mcp" rel="noopener noreferrer"&gt;real-world example&lt;/a&gt; from our burger ordering system.&lt;/p&gt;

&lt;p&gt;If you already have a working Node.js MCP server, you can just follow this to make it compatible with Azure Functions hosting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Add the &lt;code&gt;host.json&lt;/code&gt; configuration
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;host.json&lt;/code&gt; file at the root of your Node.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"configurationProfile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcp-custom-handler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customHandler"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"defaultExecutablePath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lib/server.js"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"DefaultAuthorizationLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"anonymous"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3000"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Adjust the &lt;code&gt;arguments&lt;/code&gt; array to point to your compiled server file (e.g., &lt;code&gt;lib/server.js&lt;/code&gt; or &lt;code&gt;dist/server.js&lt;/code&gt;), depending on your build setup. You can also change the port if needed to match your server configuration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;hosts.json&lt;/code&gt; file holds &lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-host-json" rel="noopener noreferrer"&gt;metadata configuration&lt;/a&gt; for the Functions runtime. The most important part here is the &lt;code&gt;customHandler&lt;/code&gt; section. It configures the Azure Functions runtime to run your Node.js MCP server as a &lt;em&gt;custom handler&lt;/em&gt;, which allows you to use any HTTP server framework (like Express, Fastify, etc.) without modification (&lt;strong&gt;tip: it can do more than MCP servers!&lt;/strong&gt; 😉).&lt;/p&gt;

&lt;p&gt;There's no step 2 or 3. That's it! 😎&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We're not covering the authentication and authorization aspects of Azure Functions here, but you can easily &lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-mcp-tutorial?tabs=self-hosted&amp;amp;pivots=programming-language-typescript#enable-built-in-server-authorization-and-authentication" rel="noopener noreferrer"&gt;add those later if needed&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Real-world example: Burger MCP Server
&lt;/h2&gt;

&lt;p&gt;Let's look at how this works in practice with a &lt;a href="https://github.com/Azure-Samples/mcp-agent-langchainjs/tree/main/packages/burger-mcp" rel="noopener noreferrer"&gt;burger ordering MCP server&lt;/a&gt;. This server exposes 9 tools for AI agents to interact with a burger API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;get_burgers&lt;/code&gt; - Browse the menu&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_burger_by_id&lt;/code&gt; - Get burger details&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;place_order&lt;/code&gt; - Place an order&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_orders&lt;/code&gt; - View order history&lt;/li&gt;
&lt;li&gt;And more...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the complete server implementation using Express and the MCP SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StreamableHTTPServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/streamableHttp.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getMcpServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./mcp.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Handle all MCP Streamable HTTP requests&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/mcp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StreamableHTTPServerTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;sessionIdGenerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Connect the transport to the MCP server&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getMcpServer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Handle the request with the transport&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Clean up when the response is closed&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Note: error handling not shown for brevity&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// The port configuration&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Burger MCP server listening on port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP tools are defined using the official SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;McpServer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/mcp.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getMcpServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;McpServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;burger-mcp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get_burgers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get a list of all burgers in the menu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;burgerApiUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/burgers`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;burgers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;burgers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}]&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ... more tools&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the actual implementation of the tool is forwarding an HTTP request to the burger API and returning the result in the MCP response format. This is a common pattern for MCP tools in enterprise contexts, that act as wrappers around one or more existing APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Current limitations
&lt;/h3&gt;

&lt;p&gt;Note that this Azure Functions MCP hosting currently has some limitations: &lt;strong&gt;it only supports stateless servers using the HTTP Streaming protocol&lt;/strong&gt;. The legacy SSE protocol is not supported as it requires stateful connections, so you'll either have to migrate your client to use HTTP Streaming or use another hosting option, like using containers for example.&lt;/p&gt;

&lt;p&gt;For most use cases, HTTP Streaming is the recommended approach anyway as it's more scalable and doesn't require persistent connections. Stateful MCP servers comes with additional complexity challenges and have limited scalability if you need to handle many concurrent connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the MCP server locally
&lt;/h2&gt;

&lt;p&gt;First let's run the MCP server locally and play a bit with it.&lt;/p&gt;

&lt;p&gt;If you don't want to bother with setting up a local environment, you can use the following link or open it in a new tab to launch a GitHub Codespace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codespaces.new/Azure-Samples/mcp-agent-langchainjs?hide_repo_select=true&amp;amp;ref=main&amp;amp;quickstart=true" rel="noopener noreferrer"&gt;Create Codespace&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will open a VS Code environment in your browser with the repo already cloned and all the tools installed and ready to go. Otherwise you can just &lt;a href="https://github.com/Azure-Samples/mcp-agent-langchainjs" rel="noopener noreferrer"&gt;clone the repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have the code ready, open a terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Start the burger MCP server and API&lt;/span&gt;
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start multiple services locally, including the Burger API and the MCP server, which will be available at &lt;code&gt;http://localhost:3000/mcp&lt;/code&gt;. This may take a few seconds, wait until you see this message in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🚀 All services ready 🚀
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're only interested in the MCP server for now, so let's focus on that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using MCP Inspector
&lt;/h3&gt;

&lt;p&gt;The easiest way to test the MCP server is with the MCP Inspector tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; @modelcontextprotocol/inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the URL shown in the console in your browser, then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set transport type to &lt;strong&gt;Streamable HTTP&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter your local server URL: &lt;code&gt;http://localhost:3000/mcp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Connect&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After you're connected, go to the &lt;strong&gt;Tools&lt;/strong&gt; tab to list available tools. You can then try the &lt;code&gt;get_burgers&lt;/code&gt; tool to see the burger menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuo3lgw3v80we4v31p57u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuo3lgw3v80we4v31p57u.png" alt="MCP Inspector Screenshot" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using GitHub Copilot (with remote MCP)
&lt;/h3&gt;

&lt;p&gt;Configure GitHub Copilot to use your deployed MCP server by adding this to your project's &lt;code&gt;.vscode/mcp.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"burger-mcp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:3000/mcp"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click on "Start" button that will appear in the JSON file to activate the MCP server connection.&lt;/p&gt;

&lt;p&gt;Now you can use Copilot in agent mode and ask things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What spicy burgers do you have?"&lt;/li&gt;
&lt;li&gt;"Place an order for two cheeseburgers"&lt;/li&gt;
&lt;li&gt;"Show my recent orders"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copilot will automatically discover and use the MCP tools! 🎉&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If Copilot doesn't call the burger MCP tools, try checking if it's enabled by clicking on the tool icon in the chat input box and ensuring that "burger-mcp" is selected. You can also force tool usage by adding &lt;code&gt;#burger-mcp&lt;/code&gt; in your prompt.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  (Bonus) Deploying to Azure with Infrastructure as Code
&lt;/h2&gt;

&lt;p&gt;Deploying an application to Azure is usually not the fun part, especially when it involves multiple resources and configurations.&lt;br&gt;
With the &lt;a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/overview" rel="noopener noreferrer"&gt;Azure Developer CLI (AZD)&lt;/a&gt;, you can define your entire application infrastructure and deployment process as code, and deploy everything with a single command.&lt;/p&gt;

&lt;p&gt;If you've used the automated setup with GitHub Copilot, you should already have the necessary files. Our burger example also comes with these files pre-configured. The MCP server is defined as a service in &lt;code&gt;azure.yaml&lt;/code&gt;, and the files under the &lt;code&gt;infra&lt;/code&gt; folder defines the Azure Functions app and related resources.&lt;/p&gt;

&lt;p&gt;Here's the relevant part of &lt;code&gt;azure.yaml&lt;/code&gt; that defines the burger MCP service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-agent-langchainjs&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;burger-mcp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./packages/burger-mcp&lt;/span&gt;
    &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ts&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the infrastructure files can look intimidating at first, you don't need to understand all the details to get started. There are tons of templates and examples available to help you get going quickly, the important part is that everything is defined as code, so you can version control it and reuse it.&lt;/p&gt;

&lt;p&gt;Now let's deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Login to Azure&lt;/span&gt;
azd auth login

&lt;span class="c"&gt;# Provision resources and deploy&lt;/span&gt;
azd up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pick your preferred Azure region when prompted (if you're not sure, choose &lt;strong&gt;East US2&lt;/strong&gt;), and voilà! In a few minutes, you'll have a fully deployed MCP server running on Azure Functions.&lt;/p&gt;

&lt;p&gt;Once the deployment is finished, the CLI will show you the URL of the deployed resources, including the MCP server endpoint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F95d7ypphekrsa5v8ecn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F95d7ypphekrsa5v8ecn3.png" alt="AZD deployment output for the burger MCP example app" width="800" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example projects
&lt;/h2&gt;

&lt;p&gt;The burger MCP server is actually part of a larger example project that demonstrates building an AI agent with LangChain.js, that uses the burger MCP server to place orders. If you're interested in the next steps of building an AI agent on top of MCP, this is a great resource as it includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI agent web API using LangChain.js&lt;/li&gt;
&lt;li&gt;Web app interface built with Lit web components&lt;/li&gt;
&lt;li&gt;MCP server on Functions (the one we just saw)&lt;/li&gt;
&lt;li&gt;Burger ordering API (used by the MCP server)&lt;/li&gt;
&lt;li&gt;Live order visualization&lt;/li&gt;
&lt;li&gt;Complete Infrastructure as Code, to deploy everything with one command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if you're only interested in the MCP server part, then you might want to look at this simpler example that you can use as a starting point for your own MCP servers: &lt;a href="https://github.com/Azure-Samples/mcp-sdk-functions-hosting-node" rel="noopener noreferrer"&gt;mcp-sdk-functions-hosting-node&lt;/a&gt; is a server template for a Node.js MCP server using TypeScript and MCP SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the cost?
&lt;/h2&gt;

&lt;p&gt;Azure Functions Flex Consumption pricing is attractive for MCP servers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free grant&lt;/strong&gt;: 1 million requests and 400,000 GB-s execution time per month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After free grant&lt;/strong&gt;: Pay only for actual execution time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic scaling&lt;/strong&gt;: From zero to hundreds of instances&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The free grant is generous enough to allow running a typical MCP server with moderate usage, and all the experimentation you might need. It's easy to configure the scaling limits to control costs as needed, with an option to scale down to zero when idle. This flexibility is why Functions is my personal go-to choice for TypeScript projects on Azure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;Hosting MCP servers on Azure Functions gives you the best of both worlds: the simplicity of serverless infrastructure and the power of the official Anthropic SDK. With just &lt;strong&gt;one simple configuration step&lt;/strong&gt;, you can take your existing Node.js MCP server and deploy it to a production-ready, auto-scaling platform.&lt;/p&gt;

&lt;p&gt;The combination of MCP's standardized protocol and Azure's serverless platform means you can focus on building amazing AI experiences instead of managing infrastructure. Boom. 😎&lt;/p&gt;

&lt;p&gt;Star the repos ⭐️ if you found this helpful! Try deploying your own MCP server and share your experience in the comments. If you run into any issues or have questions, you can reach for help on the &lt;a href="https://aka.ms/foundry/discord" rel="noopener noreferrer"&gt;Azure AI community on Discord&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>ai</category>
      <category>azure</category>
    </item>
    <item>
      <title>Serverless MCP Agent with LangChain.js v1 — Burgers, Tools, and Traces 🍔</title>
      <dc:creator>Yohan Lasorsa</dc:creator>
      <pubDate>Tue, 21 Oct 2025 16:09:46 +0000</pubDate>
      <link>https://dev.to/azure/serverless-mcp-agent-with-langchainjs-v1-burgers-tools-and-traces-25oo</link>
      <guid>https://dev.to/azure/serverless-mcp-agent-with-langchainjs-v1-burgers-tools-and-traces-25oo</guid>
      <description>&lt;p&gt;AI agents that can actually do stuff (not just chat) are the fun part nowadays, but wiring them cleanly into real APIs, keeping things observable, and shipping them to the cloud can get... messy. So we built a fresh end‑to‑end sample to show how to do it right with the brand new &lt;strong&gt;LangChain.js v1&lt;/strong&gt; and &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;. In case you missed it, MCP is a recent open standard that makes it easy for LLM agents to consume tools and APIs, and LangChain.js, a great framework for building GenAI apps and agents, has first-class support for it.&lt;/p&gt;

&lt;p&gt;This new sample gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A LangChain.js v1 agent that streams its result, along reasoning + tool steps&lt;/li&gt;
&lt;li&gt;An MCP server exposing real tools (burger menu + ordering) from a business API&lt;/li&gt;
&lt;li&gt;A web interface with authentication, sessions history, and a debug panel (for developers)&lt;/li&gt;
&lt;li&gt;A production-ready multi-service architecture&lt;/li&gt;
&lt;li&gt;Serverless deployment on Azure in one command (&lt;code&gt;azd up&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flyd3ybr83tyyogakr7ou.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flyd3ybr83tyyogakr7ou.gif" alt="GIF animation of the agent in action" width="760" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, it’s a burger ordering system. Who doesn't like burgers? Grab your favorite beverage ☕, and let’s dive in for a quick tour!&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;New sample: full-stack Node.js AI agent using LangChain.js v1 + MCP tools&lt;/li&gt;
&lt;li&gt;Architecture: web app → agent API → MCP server → burger API&lt;/li&gt;
&lt;li&gt;Runs locally with a single &lt;code&gt;npm start&lt;/code&gt;, deploys with &lt;code&gt;azd up&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Uses streaming (NDJSON) with intermediate tool + LLM steps surfaced to the UI&lt;/li&gt;
&lt;li&gt;Ready to fork, extend, and plug into your own domain / tools&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What will you learn here?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What this sample is about and its high-level architecture&lt;/li&gt;
&lt;li&gt;What LangChain.js v1 brings to the table for agents&lt;/li&gt;
&lt;li&gt;How to deploy and run the sample&lt;/li&gt;
&lt;li&gt;How MCP tools can expose real-world APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reference links for everything we use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure-Samples/mcp-agent-langchainjs" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.langchain.com/oss/javascript/langchain/overview" rel="noopener noreferrer"&gt;LangChain.js docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/" rel="noopener noreferrer"&gt;Azure Developer CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@modelcontextprotocol/inspector" rel="noopener noreferrer"&gt;MCP Inspector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use case
&lt;/h2&gt;

&lt;p&gt;You want an AI assistant that can take a natural language request like “Order two spicy burgers and show me my pending orders” and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand intent (query menu, then place order)&lt;/li&gt;
&lt;li&gt;Call the right MCP tools in sequence, calling in turn the necessary APIs&lt;/li&gt;
&lt;li&gt;Stream progress (LLM tokens + tool steps)&lt;/li&gt;
&lt;li&gt;Return a clean final answer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Swap “burgers” for “inventory”, “bookings”, “support tickets”, or “IoT devices” and you’ve got a reusable pattern!&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample overview
&lt;/h2&gt;

&lt;p&gt;Before we play a bit with the sample, let's have a look at the main services implemented here:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent Web App (&lt;code&gt;agent-webapp&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Chat UI + streaming + session history&lt;/td&gt;
&lt;td&gt;Azure Static Web Apps, Lit web components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent API (&lt;code&gt;agent-api&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;LangChain.js v1 agent orchestration + auth + history&lt;/td&gt;
&lt;td&gt;Azure Functions, Node.js&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Burger MCP Server (&lt;code&gt;burger-mcp&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Exposes burger API as tools over MCP (Streamable HTTP + SSE)&lt;/td&gt;
&lt;td&gt;Azure Functions, Express, MCP SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Burger API (&lt;code&gt;burger-api&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Business logic: burgers, toppings, orders lifecycle&lt;/td&gt;
&lt;td&gt;Azure Functions, Cosmos DB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here's a simplified view of how they interact:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuzs3kcdu4b537q2yx3hl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuzs3kcdu4b537q2yx3hl.png" alt="Architecture Diagram" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are also other supporting components like databases and storage not shown here for clarity.&lt;/p&gt;

&lt;p&gt;For this quickstart we'll only interact with the &lt;strong&gt;Agent Web App&lt;/strong&gt; and the &lt;strong&gt;Burger MCP Server&lt;/strong&gt;, as they are the main stars of the show here.&lt;/p&gt;

&lt;h3&gt;
  
  
  LangChain.js v1 agent features
&lt;/h3&gt;

&lt;p&gt;The recent release of LangChain.js v1 is a huge milestone for the JavaScript AI community! It marks a significant shift from experimental tools to a production-ready framework. The new version doubles down on what’s needed to build robust AI applications, with a strong focus on &lt;strong&gt;agents&lt;/strong&gt;. This includes first-class support for streaming not just the final output, but also intermediate steps like tool calls and agent reasoning. This makes building transparent and interactive agent experiences (like the one in this sample) much more straightforward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quickstart
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/signup" rel="noopener noreferrer"&gt;GitHub account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://azure.microsoft.com/free" rel="noopener noreferrer"&gt;Azure account&lt;/a&gt; (free signup, or if you're a student, &lt;a href="https://azure.microsoft.com/free/students" rel="noopener noreferrer"&gt;get free credits here&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd?tabs=winget-windows%2Cbrew-mac%2Cscript-linux&amp;amp;pivots=os-windows" rel="noopener noreferrer"&gt;Azure Developer CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deploy and run the sample
&lt;/h3&gt;

&lt;p&gt;We'll use GitHub Codespaces for a quick zero-install setup here, but if you prefer to run it locally, check the &lt;a href="https://github.com/Azure-Samples/mcp-agent-langchainjs?tab=readme-ov-file#getting-started" rel="noopener noreferrer"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Click on the following link or open it in a new tab to launch a Codespace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codespaces.new/Azure-Samples/mcp-agent-langchainjs?hide_repo_select=true&amp;amp;ref=main&amp;amp;quickstart=true" rel="noopener noreferrer"&gt;Create Codespace&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will open a VS Code environment in your browser with the repo already cloned and all the tools installed and ready to go.&lt;/p&gt;

&lt;h4&gt;
  
  
  Provision and deploy to Azure
&lt;/h4&gt;

&lt;p&gt;Open a terminal and run these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Login to Azure&lt;/span&gt;
azd auth login

&lt;span class="c"&gt;# Provision and deploy all resources&lt;/span&gt;
azd up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts to select your Azure subscription and region. If you're unsure of which one to pick, choose &lt;code&gt;East US 2&lt;/code&gt;.&lt;br&gt;
The deployment will take about 15 minutes the first time, to create all the necessary resources (Functions, Static Web Apps, Cosmos DB, AI Models).&lt;/p&gt;

&lt;p&gt;If you're curious about what happens under the hood, you can take a look at the &lt;code&gt;main.bicep&lt;/code&gt; file in the &lt;code&gt;infra&lt;/code&gt; folder, which defines the infrastructure as code for this sample.&lt;/p&gt;
&lt;h3&gt;
  
  
  Test the MCP server
&lt;/h3&gt;

&lt;p&gt;While the deployment is running, you can run the MCP server and API locally (even in Codespaces) to see how it works. Open another terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start all services locally, including the Burger API and the MCP server, which will be available at &lt;code&gt;http://localhost:3000/mcp&lt;/code&gt;. This may take a few seconds, wait until you see this message in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🚀 All services ready 🚀
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When these services are running without Azure resources provisioned, they will use in-memory data instead of Cosmos DB so you can experiment freely with the API and MCP server, though the agent won't be functional as it requires a LLM resource.&lt;/p&gt;

&lt;h4&gt;
  
  
  MCP tools
&lt;/h4&gt;

&lt;p&gt;The MCP server exposes the following tools, which the agent can use to interact with the burger ordering system:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_burgers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get a list of all burgers in the menu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_burger_by_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get a specific burger by its ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_toppings&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get a list of all toppings in the menu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_topping_by_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get a specific topping by its ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_topping_categories&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get a list of all topping categories&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_orders&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get a list of all orders in the system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_order_by_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get a specific order by its ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;place_order&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Place a new order with burgers (requires &lt;code&gt;userId&lt;/code&gt;, optional &lt;code&gt;nickname&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;delete_order_by_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cancel an order if it has not yet been started (status must be &lt;code&gt;pending&lt;/code&gt;, requires &lt;code&gt;userId&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can test these tools using the MCP Inspector. Open another terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; @modelcontextprotocol/inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the URL printed in the terminal in your browser and connect using these settings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transport&lt;/strong&gt;: Streamable HTTP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL&lt;/strong&gt;: &lt;a href="http://localhost:3000/mcp" rel="noopener noreferrer"&gt;http://localhost:3000/mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection Type&lt;/strong&gt;: Via Proxy (should be default)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click on &lt;strong&gt;Connect&lt;/strong&gt;, then try listing the tools first, and run &lt;code&gt;get_burgers&lt;/code&gt; tool to get the menu info.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1x7jghzwa5rvdi32lfa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1x7jghzwa5rvdi32lfa.png" alt="MCP Inspector Screenshot" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the Agent Web App
&lt;/h3&gt;

&lt;p&gt;After the deployment is completed, you can run the command &lt;code&gt;npm run env&lt;/code&gt; to print the URLs of the deployed services. Open the Agent Web App URL in your browser (it should look like &lt;code&gt;https://&amp;lt;your-web-app&amp;gt;.azurestaticapps.net&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You'll first be greeted by an authentication page, you can sign in either with your GitHub or Microsoft account and then you should be able to access the chat interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3hhz6xv0g1djbendzrd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3hhz6xv0g1djbendzrd.png" alt="Agent chat interface screenshot" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From there, you can start asking any question or use one of the suggested prompts, for example try asking: &lt;code&gt;Recommend me an extra spicy burger&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As the agent processes your request, you'll see the response streaming in real-time, along with the intermediate steps and tool calls. Once the response is complete, you can also unfold the debug panel to see the full reasoning chain and the tools that were invoked:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrk3nr22ypq4jm0qfaum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrk3nr22ypq4jm0qfaum.png" alt="Intermediate steps debug panel screenshot" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Our agent service also sends detailed tracing data using OpenTelemetry. You can explore these either in Azure Monitor for the deployed service, or locally using an OpenTelemetry collector. We'll cover this in more detail in a future post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Wrap it up
&lt;/h2&gt;

&lt;p&gt;Congratulations, you just finished spinning up a full-stack serverless AI agent using LangChain.js v1, MCP tools, and Azure’s serverless platform. Now it's your turn to dive in the code and extend it for your use cases! 😎 And don't forget to &lt;code&gt;azd down&lt;/code&gt; once you're done to avoid any unwanted costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going further
&lt;/h2&gt;

&lt;p&gt;This was just a quick introduction to this sample, and you can expect more in-depth posts and tutorials soon.&lt;/p&gt;

&lt;p&gt;Since we're in the era of AI agents, we've also made sure that this sample can be explored and extended easily with code agents like GitHub Copilot.&lt;br&gt;
We even built a custom chat mode to help you discover and understand the codebase faster! Check out the &lt;a href=".https://github.com/Azure-Samples/mcp-agent-langchainjs/blob/main/docs/copilot.md"&gt;Copilot setup guide&lt;/a&gt; in the repo to get started.&lt;/p&gt;

&lt;p&gt;If you like this sample, don't forget to star the repo ⭐️! You can also join us in the &lt;a href="https://aka.ms/foundry/discord" rel="noopener noreferrer"&gt;Azure AI community Discord&lt;/a&gt; to chat and ask any questions.&lt;/p&gt;

&lt;p&gt;Happy coding and burger ordering! 🍔&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>langchain</category>
      <category>azure</category>
    </item>
    <item>
      <title>What’s in a Name? Fuzzy Matching for Real-World Data</title>
      <dc:creator>Renee Noble</dc:creator>
      <pubDate>Fri, 17 Oct 2025 00:47:36 +0000</pubDate>
      <link>https://dev.to/azure/whats-in-a-name-fuzzy-matching-for-real-world-data-5b5o</link>
      <guid>https://dev.to/azure/whats-in-a-name-fuzzy-matching-for-real-world-data-5b5o</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=-AQBJTt1qR4" rel="noopener noreferrer"&gt;🎥&amp;nbsp;Watch the full PyCon AU 2025 talk here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/-AQBJTt1qR4"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;When you work with human-entered data (registrations, surveys, customer forms, you name it!) you soon discover that &lt;strong&gt;people are very creative typists&lt;/strong&gt;. Names, schools, companies, and addresses come in with abbreviations, nicknames, missing words, and typos galore.&lt;/p&gt;

&lt;p&gt;That mess makes it hard to answer even simple questions like: &lt;em&gt;“Do these two records refer to the same person?”&lt;/em&gt; or &lt;em&gt;“How many participants came from this organisation?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At PyCon AU 2025, I explored how different fuzzy matching techniques, from traditional algorithms to generative AI, can help make sense of that chaos.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fuzzy Matching Challenge
&lt;/h2&gt;

&lt;p&gt;String comparison looks straightforward until you meet real-world data. “PLC Sydney” might really be “Presbyterian Ladies’ College Sydney.” “Certain Collage” is obviously a typo for “Certain College” (hopefully). And nicknames like Liz, Lizzy, and Elizabeth might all belong to the same person.&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;fuzzy matching&lt;/strong&gt; comes in, using a variety of techniques we can rank how similar different non-identical words are to try and find the most likely match. But the question is, what fuzzy matching algorithms are best suited for matching what types of data? And can generative AI play a part in this matching game?&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparing Algorithmic Approaches
&lt;/h3&gt;

&lt;p&gt;I put six Python libraries to the test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TextDistance&lt;/strong&gt; and &lt;strong&gt;Python-Levenshtein&lt;/strong&gt; – classic edit-distance approaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FuzzyWuzzy&lt;/strong&gt; and &lt;strong&gt;RapidFuzz&lt;/strong&gt; – hybrids that combine multiple distance metrics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nicknames&lt;/strong&gt; and &lt;strong&gt;PyNameMatcher&lt;/strong&gt; – specialised tools for given-name variations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test them, I generated around 100 fake student names with nicknames, misspellings, and swapped orderings. Then I measured how accurately each library matched them to their correct counterparts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RapidFuzz&lt;/strong&gt; came out ahead, matching almost every record correctly, and doing it fast! The edit-distance methods struggled most with multicultural names where order or character sets varied, and the nickname libraries were strong but less consistent overall.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Generative AI Shines
&lt;/h3&gt;

&lt;p&gt;Algorithmic fuzzy matching is fast and accurate, but it only looks at characters, not meaning. That’s where I turned to &lt;strong&gt;Azure OpenAI Service&lt;/strong&gt; for a different kind of help.&lt;/p&gt;

&lt;p&gt;By feeding in real school-name data, I found that straight out of the box &lt;strong&gt;GPT-5 was exceptionally good at recognising and correcting school names&lt;/strong&gt;, especially when they were abbreviated, misspelled, or included local school nicknames.&lt;/p&gt;

&lt;p&gt;For example, it could confidently map:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“PLC Syd” → “Presbyterian Ladies’ College Sydney”&lt;/li&gt;
&lt;li&gt;“Cerdon Collage” → “Cerdon College”&lt;/li&gt;
&lt;li&gt;“St Cats” → “St Catherine’s School, Waverley”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That level of contextual correction is almost impossible to achieve with pure algorithmic matching unless you maintain a custom dictionary of every possible variation. And who has time for that!&lt;/p&gt;

&lt;p&gt;The trade-off, of course, is performance. Generative models are slower and costlier to run at scale. But when used selectively, just for ambiguous or hard-to-match cases, they can dramatically improve accuracy. And of course this is something this specifically works well for names, like schools, that are well documented on the internet – something that doesn’t apply to the names of individual school students.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can we have the best of both worlds?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;hybrid AI + Algorithmic matching!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In practice, the best results came from a &lt;strong&gt;hybrid approach&lt;/strong&gt;, using traditional fuzzy-matching algorithms for most cases, and bringing in &lt;strong&gt;Azure OpenAI&lt;/strong&gt; only when the names got tricky. For example, RapidFuzz could quickly match “Lizzy Wong” to “Elizabeth Wong,” while the generative model was better at reasoning through ambiguous inputs like “Sally-Anne W.” or reversed multicultural name orders. By combining both, I could match almost every student record accurately, keeping the speed of algorithmic methods while adding the contextual understanding of generative AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;🎥 You can watch my full PyCon AU 2025 talk here:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=-AQBJTt1qR4" rel="noopener noreferrer"&gt;What’s in a Name: Fuzzy Matching Techniques for Proper Nouns&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📁 If you’d like to explore this further you can check out my &lt;strong&gt;&lt;a href="https://aka.ms/rn-whats-in-a-name" rel="noopener noreferrer"&gt;fuzzy matching repo&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Take a look at the libraries and tool I mentioned above, they’re easy to install and experiment with in Python. If you’re already using Azure OpenAI, it’s worth testing how a small retrieval-augmented setup might complement your existing matching logic.&lt;/p&gt;
&lt;h2&gt;
  
  
  Chat to us!
&lt;/h2&gt;

&lt;p&gt;💬 To chat more about AI solutions you can join the AI Foundry Discord, where advocates like me are chatting about the latest tools all the time. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://aka.ms/AI-Discord-rn-FM-blog" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Join the Azure AI Foundry Discord here&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Good luck on your fuzzy matching adventures!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>azure</category>
      <category>ai</category>
      <category>datascience</category>
    </item>
    <item>
      <title>A Better Way to Tune the JVM in Dockerfiles and Kubernetes Manifests</title>
      <dc:creator>Bruno Borges</dc:creator>
      <pubDate>Fri, 12 Sep 2025 03:36:26 +0000</pubDate>
      <link>https://dev.to/azure/a-better-way-to-tune-the-jvm-in-dockerfiles-and-kubernetes-manifests-329c</link>
      <guid>https://dev.to/azure/a-better-way-to-tune-the-jvm-in-dockerfiles-and-kubernetes-manifests-329c</guid>
      <description>&lt;p&gt;When tuning the JVM inside containers, I often see Dockerfiles and Kubernetes manifests with long, hard-to-read java commands packed with -Xmx, -XX:+UseG1GC, and other flags. Every time you want to tweak memory or GC settings, you have to edit those commands and rebuild or redeploy.&lt;/p&gt;




&lt;h3&gt;
  
  
  Free webinar Java on Kubernetes Performance Engineering
&lt;/h3&gt;

&lt;p&gt;Running Java on Kubernetes? It's harder - and more critical - than you think. Join us September 25th, 2025, for a live webinar with Akamas &amp;amp; Microsoft on tuning Java apps at scale. JVM tips, GC tuning, JDK 25, Project Leyden &amp;amp; more.&lt;/p&gt;

&lt;p&gt;Register at &lt;a href="https://akamas.io/events/java-on-kubernetes-lessons-in-performance-engineering-with-akamas-and-microsoft/" rel="noopener noreferrer"&gt;https://akamas.io/events/java-on-kubernetes-lessons-in-performance-engineering-with-akamas-and-microsoft/&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  What about JAVA_OPTS?
&lt;/h1&gt;

&lt;p&gt;This flag is not read by the JVM itself. It only works if the launch script explicitly uses it and expands its content into the call to the java launcher. It behaves exactly the same as Apache Tomcat's CATALINA_OPTS, which is read by catalina.sh.&lt;/p&gt;

&lt;p&gt;There’s a much cleaner way to do this... and it’s built into the JDK. It’s the most modern, well-scoped solution, playing well with deployment orchestration solutions like Kubernetes.&lt;/p&gt;

&lt;h1&gt;
  
  
  🚀 Enter JDK_JAVA_OPTIONS
&lt;/h1&gt;

&lt;p&gt;JDK_JAVA_OPTIONS is an environment variable that the JVM reads automatically. Whatever you put there gets appended to the command line of every JDK tool (java, javac, jshell, etc.) This means you can move all your tuning flags out of your launcher command, keeping your Dockerfiles and manifests clean and maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaned-up Dockerfile
&lt;/h2&gt;

&lt;p&gt;Before (messy):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["java", "-Xmx512m", "-XX:+UseG1GC", "-jar", "app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After (clean):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; JDK_JAVA_OPTIONS="-Xmx512m -XX:+UseG1GC"&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["java", "-jar", "app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if you need to change heap size or GC settings, you just update the environment variable. No need to touch the command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes Example
&lt;/h2&gt;

&lt;p&gt;If your container is likely to end up on Kubernetes, don't even tune the JVM in the Dockerfile. Consider leaving this as an external configuration, coming from the Kubernetes manifest. &lt;/p&gt;

&lt;p&gt;This is because the container image doesn't know what memory limits will be applied during runtime. And even if you set a MaxRAMPercentage for the heap, the amount you set may not be ideal if the container ends up with too much memory, potentially wasting memory from the delta not used, for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp:latest&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JDK_JAVA_OPTIONS&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-Xmx512m&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-XX:+UseG1GC"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your deployment YAML stays clean and your operations team can tune JVM behavior at deploy time without changing the image.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why JDK_JAVA_OPTIONS Is Better
&lt;/h1&gt;

&lt;p&gt;✅ Cleaner Manifests – fewer arguments to maintain&lt;br&gt;
🔄 Configurable at Runtime – no rebuild required&lt;br&gt;
🛠 Debug-Friendly – JVM prints the options it picked up&lt;br&gt;
🐳 Perfect for Containers – works across Docker, Kubernetes, ECS, etc.&lt;br&gt;
🎯 Applies to All JDK Tools – not just java, but also javac, jshell, etc.&lt;/p&gt;

&lt;p&gt;If you’re running Java apps in Docker or Kubernetes, stop hardcoding JVM flags into your command line. Use JDK_JAVA_OPTIONS instead. It makes your images cleaner, your manifests easier to read, and your JVM tuning more flexible.&lt;/p&gt;
&lt;h1&gt;
  
  
  Precedence, Order of Priority, and Scope
&lt;/h1&gt;

&lt;p&gt;The HotSpot JVM supports, in practice, three environment variables. And for many historical reasons we ended up in this situation. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkl535gcb2dgp018an66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgkl535gcb2dgp018an66.png" alt=" " width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But in what order are they processed, and where? The rule of thumb is below. Except that in JDK 8, the variable JDK_JAVA_OPTIONS is not supported.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
_JAVA_OPTIONS &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; JDK_JAVA_OPTIONS &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; JAVA_TOOL_OPTIONS

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides the order they are processed, there is also where they are processed and how this impacts what parameters are effective. &lt;/p&gt;

&lt;p&gt;According to the bug &lt;a href="https://bugs.openjdk.org/browse/JDK-8170832" rel="noopener noreferrer"&gt;JDK-8170832&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;_JAVA_OPTIONS&lt;/code&gt; and &lt;code&gt;JAVA_TOOL_OPTIONS&lt;/code&gt; environment variable are interpreted by the VM, not the launcher [java], hence no @-files or launcher-only options. The former is undocumented and unsupported but widely used; the latter is documented and supported.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can see for yourself the behaviour of these environment variables with this little project I built (with GitHub Copilot): &lt;a href="https://github.com/brunoborges/jdk-env-vars" rel="noopener noreferrer"&gt;github.com/brunoborges/jdk-env-vars&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Thoughts?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;What JVM tuning tricks are you using in containers today?&lt;/li&gt;
&lt;li&gt;Have you tried JDK_JAVA_OPTIONS yet? &lt;/li&gt;
&lt;li&gt;Did you know about it? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comment below.&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;p&gt;Resources&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/troubleshoot/environment-variables-and-system-properties.html#GUID-A91E7E21-2E91-48C4-89A4-836A7C0EE93B" rel="noopener noreferrer"&gt;OpenJDK 21: JAVA_TOOL_OPTIONS documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html#using-the-jdk_java_options-launcher-environment-variable" rel="noopener noreferrer"&gt;OpenJDK 21: JDK_JAVA_OPTIONS documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bugs.openjdk.org/browse/JDK-8170832" rel="noopener noreferrer"&gt;JDK-8170832&lt;/a&gt;: Add a new launcher environment variables&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>java</category>
      <category>docker</category>
      <category>performance</category>
    </item>
    <item>
      <title>Model Mondays S2E04 - AI Developer Experiences</title>
      <dc:creator>Nitya Narasimhan, Ph.D</dc:creator>
      <pubDate>Fri, 11 Jul 2025 03:25:13 +0000</pubDate>
      <link>https://dev.to/azure/model-mondays-s2e04-ai-developer-experiences-41mf</link>
      <guid>https://dev.to/azure/model-mondays-s2e04-ai-developer-experiences-41mf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifnd5j9v3lbqzkctlvx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fifnd5j9v3lbqzkctlvx1.png" alt="Model Mondays Banner"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;🧪 | Some parts of this blog were generated with AI assistance, and reviewed manually before publishing. To learn more about the why and the how, please refer to &lt;a href="https://github.com/microsoft/model-mondays/blob/main/docs/README.ai.md" rel="noopener noreferrer"&gt;this document&lt;/a&gt; in our website.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Model Mondays is a weekly series that helps you build your AI Model IQ with 5-min news recaps, 15-min tech spotlights and 30-min AMA sessions with subject matter experts. Join us!&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://aka.ms/model-mondays/rsvp" rel="noopener noreferrer"&gt;Register&lt;/a&gt;&lt;/strong&gt; for upcoming livestreams (Mon @1:30pm ET) &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://aka.ms/model-mondays/forum" rel="noopener noreferrer"&gt;Register&lt;/a&gt;&lt;/strong&gt; for upcoming AMAs (Fri @1:30pm ET) &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://aka.ms/model-mondays/newsletter" rel="noopener noreferrer"&gt;Subscribe&lt;/a&gt;&lt;/strong&gt; to the weekly newsletter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://aka.ms/model-mondays" rel="noopener noreferrer"&gt;Explore&lt;/a&gt;&lt;/strong&gt; Season 1 &amp;amp; Season 2 episodes on our repo!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;⁉️ | Have questions on the &lt;strong&gt;AI TOOLKIT EXTENSION FOR VS CODE&lt;/strong&gt; &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://aka.ms/aitoolkit" rel="noopener noreferrer"&gt;Download the AI Toolkit&lt;/a&gt; and try it!&lt;/li&gt;
&lt;li&gt;Join the AMA on Friday, Jul 11 on the &lt;a href="https://discord.gg/azureaifoundry?event=1382861578201858058" rel="noopener noreferrer"&gt;Azure AI Foundry Discord&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Visit recaps &amp;amp; resources &lt;a href="https://github.com/orgs/azure-ai-foundry/discussions/90" rel="noopener noreferrer"&gt;on the Forum&lt;/a&gt; to keep learning.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Spotlight On: AI Developer Experiences
&lt;/h2&gt;

&lt;p&gt;In this episode we got to see a hands-on demo from Leo Yao, a Product Manager for the AI Toolkit, who took us through the various tools and capabilities that this extension brings to Visual Studio Code, to streamline our AI development journey. If you missed the livestream, you can catch up on the recap here:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/tNiFbf3XP6k"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  What You'll Learn
&lt;/h2&gt;

&lt;p&gt;So why should you watch this episode? Simple! If you wanted to see how you could streamline your AI Developer Experience without ever leaving Visual Studio Code, then the AI Toolkit is the extension you want to explore. In the space of just 15 minutes, I got to see Leo complete the following tasks, all within the IDE!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Discover &amp;amp; use GitHub Models with a built-in playground feature.&lt;/li&gt;
&lt;li&gt;Deploy models (GPT-4) to Azure AI Foundry directly from VS Code.&lt;/li&gt;
&lt;li&gt;Build AI agents with Agent Builder (to createa a math tutor)&lt;/li&gt;
&lt;li&gt;Configure agents with prompts &amp;amp; tools (for an escape room helper)&lt;/li&gt;
&lt;li&gt;Integrate MCP servers to extend functionality (custom Python code)&lt;/li&gt;
&lt;li&gt;Deploy agents locally, and to Azure AI Foundry (for flexibility)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that was just in 15-minutes. I can only imagine what other features and tools we are yet to discover if we try this out ourselves. Want to get links to the extension, documentation and key resources to skill up? You'll find the links in the deck below:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="speakerdeck-iframe ltag_speakerdeck" src="https://speakerdeck.com/player/f33b97a07e65480797877c5168edbe17"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Get Started
&lt;/h2&gt;

&lt;p&gt;Looking back, my first introduction to the AI Toolkit was in Model Mondays Season 1, from Microsoft Product PM Rong Lu. She gave us a comprehensive overview of the various features including support for data generation and evaluation. I recommend taking 15 minutes to review her demo in this episode:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/MgIfvEEZN7o"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Once you're familiar with the basics, I recommend you check out these three links to dive deeper into the process of building agent-based solutions on Azure AI Foundry with AI Toolkit and Visual Studio Code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. &lt;a href="https://learn.microsoft.com/en-us/windows/ai/toolkit/toolkit-getting-started" rel="noopener noreferrer"&gt;AI Toolkit for Visual Studio Code - Getting Started Guide&lt;/a&gt;&lt;/strong&gt; - This is my recommended starting point. The tutorial covers installation, then walks you through the steps for downloading models from the catalog, then testing and integrating models into your application. You can then keep going with more tutorials to learn other features like fine-tuning support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;a href="https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/develop/get-started-projects-vs-code" rel="noopener noreferrer"&gt;Azure AI Foundry Extension for Visual Studio Code&lt;/a&gt;&lt;/strong&gt; - This extension now lets you work with the Azure AI Foundry platform capabilities directly from VS Code. This screenshot from the docs gives you a sense of the tasks you can achieve from your IDE - including project setup and model deployments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd60mt0hydl8pa93htabd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd60mt0hydl8pa93htabd.png" alt="Menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. &lt;a href="https://code.visualstudio.com/docs/intelligentapps/agentbuilder" rel="noopener noreferrer"&gt;Agent Builder in AI Toolkit&lt;/a&gt;&lt;/strong&gt; -The Agent Builder in AI Toolkit simplifies and streamlines your workflow for building agents - from prompt engineering to tool integration (including with MCP servers). Get an intuitive sense for going from model to prompt to agentic workflows with tooling help.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx7wyimzlfce8p9skhos.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvx7wyimzlfce8p9skhos.gif" alt="Agent Builder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⁉️ | Have questions? Don't forget to join us for the AMA on Friday (Jul 11) on the &lt;a href="https://discord.gg/azureaifoundry?event=1382861578201858058" rel="noopener noreferrer"&gt;Azure AI Foundry Discord&lt;/a&gt;. Post your questions early &lt;a href="https://github.com/orgs/azure-ai-foundry/discussions/90" rel="noopener noreferrer"&gt;on the Forum&lt;/a&gt; or revisit it later to get the transcript and resources from the discussion!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Read The Blog
&lt;/h2&gt;

&lt;p&gt;Want an easy way to catch up on all the news? Check out complete blog series written by our resident student blogger &lt;a href="https://aka.ms/model-mondays/blog" rel="noopener noreferrer"&gt;here on Tech Community&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;You can also follow her posts, right here on dev.to:&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__1940688"&gt;
    &lt;a href="/sharda_kaur" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1940688%2F8406e1c5-5e99-4711-9ca5-f3bae3dde4fa.jpg" alt="sharda_kaur image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/sharda_kaur"&gt;Sharda Kaur&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/sharda_kaur"&gt;Gold @Microsoft MLSA  || Technical Content Writer || Open Source Contributor || Web Developer || CUIET MCA'26&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  Build Your Model IQ!
&lt;/h2&gt;

&lt;p&gt;Model Mondays Season 2 is currently scheduled to go from June to September, covering the 12 key topics shown below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;👉🏽👉🏽 &lt;a href="https://aka.ms/model-mondays/rsvp" rel="noopener noreferrer"&gt;Register for Upcoming Livestreams&lt;/a&gt; to get reminders&lt;/li&gt;
&lt;li&gt;👉🏽👉🏽 &lt;a href="https://github.com/orgs/azure-ai-foundry/discussions/90" rel="noopener noreferrer"&gt;Register for Upcoming AMAs&lt;/a&gt; to get reminders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetcnia5e90rhttuw3n13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fetcnia5e90rhttuw3n13.png" alt="Season 2"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>azureaifoundry</category>
      <category>ama</category>
      <category>modelmondays</category>
    </item>
  </channel>
</rss>
