Skip to main content
Version: Latest

MCP Resource Types

Register custom resource type handlers to expose files, data, or content from any protocol as MCP resources.

Quick Start​

builder.Services
.AddCoreAIMcpServer()
.AddCoreAIFtpMcpResources()
.AddCoreAISftpMcpResources()
.AddMcpResourceType<MyDatabaseResourceHandler>("database");

Or, using the builder pattern with stores:

builder.Services.AddCrestAppsCore(crestApps => crestApps
.AddAISuite(ai => ai
.AddMcpServer(mcpServer => mcpServer
.AddYesSqlStores()
.AddFtpResources()
.AddSftpResources()
)
)
);

Problem & Solution​

MCP resources represent files, URLs, or data that clients can read. FTP and SFTP handlers are available as optional packages (CrestApps.Core.AI.Ftp and CrestApps.Core.AI.Sftp), and applications often need additional resource types for databases, APIs, blob storage, or custom protocols. Resource type handlers provide a pluggable extension point.

Built-in Resource Types​

TypeHandlerProtocol
ftpFtpResourceTypeHandlerFTP/FTPS
sftpSftpResourceTypeHandlerSFTP
datasource-figureDataSourceFigureResourceHandlerKnowledge figures and charts in a File data source

Register them explicitly with AddCoreAIFtpMcpResources(), AddCoreAISftpMcpResources() and AddCoreAIKnowledgeMcpResources().

Knowledge figures​

CrestApps.Core.AI.Mcp.Knowledge publishes one template, crestapps://datasource/{dataSourceId}/figure/{figureId} — the same address a search result carries, so a client can read a figure straight out of what a search told it. Listing resources never enumerates the figures in a knowledge base; only the template is published.

A canonical identifier is short and guessable, so the handler establishes that the object belongs to the data source in the address and is actually a figure or chart before it serves any bytes. Anything else is a not-found.

Registration​

builder.Services.AddMcpResourceType<MyHandler>("my-type", entry =>
{
entry.DisplayName = "My Resource Type";
entry.Description = "Reads resources from my custom source";
});

AddMcpResourceType<THandler>(type, configure?)​

ParameterDescription
typeUnique type identifier string
configureOptional action to set display name and description

Implementing a Resource Type Handler​

public sealed class BlobStorageResourceHandler : McpResourceTypeHandlerBase
{
private readonly BlobServiceClient _blobClient;

public BlobStorageResourceHandler(BlobServiceClient blobClient)
{
_blobClient = blobClient;
}

protected override async Task<McpResourceReadResult> GetResultAsync(
McpResourceReadContext context,
CancellationToken cancellationToken)
{
var containerClient = _blobClient.GetBlobContainerClient(context.ContainerName);
var blobClient = containerClient.GetBlobClient(context.ResourcePath);

var download = await blobClient.DownloadContentAsync(cancellationToken);
var content = download.Value.Content.ToString();

return new McpResourceReadResult
{
Contents = [new TextResourceContents
{
Text = content,
Uri = context.Uri,
MimeType = "text/plain",
}],
};
}
}

Key Interfaces​

IMcpResourceTypeHandler​

public interface IMcpResourceTypeHandler
{
Task<McpResourceReadResult> ReadAsync(
McpResourceReadContext context,
CancellationToken cancellationToken = default);
}

McpResourceTypeHandlerBase​

A convenience base class — implement GetResultAsync() instead:

protected abstract Task<McpResourceReadResult> GetResultAsync(
McpResourceReadContext context,
CancellationToken cancellationToken);