|
1 | | -# The engsys `everything` server |
| 1 | +# Azure SDK CLI and MCP server |
2 | 2 |
|
3 | | -This tool will serve as the primary integration point for all of the `azure-sdk` provided MCP tools. This tool will be built and published out of the `azure-sdk-tools` repo, but consumed primarily through the `.vscode/mcp.json` within each `Azure-sdk-for-X` language repo. Tool installation will be carried out by the eng/common scripts present at `eng/common/mcp/azure-sdk-mcp.ps`. |
| 3 | +This project is the primary integration point for all `azure-sdk` provided [MCP](https://modelcontextprotocol.io/introduction) tools as well as a convenient CLI app for azure sdk developers. It is built and published out of the `azure-sdk-tools` repo but consumed primarily through the `.vscode/mcp.json` file within each `Azure-sdk-for-<lang>` language repository. Server installation is carried out by the eng/common scripts present at `eng/common/mcp/azure-sdk-mcp.ps1`. |
4 | 4 |
|
5 | | -## Integration |
| 5 | +* [Getting Started](#getting-started) |
| 6 | + * [Prerequisites](#prerequisites) |
| 7 | + * [Setup](#setup) |
| 8 | + * [Build](#build) |
| 9 | + * [Run](#run) |
| 10 | + * [Test](#test) |
| 11 | +* [Project Structure and Information](#project-structure-and-information) |
| 12 | + * [Directory Structure](#directory-structure) |
| 13 | + * [Pipelines](#pipelines) |
| 14 | +* [Adding a New Tool](#adding-a-new-tool) |
6 | 15 |
|
7 | | -This `everything` or `hub` server starts up and _should_ be able to pass requests for the requested tool. How the server actually runs these classes is very important. Especially when it comes to versioning etc. |
| 16 | +## Getting Started |
8 | 17 |
|
9 | | -These are different proposals for how we can organize this. Examples will be linked within this same folder until we settle on one. |
| 18 | +### Prerequisites |
10 | 19 |
|
11 | | -### Specific classes within a server |
| 20 | +- [.NET 8.0 SDK or later](https://dotnet.microsoft.com/download) |
12 | 21 |
|
13 | | -Users will add classes to a specific folder in the hub server's code. These classes will have to meet an interface, but will be free to implement however they want other than that. |
| 22 | +### Setup |
14 | 23 |
|
15 | | -|Pro/Con|Description| |
16 | | -|---|---| |
17 | | -|✅|Very easy for users to add new functionalities.| |
18 | | -|🟥|Version selection will be gated at the server.| |
19 | | -|🟥|Aside from disabling specific `tools` and changing installed version of the `hub` server, users won't be able to customize their server installation| |
| 24 | +1. Clone the repository: |
| 25 | + ```sh |
| 26 | + git clone https://github.com/Azure/azure-sdk-tools.git |
| 27 | + cd azure-sdk-tools/tools/azsdk-cli |
| 28 | + ``` |
20 | 29 |
|
21 | | -### Individual MCP servers that are **referenced** from `hub` |
| 30 | +2. Restore dependencies: |
| 31 | + ```sh |
| 32 | + dotnet restore |
| 33 | + ``` |
22 | 34 |
|
23 | | -Everything server csproj: |
| 35 | +### Build |
24 | 36 |
|
25 | | -```xml |
26 | | - <ItemGroup> |
27 | | - <PackageReference Include="Azure.SDK.Tools.MCP.ToolName1" Version="1.0.0" /> |
28 | | - <PackageReference Include="Azure.SDK.Tools.MCP.ToolName2" Version="1.0.0" /> |
29 | | - <PackageReference Include="Azure.SDK.Tools.MCP.ToolName3" Version="1.0.0" /> |
| 37 | +To build the project: |
| 38 | + |
| 39 | +```sh |
| 40 | +dotnet build |
| 41 | +``` |
| 42 | + |
| 43 | +### Run |
| 44 | + |
| 45 | +To run the CLI locally: |
| 46 | + |
| 47 | +```sh |
| 48 | +dotnet run --project Azure.Sdk.Tools.Cli -- --help |
30 | 49 | ``` |
31 | 50 |
|
32 | | -My vision here is that these individual tools should be: |
33 | | -- implemented as standalone servers |
34 | | -- when DI-ed into our `hub` server, provide a `route` that can be provided by the hub server |
| 51 | +### Test |
| 52 | + |
| 53 | +To run the tests: |
| 54 | + |
| 55 | +```sh |
| 56 | +dotnet test |
| 57 | +``` |
| 58 | + |
| 59 | +## Project Structure and Information |
| 60 | + |
| 61 | +This project is both a [System.CommandLine](https://learn.microsoft.com/en-us/dotnet/standard/commandline/) app and an MCP server using the [MCP C# SDK](https://github.com/modelcontextprotocol/csharp-sdk). |
35 | 62 |
|
36 | | -This way, users can add local `mcp` |
| 63 | +### Directory Structure |
37 | 64 |
|
38 | | -|Pro/Con|Description| |
39 | | -|---|---| |
40 | | -|✅|Tools will work standalone for easy development and testing.| |
41 | | -|✅|Much more granular control over what versions of which tools are present in the hub.| |
42 | | -|🟥|Users will have to match a server convention at the very least, and implement an interface that makes their actual workload pluggable into the `hub`.| |
43 | | -|🟥|EngSys will need to add good integration testing of the contract, so that local development -> deployment in `everything server` will never surprise them.| |
| 65 | +- *Azure.Sdk.Tools.Cli* - Core project for cli/mcp logic |
| 66 | + - *Commands* - Shared classes for CLI commands |
| 67 | + - *Configuration* - Constants and other classes |
| 68 | + - *Helpers* - Helper logic for parsing data |
| 69 | + - *Models* - Shared models, response classes and schemas |
| 70 | + - *Services* - Helper classes for working with upstream services, e.g. azure, devops, github |
| 71 | + - *Tools* - CLI commands and MCP tool implementations |
| 72 | +- *Azure.Sdk.Tools.Cli.Tests* - Test project |
| 73 | +- *Azure.Sdk.Tools.Cli.Contract* - Common classes/interfaces |
| 74 | +- *Azure.Sdk.Tools.Cli.Analyzer* - Compilation addons to enforce conventions |
| 75 | + - Enforce all tools handled by try/catch |
| 76 | + - Enforce tool inclusion in service registration for dependency injector |
44 | 77 |
|
45 | | -## Additional features |
| 78 | +### Pipelines |
46 | 79 |
|
47 | | -Concept of `chaining` of various MCP servers. Can this hub support taking the output of one spoke and shoving it to another? We probably should right? |
| 80 | +Public CI - https://dev.azure.com/azure-sdk/public/_build?definitionId=7677 |
48 | 81 |
|
| 82 | +Release - https://dev.azure.com/azure-sdk/internal/_build?definitionId=7684 |
49 | 83 |
|
50 | | -## Some random DOs and DON'Ts of this server |
| 84 | +## Design Guidelines |
| 85 | + |
| 86 | +- Think of the server primarily as a first class CLI app |
| 87 | + - Add attributes to enable MCP hooks, but MCP server functionality is a pluggable feature, not foundational to the architecture |
| 88 | + - Rapid ad-hoc testing is easier via CLI than MCP, and any tools we build can be consumed by other software/scripts outside of MCP |
| 89 | + - For example, the engsys/azsdk cli app is built around System.CommandLine along with some dependency injection and ASP.net glue + attributes to get it working with the MCP C# sdk |
| 90 | +- Return structured data from all tools/commands. Define response classes that can `ToString()` or `ToJson()` for different output modes (and handle failure flows) |
| 91 | +- Write debug logging to stderr and/or a file in MCP mode. This avoids the misleading "FAILURE TO PARSE MESSAGE" type errors in the MCP client logs |
| 92 | +- Support both stdio and http mode for MCP to enable easy debugging with tools like mcp inspector |
| 93 | +- Where possible, avoid dependencies/pre-requisites requiring manual setup, prefer being able to set them up within the app (e.g. az login, gh login, etc.) |
| 94 | +
|
| 95 | +## Adding a New Tool |
| 96 | +
|
| 97 | +Tool classes are the core of the azure sdk app and implement CLI commands or MCP server tools. To add a new tool start with the following: |
| 98 | +
|
| 99 | +- Determine the right directory and tool class name under `Azure.Sdk.Tools.Cli/Tools` |
| 100 | +- Reference or copy from the [hello world tool](Azure.Sdk.Tools.Cli/Tools/HelloWorldTool/HelloWorldTool.cs) for an example. |
| 101 | +- See [Tools/README.md](./Azure.Sdk.Tools.Cli/Tools/README.md) for more details |
| 102 | +
|
| 103 | +Each tool class should implement a `GetCommand()` method and a `HandleCommand(...)` method. These allow the tools to be called from CLI mode. |
| 104 | +Some exceptions may apply on a case by case basis for tool classes where we implement MCP mode but not CLI mode and vice versa. |
| 105 | +
|
| 106 | +```csharp |
| 107 | +public override Command GetCommand() |
| 108 | +{ |
| 109 | + Command command = new("example", "An example CLI command"); |
| 110 | + command.SetHandler(async ctx => { await HandleCommand(ctx, ctx.GetCancellationToken()); }); |
| 111 | + return command; |
| 112 | +} |
| 113 | +
|
| 114 | +public override async Task HandleCommand(InvocationContext ctx, CancellationToken ct) |
| 115 | +{ |
| 116 | + var result = await SomeMethod(); |
| 117 | + ctx.ExitCode = ExitCode; |
| 118 | + output.Output(result); |
| 119 | +} |
| 120 | +``` |
| 121 | +
|
| 122 | +Additionally, the tool class and any methods that will be included in the MCP server tools list must have the MCP attributes: |
| 123 | +
|
| 124 | +```csharp |
| 125 | +[McpServerToolType, Description("Example tool")] |
| 126 | +public class ExampleTool(ILogger<ExampleTool> logger, IOutputService output) : MCPTool |
| 127 | +{ |
| 128 | + [McpServerTool(Name = "example-1"), Description("Example tool call 1")] |
| 129 | + public DefaultCommandResponse Success(string message) |
| 130 | + { |
| 131 | + try |
| 132 | + { |
| 133 | + return new() |
| 134 | + { |
| 135 | + Message = "success" |
| 136 | + } |
| 137 | + } |
| 138 | + catch (Exception ex) |
| 139 | + { |
| 140 | + SetFailure(1); |
| 141 | + return new() |
| 142 | + { |
| 143 | + ResponseError = $"failure: {ex.Message}" |
| 144 | + } |
| 145 | + } |
| 146 | + } |
| 147 | +} |
| 148 | +``` |
51 | 149 |
|
52 | | -- [x] DO build with the idea that authentication WILL be coming. Right now the sole protection we have is that these tools will be running in context of the "current user." This means access to `DefaultAzureCredential` should be enough to allow it to function. Users will be adding other external servers to their `mcp.json` at their own risk. |
53 | | - - What does this actually look like in practice? |
54 | | -- [x] DO Provide `--tools` startup parameter: |
55 | | - - Provide `--tools <name>,<name>,<name>` to _enable_ specific functionalities of the `hub` server? |
56 | | - - Provide `--tools-exclude <name>,<name>,<name>` to _disable_ specific functionalities of the `hub` server? |
| 150 | +**Rather than bubbling up exceptions, all `McpServerTool` methods must handle failures and format them into its response object. This allows tools to be interoperable between CLI and MCP mode.** |
0 commit comments