Skip to content

Commit f46474b

Browse files
authored
Merge branch 'main' into copilot/fix-tojsonobject-issue
2 parents c1212c6 + aa2f8f4 commit f46474b

9 files changed

Lines changed: 452 additions & 25 deletions

File tree

docs/concepts/elicitation/elicitation.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ uid: elicitation
1010
The **elicitation** feature allows servers to request additional information from users during interactions. This enables more dynamic and interactive AI experiences, making it easier to gather necessary context before executing tasks.
1111

1212
The protocol supports two modes of elicitation:
13-
- **Form (In-Band)**: The server requests structured data (strings, numbers, booleans, enums) which the client collects via a form interface and returns to the server.
14-
- **URL Mode**: The server provides a URL for the user to visit (e.g., for OAuth, payments, or sensitive data entry). The interaction happens outside the MCP client.
13+
14+
- **Form (In-Band)**: The server requests structured data (strings, numbers, Booleans, enums) which the client collects via a form interface and returns to the server.
15+
- **URL Mode**: The server provides a URL for the user to visit (for example, for OAuth, payments, or sensitive data entry). The interaction happens outside the MCP client.
1516

1617
### Server Support for Elicitation
1718

@@ -208,6 +209,7 @@ await using var completionHandler = client.RegisterNotificationHandler(
208209
```
209210

210211
This pattern is particularly useful for:
212+
211213
- **Third-party OAuth flows**: When the MCP server needs to obtain tokens from external services on behalf of the user
212214
- **Payment processing**: When user confirmation is required through a secure payment interface
213215
- **Sensitive credential collection**: When API keys or other secrets must be entered directly on a trusted server page rather than through the MCP client

docs/concepts/httpcontext/httpcontext.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ uid: httpcontext
88
## HTTP Context
99

1010
When using the Streamable HTTP transport, an MCP server might need to access the underlying [HttpContext] for a request.
11-
The [HttpContext] contains request metadata such as the HTTP headers, authorization context, and the actual path and query string for the request.
11+
The [HttpContext] object contains request metadata such as the HTTP headers, authorization context, and the actual path and query string for the request.
1212

1313
To access the [HttpContext], the MCP server should add the [IHttpContextAccessor] service to the application service collection (typically in Program.cs).
1414
Then any classes, for example, a class containing MCP tools, should accept an [IHttpContextAccessor] in their constructor and store this for use by its methods.

docs/concepts/index.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,13 @@
1+
# Conceptual documentation
12

23
Welcome to the conceptual documentation for the Model Context Protocol SDK. Here you'll find high-level overviews, explanations, and guides to help you understand how the SDK implements the Model Context Protocol.
4+
5+
## Contents
6+
7+
| Title | Description |
8+
| - | - |
9+
| [Progress tracking](progress/progress.md) | Learn how to track progress for long-running operations through notification messages. |
10+
| [Elicitation](elicitation/elicitation.md) | Learn how to request additional information from users during interactions. |
11+
| [Logging](logging/logging.md) | Learn how to implement logging in MCP servers and how clients can consume log messages. |
12+
| [HTTP Context](httpcontext/httpcontext.md) | Learn how to access the underlying `HttpContext` for a request. |
13+
| [MCP Server Handler Filters](filters.md) | Learn how to add filters to the handler pipeline. Filters let you wrap the original handler with additional functionality. |

docs/index.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ _layout: landing
44

55
# Overview
66

7-
The official C# SDK for the [Model Context Protocol](https://modelcontextprotocol.io/), enabling .NET applications, services, and libraries to implement and interact with MCP clients and servers. For more details on available functionality, please see the [API documentation](https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.html).
7+
This SDK is the official C# SDK for the [Model Context Protocol](https://modelcontextprotocol.io/), enabling .NET applications, services, and libraries to implement and interact with MCP clients and servers.
8+
9+
For more details on available functionality, see:
10+
11+
- [Conceptual documentation](https://modelcontextprotocol.github.io/csharp-sdk/concepts/index.html)
12+
- [API documentation](https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.html).
813

914
## About MCP
1015

1116
The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to Large Language Models (LLMs). It enables secure integration between LLMs and various data sources and tools.
1217

1318
For more information about MCP:
1419

15-
- [Official Documentation](https://modelcontextprotocol.io/)
20+
- [Official MCP Documentation](https://modelcontextprotocol.io/)
1621
- [Protocol Specification](https://modelcontextprotocol.io/specification/)
1722
- [GitHub Organization](https://github.com/modelcontextprotocol)
1823

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using Microsoft.CodeAnalysis.Diagnostics;
5+
using System.Collections.Generic;
6+
using System.Collections.Immutable;
7+
using System.Threading;
8+
9+
namespace ModelContextProtocol.Analyzers;
10+
11+
/// <summary>
12+
/// Suppresses CS1066 warnings for MCP server methods that have optional parameters.
13+
/// </summary>
14+
/// <remarks>
15+
/// <para>
16+
/// CS1066 is issued when a partial method's implementing declaration has default parameter values.
17+
/// For partial methods, only the defining declaration's defaults are used by callers,
18+
/// making the implementing declaration's defaults redundant.
19+
/// </para>
20+
/// <para>
21+
/// However, for MCP tool, prompt, and resource methods, users often want to specify default values
22+
/// in their implementing declaration for documentation purposes. The XmlToDescriptionGenerator
23+
/// automatically copies these defaults to the generated defining declaration, making them functional.
24+
/// </para>
25+
/// <para>
26+
/// This suppressor suppresses CS1066 for methods marked with [McpServerTool], [McpServerPrompt],
27+
/// or [McpServerResource] attributes, allowing users to specify defaults in their code without warnings.
28+
/// </para>
29+
/// </remarks>
30+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
31+
public sealed class CS1066Suppressor : DiagnosticSuppressor
32+
{
33+
private static readonly SuppressionDescriptor McpToolSuppression = new(
34+
id: "MCP_CS1066_TOOL",
35+
suppressedDiagnosticId: "CS1066",
36+
justification: "Default values on MCP tool method implementing declarations are copied to the generated defining declaration by the source generator.");
37+
38+
private static readonly SuppressionDescriptor McpPromptSuppression = new(
39+
id: "MCP_CS1066_PROMPT",
40+
suppressedDiagnosticId: "CS1066",
41+
justification: "Default values on MCP prompt method implementing declarations are copied to the generated defining declaration by the source generator.");
42+
43+
private static readonly SuppressionDescriptor McpResourceSuppression = new(
44+
id: "MCP_CS1066_RESOURCE",
45+
suppressedDiagnosticId: "CS1066",
46+
justification: "Default values on MCP resource method implementing declarations are copied to the generated defining declaration by the source generator.");
47+
48+
/// <inheritdoc/>
49+
public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions =>
50+
ImmutableArray.Create(McpToolSuppression, McpPromptSuppression, McpResourceSuppression);
51+
52+
/// <inheritdoc/>
53+
public override void ReportSuppressions(SuppressionAnalysisContext context)
54+
{
55+
// Cache semantic models and attribute symbols per syntax tree/compilation to avoid redundant calls
56+
Dictionary<SyntaxTree, SemanticModel>? semanticModelCache = null;
57+
INamedTypeSymbol? mcpToolAttribute = null;
58+
INamedTypeSymbol? mcpPromptAttribute = null;
59+
INamedTypeSymbol? mcpResourceAttribute = null;
60+
bool attributesResolved = false;
61+
62+
foreach (Diagnostic diagnostic in context.ReportedDiagnostics)
63+
{
64+
Location? location = diagnostic.Location;
65+
SyntaxTree? tree = location.SourceTree;
66+
if (tree is null)
67+
{
68+
continue;
69+
}
70+
71+
SyntaxNode root = tree.GetRoot(context.CancellationToken);
72+
SyntaxNode? node = root.FindNode(location.SourceSpan);
73+
74+
// Find the containing method declaration
75+
MethodDeclarationSyntax? method = node.FirstAncestorOrSelf<MethodDeclarationSyntax>();
76+
if (method is null)
77+
{
78+
continue;
79+
}
80+
81+
// Get or cache the semantic model for this tree
82+
semanticModelCache ??= new Dictionary<SyntaxTree, SemanticModel>();
83+
if (!semanticModelCache.TryGetValue(tree, out SemanticModel? semanticModel))
84+
{
85+
semanticModel = context.GetSemanticModel(tree);
86+
semanticModelCache[tree] = semanticModel;
87+
}
88+
89+
// Resolve attribute symbols once per compilation
90+
if (!attributesResolved)
91+
{
92+
mcpToolAttribute = semanticModel.Compilation.GetTypeByMetadataName(McpAttributeNames.McpServerToolAttribute);
93+
mcpPromptAttribute = semanticModel.Compilation.GetTypeByMetadataName(McpAttributeNames.McpServerPromptAttribute);
94+
mcpResourceAttribute = semanticModel.Compilation.GetTypeByMetadataName(McpAttributeNames.McpServerResourceAttribute);
95+
attributesResolved = true;
96+
}
97+
98+
// Check for MCP attributes
99+
SuppressionDescriptor? suppression = GetSuppressionForMethod(method, semanticModel, mcpToolAttribute, mcpPromptAttribute, mcpResourceAttribute, context.CancellationToken);
100+
if (suppression is not null)
101+
{
102+
context.ReportSuppression(Suppression.Create(suppression, diagnostic));
103+
}
104+
}
105+
}
106+
107+
private static SuppressionDescriptor? GetSuppressionForMethod(
108+
MethodDeclarationSyntax method,
109+
SemanticModel semanticModel,
110+
INamedTypeSymbol? mcpToolAttribute,
111+
INamedTypeSymbol? mcpPromptAttribute,
112+
INamedTypeSymbol? mcpResourceAttribute,
113+
CancellationToken cancellationToken)
114+
{
115+
IMethodSymbol? methodSymbol = semanticModel.GetDeclaredSymbol(method, cancellationToken);
116+
117+
if (methodSymbol is null)
118+
{
119+
return null;
120+
}
121+
122+
foreach (AttributeData attribute in methodSymbol.GetAttributes())
123+
{
124+
INamedTypeSymbol? attributeClass = attribute.AttributeClass;
125+
if (attributeClass is null)
126+
{
127+
continue;
128+
}
129+
130+
if (mcpToolAttribute is not null && SymbolEqualityComparer.Default.Equals(attributeClass, mcpToolAttribute))
131+
{
132+
return McpToolSuppression;
133+
}
134+
135+
if (mcpPromptAttribute is not null && SymbolEqualityComparer.Default.Equals(attributeClass, mcpPromptAttribute))
136+
{
137+
return McpPromptSuppression;
138+
}
139+
140+
if (mcpResourceAttribute is not null && SymbolEqualityComparer.Default.Equals(attributeClass, mcpResourceAttribute))
141+
{
142+
return McpResourceSuppression;
143+
}
144+
}
145+
146+
return null;
147+
}
148+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace ModelContextProtocol.Analyzers;
2+
3+
/// <summary>
4+
/// Contains the fully qualified metadata names for MCP server attributes.
5+
/// </summary>
6+
internal static class McpAttributeNames
7+
{
8+
public const string McpServerToolAttribute = "ModelContextProtocol.Server.McpServerToolAttribute";
9+
public const string McpServerPromptAttribute = "ModelContextProtocol.Server.McpServerPromptAttribute";
10+
public const string McpServerResourceAttribute = "ModelContextProtocol.Server.McpServerResourceAttribute";
11+
public const string DescriptionAttribute = "System.ComponentModel.DescriptionAttribute";
12+
}

src/ModelContextProtocol.Analyzers/XmlToDescriptionGenerator.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,14 @@ namespace ModelContextProtocol.Analyzers;
1818
public sealed class XmlToDescriptionGenerator : IIncrementalGenerator
1919
{
2020
private const string GeneratedFileName = "ModelContextProtocol.Descriptions.g.cs";
21-
private const string McpServerToolAttributeName = "ModelContextProtocol.Server.McpServerToolAttribute";
22-
private const string McpServerPromptAttributeName = "ModelContextProtocol.Server.McpServerPromptAttribute";
23-
private const string McpServerResourceAttributeName = "ModelContextProtocol.Server.McpServerResourceAttribute";
24-
private const string DescriptionAttributeName = "System.ComponentModel.DescriptionAttribute";
2521

2622
public void Initialize(IncrementalGeneratorInitializationContext context)
2723
{
2824
// Extract method information for all MCP tools, prompts, and resources.
2925
// The transform extracts all necessary data upfront so the output doesn't depend on the compilation.
30-
var allMethods = CreateProviderForAttribute(context, McpServerToolAttributeName).Collect()
31-
.Combine(CreateProviderForAttribute(context, McpServerPromptAttributeName).Collect())
32-
.Combine(CreateProviderForAttribute(context, McpServerResourceAttributeName).Collect())
26+
var allMethods = CreateProviderForAttribute(context, McpAttributeNames.McpServerToolAttribute).Collect()
27+
.Combine(CreateProviderForAttribute(context, McpAttributeNames.McpServerPromptAttribute).Collect())
28+
.Combine(CreateProviderForAttribute(context, McpAttributeNames.McpServerResourceAttribute).Collect())
3329
.Select(static (tuple, _) =>
3430
{
3531
var ((tools, prompts), resources) = tuple;
@@ -84,7 +80,7 @@ private static MethodToGenerate ExtractMethodInfo(
8480
Compilation compilation)
8581
{
8682
bool isPartial = methodDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword);
87-
var descriptionAttribute = compilation.GetTypeByMetadataName(DescriptionAttributeName);
83+
var descriptionAttribute = compilation.GetTypeByMetadataName(McpAttributeNames.DescriptionAttribute);
8884

8985
// Try to extract XML documentation
9086
var (xmlDocs, hasInvalidXml) = TryExtractXmlDocumentation(methodSymbol);

0 commit comments

Comments
 (0)