Skip to content

Commit 74622d0

Browse files
Copilotstephentoub
andauthored
Remove server back-references from protocol DTO types (#1345)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> Co-authored-by: Stephen Toub <stoub@microsoft.com>
1 parent 2c9bb5d commit 74622d0

9 files changed

Lines changed: 195 additions & 96 deletions

File tree

src/ModelContextProtocol.AspNetCore/AuthorizationFilterSetup.cs

Lines changed: 96 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -43,31 +43,39 @@ public void PostConfigure(string? name, McpServerOptions options)
4343

4444
private void ConfigureListToolsFilter(McpServerOptions options)
4545
{
46-
options.Filters.Request.ListToolsFilters.Add(next => async (context, cancellationToken) =>
46+
options.Filters.Request.ListToolsFilters.Add(next =>
4747
{
48-
context.Items[AuthorizationFilterInvokedKey] = true;
49-
50-
var result = await next(context, cancellationToken);
51-
await FilterAuthorizedItemsAsync(
52-
result.Tools, static tool => tool.McpServerTool,
53-
context.User, context.Services, context);
54-
return result;
48+
var toolCollection = options.ToolCollection;
49+
return async (context, cancellationToken) =>
50+
{
51+
context.Items[AuthorizationFilterInvokedKey] = true;
52+
53+
var result = await next(context, cancellationToken);
54+
await FilterAuthorizedItemsAsync(
55+
result.Tools, tool => toolCollection is not null && toolCollection.TryGetPrimitive(tool.Name, out var serverTool) ? serverTool : null,
56+
context.User, context.Services, context);
57+
return result;
58+
};
5559
});
5660
}
5761

5862
private static void CheckListToolsFilter(McpServerOptions options)
5963
{
60-
options.Filters.Request.ListToolsFilters.Add(next => async (context, cancellationToken) =>
64+
options.Filters.Request.ListToolsFilters.Add(next =>
6165
{
62-
var result = await next(context, cancellationToken);
63-
64-
if (HasAuthorizationMetadata(result.Tools.Select(static tool => tool.McpServerTool))
65-
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
66+
var toolCollection = options.ToolCollection;
67+
return async (context, cancellationToken) =>
6668
{
67-
throw new InvalidOperationException("Authorization filter was not invoked for tools/list operation, but authorization metadata was found on the tools. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
68-
}
69+
var result = await next(context, cancellationToken);
70+
71+
if (HasAuthorizationMetadata(result.Tools.Select(tool => toolCollection is not null && toolCollection.TryGetPrimitive(tool.Name, out var serverTool) ? serverTool : null))
72+
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
73+
{
74+
throw new InvalidOperationException("Authorization filter was not invoked for tools/list operation, but authorization metadata was found on the tools. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
75+
}
6976

70-
return result;
77+
return result;
78+
};
7179
});
7280
}
7381

@@ -103,61 +111,77 @@ private static void CheckCallToolFilter(McpServerOptions options)
103111

104112
private void ConfigureListResourcesFilter(McpServerOptions options)
105113
{
106-
options.Filters.Request.ListResourcesFilters.Add(next => async (context, cancellationToken) =>
114+
options.Filters.Request.ListResourcesFilters.Add(next =>
107115
{
108-
context.Items[AuthorizationFilterInvokedKey] = true;
109-
110-
var result = await next(context, cancellationToken);
111-
await FilterAuthorizedItemsAsync(
112-
result.Resources, static resource => resource.McpServerResource,
113-
context.User, context.Services, context);
114-
return result;
116+
var resourceCollection = options.ResourceCollection;
117+
return async (context, cancellationToken) =>
118+
{
119+
context.Items[AuthorizationFilterInvokedKey] = true;
120+
121+
var result = await next(context, cancellationToken);
122+
await FilterAuthorizedItemsAsync(
123+
result.Resources, resource => resourceCollection is not null && resourceCollection.TryGetPrimitive(resource.Uri, out var serverResource) ? serverResource : null,
124+
context.User, context.Services, context);
125+
return result;
126+
};
115127
});
116128
}
117129

118130
private static void CheckListResourcesFilter(McpServerOptions options)
119131
{
120-
options.Filters.Request.ListResourcesFilters.Add(next => async (context, cancellationToken) =>
132+
options.Filters.Request.ListResourcesFilters.Add(next =>
121133
{
122-
var result = await next(context, cancellationToken);
123-
124-
if (HasAuthorizationMetadata(result.Resources.Select(static resource => resource.McpServerResource))
125-
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
134+
var resourceCollection = options.ResourceCollection;
135+
return async (context, cancellationToken) =>
126136
{
127-
throw new InvalidOperationException("Authorization filter was not invoked for resources/list operation, but authorization metadata was found on the resources. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
128-
}
137+
var result = await next(context, cancellationToken);
138+
139+
if (HasAuthorizationMetadata(result.Resources.Select(resource => resourceCollection is not null && resourceCollection.TryGetPrimitive(resource.Uri, out var serverResource) ? serverResource : null))
140+
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
141+
{
142+
throw new InvalidOperationException("Authorization filter was not invoked for resources/list operation, but authorization metadata was found on the resources. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
143+
}
129144

130-
return result;
145+
return result;
146+
};
131147
});
132148
}
133149

134150
private void ConfigureListResourceTemplatesFilter(McpServerOptions options)
135151
{
136-
options.Filters.Request.ListResourceTemplatesFilters.Add(next => async (context, cancellationToken) =>
152+
options.Filters.Request.ListResourceTemplatesFilters.Add(next =>
137153
{
138-
context.Items[AuthorizationFilterInvokedKey] = true;
139-
140-
var result = await next(context, cancellationToken);
141-
await FilterAuthorizedItemsAsync(
142-
result.ResourceTemplates, static resourceTemplate => resourceTemplate.McpServerResource,
143-
context.User, context.Services, context);
144-
return result;
154+
var resourceCollection = options.ResourceCollection;
155+
return async (context, cancellationToken) =>
156+
{
157+
context.Items[AuthorizationFilterInvokedKey] = true;
158+
159+
var result = await next(context, cancellationToken);
160+
await FilterAuthorizedItemsAsync(
161+
result.ResourceTemplates, resourceTemplate => resourceCollection is not null && resourceCollection.TryGetPrimitive(resourceTemplate.UriTemplate, out var serverResource) ? serverResource : null,
162+
context.User, context.Services, context);
163+
return result;
164+
};
145165
});
146166
}
147167

148168
private static void CheckListResourceTemplatesFilter(McpServerOptions options)
149169
{
150-
options.Filters.Request.ListResourceTemplatesFilters.Add(next => async (context, cancellationToken) =>
170+
options.Filters.Request.ListResourceTemplatesFilters.Add(next =>
151171
{
152-
var result = await next(context, cancellationToken);
153-
154-
if (HasAuthorizationMetadata(result.ResourceTemplates.Select(static resourceTemplate => resourceTemplate.McpServerResource))
155-
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
172+
var resourceCollection = options.ResourceCollection;
173+
return async (context, cancellationToken) =>
156174
{
157-
throw new InvalidOperationException("Authorization filter was not invoked for resources/templates/list operation, but authorization metadata was found on the resource templates. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
158-
}
175+
var result = await next(context, cancellationToken);
176+
177+
if (HasAuthorizationMetadata(result.ResourceTemplates.Select(resourceTemplate => resourceCollection is not null && resourceCollection.TryGetPrimitive(resourceTemplate.UriTemplate, out var serverResource) ? serverResource : null))
178+
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
179+
{
180+
throw new InvalidOperationException("Authorization filter was not invoked for resources/templates/list operation, but authorization metadata was found on the resource templates. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
181+
}
159182

160-
return result;
183+
return result;
184+
};
161185
});
162186
}
163187

@@ -193,31 +217,39 @@ private static void CheckReadResourceFilter(McpServerOptions options)
193217

194218
private void ConfigureListPromptsFilter(McpServerOptions options)
195219
{
196-
options.Filters.Request.ListPromptsFilters.Add(next => async (context, cancellationToken) =>
220+
options.Filters.Request.ListPromptsFilters.Add(next =>
197221
{
198-
context.Items[AuthorizationFilterInvokedKey] = true;
199-
200-
var result = await next(context, cancellationToken);
201-
await FilterAuthorizedItemsAsync(
202-
result.Prompts, static prompt => prompt.McpServerPrompt,
203-
context.User, context.Services, context);
204-
return result;
222+
var promptCollection = options.PromptCollection;
223+
return async (context, cancellationToken) =>
224+
{
225+
context.Items[AuthorizationFilterInvokedKey] = true;
226+
227+
var result = await next(context, cancellationToken);
228+
await FilterAuthorizedItemsAsync(
229+
result.Prompts, prompt => promptCollection is not null && promptCollection.TryGetPrimitive(prompt.Name, out var serverPrompt) ? serverPrompt : null,
230+
context.User, context.Services, context);
231+
return result;
232+
};
205233
});
206234
}
207235

208236
private static void CheckListPromptsFilter(McpServerOptions options)
209237
{
210-
options.Filters.Request.ListPromptsFilters.Add(next => async (context, cancellationToken) =>
238+
options.Filters.Request.ListPromptsFilters.Add(next =>
211239
{
212-
var result = await next(context, cancellationToken);
213-
214-
if (HasAuthorizationMetadata(result.Prompts.Select(static prompt => prompt.McpServerPrompt))
215-
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
240+
var promptCollection = options.PromptCollection;
241+
return async (context, cancellationToken) =>
216242
{
217-
throw new InvalidOperationException("Authorization filter was not invoked for prompts/list operation, but authorization metadata was found on the prompts. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
218-
}
243+
var result = await next(context, cancellationToken);
244+
245+
if (HasAuthorizationMetadata(result.Prompts.Select(prompt => promptCollection is not null && promptCollection.TryGetPrimitive(prompt.Name, out var serverPrompt) ? serverPrompt : null))
246+
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
247+
{
248+
throw new InvalidOperationException("Authorization filter was not invoked for prompts/list operation, but authorization metadata was found on the prompts. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
249+
}
219250

220-
return result;
251+
return result;
252+
};
221253
});
222254
}
223255

src/ModelContextProtocol.Core/Protocol/Prompt.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Diagnostics;
22
using System.Text.Json.Nodes;
33
using System.Text.Json.Serialization;
4-
using ModelContextProtocol.Server;
54

65
namespace ModelContextProtocol.Protocol;
76

@@ -72,12 +71,6 @@ public sealed class Prompt : IBaseMetadata
7271
[JsonPropertyName("_meta")]
7372
public JsonObject? Meta { get; set; }
7473

75-
/// <summary>
76-
/// Gets or sets the callable server prompt corresponding to this metadata if any.
77-
/// </summary>
78-
[JsonIgnore]
79-
public McpServerPrompt? McpServerPrompt { get; set; }
80-
8174
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
8275
private string DebuggerDisplay
8376
{

src/ModelContextProtocol.Core/Protocol/Resource.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Diagnostics.CodeAnalysis;
33
using System.Text.Json.Nodes;
44
using System.Text.Json.Serialization;
5-
using ModelContextProtocol.Server;
65

76
namespace ModelContextProtocol.Protocol;
87

@@ -101,10 +100,4 @@ public sealed class Resource : IBaseMetadata
101100
/// </remarks>
102101
[JsonPropertyName("_meta")]
103102
public JsonObject? Meta { get; set; }
104-
105-
/// <summary>
106-
/// Gets or sets the callable server resource corresponding to this metadata if any.
107-
/// </summary>
108-
[JsonIgnore]
109-
public McpServerResource? McpServerResource { get; set; }
110103
}

src/ModelContextProtocol.Core/Protocol/ResourceTemplate.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Text.Json.Nodes;
22
using System.Text.Json.Serialization;
3-
using ModelContextProtocol.Server;
43

54
namespace ModelContextProtocol.Protocol;
65

@@ -94,12 +93,6 @@ public sealed class ResourceTemplate : IBaseMetadata
9493
[JsonIgnore]
9594
public bool IsTemplated => UriTemplate.Contains('{');
9695

97-
/// <summary>
98-
/// Gets or sets the callable server resource corresponding to this metadata, if any.
99-
/// </summary>
100-
[JsonIgnore]
101-
public McpServerResource? McpServerResource { get; set; }
102-
10396
/// <summary>Converts the <see cref="ResourceTemplate"/> into a <see cref="Resource"/>.</summary>
10497
/// <returns>A <see cref="Resource"/> if <see cref="IsTemplated"/> is <see langword="false"/>; otherwise, <see langword="null"/>.</returns>
10598
public Resource? AsResource()
@@ -119,7 +112,6 @@ public sealed class ResourceTemplate : IBaseMetadata
119112
Annotations = Annotations,
120113
Icons = Icons,
121114
Meta = Meta,
122-
McpServerResource = McpServerResource,
123115
};
124116
}
125117
}

src/ModelContextProtocol.Core/Protocol/Tool.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using ModelContextProtocol.Server;
21
using System.Diagnostics;
32
using System.Diagnostics.CodeAnalysis;
43
using System.Text.Json;
@@ -158,12 +157,6 @@ public ToolExecution? Execution
158157
[JsonPropertyName("_meta")]
159158
public JsonObject? Meta { get; set; }
160159

161-
/// <summary>
162-
/// Gets or sets the callable server tool corresponding to this metadata if any.
163-
/// </summary>
164-
[JsonIgnore]
165-
public McpServerTool? McpServerTool { get; set; }
166-
167160
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
168161
private string DebuggerDisplay
169162
{

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerPrompt.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ private AIFunctionMcpServerPrompt(AIFunction function, Prompt prompt, IReadOnlyL
182182
{
183183
AIFunction = function;
184184
ProtocolPrompt = prompt;
185-
ProtocolPrompt.McpServerPrompt = this;
186185
_metadata = metadata;
187186
}
188187

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerResource.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,6 @@ private AIFunctionMcpServerResource(AIFunction function, ResourceTemplate resour
294294
{
295295
AIFunction = function;
296296
ProtocolResourceTemplate = resourceTemplate;
297-
ProtocolResourceTemplate.McpServerResource = this;
298297
ProtocolResource = resourceTemplate.AsResource();
299298
_metadata = metadata;
300299

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ private AIFunctionMcpServerTool(AIFunction function, Tool tool, IServiceProvider
234234

235235
AIFunction = function;
236236
ProtocolTool = tool;
237-
ProtocolTool.McpServerTool = this;
238237

239238
_structuredOutputRequiresWrapping = structuredOutputRequiresWrapping;
240239
_metadata = metadata;

0 commit comments

Comments
 (0)