Skip to content

Commit 2f44765

Browse files
committed
Update with proper token logic
1 parent e6c1995 commit 2f44765

File tree

8 files changed

+50
-98
lines changed

8 files changed

+50
-98
lines changed

samples/AuthorizationExample/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ public static async Task Main(string[] args)
8686
{
8787
Console.WriteLine($"Inner Error: {ex.InnerException.Message}");
8888
}
89+
// Print the stack trace for debugging
90+
Console.WriteLine($"Stack Trace:\n{ex.StackTrace}");
8991
}
9092
}
9193
}

samples/AuthorizationServerExample/Program.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,8 @@ public static async Task Main(string[] args)
3535
// In a real application, this would verify the token with your identity provider
3636
async Task<bool> ValidateToken(string token)
3737
{
38-
// For demo purposes, we'll accept any token that starts with "valid_"
39-
// In production, you would validate the token with your identity provider
40-
var isValid = token.StartsWith("valid_", StringComparison.OrdinalIgnoreCase);
41-
Console.WriteLine($"Token validation result: {(isValid ? "Valid" : "Invalid")}");
42-
return isValid;
38+
// For demo purposes, we'll accept any token.
39+
return true;
4340
}
4441

4542
// 3. Create an authorization provider with the PRM and token validator

src/ModelContextProtocol.AspNetCore/AuthorizationMiddleware.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,14 @@ public AuthorizationMiddleware(RequestDelegate next, ILogger<AuthorizationMiddle
3232
/// </summary>
3333
/// <param name="context">The HTTP context.</param>
3434
/// <param name="serverOptions">The MCP server options.</param>
35+
/// <param name="authProvider">The authorization provider.</param>
3536
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
36-
public async Task InvokeAsync(HttpContext context, IOptions<McpServerOptions> serverOptions)
37+
public async Task InvokeAsync(
38+
HttpContext context,
39+
IOptions<McpServerOptions> serverOptions,
40+
IServerAuthorizationProvider? authProvider = null)
3741
{
3842
// Check if authorization is configured
39-
var authCapability = serverOptions.Value.Capabilities?.Authorization;
40-
var authProvider = authCapability?.AuthorizationProvider;
41-
4243
if (authProvider == null)
4344
{
4445
// Authorization is not configured, proceed to the next middleware

src/ModelContextProtocol/Configuration/McpServerAuthorizationExtensions.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,12 @@ public static IMcpServerBuilder WithAuthorization(
2424
Throw.IfNull(builder);
2525
Throw.IfNull(authorizationProvider);
2626

27+
// Register the authorization provider in the DI container
28+
builder.Services.AddSingleton(authorizationProvider);
29+
2730
builder.Services.Configure<McpServerOptions>(options =>
2831
{
2932
options.Capabilities ??= new ServerCapabilities();
30-
options.Capabilities.Authorization = new AuthorizationCapability
31-
{
32-
AuthorizationProvider = authorizationProvider
33-
};
3433
});
3534

3635
return builder;

src/ModelContextProtocol/Protocol/Auth/DefaultAuthorizationHandler.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
using System.Diagnostics;
2-
using System.Net;
3-
using System.Net.Http.Headers;
41
using Microsoft.Extensions.Logging;
52
using Microsoft.Extensions.Logging.Abstractions;
63
using ModelContextProtocol.Utils;
4+
using System.Net;
5+
using System.Net.Http.Headers;
76

87
namespace ModelContextProtocol.Protocol.Auth;
98

src/ModelContextProtocol/Protocol/Transport/SseClientSessionTransport.cs

Lines changed: 36 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -89,29 +89,12 @@ public override async Task SendMessageAsync(
8989
if (_messageEndpoint == null)
9090
throw new InvalidOperationException("Transport not connected");
9191

92-
using var content = new StringContent(
93-
JsonSerializer.Serialize(message, McpJsonUtilities.JsonContext.Default.JsonRpcMessage),
94-
Encoding.UTF8,
95-
"application/json"
96-
);
97-
9892
string messageId = "(no id)";
9993

10094
if (message is JsonRpcMessageWithId messageWithId)
10195
{
10296
messageId = messageWithId.Id.ToString();
10397
}
104-
105-
using var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, _messageEndpoint)
106-
{
107-
Content = content,
108-
};
109-
110-
// Add authorization headers if needed
111-
await _authorizationHandler.AuthenticateRequestAsync(httpRequestMessage).ConfigureAwait(false);
112-
113-
// Copy additional headers
114-
CopyAdditionalHeaders(httpRequestMessage.Headers);
11598

11699
// Send the request, handling potential auth challenges
117100
HttpResponseMessage? response = null;
@@ -120,37 +103,32 @@ public override async Task SendMessageAsync(
120103
do
121104
{
122105
authRetry = false;
123-
response = await _httpClient.SendAsync(httpRequestMessage, cancellationToken).ConfigureAwait(false);
124106

125-
// Handle 401 Unauthorized response
107+
// Create a new request for each attempt
108+
using var currentRequest = new HttpRequestMessage(HttpMethod.Post, _messageEndpoint);
109+
currentRequest.Content = new StringContent(
110+
JsonSerializer.Serialize(message, McpJsonUtilities.JsonContext.Default.JsonRpcMessage),
111+
Encoding.UTF8,
112+
"application/json"
113+
);
114+
115+
// Add authorization headers if needed - the handler will only add headers if auth is required
116+
await _authorizationHandler.AuthenticateRequestAsync(currentRequest).ConfigureAwait(false);
117+
118+
// Copy additional headers
119+
CopyAdditionalHeaders(currentRequest.Headers);
120+
121+
// Dispose previous response before making a new request
122+
response?.Dispose();
123+
124+
response = await _httpClient.SendAsync(currentRequest, cancellationToken).ConfigureAwait(false);
125+
126+
// Handle 401 Unauthorized response - this will only execute if the server requires auth
126127
if (response.StatusCode == HttpStatusCode.Unauthorized)
127128
{
128129
// Try to handle the unauthorized response
129130
authRetry = await _authorizationHandler.HandleUnauthorizedResponseAsync(
130131
response, _messageEndpoint).ConfigureAwait(false);
131-
132-
if (authRetry)
133-
{
134-
// Create a new request (we can't reuse the previous one)
135-
using var newRequest = new HttpRequestMessage(HttpMethod.Post, _messageEndpoint)
136-
{
137-
Content = new StringContent(
138-
JsonSerializer.Serialize(message, McpJsonUtilities.JsonContext.Default.JsonRpcMessage),
139-
Encoding.UTF8,
140-
"application/json"
141-
)
142-
};
143-
144-
// Add authorization headers for the new request
145-
await _authorizationHandler.AuthenticateRequestAsync(newRequest).ConfigureAwait(false);
146-
CopyAdditionalHeaders(newRequest.Headers);
147-
148-
// Dispose the previous response
149-
response.Dispose();
150-
151-
// Send the new request
152-
response = await _httpClient.SendAsync(newRequest, cancellationToken).ConfigureAwait(false);
153-
}
154132
}
155133
} while (authRetry);
156134

@@ -252,55 +230,39 @@ private async Task ReceiveMessagesAsync(CancellationToken cancellationToken)
252230
{
253231
try
254232
{
255-
using var request = new HttpRequestMessage(HttpMethod.Get, _sseEndpoint);
256-
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
257-
258-
// Add authorization headers if needed
259-
await _authorizationHandler.AuthenticateRequestAsync(request).ConfigureAwait(false);
260-
261-
// Copy additional headers
262-
CopyAdditionalHeaders(request.Headers);
263-
264233
// Send the request, handling potential auth challenges
265234
HttpResponseMessage? response = null;
266235
bool authRetry = false;
267236

268237
do
269238
{
270239
authRetry = false;
240+
241+
// Create a new request for each attempt
242+
using var currentRequest = new HttpRequestMessage(HttpMethod.Get, _sseEndpoint);
243+
currentRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
244+
245+
// Add authorization headers if needed - the handler will only add headers if auth is required
246+
await _authorizationHandler.AuthenticateRequestAsync(currentRequest).ConfigureAwait(false);
247+
248+
// Copy additional headers
249+
CopyAdditionalHeaders(currentRequest.Headers);
250+
251+
// Dispose previous response before making a new request
252+
response?.Dispose();
253+
271254
response = await _httpClient.SendAsync(
272-
request,
255+
currentRequest,
273256
HttpCompletionOption.ResponseHeadersRead,
274257
cancellationToken
275258
).ConfigureAwait(false);
276259

277-
// Handle 401 Unauthorized response
260+
// Handle 401 Unauthorized response - this will only execute if the server requires auth
278261
if (response.StatusCode == HttpStatusCode.Unauthorized)
279262
{
280263
// Try to handle the unauthorized response
281264
authRetry = await _authorizationHandler.HandleUnauthorizedResponseAsync(
282265
response, _sseEndpoint).ConfigureAwait(false);
283-
284-
if (authRetry)
285-
{
286-
// Create a new request (we can't reuse the previous one)
287-
using var newRequest = new HttpRequestMessage(HttpMethod.Get, _sseEndpoint);
288-
newRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
289-
290-
// Add authorization headers for the new request
291-
await _authorizationHandler.AuthenticateRequestAsync(newRequest).ConfigureAwait(false);
292-
CopyAdditionalHeaders(newRequest.Headers);
293-
294-
// Dispose the previous response
295-
response.Dispose();
296-
297-
// Send the new request
298-
response = await _httpClient.SendAsync(
299-
newRequest,
300-
HttpCompletionOption.ResponseHeadersRead,
301-
cancellationToken
302-
).ConfigureAwait(false);
303-
}
304266
}
305267
} while (authRetry);
306268

src/ModelContextProtocol/Protocol/Types/ServerCapabilities.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ public class ServerCapabilities
3535
[JsonPropertyName("experimental")]
3636
public Dictionary<string, object>? Experimental { get; set; }
3737

38-
/// <summary>
39-
/// Gets or sets a server's authorization capability, supporting OAuth 2.0 authorization flows.
40-
/// </summary>
41-
[JsonPropertyName("authorization")]
42-
public AuthorizationCapability? Authorization { get; set; }
43-
4438
/// <summary>
4539
/// Gets or sets a server's logging capability, supporting sending log messages to the client.
4640
/// </summary>

src/ModelContextProtocol/Server/McpServer.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ await originalListPromptsHandler(request, cancellationToken).ConfigureAwait(fals
328328
ServerCapabilities = new()
329329
{
330330
Experimental = options.Capabilities?.Experimental,
331-
Authorization = options.Capabilities?.Authorization,
332331
Logging = options.Capabilities?.Logging,
333332
Tools = options.Capabilities?.Tools,
334333
Resources = options.Capabilities?.Resources,
@@ -427,7 +426,6 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
427426
ServerCapabilities = new()
428427
{
429428
Experimental = options.Capabilities?.Experimental,
430-
Authorization = options.Capabilities?.Authorization,
431429
Logging = options.Capabilities?.Logging,
432430
Prompts = options.Capabilities?.Prompts,
433431
Resources = options.Capabilities?.Resources,

0 commit comments

Comments
 (0)