Skip to content

Commit 5c35ea9

Browse files
Copilotstephentoub
andauthored
Replace concrete collection types with interfaces in public API surface (#1326)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
1 parent 539481f commit 5c35ea9

File tree

7 files changed

+25
-25
lines changed

7 files changed

+25
-25
lines changed

src/ModelContextProtocol.Core/Authentication/DynamicClientRegistrationResponse.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public sealed class DynamicClientRegistrationResponse
2323
/// Gets or initializes the redirect URIs for the client.
2424
/// </summary>
2525
[JsonPropertyName("redirect_uris")]
26-
public string[]? RedirectUris { get; init; }
26+
public IList<string>? RedirectUris { get; init; }
2727

2828
/// <summary>
2929
/// Gets or initializes the token endpoint authentication method.
@@ -35,13 +35,13 @@ public sealed class DynamicClientRegistrationResponse
3535
/// Gets or initializes the grant types that the client will use.
3636
/// </summary>
3737
[JsonPropertyName("grant_types")]
38-
public string[]? GrantTypes { get; init; }
38+
public IList<string>? GrantTypes { get; init; }
3939

4040
/// <summary>
4141
/// Gets or initializes the response types that the client will use.
4242
/// </summary>
4343
[JsonPropertyName("response_types")]
44-
public string[]? ResponseTypes { get; init; }
44+
public IList<string>? ResponseTypes { get; init; }
4545

4646
/// <summary>
4747
/// Gets or initializes the timestamp at which the client ID was issued.

src/ModelContextProtocol.Core/Authentication/ProtectedResourceMetadata.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public sealed class ProtectedResourceMetadata
3535
/// OPTIONAL.
3636
/// </remarks>
3737
[JsonPropertyName("authorization_servers")]
38-
public List<string> AuthorizationServers { get; set; } = [];
38+
public IList<string> AuthorizationServers { get; set; } = [];
3939

4040
/// <summary>
4141
/// Gets or sets the supported bearer token methods.
@@ -48,7 +48,7 @@ public sealed class ProtectedResourceMetadata
4848
/// OPTIONAL.
4949
/// </remarks>
5050
[JsonPropertyName("bearer_methods_supported")]
51-
public List<string> BearerMethodsSupported { get; set; } = ["header"];
51+
public IList<string> BearerMethodsSupported { get; set; } = ["header"];
5252

5353
/// <summary>
5454
/// Gets or sets the supported scopes.
@@ -61,7 +61,7 @@ public sealed class ProtectedResourceMetadata
6161
/// RECOMMENDED.
6262
/// </remarks>
6363
[JsonPropertyName("scopes_supported")]
64-
public List<string> ScopesSupported { get; set; } = [];
64+
public IList<string> ScopesSupported { get; set; } = [];
6565

6666
/// <summary>
6767
/// Gets or sets the URL of the protected resource's JSON Web Key (JWK) Set document.
@@ -85,7 +85,7 @@ public sealed class ProtectedResourceMetadata
8585
/// OPTIONAL. No default algorithms are implied if this entry is omitted. The value "none" MUST NOT be used.
8686
/// </remarks>
8787
[JsonPropertyName("resource_signing_alg_values_supported")]
88-
public List<string>? ResourceSigningAlgValuesSupported { get; set; }
88+
public IList<string>? ResourceSigningAlgValuesSupported { get; set; }
8989

9090
/// <summary>
9191
/// Gets or sets the human-readable name of the protected resource intended for display to the end user.
@@ -157,7 +157,7 @@ public sealed class ProtectedResourceMetadata
157157
/// OPTIONAL.
158158
/// </remarks>
159159
[JsonPropertyName("authorization_details_types_supported")]
160-
public List<string>? AuthorizationDetailsTypesSupported { get; set; }
160+
public IList<string>? AuthorizationDetailsTypesSupported { get; set; }
161161

162162
/// <summary>
163163
/// Gets or sets the list of the JWS algorithm values supported by the resource server for validating DPoP proof JWTs.
@@ -170,7 +170,7 @@ public sealed class ProtectedResourceMetadata
170170
/// OPTIONAL.
171171
/// </remarks>
172172
[JsonPropertyName("dpop_signing_alg_values_supported")]
173-
public List<string>? DpopSigningAlgValuesSupported { get; set; }
173+
public IList<string>? DpopSigningAlgValuesSupported { get; set; }
174174

175175
/// <summary>
176176
/// Gets or sets a value indicating whether the protected resource always requires the use of DPoP-bound access tokens.

src/ModelContextProtocol.Core/Protocol/ContentBlock.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ public sealed class ToolResultContentBlock : ContentBlock
753753
/// audio, resource links, and embedded resources.
754754
/// </remarks>
755755
[JsonPropertyName("content")]
756-
public required List<ContentBlock> Content { get; set; }
756+
public required IList<ContentBlock> Content { get; set; }
757757

758758
/// <summary>
759759
/// Gets or sets an optional structured result object.

src/ModelContextProtocol.Core/Protocol/ListTasksRequestParams.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ public sealed class ListTasksResult : PaginatedResult
3030
/// Gets or sets the list of tasks.
3131
/// </summary>
3232
[JsonPropertyName("tasks")]
33-
public required McpTask[] Tasks { get; set; }
33+
public required IList<McpTask> Tasks { get; set; }
3434
}

src/ModelContextProtocol.Core/Server/McpServer.Methods.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ public async ValueTask<IList<McpTask>> ListTasksAsync(
462462
var taskResults = await ListTasksAsync(requestParams, cancellationToken).ConfigureAwait(false);
463463
if (tasks is null)
464464
{
465-
tasks = new List<McpTask>(taskResults.Tasks.Length);
465+
tasks = new List<McpTask>(taskResults.Tasks.Count);
466466
}
467467

468468
foreach (var mcpTask in taskResults.Tasks)

tests/ModelContextProtocol.Tests/Protocol/ListTasksResultTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public static void ListTasksResult_SerializationRoundTrip()
3838
// Assert
3939
Assert.NotNull(deserialized);
4040
Assert.NotNull(deserialized.Tasks);
41-
Assert.Equal(2, deserialized.Tasks.Length);
41+
Assert.Equal(2, deserialized.Tasks.Count);
4242
Assert.Equal(original.Tasks[0].TaskId, deserialized.Tasks[0].TaskId);
4343
Assert.Equal(original.Tasks[1].TaskId, deserialized.Tasks[1].TaskId);
4444
Assert.Equal(original.NextCursor, deserialized.NextCursor);

tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ public async Task ListTasksAsync_ReturnsAllTasks()
353353
var result = await store.ListTasksAsync(cancellationToken: TestContext.Current.CancellationToken);
354354

355355
// Assert
356-
Assert.Equal(2, result.Tasks.Length);
356+
Assert.Equal(2, result.Tasks.Count);
357357
Assert.Contains(result.Tasks, t => t.TaskId == task1.TaskId);
358358
Assert.Contains(result.Tasks, t => t.TaskId == task2.TaskId);
359359
Assert.Null(result.NextCursor);
@@ -397,9 +397,9 @@ public async Task ListTasksAsync_SupportsPagination()
397397
var secondPageResult = await store.ListTasksAsync(cursor: firstPageResult.NextCursor, cancellationToken: TestContext.Current.CancellationToken);
398398

399399
// Assert
400-
Assert.Equal(100, firstPageResult.Tasks.Length);
400+
Assert.Equal(100, firstPageResult.Tasks.Count);
401401
Assert.NotNull(firstPageResult.NextCursor);
402-
Assert.Equal(50, secondPageResult.Tasks.Length);
402+
Assert.Equal(50, secondPageResult.Tasks.Count);
403403
Assert.Null(secondPageResult.NextCursor);
404404
}
405405

@@ -779,11 +779,11 @@ public async Task ListTasksAsync_PaginationWithCustomPageSize()
779779
var result3 = await store.ListTasksAsync(cursor: result2.NextCursor, cancellationToken: TestContext.Current.CancellationToken);
780780

781781
// Assert
782-
Assert.Equal(10, result1.Tasks.Length);
782+
Assert.Equal(10, result1.Tasks.Count);
783783
Assert.NotNull(result1.NextCursor);
784-
Assert.Equal(10, result2.Tasks.Length);
784+
Assert.Equal(10, result2.Tasks.Count);
785785
Assert.NotNull(result2.NextCursor);
786-
Assert.Equal(5, result3.Tasks.Length);
786+
Assert.Equal(5, result3.Tasks.Count);
787787
Assert.Null(result3.NextCursor);
788788

789789
// Verify no duplicates across pages
@@ -854,7 +854,7 @@ public async Task ListTasksAsync_ConsistentWithExpiredTasksRemovedBetweenPages()
854854
var result2 = await store.ListTasksAsync(cursor: result1.NextCursor, cancellationToken: TestContext.Current.CancellationToken);
855855

856856
// Assert - First page should have 5 tasks, second page should have 0 (all expired)
857-
Assert.Equal(5, result1.Tasks.Length);
857+
Assert.Equal(5, result1.Tasks.Count);
858858
Assert.NotNull(result1.NextCursor);
859859
Assert.Empty(result2.Tasks);
860860
Assert.Null(result2.NextCursor);
@@ -874,7 +874,7 @@ public async Task ListTasksAsync_KeysetPaginationMaintainsConsistencyWithNewTask
874874

875875
// Get first page
876876
var result1 = await store.ListTasksAsync(cancellationToken: TestContext.Current.CancellationToken);
877-
Assert.Equal(5, result1.Tasks.Length);
877+
Assert.Equal(5, result1.Tasks.Count);
878878

879879
// Add more tasks between pages (these should appear in later queries, not retroactively in page 2)
880880
for (int i = 10; i < 15; i++)
@@ -886,7 +886,7 @@ public async Task ListTasksAsync_KeysetPaginationMaintainsConsistencyWithNewTask
886886
var result2 = await store.ListTasksAsync(cursor: result1.NextCursor, cancellationToken: TestContext.Current.CancellationToken);
887887

888888
// Assert - Second page should have 5 tasks from original set
889-
Assert.Equal(5, result2.Tasks.Length);
889+
Assert.Equal(5, result2.Tasks.Count);
890890
Assert.NotNull(result2.NextCursor);
891891

892892
// Verify no overlap between pages
@@ -1128,14 +1128,14 @@ public async Task ListTasksAsync_KeysetPaginationWorksWithIdenticalTimestamps()
11281128
var result1 = await store.ListTasksAsync(cancellationToken: TestContext.Current.CancellationToken);
11291129

11301130
// Assert - First page should have 5 tasks
1131-
Assert.Equal(5, result1.Tasks.Length);
1131+
Assert.Equal(5, result1.Tasks.Count);
11321132
Assert.NotNull(result1.NextCursor);
11331133

11341134
// Get second page using cursor
11351135
var result2 = await store.ListTasksAsync(cursor: result1.NextCursor, cancellationToken: TestContext.Current.CancellationToken);
11361136

11371137
// Assert - Second page should have 5 tasks
1138-
Assert.Equal(5, result2.Tasks.Length);
1138+
Assert.Equal(5, result2.Tasks.Count);
11391139
Assert.Null(result2.NextCursor); // No more pages
11401140

11411141
// Verify no overlap between pages
@@ -1180,7 +1180,7 @@ public async Task ListTasksAsync_TasksCreatedAfterFirstPageWithSameTimestampAppe
11801180

11811181
// Get first page - should have 5 tasks with a cursor
11821182
var result1 = await store.ListTasksAsync(cancellationToken: TestContext.Current.CancellationToken);
1183-
Assert.Equal(5, result1.Tasks.Length);
1183+
Assert.Equal(5, result1.Tasks.Count);
11841184
Assert.NotNull(result1.NextCursor);
11851185

11861186
// Now create 5 more tasks AFTER we got the first page cursor

0 commit comments

Comments
 (0)