website/src/docs/hotchocolate/v16/guides/mcp-adapter.md
The MCP (Model Context Protocol) adapter exposes your Hot Chocolate GraphQL schema as MCP tools, prompts, and resources. AI agents and LLMs that support MCP can discover and call your GraphQL operations without any manual tool definition. The adapter reads your schema, converts GraphQL operations into MCP tool definitions with full input and output JSON schemas, and serves them over the MCP protocol.
This is useful when you want AI assistants to interact with your existing GraphQL API. Instead of writing custom integrations, you register the adapter and it handles the translation between MCP and GraphQL automatically.
Install the HotChocolate.Adapters.Mcp package:
dotnet add package HotChocolate.Adapters.Mcp
Register the MCP adapter on your GraphQL server and map the MCP endpoint:
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder
.AddGraphQL()
.AddQueryType<Query>()
.AddMutationType<Mutation>()
.AddMcp()
.AddMcpStorage(myStorage);
var app = builder.Build();
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapGraphQLMcp());
app.Run();
AddMcp() registers the MCP protocol handlers and directive types. AddMcpStorage() provides the tool and prompt definitions. MapGraphQLMcp() maps the MCP endpoint at /graphql/mcp by default.
Each MCP tool is defined by a GraphQL operation document. You create an OperationToolDefinition with a parsed GraphQL document that contains exactly one operation:
// Services/MyMcpStorage.cs
using HotChocolate.Adapters.Mcp.Storage;
using HotChocolate.Language;
var tool = new OperationToolDefinition(
Utf8GraphQLParser.Parse(
"""
query GetBooks {
books {
title
}
}
"""));
The adapter derives the tool name from the operation name, converting it to snake_case. The operation GetBooks becomes the MCP tool get_books. The operation's variable definitions become the tool's input parameters, and the selected fields define the output schema.
The adapter translates between GraphQL and MCP concepts:
| GraphQL Concept | MCP Concept |
|---|---|
| Query operation | Read-only tool (readOnlyHint: true) |
| Mutation operation | Tool (readOnlyHint: false) |
| Operation variables | Tool input parameters (JSON Schema) |
| Selected fields | Tool output schema (JSON Schema) |
| Operation name | Tool name (converted to snake_case) |
| Operation description | Tool description |
When an AI agent calls an MCP tool, the adapter takes the JSON arguments, maps them to GraphQL variables, executes the operation against your schema, and returns the result as structured JSON content. The response includes both data and errors fields, following the standard GraphQL response format.
The IMcpStorage interface provides tool and prompt definitions to the adapter. You implement this interface to load definitions from any source: a file system, database, or in-memory collection.
// Services/FileMcpStorage.cs
using HotChocolate.Adapters.Mcp.Storage;
public class FileMcpStorage : IMcpStorage
{
public async ValueTask<IEnumerable<OperationToolDefinition>>
GetOperationToolDefinitionsAsync(
CancellationToken cancellationToken = default)
{
// Load tool definitions from your preferred source.
var graphql = await File.ReadAllTextAsync(
"tools/get-books.graphql", cancellationToken);
var document = Utf8GraphQLParser.Parse(graphql);
return [new OperationToolDefinition(document)];
}
public ValueTask<IEnumerable<PromptDefinition>>
GetPromptDefinitionsAsync(
CancellationToken cancellationToken = default)
{
return ValueTask.FromResult(
Enumerable.Empty<PromptDefinition>());
}
// IMcpStorage also extends IObservable for both tool and
// prompt events, enabling hot-reload when definitions change.
public IDisposable Subscribe(
IObserver<OperationToolStorageEventArgs> observer)
=> /* your subscription logic */;
public IDisposable Subscribe(
IObserver<PromptStorageEventArgs> observer)
=> /* your subscription logic */;
}
The storage implements IObservable<OperationToolStorageEventArgs> and IObservable<PromptStorageEventArgs>. When you push change events through these observables, connected MCP clients receive a tools/list_changed or prompts/list_changed notification. This enables hot-reload: you can add, update, or remove tools at runtime without restarting the server.
MCP tool annotations provide hints to AI agents about a tool's behavior. The adapter infers default annotations from the operation type, but you can override them.
Default behavior:
destructiveHint: true and idempotentHint: false.readOnlyHint: true.Override on the tool definition:
var tool = new OperationToolDefinition(
Utf8GraphQLParser.Parse(
"""
mutation AddBook($title: String!) {
addBook(title: $title) { title }
}
"""))
{
DestructiveHint = false,
IdempotentHint = true,
OpenWorldHint = false
};
Override in the GraphQL schema:
You can annotate resolver methods with [McpToolAnnotations] to set hints at the schema level:
// Types/Mutation.cs
using HotChocolate.Adapters.Mcp.Directives;
public class Mutation
{
[McpToolAnnotations(DestructiveHint = false, IdempotentHint = true)]
public Book AddBook(string title) => new(title);
}
You can also apply annotations using the fluent descriptor API:
// Types/MutationType.cs
using HotChocolate.Adapters.Mcp.Extensions;
public class MutationType : ObjectType<Mutation>
{
protected override void Configure(
IObjectTypeDescriptor<Mutation> descriptor)
{
descriptor
.Field(m => m.AddBook(default!))
.McpToolAnnotations(
destructiveHint: false,
idempotentHint: true);
}
}
Annotations set on the OperationToolDefinition take priority over annotations set in the schema.
You can customize the display title and icons of a tool:
var tool = new OperationToolDefinition(
Utf8GraphQLParser.Parse("query GetBooks { books { title } }"))
{
Title = "Search Books",
Icons =
[
new IconDefinition(new Uri("https://example.com/books.png"))
{
MimeType = "image/png",
Sizes = ["48x48"],
Theme = "light"
}
]
};
The adapter supports MCP prompts, which are reusable prompt templates that AI agents can discover and use. Define prompts through your IMcpStorage implementation:
var prompt = new PromptDefinition("code_review")
{
Title = "Code Review",
Description =
"Asks the LLM to analyze code quality and suggest improvements.",
Arguments =
[
new PromptArgumentDefinition("code")
{
Title = "Code to Review",
Description = "The code to review",
Required = true
}
],
Messages =
[
new PromptMessageDefinition(
RoleDefinition.User,
new TextContentBlockDefinition(
"""
Please review this code:
```
{code}
```
"""))
]
};
You can configure the underlying MCP server options and add custom (non-GraphQL) tools through the AddMcp overload:
// Program.cs
builder
.AddGraphQL()
.AddQueryType<Query>()
.AddMcp(
configureServerOptions: options =>
{
options.InitializationTimeout = TimeSpan.FromSeconds(10);
},
configureServer: server =>
{
server.WithTools([typeof(MyCustomTool)]);
})
.AddMcpStorage(myStorage);
Custom tools registered through configureServer appear alongside the GraphQL-derived tools. This lets you mix GraphQL operations and native MCP tools in the same server.
The MCP endpoint defaults to /graphql/mcp. You can change the path:
app.UseEndpoints(endpoints =>
{
endpoints.MapGraphQLMcp("/api/mcp");
});
The adapter supports two MCP transport modes:
/sse and POST on /message sub-paths.In stateless mode, only the Streamable HTTP POST endpoint is available.
The MCP adapter works with Fusion gateway servers. Instead of AddGraphQL(), use AddGraphQLGateway() and the rest of the configuration remains the same:
// Program.cs
builder
.AddGraphQLGateway()
.AddInMemoryConfiguration(compositeSchema)
.AddHttpClientConfiguration("Subgraph", subgraphUri)
.AddMcp()
.AddMcpStorage(myStorage);
When the Fusion gateway schema changes (for example, a new subgraph is composed), connected MCP clients receive tool list changed notifications automatically.