diff --git a/samples/AzureB2CClientCredentials/AzureB2CClientCredentials.csproj b/samples/AzureB2CClientCredentials/AzureB2CClientCredentials.csproj
new file mode 100644
index 000000000..b4c35c779
--- /dev/null
+++ b/samples/AzureB2CClientCredentials/AzureB2CClientCredentials.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net9.0
+ enable
+ enable
+ 783daef3-9c45-408d-a1d3-7caf44724f39
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/AzureB2CClientCredentials/Program.cs b/samples/AzureB2CClientCredentials/Program.cs
new file mode 100644
index 000000000..5ac2e70a5
--- /dev/null
+++ b/samples/AzureB2CClientCredentials/Program.cs
@@ -0,0 +1,113 @@
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.IdentityModel.Tokens;
+using ModelContextProtocol.AspNetCore.Authentication;
+using AzureB2CClientCredentials.Tools;
+using System.Net.Http.Headers;
+using System.Security.Claims;
+
+var builder = WebApplication.CreateBuilder(args);
+
+var serverUrl = "http://localhost:7071/";
+
+// Azure B2C Configuration for Client Credentials Flow
+// IMPORTANT: Azure B2C requires a policy even for client credentials flow
+// This is different from Azure AD which supports policy-free client credentials
+var azureB2CInstance = builder.Configuration["AzureB2C:Instance"] ?? "https://yourtenant.b2clogin.com";
+var azureB2CTenant = builder.Configuration["AzureB2C:Tenant"] ?? "yourtenant.onmicrosoft.com";
+var azureB2CPolicy = builder.Configuration["AzureB2C:Policy"] ?? "B2C_1_signupsignin";
+var azureB2CClientId = builder.Configuration["AzureB2C:ClientId"] ?? "your-client-id";
+// Azure B2C requires the policy in the authority URL even for client credentials flow
+var azureB2CAuthority = $"{azureB2CInstance}/{azureB2CTenant}/{azureB2CPolicy}/v2.0";
+var azureB2CMetadataAddress = $"{azureB2CAuthority}/.well-known/openid-configuration";
+
+builder.Services.AddAuthentication(options =>
+{
+ options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme;
+ options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
+})
+.AddJwtBearer(options =>
+{
+ // Configure to validate tokens from Azure B2C
+ options.Authority = azureB2CAuthority;
+ options.MetadataAddress = azureB2CMetadataAddress;
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateIssuer = true,
+ ValidateAudience = true,
+ ValidateLifetime = true,
+ ValidateIssuerSigningKey = true,
+ ValidAudience = azureB2CClientId,
+ ValidIssuer = azureB2CAuthority,
+ NameClaimType = ClaimTypes.Name,
+ RoleClaimType = ClaimTypes.Role,
+ // Azure B2C uses 'aud' claim for audience validation
+ ValidAudiences = new[] { azureB2CClientId },
+ // Allow for clock skew
+ ClockSkew = TimeSpan.FromMinutes(5)
+ };
+
+ options.Events = new JwtBearerEvents
+ {
+ OnTokenValidated = context =>
+ {
+ // For client credentials flow, we don't have user claims like email
+ // Instead, we have application/service claims
+ var clientId = context.Principal?.FindFirstValue("aud") ?? "unknown";
+ var appId = context.Principal?.FindFirstValue("appid") ??
+ context.Principal?.FindFirstValue("azp") ?? "unknown";
+ var objectId = context.Principal?.FindFirstValue("oid") ??
+ context.Principal?.FindFirstValue("sub") ?? "unknown";
+ Console.WriteLine($"Token validated for client: {clientId} - App ID: {appId} - Object ID: {objectId}");
+ return Task.CompletedTask;
+ },
+ OnAuthenticationFailed = context =>
+ {
+ Console.WriteLine($"Authentication failed: {context.Exception.Message}");
+ return Task.CompletedTask;
+ },
+ OnChallenge = context =>
+ {
+ Console.WriteLine($"Challenging client to authenticate with Azure B2C");
+ return Task.CompletedTask;
+ }
+ };
+})
+.AddMcp(options =>
+{
+ options.ResourceMetadata = new()
+ {
+ Resource = new Uri(serverUrl),
+ ResourceDocumentation = new Uri("https://docs.example.com/api/weather"),
+ AuthorizationServers = { new Uri(azureB2CAuthority) },
+ ScopesSupported = ["mcp:tools"],
+ };
+});
+
+builder.Services.AddAuthorization();
+
+builder.Services.AddHttpContextAccessor();
+builder.Services.AddMcpServer()
+ .WithTools()
+ .WithHttpTransport();
+
+// Configure HttpClientFactory for weather.gov API
+builder.Services.AddHttpClient("WeatherApi", client =>
+{
+ client.BaseAddress = new Uri("https://api.weather.gov");
+ client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("weather-tool", "1.0"));
+});
+
+var app = builder.Build();
+
+app.UseAuthentication();
+app.UseAuthorization();
+
+// Use the default MCP policy name that we've configured
+app.MapMcp().RequireAuthorization();
+
+Console.WriteLine($"Starting Azure B2C Client Credentials MCP server with authorization at {serverUrl}");
+Console.WriteLine($"Using Azure B2C authority: {azureB2CAuthority}");
+Console.WriteLine($"Protected Resource Metadata URL: {serverUrl}.well-known/oauth-protected-resource");
+Console.WriteLine("Press Ctrl+C to stop the server");
+
+app.Run(serverUrl);
diff --git a/samples/AzureB2CClientCredentials/README.md b/samples/AzureB2CClientCredentials/README.md
new file mode 100644
index 000000000..9fe120ae4
--- /dev/null
+++ b/samples/AzureB2CClientCredentials/README.md
@@ -0,0 +1,303 @@
+# Azure B2C Client Credentials MCP Server
+
+This sample demonstrates how to create an MCP (Model Context Protocol) server that requires OAuth 2.0 Client Credentials authentication using Azure B2C to protect its tools and resources.
+
+> **⚠️ Important Note**: Azure B2C requires a policy/user flow even for client credentials flow, which is different from Azure AD. This is a key architectural difference between Azure B2C (consumer identity) and Azure AD (enterprise identity).
+
+## Overview
+
+The Azure B2C Client Credentials MCP Server shows how to:
+- Create an MCP server with Azure B2C OAuth 2.0 protection
+- Configure JWT bearer token authentication with Azure B2C
+- Implement protected MCP tools and resources
+- Integrate with ASP.NET Core authentication and authorization
+- Provide OAuth resource metadata for client discovery
+
+## Prerequisites
+
+- .NET 9.0 or later
+- Azure B2C tenant
+- VSCode with REST Client extension (for testing)
+
+## Azure B2C Setup
+
+### 1. Create Azure B2C Tenant
+
+1. Navigate to the Azure portal
+2. Create a new Azure AD B2C tenant
+3. Note your tenant name (e.g., `yourtenant.onmicrosoft.com`)
+
+### 2. Register Application
+
+1. In your B2C tenant, go to **App registrations**
+2. Click **New registration**
+3. Configure:
+ - **Name**: MCP Server API
+ - **Supported account types**: Accounts in any identity provider or organizational directory
+ - **Redirect URI**: Leave blank (not needed for client credentials flow)
+4. After creation, note the **Application (client) ID**
+
+### 3. Create User Flow (Required for Azure B2C)
+
+**IMPORTANT**: Unlike Azure AD, Azure B2C requires a policy/user flow even for client credentials flow. This is a key difference between Azure B2C and Azure AD.
+
+**For Azure B2C Client Credentials Flow:**
+1. Go to **User flows** in your B2C tenant
+2. Click **New user flow**
+3. Select **Sign up and sign in**
+4. Choose **Recommended** version
+5. Name it `B2C_1_signupsignin` (or your preferred name)
+6. Configure the user flow (even though it won't be used for user interaction)
+
+**Note**: While the user flow won't be used for actual user sign-in (since this is machine-to-machine authentication), Azure B2C's architecture requires the policy context for token issuance. This is different from Azure AD which supports policy-free client credentials flow.
+
+### 4. Generate Client Secret
+
+1. Go to **Certificates & secrets** in your app registration
+2. Click **New client secret**
+3. Add a description and set expiration
+4. Copy the secret value (you won't be able to see it again)
+
+### 5. Configure API Permissions (Optional)
+
+For client credentials flow, you may want to:
+1. Go to **API permissions** in your app registration
+2. Add any required permissions for your application
+3. Grant admin consent if needed
+
+## Configuration
+
+Update the configuration in `appsettings.Development.json`:
+
+```json
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "Microsoft.AspNetCore": "Information",
+ "Microsoft.AspNetCore.Authentication": "Debug"
+ }
+ },
+ "AzureB2C": {
+ "Instance": "https://yourtenant.b2clogin.com",
+ "Tenant": "yourtenant.onmicrosoft.com",
+ "Policy": "B2C_1A_SIGNUP_SIGNIN",
+ "ClientId": "your-actual-client-id"
+ }
+}
+```
+
+**Important Notes:**
+- Replace `yourtenant` with your actual B2C tenant name
+- Replace `your-actual-client-id` with your application's client ID
+- **Policy is Required**: Azure B2C requires the policy even for client credentials flow (unlike Azure AD)
+- The `Policy` should match the user flow you created (e.g., `B2C_1_signupsignin`) or custom policy (e.g., `B2C_1A_SIGNUP_SIGNIN`)
+- Client secrets are not stored in configuration files for security reasons - they should be provided via environment variables or Azure Key Vault in production
+
+## Running the Server
+
+1. Update the Azure B2C configuration in `appsettings.Development.json`
+2. Run the server:
+ ```bash
+ dotnet run
+ ```
+3. The server will start at `http://localhost:7071/`
+
+## What the Server Provides
+
+### Protected Resources
+
+- **MCP Endpoint**: `http://localhost:7071/` (requires authentication)
+- **OAuth Resource Metadata**: `http://localhost:7071/.well-known/oauth-protected-resource`
+
+### Available Tools
+
+The server provides weather-related tools that require authentication:
+
+1. **get_alerts**: Get weather alerts for a US state
+ - Parameter: `state` (string) - 2-letter US state abbreviation
+ - Example: `get_alerts` with `state: "WA"`
+
+2. **get_forecast**: Get weather forecast for a location
+ - Parameters:
+ - `latitude` (number) - Latitude coordinate
+ - `longitude` (number) - Longitude coordinate
+ - Example: `get_forecast` with `latitude: 47.6062, longitude: -122.3321`
+
+> **Note**: Tool names follow the MCP convention of snake_case. The C# method names `GetAlerts` and `GetForecast` are automatically converted to `get_alerts` and `get_forecast` respectively.
+
+## Testing the Server
+
+### Using REST Client Extension
+
+1. Install the REST Client extension in VSCode
+2. Use the included `test-azure-b2c.http` file to test the API:
+
+```http
+### Get Azure B2C Token
+POST https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/oauth2/v2.0/token
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=client_credentials
+&client_id=your-client-id
+&client_secret=your-client-secret
+&scope=https://yourtenant.onmicrosoft.com/your-client-id/.default
+
+### Test MCP Server Metadata (replace {{token}} with actual token from above)
+GET http://localhost:7071/.well-known/oauth-protected-resource
+Authorization: Bearer {{token}}
+
+### Test MCP Tools List
+POST http://localhost:7071/
+Authorization: Bearer {{token}}
+Content-Type: application/json
+
+{
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "tools/list",
+ "params": {}
+}
+
+### Test Weather Forecast Tool
+POST http://localhost:7071/
+Authorization: Bearer {{token}}
+Content-Type: application/json
+
+{
+ "jsonrpc": "2.0",
+ "id": 2,
+ "method": "tools/call",
+ "params": {
+ "name": "get_forecast",
+ "arguments": {
+ "latitude": 47.6062,
+ "longitude": -122.3321
+ }
+ }
+}
+```
+
+**Important Notes:**
+- Replace `yourtenant` with your actual B2C tenant name
+- Replace `your-client-id` with your application's client ID
+- Replace `your-client-secret` with your application's client secret
+- The scope format is `https://yourtenant.onmicrosoft.com/your-client-id/.default`
+- Copy the `access_token` from the first request and use it in subsequent requests
+
+## Authentication Flow
+
+1. **Client Credentials Grant**: Client (application) requests token from Azure B2C using client credentials (client ID and client secret)
+2. **Token Request**: POST to `https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/oauth2/v2.0/token`
+3. **Token Response**: Azure B2C returns JWT access token (note: policy is required in URL even for client credentials)
+4. **API Call**: Client includes token in Authorization header: `Bearer `
+5. **Token Validation**: MCP Server validates token against Azure B2C's public keys
+6. **Access Granted**: If valid, MCP tools are accessible
+
+**Key Points:**
+- **Policy Required**: Azure B2C requires a policy in the URL even for client credentials flow (unlike Azure AD)
+- No user interaction required (server-to-server authentication)
+- Client must be registered in Azure B2C
+- Client secret must be kept secure
+- Tokens have expiration times and should be refreshed as needed
+
+## Architecture
+
+The server uses:
+- **ASP.NET Core** for hosting and HTTP handling
+- **JWT Bearer Authentication** for Azure B2C token validation
+- **MCP Authentication Extensions** for OAuth resource metadata
+- **HttpClient** for calling the weather.gov API
+- **Authorization** to protect MCP endpoints
+
+## Configuration Details
+
+- **Server URL**: `http://localhost:7071`
+- **Azure B2C Authority**: `https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/v2.0`
+- **OAuth Metadata**: `https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/v2.0/.well-known/openid-configuration`
+- **Token Endpoint**: `https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1A_SIGNUP_SIGNIN/oauth2/v2.0/token`
+- **Token Validation**: Audience (ClientId) and issuer validation against Azure B2C
+- **CORS**: Enabled for all origins (configure appropriately for production)
+- **Scope Format**: `https://yourtenant.onmicrosoft.com/your-client-id/.default`
+
+**Azure B2C vs Azure AD Differences:**
+- **Azure B2C**: Requires policy in URL even for client credentials flow
+- **Azure AD**: Supports policy-free client credentials flow
+- **Azure B2C**: Designed for consumer identity scenarios
+- **Azure AD**: Designed for enterprise/application scenarios
+
+## Security Considerations
+
+- Use HTTPS in production
+- Implement proper CORS policies
+- Use Azure Key Vault for secrets
+- Enable logging and monitoring
+- Implement rate limiting
+- Use least privilege access
+
+## Troubleshooting
+
+### Common Issues
+
+1. **Token validation fails**:
+ - Check that the Authority URL is correct and matches your B2C tenant
+ - Verify the metadata endpoint is accessible (no policy needed for client credentials)
+ - Ensure the tenant domain is correct
+
+2. **Audience validation fails**:
+ - Ensure ClientId in configuration matches the token audience
+ - Check that the client ID is correct in both the token request and server configuration
+
+3. **Issuer validation fails**:
+ - Verify the Azure B2C tenant configuration
+ - Check that the issuer URL format matches the expected pattern (without policy)
+
+4. **Authentication fails**:
+ - Verify client secret is correct and not expired
+ - Check that the scope format is correct: `https://yourtenant.onmicrosoft.com/your-client-id/.default`
+ - Ensure the token endpoint URL is correct (without policy path)
+
+5. **CORS issues**:
+ - Check browser developer tools for CORS-related errors
+ - Verify CORS policy configuration in the server
+
+6. **PowerShell Unicode errors**:
+ - Use the provided test script which handles Unicode properly
+ - Consider using UTF-8 encoding for HTTP files
+
+### Debug Logging
+
+Enable debug logging in `appsettings.Development.json`:
+
+```json
+{
+ "Logging": {
+ "LogLevel": {
+ "Microsoft.AspNetCore.Authentication": "Debug"
+ }
+ }
+}
+```
+
+## External Dependencies
+
+- **National Weather Service API**: The weather tools use the free API at `api.weather.gov` to fetch real weather data
+- **Microsoft.AspNetCore.Authentication.JwtBearer**: For JWT token validation
+- **Microsoft.IdentityModel.Tokens**: For token validation parameters
+- **ModelContextProtocol.AspNetCore**: For MCP server functionality and OAuth metadata
+
+## Key Files
+
+- `Program.cs`: Server setup with Azure B2C authentication and MCP configuration
+- `Tools/WeatherTools.cs`: Weather tool implementations
+- `Tools/HttpClientExt.cs`: HTTP client extensions
+- `test-azure-b2c.http`: REST client test file
+- `appsettings.Development.json`: Development configuration
+
+## Next Steps
+
+1. Set up Azure B2C tenant and application
+2. Configure the application settings
+3. Test the authentication flow
+4. Implement additional MCP tools as needed
+5. Deploy to Azure with proper security configurations
\ No newline at end of file
diff --git a/samples/AzureB2CClientCredentials/Tools/HttpClientExt.cs b/samples/AzureB2CClientCredentials/Tools/HttpClientExt.cs
new file mode 100644
index 000000000..f7b2b5499
--- /dev/null
+++ b/samples/AzureB2CClientCredentials/Tools/HttpClientExt.cs
@@ -0,0 +1,13 @@
+using System.Text.Json;
+
+namespace ModelContextProtocol;
+
+internal static class HttpClientExt
+{
+ public static async Task ReadJsonDocumentAsync(this HttpClient client, string requestUri)
+ {
+ using var response = await client.GetAsync(requestUri);
+ response.EnsureSuccessStatusCode();
+ return await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
+ }
+}
\ No newline at end of file
diff --git a/samples/AzureB2CClientCredentials/Tools/WeatherTools.cs b/samples/AzureB2CClientCredentials/Tools/WeatherTools.cs
new file mode 100644
index 000000000..b7ab90d14
--- /dev/null
+++ b/samples/AzureB2CClientCredentials/Tools/WeatherTools.cs
@@ -0,0 +1,67 @@
+using ModelContextProtocol;
+using ModelContextProtocol.Server;
+using System.ComponentModel;
+using System.Globalization;
+using System.Text.Json;
+
+namespace AzureB2CClientCredentials.Tools;
+
+[McpServerToolType]
+public sealed class WeatherTools
+{
+ private readonly IHttpClientFactory _httpClientFactory;
+
+ public WeatherTools(IHttpClientFactory httpClientFactory)
+ {
+ _httpClientFactory = httpClientFactory;
+ }
+
+ [McpServerTool, Description("Get weather alerts for a US state.")]
+ public async Task GetAlerts(
+ [Description("The US state to get alerts for. Use the 2 letter abbreviation for the state (e.g. NY).")] string state)
+ {
+ var client = _httpClientFactory.CreateClient("WeatherApi");
+ using var jsonDocument = await client.ReadJsonDocumentAsync($"/alerts/active/area/{state}");
+ var jsonElement = jsonDocument.RootElement;
+ var alerts = jsonElement.GetProperty("features").EnumerateArray();
+
+ if (!alerts.Any())
+ {
+ return "No active alerts for this state.";
+ }
+
+ return string.Join("\n--\n", alerts.Select(alert =>
+ {
+ JsonElement properties = alert.GetProperty("properties");
+ return $"""
+ Event: {properties.GetProperty("event").GetString()}
+ Area: {properties.GetProperty("areaDesc").GetString()}
+ Severity: {properties.GetProperty("severity").GetString()}
+ Description: {properties.GetProperty("description").GetString()}
+ Instruction: {properties.GetProperty("instruction").GetString()}
+ """;
+ }));
+ }
+
+ [McpServerTool, Description("Get weather forecast for a location.")]
+ public async Task GetForecast(
+ [Description("Latitude of the location.")] double latitude,
+ [Description("Longitude of the location.")] double longitude)
+ {
+ var client = _httpClientFactory.CreateClient("WeatherApi");
+ var pointUrl = string.Create(CultureInfo.InvariantCulture, $"/points/{latitude},{longitude}");
+ using var jsonDocument = await client.ReadJsonDocumentAsync(pointUrl);
+ var forecastUrl = jsonDocument.RootElement.GetProperty("properties").GetProperty("forecast").GetString()
+ ?? throw new Exception($"No forecast URL provided by {client.BaseAddress}points/{latitude},{longitude}");
+
+ using var forecastDocument = await client.ReadJsonDocumentAsync(forecastUrl);
+ var periods = forecastDocument.RootElement.GetProperty("properties").GetProperty("periods").EnumerateArray();
+
+ return string.Join("\n---\n", periods.Select(period => $"""
+ {period.GetProperty("name").GetString()}
+ Temperature: {period.GetProperty("temperature").GetInt32()}°F
+ Wind: {period.GetProperty("windSpeed").GetString()} {period.GetProperty("windDirection").GetString()}
+ Forecast: {period.GetProperty("detailedForecast").GetString()}
+ """));
+ }
+}
diff --git a/samples/AzureB2CClientCredentials/appsettings.json b/samples/AzureB2CClientCredentials/appsettings.json
new file mode 100644
index 000000000..108cfd0fb
--- /dev/null
+++ b/samples/AzureB2CClientCredentials/appsettings.json
@@ -0,0 +1,15 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*",
+ "AzureB2C": {
+ "Instance": "https://yourtenant.b2clogin.com",
+ "Tenant": "yourtenant.onmicrosoft.com",
+ "Policy": "B2C_1A_SIGNUP_SIGNIN",
+ "ClientId": "your-client-id-here"
+ }
+}
diff --git a/samples/AzureB2CClientCredentials/test-azure-b2c.http b/samples/AzureB2CClientCredentials/test-azure-b2c.http
new file mode 100644
index 000000000..deca20cc3
--- /dev/null
+++ b/samples/AzureB2CClientCredentials/test-azure-b2c.http
@@ -0,0 +1,108 @@
+### Azure B2C Client Credentials MCP Server Testing
+
+# Your Azure B2C configuration for Client Credentials Flow
+# IMPORTANT: Azure B2C requires a policy even for client credentials flow
+# This is different from Azure AD which supports policy-free client credentials
+@tenantName = yourtenant
+@tenantDomain = yourtenant.onmicrosoft.com
+@policyName = B2C_1A_SIGNUP_SIGNIN
+@clientId = your-client-id-here
+@clientSecret = your-client-secret-here
+@serverUrl = http://localhost:7071
+
+# This will be populated after running step 1
+@accessToken = your-access-token-here
+
+# Azure B2C endpoints - policy is required even for client credentials
+@authority = https://{{tenantName}}.b2clogin.com/{{tenantDomain}}/{{policyName}}
+@tokenEndpoint = {{authority}}/oauth2/v2.0/token
+@scope = https://{{tenantDomain}}/{{clientId}}/.default
+
+### 1. Get Access Token from Azure B2C
+# Run this first and copy the access_token from the response
+# Then update the @accessToken variable above with the token value
+POST {{tokenEndpoint}}
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=client_credentials
+&client_id={{clientId}}
+&client_secret={{clientSecret}}
+&scope={{scope}}
+
+### 2. Test MCP Server Metadata (make sure to update @accessToken first)
+GET {{serverUrl}}/.well-known/oauth-protected-resource
+Authorization: Bearer {{accessToken}}
+
+### 3. Test MCP Server with JSON-RPC (this is the correct way to call MCP tools)
+### This is a JSON-RPC request to list available tools
+POST {{serverUrl}}/
+Authorization: Bearer {{accessToken}}
+Content-Type: application/json
+Accept: application/json, text/event-stream
+
+{
+ "jsonrpc": "2.0",
+ "id": 1,
+ "method": "tools/list",
+ "params": {}
+}
+
+### 4. Test Weather Forecast Tool using JSON-RPC
+POST {{serverUrl}}/
+Authorization: Bearer {{accessToken}}
+Content-Type: application/json
+Accept: application/json, text/event-stream
+
+{
+ "jsonrpc": "2.0",
+ "id": 2,
+ "method": "tools/call",
+ "params": {
+ "name": "get_forecast",
+ "arguments": {
+ "latitude": 47.6062,
+ "longitude": -122.3321
+ }
+ }
+}
+
+### 5. Test Weather Alerts Tool using JSON-RPC
+POST {{serverUrl}}/
+Authorization: Bearer {{accessToken}}
+Content-Type: application/json
+Accept: application/json, text/event-stream
+
+{
+ "jsonrpc": "2.0",
+ "id": 3,
+ "method": "tools/call",
+ "params": {
+ "name": "get_alerts",
+ "arguments": {
+ "state": "WA"
+ }
+ }
+}
+
+### 6. Test without Authorization (should fail)
+POST {{serverUrl}}/
+Content-Type: application/json
+
+{
+ "jsonrpc": "2.0",
+ "id": 4,
+ "method": "tools/list",
+ "params": {}
+}
+
+### 7. Test with Invalid Token (should fail)
+POST {{serverUrl}}/
+Authorization: Bearer invalid-token
+Content-Type: application/json
+
+{
+ "jsonrpc": "2.0",
+ "id": 5,
+ "method": "tools/list",
+ "params": {}
+}