Skip to content

Commit 83a18ac

Browse files
Merge branch 'main' into feature/docker-based-server-examples
2 parents c459392 + 51a4fde commit 83a18ac

File tree

9 files changed

+349
-15
lines changed

9 files changed

+349
-15
lines changed

.github/skills/prepare-release/SKILL.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ Sort every PR into one of four categories. See [references/categorization.md](re
4545
```
4646

4747
**Attribution rules:**
48-
- Harvest `Co-authored-by` trailers from all commits in each PR's merge commit
49-
- For Copilot-authored PRs, check the `copilot_work_started` timeline event to identify the triggering user. That person becomes the primary author; `@Copilot` becomes a co-author
48+
- Harvest `Co-authored-by` trailers from **all commits** in each PR (not just the merge commit) to identify co-authors. Do this for every PR regardless of primary author.
49+
- For Copilot-authored PRs, additionally check the `copilot_work_started` timeline event to identify the triggering user. That person becomes the primary author; `@Copilot` becomes a co-author.
5050
- Omit the co-author parenthetical when there are none
5151
- Sort entries within each section by merge date (chronological)
5252

@@ -187,7 +187,7 @@ Only after explicit user confirmation in Step 11:
187187
## Edge Cases
188188

189189
- **PR spans categories**: categorize by primary intent
190-
- **Copilot timeline missing**: fall back to `Co-authored-by` trailers; if still unclear, use `@Copilot` as primary author
190+
- **Copilot timeline missing**: fall back to `Co-authored-by` trailers to determine whether `@Copilot` should be a co-author; if still unclear, use `@Copilot` as primary author
191191
- **No breaking changes**: omit the Breaking Changes section from release notes entirely
192192
- **Single breaking change**: use the same numbered format as multiple
193193
- **No user-facing changes**: if all PRs are documentation, tests, or infrastructure, flag that a release may not be warranted and ask the user whether to proceed

.github/skills/prepare-release/references/categorization.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Use this simplified format (GitHub auto-links `#PR` and `@user`):
4949
* Description #PR by @author
5050
```
5151

52-
For PRs with co-authors (harvested from `Co-authored-by` commit trailers):
52+
For PRs with co-authors (harvested from `Co-authored-by` trailers across **all commits** in the PR, not just the merge commit):
5353
```
5454
* Description #PR by @author (co-authored by @user1 @user2)
5555
```
@@ -64,7 +64,7 @@ For direct commits without an associated PR (e.g., version bumps merged directly
6464
* Bump version to v0.1.0-preview.12 by @halter73
6565
```
6666

67-
For Copilot-authored PRs, identify who triggered Copilot using the `copilot_work_started` timeline event on the PR. That person becomes the primary author, and @Copilot becomes a co-author:
67+
For Copilot-authored PRs, additionally identify who triggered Copilot using the `copilot_work_started` timeline event on the PR. That person becomes the primary author, and @Copilot becomes a co-author:
6868
```
6969
* Add trace-level logging for JSON-RPC payloads #1234 by @halter73 (co-authored by @Copilot)
7070
```

.github/skills/publish-release/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ Re-categorize all PRs in the commit range (including any new ones from Step 3).
6464

6565
1. **Re-run the breaking change audit** using the **breaking-changes** skill if new PRs were found that may introduce breaks. Otherwise, carry forward the results from the prepare-release PR.
6666
2. **Re-categorize** all PRs into sections (What's Changed, Documentation, Tests, Infrastructure).
67-
3. **Re-attribute** co-authors for any new PRs.
67+
3. **Re-attribute** co-authors for any new PRs by harvesting `Co-authored-by` trailers from all commits in each PR.
6868
4. **Update acknowledgements** to include contributors from new PRs.
6969

7070
### Step 5: Validate README Code Samples
@@ -125,7 +125,7 @@ When the user requests revisions after the initial creation, always rewrite the
125125
- **PR not found**: if the prepare-release PR cannot be identified, offer to proceed manually by specifying a version and target commit
126126
- **Draft already exists**: if a draft release with the same tag already exists, offer to update it
127127
- **PR spans categories**: categorize by primary intent
128-
- **Copilot timeline missing**: fall back to `Co-authored-by` trailers; if still unclear, use `@Copilot` as primary author
128+
- **Copilot timeline missing**: fall back to `Co-authored-by` trailers to determine whether `@Copilot` should be a co-author; if still unclear, use `@Copilot` as primary author
129129
- **No breaking changes**: omit the Breaking Changes section entirely
130130
- **Single breaking change**: use the same numbered format as multiple
131131

.github/workflows/ci-code-coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
pattern: testresults-*
2525

2626
- name: Combine coverage reports
27-
uses: danielpalme/ReportGenerator-GitHub-Action@5.5.2
27+
uses: danielpalme/ReportGenerator-GitHub-Action@5.5.4
2828
with:
2929
reports: "**/*.cobertura.xml"
3030
targetdir: "${{ github.workspace }}/report"

Directory.Packages.props

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
<System8Version>8.0.22</System8Version>
55
<System9Version>9.0.11</System9Version>
6-
<System10Version>10.0.3</System10Version>
7-
<MicrosoftExtensionsVersion>10.3.0</MicrosoftExtensionsVersion>
6+
<System10Version>10.0.5</System10Version>
7+
<MicrosoftExtensionsVersion>10.4.1</MicrosoftExtensionsVersion>
88
</PropertyGroup>
99

1010
<!-- Product dependencies shared -->
@@ -62,12 +62,12 @@
6262

6363
<!-- Testing dependencies -->
6464
<ItemGroup>
65-
<PackageVersion Include="Anthropic" Version="12.8.0" />
65+
<PackageVersion Include="Anthropic" Version="12.9.0" />
6666
<PackageVersion Include="coverlet.collector" Version="8.0.0">
6767
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
6868
<PrivateAssets>all</PrivateAssets>
6969
</PackageVersion>
70-
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="10.2.0-preview.1.26063.2" />
70+
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="$(MicrosoftExtensionsVersion)" />
7171
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="$(System10Version)" />
7272
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="$(System10Version)" />
7373
<PackageVersion Include="Microsoft.Extensions.Logging" Version="$(System10Version)" />
@@ -92,6 +92,6 @@
9292
<PackageVersion Include="xunit.v3" Version="3.2.2" />
9393
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
9494
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
95-
<PackageVersion Include="JsonSchema.Net" Version="9.1.1" />
95+
<PackageVersion Include="JsonSchema.Net" Version="9.1.3" />
9696
</ItemGroup>
97-
</Project>
97+
</Project>

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,13 @@ private static McpServerToolCreateOptions DeriveOptions(MethodInfo method, McpSe
206206

207207
newOptions.UseStructuredContent = toolAttr.UseStructuredContent;
208208

209+
if (toolAttr.OutputSchemaType is Type outputSchemaType)
210+
{
211+
newOptions.OutputSchema ??= AIJsonUtilities.CreateJsonSchema(outputSchemaType,
212+
serializerOptions: newOptions.SerializerOptions ?? McpJsonUtilities.DefaultOptions,
213+
inferenceOptions: newOptions.SchemaCreateOptions);
214+
}
215+
209216
if (toolAttr._taskSupport is { } taskSupport)
210217
{
211218
newOptions.Execution ??= new ToolExecution();
@@ -487,7 +494,17 @@ schema.ValueKind is not JsonValueKind.Object ||
487494
return null;
488495
}
489496

490-
if (function.ReturnJsonSchema is not JsonElement outputSchema)
497+
// Explicit OutputSchema takes precedence over AIFunction's return schema.
498+
JsonElement outputSchema;
499+
if (toolCreateOptions.OutputSchema is { } explicitSchema)
500+
{
501+
outputSchema = explicitSchema;
502+
}
503+
else if (function.ReturnJsonSchema is { } returnSchema)
504+
{
505+
outputSchema = returnSchema;
506+
}
507+
else
491508
{
492509
return null;
493510
}

src/ModelContextProtocol.Core/Server/McpServerToolAttribute.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,27 @@ public bool ReadOnly
265265
/// </remarks>
266266
public bool UseStructuredContent { get; set; }
267267

268+
/// <summary>
269+
/// Gets or sets a <see cref="Type"/> from which to generate the tool's output schema.
270+
/// </summary>
271+
/// <value>
272+
/// The default is <see langword="null"/>, which means the output schema is inferred from the return type.
273+
/// </value>
274+
/// <remarks>
275+
/// <para>
276+
/// When set, a JSON schema is generated from the specified <see cref="Type"/> and used as the
277+
/// <see cref="Tool.OutputSchema"/> instead of the schema inferred from the tool method's return type.
278+
/// This is particularly useful when a tool method returns <see cref="CallToolResult"/> directly
279+
/// (to control properties like <see cref="Result.Meta"/>, <see cref="CallToolResult.IsError"/>,
280+
/// or <see cref="CallToolResult.StructuredContent"/>) but still needs to advertise a meaningful output
281+
/// schema to clients.
282+
/// </para>
283+
/// <para>
284+
/// <see cref="UseStructuredContent"/> must also be set to <see langword="true"/> for this property to take effect.
285+
/// </para>
286+
/// </remarks>
287+
public Type? OutputSchemaType { get; set; }
288+
268289
/// <summary>
269290
/// Gets or sets the source URI for the tool's icon.
270291
/// </summary>

src/ModelContextProtocol.Core/Server/McpServerToolCreateOptions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,26 @@ public sealed class McpServerToolCreateOptions
129129
/// </remarks>
130130
public bool UseStructuredContent { get; set; }
131131

132+
/// <summary>
133+
/// Gets or sets an explicit JSON schema to use as the tool's output schema.
134+
/// </summary>
135+
/// <value>
136+
/// The default is <see langword="null"/>, which means the output schema is inferred from the return type.
137+
/// </value>
138+
/// <remarks>
139+
/// <para>
140+
/// When set, this schema is used as the <see cref="Tool.OutputSchema"/> instead of the schema
141+
/// inferred from the tool method's return type. This is particularly useful when a tool method
142+
/// returns <see cref="CallToolResult"/> directly (to control properties like <see cref="Result.Meta"/>,
143+
/// <see cref="CallToolResult.IsError"/>, or <see cref="CallToolResult.StructuredContent"/>) but still
144+
/// needs to advertise a meaningful output schema to clients.
145+
/// </para>
146+
/// <para>
147+
/// <see cref="UseStructuredContent"/> must also be set to <see langword="true"/> for this property to take effect.
148+
/// </para>
149+
/// </remarks>
150+
public JsonElement? OutputSchema { get; set; }
151+
132152
/// <summary>
133153
/// Gets or sets the JSON serializer options to use when marshalling data to/from JSON.
134154
/// </summary>
@@ -209,6 +229,7 @@ internal McpServerToolCreateOptions Clone() =>
209229
OpenWorld = OpenWorld,
210230
ReadOnly = ReadOnly,
211231
UseStructuredContent = UseStructuredContent,
232+
OutputSchema = OutputSchema,
212233
SerializerOptions = SerializerOptions,
213234
SchemaCreateOptions = SchemaCreateOptions,
214235
Metadata = Metadata,

0 commit comments

Comments
 (0)