This feature is currently in preview and may change before the final release. Functionality, configuration options, APIs, and behavior may be modified based on feedback and further development.
Purpose
An MCP server artifact exposes custom Link functionality as Model Context Protocol tools. Typical uses include:
-
Exposing controlled lookup or search functionality to an AI assistant.
-
Providing business operations that an MCP client can invoke.
-
Connecting an MCP client to Link and selected external systems through a purpose-built tool set.
An artifact describes its tools using Link contracts. It does not reference the Microsoft MCP SDK or configure HTTP transport. The Generic HTTP Handler host owns the MCP protocol, HTTP transport, authentication and routing.
Before developing a new artifact, check whether an existing Link Community Component already solves the use case.
How
Create a class that inherits Bizbrains.Link.Base.McpServerBase<T> from the Bizbrains.Link.Base package. This follows the normal Link artifact pattern: an ILinkConfig implementation provides configuration and a LinkStepFactoryBase<T> implementation registers and creates the artifact.
Override ConfigureServer. Use its IMcpServerConfiguration parameter to configure server metadata and register tools.
using Bizbrains.Link.Base;
using System.ComponentModel;
namespace Contoso.McpServers.CustomerLookup;
public class CustomerLookupMcpServer : McpServerBase<CustomerLookupConfig>
{
public override Task ConfigureServer(
IMcpServerConfiguration serverConfiguration,
CustomerLookupConfig config)
{
serverConfiguration
.SetTitle("Customer lookup")
.SetVersion("1.0.0")
.SetInstructions("Use the customer lookup tool to retrieve a customer by number.");
serverConfiguration
.MapTool("get_customer", (string customerNumber, string? countryCode) => GetCustomer(customerNumber, countryCode))
.WithTitle("Get customer")
.WithDescription("Returns a customer by customer number.")
.ConfigureAnnotations(annotations => annotations
.ReadOnly()
.Destructive(false)
.Idempotent()
.OpenWorld(false));
return Task.CompletedTask;
}
public CustomerResult GetCustomer(
[Description("The customer number to look up.")] string customerNumber,
[Description("Optional country code. Uses the configured default when omitted.")] string? countryCode = null)
{
return new CustomerResult
{
CustomerNumber = customerNumber,
CountryCode = countryCode ?? "DK",
Name = "Example customer"
};
}
}
Tool implementation using MapTool
A tool can be registered directly with MapTool, as in the preceding example. This is the recommended approach when the tool set is small or when each tool needs explicit configuration, and it follows the same delegate-mapping style as Advanced HTTP Handlers.
serverConfiguration
.MapTool("get_customer", (string customerNumber) => GetCustomer(customerNumber))
.WithTitle("Get customer")
.WithDescription("Returns a customer by customer number.")
.ConfigureAnnotations(annotations => annotations
.ReadOnly()
.Destructive(false)
.Idempotent()
.OpenWorld(false));
The delegate can be synchronous or asynchronous. Its parameters become the tool input schema and its return value is returned to the MCP client. Use simple, JSON-serializable parameter and return types.
Tool names must be unique within an MCP server. Treat a published tool name as a stable client contract.
Tool implementation using MapTools
MapTools(object) is an alternative for servers with several tools. It registers every public, internal or static method on the supplied object that is decorated with LinkMcpToolAttribute.
Use a separate tool container when this approach is chosen. It keeps MCP server setup, tool implementations and their dependencies separate and readable.
public override Task ConfigureServer(
IMcpServerConfiguration serverConfiguration,
CustomerLookupConfig config)
{
serverConfiguration
.SetTitle("Customer lookup")
.SetVersion("1.0.0")
.SetInstructions("Use the customer lookup tools to retrieve customers and addresses.");
serverConfiguration.MapTools(new CustomerLookupTools(config));
return Task.CompletedTask;
}
public class CustomerLookupTools(CustomerLookupConfig config)
{
[LinkMcpTool(
Name = "get_customer",
Title = "Get customer",
Description = "Returns a customer by customer number.",
ReadOnly = true,
Destructive = false,
Idempotent = true,
OpenWorld = false)]
public CustomerResult GetCustomer(
[Description("The customer number to look up.")] string customerNumber,
[Description("Optional country code. Uses the configured default when omitted.")] string? countryCode = null)
{
return new CustomerResult
{
CustomerNumber = customerNumber,
CountryCode = countryCode ?? config.DefaultCountryCode,
Name = "Example customer"
};
}
}
The tool container can receive configuration and services through its constructor. For services registered in the artifact factory, inject the tool container into the MCP server and pass that injected instance to MapTools.
LinkMcpToolAttribute supplies the same name, title, description and behavioral annotations that are configured fluently through MapTool.
Tool metadata
MCP clients use tool metadata to decide whether and how to invoke a tool. Provide an accurate description and annotations for each tool.
|
Attribute property |
Meaning |
|---|---|
|
|
Stable machine-readable tool name. Defaults to the method name. |
|
|
Human-readable tool title. |
|
|
What the tool does and when it should be used. A method-level |
|
|
The tool does not modify its environment. |
|
|
The tool may make destructive changes. |
|
|
A repeated call with identical arguments has no additional effect. |
|
|
The tool interacts with entities outside the controlled Link environment, for example an external system. |
Use System.ComponentModel.DescriptionAttribute on parameters. Clear parameter descriptions improve the schema presented to MCP clients.
The annotations are hints for clients. They do not enforce security, validation or business rules. Enforce those concerns in the tool implementation.
Configuration
An MCP server configuration class must implement ILinkConfig. Use the regular Link configuration attributes to expose configuration fields in the Link UI.
using Bizbrains.Link.Base;
using Bizbrains.Link.Base.ConfigAttributes;
namespace Contoso.McpServers.CustomerLookup;
public class CustomerLookupConfig : ILinkConfig
{
[LinkDisplay(
Name = "Default country code",
Description = "Country code used when the tool caller does not provide one.",
GroupName = "General",
Order = 1)]
[LinkRequired]
public string DefaultCountryCode { get; set; } = "DK";
}
Use LinkConfigBase only when its general step settings, including retry settings, are relevant to the server. A small configuration class that implements ILinkConfig directly is normally more appropriate for an MCP server.
Factory and dependency injection
Every Link artifact requires a factory. Register the MCP server as a transient service and resolve the same instance in Create.
using Bizbrains.Link.Base;
using Microsoft.Extensions.DependencyInjection;
namespace Contoso.McpServers.CustomerLookup;
public class CustomerLookupMcpServerFactory : LinkStepFactoryBase<ILinkMcpServer>
{
public override string StepDisplayName => "Customer lookup MCP server";
public override string StepDescription => "Exposes customer lookup tools through MCP.";
public override void ConfigureServices(IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<CustomerLookupMcpServer>();
}
public override ILinkMcpServer Create(IServiceProvider serviceProvider)
=> serviceProvider.GetRequiredService<CustomerLookupMcpServer>();
}
Do not register an ILinkStep implementation as a singleton. Do not store per-call data in mutable instance fields: tool calls can run concurrently and artifact instances can be reused by the runtime.
Configuration in Link
After compiling and uploading the assembly, configure it in Link under Transport > MCP servers.
Name
A logical name for the configured MCP server. It is shown in the Link UI and reported to clients when no explicit title is configured by the artifact.
Description
An optional description of the configured server. It has no protocol effect.
URL key
A unique key used as the final path segment of the MCP endpoint. It must be a single path segment: do not include a slash, backslash or base URL.
For URL key customer-lookup, the endpoint is:
{BaseApiUrl}/api/mcphandler/customer-lookup
The health endpoint is:
{BaseApiUrl}/api/mcphandler/customer-lookup/health
Built-in security
When enabled, standard Link authentication is required before the host processes MCP requests. Selecting an authorized user group implicitly enables built-in security.
Authorized user group
Assign a user group to limit tool access to members of that group. Implement any finer-grained permission checks inside the tool itself.
MCP server artifact
Select the uploaded assembly artifact with type MCP server. Link displays any configuration fields associated with the artifact's ILinkConfig type.
Build and upload
Build the project as a class library and upload the resulting assembly through Developer > Assembly Artifacts. Select MCP server as the artifact type.
For improved production diagnostics, embed debugging information in the artifact assembly:
<PropertyGroup>
<DebugSymbols>true</DebugSymbols>
<DebugType>embedded</DebugType>
<Deterministic>true</Deterministic>
</PropertyGroup>
Testing
First verify that Link registered the server:
GET {BaseApiUrl}/api/mcphandler/customer-lookup/health
A healthy server returns HTTP 200 and status Healthy. An unavailable server returns HTTP 503. The endpoint deliberately does not expose detailed artifact errors; inspect the host logs when it reports an unhealthy server.
Then configure an MCP-compatible client to use:
{BaseApiUrl}/api/mcphandler/customer-lookup
Verify initialization, tool listing and each tool call. Test authorization separately for unauthenticated users, authenticated users and members of the configured user group.
Development checklist
-
The artifact derives from
McpServerBase<TConfig>or implementsILinkMcpServer. -
The factory derives from
LinkStepFactoryBase<ILinkMcpServer>and registers the artifact as transient. -
Each tool has a unique, stable name and an accurate description.
-
Parameter names, types and
DescriptionAttributevalues are useful to an MCP client. -
Tool annotations match the actual behavior.
-
The artifact has no mutable per-call instance state.
-
The assembly is uploaded as artifact type MCP server.
-
The URL key is a single path segment.
-
Authentication and user-group access are tested.
-
The health endpoint and tool invocations are tested from an MCP client.