DEV Community

Cover image for MCPConnect (EN)
Luca Minuti
Luca Minuti

Posted on

MCPConnect (EN)

Note: This is an automated translation from the original Italian article.

Delphi MCP Connect (MCPConnect) is a lightweight yet robust framework designed to dramatically simplify the creation of Model Context Protocol (MCP) Servers using Embarcadero Delphi. By leveraging attributes, the framework allows you to reuse existing logic and standard Delphi classes, transforming them into protocol-aware server components. MCPConnect handles the serialization, routing, and context management required for the server-side implementation of the MCP protocol.

Introduction to MCP

The Model Context Protocol is a framework developed by Anthropic in 2024. Its purpose is to standardize how large language models (LLMs) communicate and interact with external sources. This is necessary because LLM capabilities are often limited by their ability to produce text (tokens) without being able to act on the external world or generate responses based on anything beyond their training data.

Actually, back in 2023, OpenAI had already attempted to expand the capabilities of their LLMs with a similar approach through a technology called "function-calling". The problem was that this technology, copied by most other vendors, was tied to individual product APIs. This meant anyone wanting to use it was forced to write multiple integrations.

Some typical MCP use cases include:

  • Local database access - Directly query PostgreSQL, MySQL, or SQLite databases for data analysis and complex queries

  • Filesystem integration - Gain the ability to read, search, and analyze files in your local system for development support or project analysis

  • Browser automation - Control a browser for web scraping, automated testing, or interaction with web applications

  • Third-party APIs - Integrate external services like Slack, GitHub, Linear, or Jira to manage tasks and communications

  • Custom enterprise tools - Expose internal organizational APIs and tools to allow the LLM to interact with proprietary systems

  • Complex data manipulation - Process Excel, CSV, or other structured formats with custom logic not available in standard tools

The Architecture

To achieve these capabilities, the MCP architecture is divided into three blocks:

  • MCP Host: The AI application that will use MCP, for example Claude Desktop
  • MCP Client: The component that connects to the MCP server and sends the new context (data retrieved from the server) to the host
  • MCP Server: The program that provides the context. It essentially responds to calls by providing the information requested by the host through the client

Architecture

The Server

The server is the heart of the MCP protocol, the part that actually performs the necessary tasks. It can execute multiple functions: access filesystem documents, execute database queries, send messages via email or messaging systems, sync with a calendar, etc.

To perform these tasks, the protocol defines three types of building blocks:

  • Tools: functions that the LLM can decide to call. Tools can interact with a database, call external APIs, modify files, or execute any type of logic.
  • Resources: read-only datasets that can be requested by the LLM to insert information into the context. They can be documents, files, or any other type of structured data. (currently not supported by MCPConnect)
  • Prompts: templates that can be invoked by the user (usually by writing the template name preceded by a slash) to generate a specific prompt for a particular operation. (currently not supported by MCPConnect)

Assuming you have a TDocumentService class that implements some tools, you can configure the MCPConnect server like this:

uses
  MCPConnect.JRPC.Server, 
  MCPConnect.MCP.Server.Api, // This register the standard MCP API
  MCPConnect.Configuration.MCP,

  Demo.DocumentService; // Unit with your MCP classes

// Create the JSON-RPC Server
FJRPCServer := TJRPCServer.Create(Self);
FJRPCServer
  .Plugin.Configure<IMCPConfig>
    .SetServerName('delphi-mcp-server')
    .SetServerVersion('2.0.0')
    .RegisterToolClass(TDocumentService)  // Register your tool class here
    .ApplyConfig;

Enter fullscreen mode Exit fullscreen mode

Transport

The MCP protocol uses JSON-RPC to encode messages passing between client and server, while for the actual transport it supports two types of channels:

  1. Stdio: standard input and output similar to old CGI: essentially the application will be console-based with requests arriving entirely on standard input and responses sent to standard output.
  2. Streamable HTTP: HTTP communication with the ability to keep the channel open to allow the server to directly send notifications to the client without polling.

MCP Connect supports both operating modes, and the choice depends on the project type and also the development phase. For example, debugging is generally much simpler in an HTTP application compared to one using stdio. The same application could also work in both modes depending on configuration or a startup parameter.

Aspect stdio Streamable HTTP
Scope Local Local + remote
Complexity ⭐ Low ⭐⭐⭐ High
Scalability ❌ No ✅ Yes
Security Implicit Must configure
Streaming Limited Advanced
Debug Complex Simple
Typical use Dev / local tools Production / cloud

Continuing with the previous example, with MCPConnect you can set HTTP as the transport mechanism by specifying the technology (Indy or WebBroker) to use. For example, if you want to use WebBroker, the configuration is as follows:

uses
  MCPConnect.JRPC.Server, 
  MCPConnect.MCP.Server.Api, // This register the standard MCP API
  MCPConnect.Transport.WebBroker, 
  MCPConnect.Configuration.MCP,

  Demo.DocumentService; // Unit with your MCP classes

// Create the JSON-RPC Server
FJRPCServer := TJRPCServer.Create(Self);
FJRPCServer
  .Plugin.Configure<IMCPConfig>
    ....

// Create and configure the Dispatcher
FJRPCDispatcher := TJRPCDispatcher.Create(Self); // Self should be the TWebModule
FJRPCDispatcher.PathInfo := '/mcp';  // Set the endpoint path
FJRPCDispatcher.Server := FJRPCServer;  // Connect to the server
Enter fullscreen mode Exit fullscreen mode

With the previous code, FJRPCDispatcher will handle all incoming calls to the /mcp path through the previously configured JRPC server.

Tools with MCP Connect

The most interesting aspect of MCPConnect is that it allows you to write MCP servers without worrying about the protocol architecture details. For example, suppose you want to provide information to the LLM based on a category. In Delphi, you could write a class like this:

  TDocumentService = class
  public
    function ListDocument(const ACategory: string): string;
  end;
Enter fullscreen mode Exit fullscreen mode

Since the information will end up in an LLM's context, even though MCPConnect also handles more complex return values (e.g., TArray<TDocument>, TStringList, TImage, etc.), returning a string is often more than sufficient.

Returning to our example, it doesn't matter how the ListDocument method returns the data - MCPConnect will describe it to the LLM so it can decide how and when to call it.

To do this, however, you need to "explain" to the LLM what the class is for and in particular what the method in question does. With MCPConnect, this is done primarily through attributes. This way, the class declaration will be enriched as follows:

  TDocumentService = class
  public
    // This method is published as an MCP tool
    [McpTool('doclist', 'List all the available documents')]
    function ListDocument(
      [McpParam('category', 'Document Category')] const ACategory: string
    ): string;

    // This method is NOT exposed because it lacks the [McpTool] attribute
    procedure InternalStuff;
  end;

Enter fullscreen mode Exit fullscreen mode

The McpTool and McpParam attributes take two parameters: the method name and the description. The description is essential - it's precisely based on this that the LLM understands what the element is for, whether to use it, and how to use it. Therefore, it's crucial to be as clear as possible in formulating the text.

Tool Results

In the example we've seen, the tool returns a string, which can often be sufficient, but obviously depends on the tool's purpose. We can divide tools into two broad groups:

  • Operational: whose main purpose is to perform a concrete action. They can write files, modify database state, send emails, etc. In this case, the output could even be simply an indication of the operation's outcome, for example a boolean, or a string indicating the problem detected in case of error.
  • Informational: in this case, the tool searches for data and injects it into the context. Depending on the nature of the data, it might be sufficient to return it as a string or in a structured format.

MCP Connect handles this transparently, so if the function returns a complex object, it will automatically convert it to the appropriate format.

However, there's a particular case worth mentioning, which is the TContentList class. This class maps fairly low-level to the output expected by MCP. In this case, the response can be composed of various sections, each of different type (text, image, audio, link, blob). MCPConnect allows you to simplify the use of this class through TToolResultBuilder as you can see in the following example:

function TDelphiDayTool.BuyTicket(AId, AQuantity: Integer): TContentList;
begin
  var LTicketStream := FCart.BuyTicket(AId, AQuantity);
  FGC.Add(LTicketStream); // Add the stream to the garbage collector

  var LResultBuilder := TToolResultBuilder.CreateInstance;

  LResultBuilder.AddText('Purchase completed successfully.');
  LResultBuilder.AddImage('image/png', LTicketStream);

  Result := LResultBuilder.Build;
end;
Enter fullscreen mode Exit fullscreen mode

Session Management

An essential feature of MCP is session management, which is implicit with stdio transport and explicit when using Streamable HTTP. MCP Connect handles all this transparently, and in any tool you'll be able to retrieve data from the current session. Depending on the configuration, the session can be an instance of the TSessionData object (which actually saves information in JSON) or any object derived from TSessionBase.

The following code shows how to configure an application to use a custom session (TShoppingSession) to save the necessary information during the order creation process.

uses
  ...
  MCPConnect.Configuration.Session;

begin
  ...
  FJRPCServer
    .Plugin.Configure<ISessionConfig>
      .SetLocation(TSessionIdLocation.Header) // default
      .SetHeaderName('Mcp-Session-Id') // default
      .SetTimeout(30)  // 30 minutes timeout (default)
      .SetSessionClass(TShoppingSession)  // Use custom typed session
      .ApplyConfig
Enter fullscreen mode Exit fullscreen mode

Conclusion

MCP Connect is a young but already quite extensive library. In this article, I've quickly covered some of the main topics without going into too much detail. More comprehensive documentation can be found on the GitHub page. Additionally, the demos included in the sources present numerous cases from which you can learn some techniques for creating simple MCP servers.

Other features of MCP Connect that I haven't discussed but plan to write about soon include:

  • Context injection
  • Fluent-configuration
  • Garbage collection
  • Tools namespacing
  • JSON-RPC only server (no MCP)
  • VCL/Firemonkey support

Top comments (0)