Split configuration of request and message filters (#1308)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
27a3196c7f
commit
d21aa9e5a2
1 changed files with 1288 additions and 1078 deletions
|
|
@ -1,22 +1,22 @@
|
|||
---
|
||||
title: Filters
|
||||
author: halter73
|
||||
description: MCP Server Handler Filters
|
||||
description: MCP Server Filters
|
||||
uid: filters
|
||||
---
|
||||
|
||||
# MCP Server Handler Filters
|
||||
# MCP Server Filters
|
||||
|
||||
The MCP Server provides two levels of filters for intercepting and modifying request processing:
|
||||
|
||||
1. **Message Filters** - Low-level filters (`AddIncomingMessageFilter`, `AddOutgoingMessageFilter`) that intercept all JSON-RPC messages before routing
|
||||
2. **Request-Specific Filters** - Handler-level filters (e.g., `AddListToolsFilter`, `AddCallToolFilter`) that target specific MCP operations
|
||||
1. **Message Filters** - Low-level filters (`AddIncomingFilter`, `AddOutgoingFilter`) configured via `WithMessageFilters(...)` that intercept all JSON-RPC messages before routing.
|
||||
2. **Request-Specific Filters** - Handler-level filters (e.g., `AddListToolsFilter`, `AddCallToolFilter`) configured via `WithRequestFilters(...)` that target specific MCP operations.
|
||||
|
||||
The filters are stored in `McpServerOptions.Filters` and applied during server configuration.
|
||||
The filters are stored in `McpServerOptions.Filters`.
|
||||
|
||||
## Available Request-Specific Filter Methods
|
||||
|
||||
The following filter methods are available:
|
||||
The following request filter methods are available on `IMcpRequestFilterBuilder` inside `WithRequestFilters(...)`:
|
||||
|
||||
- `AddListResourceTemplatesFilter` - Filter for list resource templates handlers
|
||||
- `AddListToolsFilter` - Filter for list tools handlers
|
||||
|
|
@ -32,10 +32,11 @@ The following filter methods are available:
|
|||
|
||||
## Message Filters
|
||||
|
||||
In addition to the request-specific filters above, there are low-level message filters that intercept all JSON-RPC messages before they are routed to specific handlers:
|
||||
In addition to the request-specific filters above, there are low-level message filters that intercept all JSON-RPC messages before they are routed to specific handlers.
|
||||
Configure these on `IMcpMessageFilterBuilder` inside `WithMessageFilters(...)`:
|
||||
|
||||
- `AddIncomingMessageFilter` - Filter for all incoming JSON-RPC messages (requests and notifications)
|
||||
- `AddOutgoingMessageFilter` - Filter for all outgoing JSON-RPC messages (responses and notifications)
|
||||
- `AddIncomingFilter` - Filter for all incoming JSON-RPC messages (requests and notifications)
|
||||
- `AddOutgoingFilter` - Filter for all outgoing JSON-RPC messages (responses and notifications)
|
||||
|
||||
### When to Use Message Filters
|
||||
|
||||
|
|
@ -49,22 +50,25 @@ Message filters operate at a lower level than request-specific filters and are u
|
|||
|
||||
### Incoming Message Filter
|
||||
|
||||
`AddIncomingMessageFilter` intercepts all incoming JSON-RPC messages before they are dispatched to request-specific handlers:
|
||||
`AddIncomingFilter` intercepts all incoming JSON-RPC messages before they are dispatched to request-specific handlers:
|
||||
|
||||
```csharp
|
||||
services.AddMcpServer()
|
||||
.AddIncomingMessageFilter(next => async (context, cancellationToken) =>
|
||||
.WithMessageFilters(messageFilters =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
// Access the raw JSON-RPC message
|
||||
if (context.JsonRpcMessage is JsonRpcRequest request)
|
||||
messageFilters.AddIncomingFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
logger?.LogInformation($"Incoming request: {request.Method}");
|
||||
}
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
// Call next to continue processing
|
||||
await next(context, cancellationToken);
|
||||
// Access the raw JSON-RPC message
|
||||
if (context.JsonRpcMessage is JsonRpcRequest request)
|
||||
{
|
||||
logger?.LogInformation($"Incoming request: {request.Method}");
|
||||
}
|
||||
|
||||
// Call next to continue processing
|
||||
await next(context, cancellationToken);
|
||||
});
|
||||
})
|
||||
.WithTools<MyTools>();
|
||||
```
|
||||
|
|
@ -83,46 +87,52 @@ Inside an incoming message filter, you have access to:
|
|||
You can skip the default handler by not calling `next`. This is useful for implementing custom protocol methods:
|
||||
|
||||
```csharp
|
||||
.AddIncomingMessageFilter(next => async (context, cancellationToken) =>
|
||||
.WithMessageFilters(messageFilters =>
|
||||
{
|
||||
if (context.JsonRpcMessage is JsonRpcRequest request && request.Method == "custom/myMethod")
|
||||
messageFilters.AddIncomingFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
// Handle the custom method directly
|
||||
var response = new JsonRpcResponse
|
||||
if (context.JsonRpcMessage is JsonRpcRequest request && request.Method == "custom/myMethod")
|
||||
{
|
||||
Id = request.Id,
|
||||
Result = JsonSerializer.SerializeToNode(new { message = "Custom response" })
|
||||
};
|
||||
await context.Server.SendMessageAsync(response, cancellationToken);
|
||||
return; // Don't call next - we handled it
|
||||
}
|
||||
// Handle the custom method directly
|
||||
var response = new JsonRpcResponse
|
||||
{
|
||||
Id = request.Id,
|
||||
Result = JsonSerializer.SerializeToNode(new { message = "Custom response" })
|
||||
};
|
||||
await context.Server.SendMessageAsync(response, cancellationToken);
|
||||
return; // Don't call next - we handled it
|
||||
}
|
||||
|
||||
await next(context, cancellationToken);
|
||||
await next(context, cancellationToken);
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
### Outgoing Message Filter
|
||||
|
||||
`AddOutgoingMessageFilter` intercepts all outgoing JSON-RPC messages before they are sent to the client:
|
||||
`AddOutgoingFilter` intercepts all outgoing JSON-RPC messages before they are sent to the client:
|
||||
|
||||
```csharp
|
||||
services.AddMcpServer()
|
||||
.AddOutgoingMessageFilter(next => async (context, cancellationToken) =>
|
||||
.WithMessageFilters(messageFilters =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
// Inspect outgoing messages
|
||||
switch (context.JsonRpcMessage)
|
||||
messageFilters.AddOutgoingFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
case JsonRpcResponse response:
|
||||
logger?.LogInformation($"Sending response for request {response.Id}");
|
||||
break;
|
||||
case JsonRpcNotification notification:
|
||||
logger?.LogInformation($"Sending notification: {notification.Method}");
|
||||
break;
|
||||
}
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
await next(context, cancellationToken);
|
||||
// Inspect outgoing messages
|
||||
switch (context.JsonRpcMessage)
|
||||
{
|
||||
case JsonRpcResponse response:
|
||||
logger?.LogInformation($"Sending response for request {response.Id}");
|
||||
break;
|
||||
case JsonRpcNotification notification:
|
||||
logger?.LogInformation($"Sending notification: {notification.Method}");
|
||||
break;
|
||||
}
|
||||
|
||||
await next(context, cancellationToken);
|
||||
});
|
||||
})
|
||||
.WithTools<MyTools>();
|
||||
```
|
||||
|
|
@ -132,16 +142,19 @@ services.AddMcpServer()
|
|||
You can suppress outgoing messages by not calling `next`:
|
||||
|
||||
```csharp
|
||||
.AddOutgoingMessageFilter(next => async (context, cancellationToken) =>
|
||||
.WithMessageFilters(messageFilters =>
|
||||
{
|
||||
// Suppress specific notifications
|
||||
if (context.JsonRpcMessage is JsonRpcNotification notification &&
|
||||
notification.Method == "notifications/progress")
|
||||
messageFilters.AddOutgoingFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
return; // Don't send this notification
|
||||
}
|
||||
// Suppress specific notifications
|
||||
if (context.JsonRpcMessage is JsonRpcNotification notification &&
|
||||
notification.Method == "notifications/progress")
|
||||
{
|
||||
return; // Don't send this notification
|
||||
}
|
||||
|
||||
await next(context, cancellationToken);
|
||||
await next(context, cancellationToken);
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
|
|
@ -150,26 +163,29 @@ You can suppress outgoing messages by not calling `next`:
|
|||
Outgoing message filters can send additional messages by calling `next` with a new `MessageContext`:
|
||||
|
||||
```csharp
|
||||
.AddOutgoingMessageFilter(next => async (context, cancellationToken) =>
|
||||
.WithMessageFilters(messageFilters =>
|
||||
{
|
||||
// Send an extra notification before certain responses
|
||||
if (context.JsonRpcMessage is JsonRpcResponse response &&
|
||||
response.Result is JsonObject result &&
|
||||
result.ContainsKey("tools"))
|
||||
messageFilters.AddOutgoingFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
var notification = new JsonRpcNotification
|
||||
// Send an extra notification before certain responses
|
||||
if (context.JsonRpcMessage is JsonRpcResponse response &&
|
||||
response.Result is JsonObject result &&
|
||||
result.ContainsKey("tools"))
|
||||
{
|
||||
Method = "custom/toolsListed",
|
||||
Params = new JsonObject { ["timestamp"] = DateTime.UtcNow.ToString("O") },
|
||||
Context = new JsonRpcMessageContext
|
||||
var notification = new JsonRpcNotification
|
||||
{
|
||||
RelatedTransport = context.JsonRpcMessage.Context?.RelatedTransport
|
||||
}
|
||||
};
|
||||
await next(new MessageContext(context.Server, notification), cancellationToken);
|
||||
}
|
||||
Method = "custom/toolsListed",
|
||||
Params = new JsonObject { ["timestamp"] = DateTime.UtcNow.ToString("O") },
|
||||
Context = new JsonRpcMessageContext
|
||||
{
|
||||
RelatedTransport = context.JsonRpcMessage.Context?.RelatedTransport
|
||||
}
|
||||
};
|
||||
await next(new MessageContext(context.Server, notification), cancellationToken);
|
||||
}
|
||||
|
||||
await next(context, cancellationToken);
|
||||
await next(context, cancellationToken);
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
|
|
@ -179,11 +195,17 @@ Message filters execute in registration order, with the first registered filter
|
|||
|
||||
```csharp
|
||||
services.AddMcpServer()
|
||||
.AddIncomingMessageFilter(incomingFilter1) // Incoming: executes first (outermost)
|
||||
.AddIncomingMessageFilter(incomingFilter2) // Incoming: executes second
|
||||
.AddOutgoingMessageFilter(outgoingFilter1) // Outgoing: executes first (outermost)
|
||||
.AddOutgoingMessageFilter(outgoingFilter2) // Outgoing: executes second
|
||||
.AddListToolsFilter(toolsFilter) // Request-specific filter
|
||||
.WithMessageFilters(messageFilters =>
|
||||
{
|
||||
messageFilters.AddIncomingFilter(incomingFilter1); // Incoming: executes first (outermost)
|
||||
messageFilters.AddIncomingFilter(incomingFilter2); // Incoming: executes second
|
||||
messageFilters.AddOutgoingFilter(outgoingFilter1); // Outgoing: executes first (outermost)
|
||||
messageFilters.AddOutgoingFilter(outgoingFilter2); // Outgoing: executes second
|
||||
})
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
requestFilters.AddListToolsFilter(toolsFilter); // Request-specific filter
|
||||
})
|
||||
.WithTools<MyTools>();
|
||||
```
|
||||
|
||||
|
|
@ -218,21 +240,25 @@ OutgoingFilter1 (after next)
|
|||
The `Items` dictionary allows you to pass data between filters processing the same message:
|
||||
|
||||
```csharp
|
||||
.AddIncomingMessageFilter(next => async (context, cancellationToken) =>
|
||||
.WithMessageFilters(messageFilters =>
|
||||
{
|
||||
context.Items["requestStartTime"] = DateTime.UtcNow;
|
||||
await next(context, cancellationToken);
|
||||
})
|
||||
.AddIncomingMessageFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
await next(context, cancellationToken);
|
||||
|
||||
if (context.Items.TryGetValue("requestStartTime", out var startTime))
|
||||
messageFilters.AddIncomingFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
var elapsed = DateTime.UtcNow - (DateTime)startTime;
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
logger?.LogInformation($"Request processed in {elapsed.TotalMilliseconds}ms");
|
||||
}
|
||||
context.Items["requestStartTime"] = DateTime.UtcNow;
|
||||
await next(context, cancellationToken);
|
||||
});
|
||||
|
||||
messageFilters.AddIncomingFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
await next(context, cancellationToken);
|
||||
|
||||
if (context.Items.TryGetValue("requestStartTime", out var startTime))
|
||||
{
|
||||
var elapsed = DateTime.UtcNow - (DateTime)startTime;
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
logger?.LogInformation($"Request processed in {elapsed.TotalMilliseconds}ms");
|
||||
}
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
|
|
@ -247,18 +273,21 @@ services.AddMcpServer()
|
|||
// Your base handler logic
|
||||
return new ListToolsResult { Tools = GetTools() };
|
||||
})
|
||||
.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
requestFilters.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
// Pre-processing logic
|
||||
logger?.LogInformation("Before handler execution");
|
||||
// Pre-processing logic
|
||||
logger?.LogInformation("Before handler execution");
|
||||
|
||||
var result = await next(context, cancellationToken);
|
||||
var result = await next(context, cancellationToken);
|
||||
|
||||
// Post-processing logic
|
||||
logger?.LogInformation("After handler execution");
|
||||
return result;
|
||||
// Post-processing logic
|
||||
logger?.LogInformation("After handler execution");
|
||||
return result;
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
|
@ -267,9 +296,12 @@ services.AddMcpServer()
|
|||
```csharp
|
||||
services.AddMcpServer()
|
||||
.WithListToolsHandler(baseHandler)
|
||||
.AddListToolsFilter(filter1) // Executes first (outermost)
|
||||
.AddListToolsFilter(filter2) // Executes second
|
||||
.AddListToolsFilter(filter3); // Executes third (closest to handler)
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
requestFilters.AddListToolsFilter(filter1); // Executes first (outermost)
|
||||
requestFilters.AddListToolsFilter(filter2); // Executes second
|
||||
requestFilters.AddListToolsFilter(filter3); // Executes third (closest to handler)
|
||||
});
|
||||
```
|
||||
|
||||
Execution flow: `filter1 -> filter2 -> filter3 -> baseHandler -> filter3 -> filter2 -> filter1`
|
||||
|
|
@ -279,76 +311,91 @@ Execution flow: `filter1 -> filter2 -> filter3 -> baseHandler -> filter3 -> filt
|
|||
### Logging
|
||||
|
||||
```csharp
|
||||
.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
requestFilters.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
logger?.LogInformation($"Processing request from {context.Meta.ProgressToken}");
|
||||
var result = await next(context, cancellationToken);
|
||||
logger?.LogInformation($"Returning {result.Tools?.Count ?? 0} tools");
|
||||
return result;
|
||||
logger?.LogInformation($"Processing request from {context.Meta.ProgressToken}");
|
||||
var result = await next(context, cancellationToken);
|
||||
logger?.LogInformation($"Returning {result.Tools?.Count ?? 0} tools");
|
||||
return result;
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```csharp
|
||||
.AddCallToolFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
try
|
||||
requestFilters.AddCallToolFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
return await next(context, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new CallToolResult
|
||||
try
|
||||
{
|
||||
Content = new[] { new TextContent { Type = "text", Text = $"Error: {ex.Message}" } },
|
||||
IsError = true
|
||||
};
|
||||
}
|
||||
return await next(context, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
logger?.LogError(ex, "Error while processing CallTool request for {ProgressToken}", context.Meta.ProgressToken);
|
||||
|
||||
return new CallToolResult
|
||||
{
|
||||
Content = new[] { new TextContent { Type = "text", Text = "An unexpected error occurred while processing the tool call." } },
|
||||
IsError = true
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Performance Monitoring
|
||||
|
||||
```csharp
|
||||
.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
requestFilters.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var result = await next(context, cancellationToken);
|
||||
stopwatch.Stop();
|
||||
logger?.LogInformation($"Handler took {stopwatch.ElapsedMilliseconds}ms");
|
||||
return result;
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var result = await next(context, cancellationToken);
|
||||
stopwatch.Stop();
|
||||
logger?.LogInformation($"Handler took {stopwatch.ElapsedMilliseconds}ms");
|
||||
return result;
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Caching
|
||||
|
||||
```csharp
|
||||
.AddListResourcesFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
var cache = context.Services!.GetRequiredService<IMemoryCache>();
|
||||
|
||||
var cacheKey = $"resources:{context.Params.Cursor}";
|
||||
if (cache.TryGetValue(cacheKey, out var cached))
|
||||
requestFilters.AddListResourcesFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
return (ListResourcesResult)cached;
|
||||
}
|
||||
var cache = context.Services!.GetRequiredService<IMemoryCache>();
|
||||
|
||||
var result = await next(context, cancellationToken);
|
||||
cache.Set(cacheKey, result, TimeSpan.FromMinutes(5));
|
||||
return result;
|
||||
var cacheKey = $"resources:{context.Params.Cursor}";
|
||||
if (cache.TryGetValue(cacheKey, out var cached))
|
||||
{
|
||||
return (ListResourcesResult)cached;
|
||||
}
|
||||
|
||||
var result = await next(context, cancellationToken);
|
||||
cache.Set(cacheKey, result, TimeSpan.FromMinutes(5));
|
||||
return result;
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Built-in Authorization Filters
|
||||
## Built-in Authorization Request Filters
|
||||
|
||||
When using the ASP.NET Core integration (`ModelContextProtocol.AspNetCore`), you can add authorization filters to support `[Authorize]` and `[AllowAnonymous]` attributes on MCP server tools, prompts, and resources by calling `AddAuthorizationFilters()` on your MCP server builder.
|
||||
|
||||
### Enabling Authorization Filters
|
||||
### Enabling Authorization Request Filters
|
||||
|
||||
To enable authorization support, call `AddAuthorizationFilters()` when configuring your MCP server:
|
||||
|
||||
|
|
@ -455,25 +502,31 @@ This allows you to implement logging, metrics, or other cross-cutting concerns t
|
|||
```csharp
|
||||
services.AddMcpServer()
|
||||
.WithHttpTransport()
|
||||
.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
requestFilters.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
// This filter runs BEFORE authorization - sees all tools
|
||||
logger?.LogInformation("Request for tools list - will see all tools");
|
||||
var result = await next(context, cancellationToken);
|
||||
logger?.LogInformation($"Returning {result.Tools?.Count ?? 0} tools after authorization");
|
||||
return result;
|
||||
// This filter runs BEFORE authorization - sees all tools
|
||||
logger?.LogInformation("Request for tools list - will see all tools");
|
||||
var result = await next(context, cancellationToken);
|
||||
logger?.LogInformation($"Returning {result.Tools?.Count ?? 0} tools after authorization");
|
||||
return result;
|
||||
});
|
||||
})
|
||||
.AddAuthorizationFilters() // Authorization filtering happens here
|
||||
.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
requestFilters.AddListToolsFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
var logger = context.Services?.GetService<ILogger<Program>>();
|
||||
|
||||
// This filter runs AFTER authorization - only sees authorized tools
|
||||
var result = await next(context, cancellationToken);
|
||||
logger?.LogInformation($"Post-auth filter sees {result.Tools?.Count ?? 0} authorized tools");
|
||||
return result;
|
||||
// This filter runs AFTER authorization - only sees authorized tools
|
||||
var result = await next(context, cancellationToken);
|
||||
logger?.LogInformation($"Post-auth filter sees {result.Tools?.Count ?? 0} authorized tools");
|
||||
return result;
|
||||
});
|
||||
})
|
||||
.WithTools<WeatherTools>();
|
||||
```
|
||||
|
|
@ -494,10 +547,13 @@ builder.Services.AddMcpServer()
|
|||
.WithHttpTransport()
|
||||
.AddAuthorizationFilters() // Required for authorization support
|
||||
.WithTools<WeatherTools>()
|
||||
.AddCallToolFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
// Custom call tool logic
|
||||
return await next(context, cancellationToken);
|
||||
requestFilters.AddCallToolFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
// Custom call tool logic
|
||||
return await next(context, cancellationToken);
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
|
@ -511,19 +567,22 @@ app.Run();
|
|||
You can also create custom authorization filters using the filter methods:
|
||||
|
||||
```csharp
|
||||
.AddCallToolFilter(next => async (context, cancellationToken) =>
|
||||
.WithRequestFilters(requestFilters =>
|
||||
{
|
||||
// Custom authorization logic
|
||||
if (context.User?.Identity?.IsAuthenticated != true)
|
||||
requestFilters.AddCallToolFilter(next => async (context, cancellationToken) =>
|
||||
{
|
||||
return new CallToolResult
|
||||
// Custom authorization logic
|
||||
if (context.User?.Identity?.IsAuthenticated != true)
|
||||
{
|
||||
Content = [new TextContent { Text = "Custom: Authentication required" }],
|
||||
IsError = true
|
||||
};
|
||||
}
|
||||
return new CallToolResult
|
||||
{
|
||||
Content = [new TextContent { Text = "Custom: Authentication required" }],
|
||||
IsError = true
|
||||
};
|
||||
}
|
||||
|
||||
return await next(context, cancellationToken);
|
||||
return await next(context, cancellationToken);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue