Skip to content

XmlToDescriptionGenerator copies async modifier to partial declarations (CS1994) #1058

@jongalloway

Description

@jongalloway

The XmlToDescriptionGenerator copies all modifiers from the original method, including async, to the generated partial declaration. This is invalid C# - partial declarations cannot have the async modifier.

Reproduction

[McpServerToolType]
public partial class Tools
{
    /// <summary>Async tool</summary>
    [McpServerTool]
    public async partial Task<string> DoWorkAsync()
    {
        await Task.Delay(100);
        return "done";
    }
}

Compiler error

CS1994: The 'async' modifier can only be used in methods that have a body.

Generated code

// Invalid - partial declaration has async modifier
public async partial Task<string> DoWorkAsync();

Current workaround

Remove async from the implementation and delegate to a private async helper:

public partial Task<string> DoWorkAsync() => DoWorkAsyncCore();

private async Task<string> DoWorkAsyncCore()
{
    await Task.Delay(100);
    return "done";
}

This adds boilerplate and obscures the implementation.

Expected behavior

The generator should exclude the async modifier when copying modifiers to the partial declaration.

Source location

All modifiers are copied without filtering:
https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/ModelContextProtocol.Analyzers/XmlToDescriptionGenerator.cs#L323-L325

writer.Write(string.Join(" ", methodDeclaration.Modifiers.Select(m => m.Text)));

Suggested fix

Filter out the async modifier:

var modifiers = methodDeclaration.Modifiers
    .Where(m => m.Kind() != SyntaxKind.AsyncKeyword)
    .Select(m => m.Text);
writer.Write(string.Join(" ", modifiers));

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions