Skip to content

TMSMCPTransport

Overview

The TMS MCP (Model Context Protocol) Transport framework provides a unified interface for various communication transport mechanisms. Built around the abstract base class TTMSMCPTransport, this framework enables developers to implement different communication protocols while maintaining a consistent API.

The framework includes three concrete implementations:

  • Standard I/O (Simple console-based communication)
  • Named Pipes (Windows-specific high-performance IPC)
  • Server-Sent Events (HTTP-based for web compatibility)
  • Streamable HTTP

Base Transport Class (TTMSMCPTransport)

Class Hierarchy

TObject
  └── TPersistent
      └── TComponent
          └── TTMSMCPCustomComponent
              └── TTMSMCPTransport

Key Features

  • Abstract base class defining the core transport interface
  • Platform-specific (Windows-only) attribute
  • Lifecycle management with start/stop controls
  • Error handling infrastructure
  • Message processing callback system

Usage Guidelines

Implementation Requirements

  1. Must inherit from TTMSMCPTransport
  2. Must implement all abstract methods
  3. Should maintain FRunning state accurately
  4. Should call LogError for internal error reporting

Lifecycle Management

var
  Transport: TTMSMCPTransport;
begin
  Transport := TMyTransport.Create(nil);
  try
    Transport.OnProcessMessage := HandleMessage;
    Transport.OnError := HandleError;
    Transport.Run; // or Start + ProcessMessages loop
  finally
    Transport.Free;
  end;
end;

Error Handling

procedure TMyTransport.LogError(const E: Exception);
begin
  inherited; // Calls OnError if assigned
  // Additional error handling
end;

Properties

Property Type Description
Running Boolean (read-only) Indicates whether the transport is currently active and processing messages
OnProcessMessage TTMSMCPTransportProcessMessageEvent Callback for processing incoming messages
OnError TProc<Exception> Error notification callback

Methods

Core Methods

procedure Start; virtual; abstract;
Initiates the transport service. Must be implemented by descendants.

procedure Stop; virtual; abstract;
Terminates the transport service. Must be implemented by descendants.

procedure Run; virtual; abstract;
Runs the transport in blocking mode (does not return until stopped).

procedure ProcessMessages; virtual; abstract;
Processes pending messages (for non-blocking implementations).

Support Methods

procedure LogError(const E: Exception); virtual;
Internal error logging method. Can be overridden for custom error handling.

function IsRunning: Boolean;
Helper method to check running status.

Events

TTMSMCPTransportProcessMessageEvent

function(const body: string): string of object;
Message processing callback signature: - Receives: Message body as string - Returns: Response string

Named Pipes Transport

Architecture

  • Server/Client model with asynchronous I/O
  • Overlapped operations for high performance
  • Thread-safe message queues
  • Connection management

Key Components

TPipeServer

  • Creates and manages named pipe instances
  • Handles multiple client connections
  • Broadcast capability

TPipeClient

  • Connects to pipe servers
  • Manages message sending/receiving
  • Automatic reconnection logic

Advanced Features

  • Write queue management with size limits
  • Thread pool for connection handling
  • Detailed error reporting with pipe contexts
  • Memory-efficient buffering

Complete Example

// Server setup
procedure SetupPipeServer;
var
  PipeServer: TPipeServer;
begin
  PipeServer := TPipeServer.Create;
  try
    PipeServer.PipeName := 'MyAppService';
    PipeServer.OnPipeMessage := HandlePipeMessage;
    PipeServer.Active := True;

    // Keep server running
    while True do Sleep(1000);
  finally
    PipeServer.Free;
  end;
end;

// Client implementation
procedure SendPipeMessage;
var
  PipeClient: TPipeClient;
begin
  PipeClient := TPipeClient.Create;
  try
    PipeClient.PipeName := 'MyAppService';
    if PipeClient.Connect(2000) then
    begin
      PipeClient.Write(JSONMessage, Length(JSONMessage));
      PipeClient.WaitUntilWriteQueueEmpty(5);
    end;
  finally
    PipeClient.Free;
  end;
end;

Streamable HTTP Transport

Architecture

  • Abstract HTTP server layer with platform specific implementations
  • HTTP-based protocol using text/event-stream
  • CORS support for web applications
  • SSL/TLS support for secure communications
  • Connection keep-alive with ping mechanism

Key Features

  • Client management with automatic cleanup
  • Thread pool for concurrent connections
  • Detailed logging infrastructure

URL reservation (Windows)

Starting from version TMS AI Studio v1.4, the server is http.sys-based on Windows systems. Http.sys needs a URL to be reserved. This reservation will automatically happen on first launch by triggering an elevated netsh command, and it reserves the url http://+:%PORT%/, where %PORT% equals to the Port property of the streamable HTTP transport. The URL will be registered for the Everyone usergroup. If you wish to register a custom URL or a different user group, proceed with manual commands before running the application. Keep in mind, the Port needs to be the same as the reserved URL.

You can do so by executing the following:

netsh http add urlacl url=http://+:%PORT%/ user=%USERDOMAIN%\%USERNAME%

Read more about the netsh command here.

Certificates

Starting from version TMS AI Studio v1.4, the server is http.sys-based on Windows systems. This means a change in how the certificates are handled. For http.sys, a certificate hash, store name and app-id needs to be provided and registered. It's possible to do this 2 ways:

  1. Provide the path to an INI file which contains the necessary information in the following format

    [Certificate]
    Hash=%HASH%
    StoreName=%STORENAME%
    AppID={00112233-4455-6677-8899-AABBCCDDEEFF}
    

    Where %HASH% is the hash of the certificate you with to bind to the server. %STORENAME% is the name of the certificate store which contains the certificate (e.g. My). This file needs to be assigend to the SSLCertFile property of the transport layer.

  2. Handle the registration manually via netsh:

netsh http add sslcert ipport=0.0.0.0:%PORT% certhash=%HASH% certstorename=%STORENAME% appid={00112233-4455-6677-8899-AABBCCDDEEFF} 

Read more about the netsh command here.

For the rest of the platforms, at this moment you need to use the certificate files as before.

Alternative to certificates

If the server is going to run on a Windows Server with IIS, it's possible to take advantage of IIS's reverse proxy support and let it handle the certificate. In that case, the server needs to run without UseSSL enabled.

Prerequisites

You'll need the URL Rewrite and the Application Request Routing modules.

In IIS manager:

  1. From the left-pane Sites the site which should act as the intermediary
  2. In the IIS settings open URL rewrite
  3. From the right-pane under Actions, select Add Rule(s)...
  4. Select Reverse Proxy
  5. Under the Inbound rules, fill in the (localhost) URL where your server is running
  6. Open the new inbound rule that was added
  7. Set the following:
    • Requested URL > Matches the Pattern
    • Using > Regular expressions (or Exact match, depending on your use case)
    • Pattern: The pattern after the URL. For example, for SSE the pattern could be sse|messages in combination with Regular expressions.
    • Action type > Rewrite
    • Rewrite URL > URL of your server + {R:0}, for example: http://localhost:8934/{R:0}

Complete Example

procedure SetupSSETransport;
var
  StreamableHTTPTransport: TTMSMCPStreamableHTTPTransport;
begin
  StreamableHTTPTransport := TTMSMCPStreamableHTTPTransport.Create(nil);
  try
    // Basic configuration
    StreamableHTTPTransport.Port := 8080;

    // SSL configuration
    StreamableHTTPTransport.ConfigureSSL(
      'C:\myapp\certificate.ini'
    );

    // Message handling
    StreamableHTTPTransport.OnProcessMessage := 
      function(const body: string): string
      var
        Json: TJSONObject;
      begin
        Json := TJSONObject.ParseJSONValue(body) as TJSONObject;
        try
          Result := ProcessAPIRequest(Json);
        finally
          Json.Free;
        end;
      end;

    // Start server
    StreamableHTTPTransport.Start;

    // Keep application running
    while True do Sleep(1000);
  finally
    StreamableHTTPTransport.Free;
  end;
end;

Standard I/O Transport

Architecture

  • Simple stdin/stdout communication
  • Blocking and non-blocking modes
  • Minimal resource usage
  • Platform independent

Key Features

  • Line-based message processing
  • Automatic output flushing
  • Error resilience
  • Simple integration

Complete Example

procedure RunStdIOTransport;
var
  StdioTransport: TTMSMCPStdioTransport;
begin
  StdioTransport := TTMSMCPStdioTransport.Create(nil);
  try
    StdioTransport.OnProcessMessage := 
      function(const body: string): string
      begin
        try
          Result := ExecuteCommand(body);
        except
          on E: Exception do
            Result := 'ERROR: ' + E.Message;
        end;
      end;

    // Run in blocking mode
    StdioTransport.Run;
  finally
    StdioTransport.Free;
  end;
end;

Comparison Matrix

Feature Named Pipes SSE STDIO
Platform Support Windows only Cross-platform Cross-platform
Protocol Named pipes IPC HTTP/HTTPS Standard streams
Performance Very high Medium Low
Encryption None TLS/SSL None
Connection Model Persistent Persistent N/A
Max Message Size 100MB Configurable Line buffer
Thread Safety Fully thread-safe Thread pool Single-threaded
Best For Windows IPC Web applications CLI tools
Complexity High Medium Low

Best Practices

General Guidelines

  1. Resource Management
  2. Always call Stop before destruction
  3. Free components in reverse creation order
  4. Use try-finally blocks for cleanup

  5. Error Handling

  6. Implement OnError handler for all transports
  7. Validate incoming message size and format
  8. Use timeouts for connection operations

  9. Performance

  10. For high throughput: Use named pipes (Windows) or optimized SSE
  11. Limit message sizes to reasonable values
  12. Use connection pooling where available

Transport-Specific Recommendations

Named Pipes

  • Set appropriate MAX_BUFFER size for expected messages
  • Use WaitUntilWriteQueuesEmpty for graceful shutdown
  • Implement proper error recovery for pipe disconnects

SSE / Streamable HTTP

  • Always use HTTPS in production
  • Implement client-side reconnection logic
  • Monitor connection counts to prevent resource exhaustion

STDIO

  • Add clear message delimiters (like newlines)
  • Implement timeout handling for blocking operations
  • Consider message size limitations

Advanced Topics

Custom Transport Implementation

To create a custom transport:

type
  TMyCustomTransport = class(TTMSMCPTransport)
  private
    FInternalComponent: TMyCommunicationLib;
  protected
    procedure Start; override;
    procedure Stop; override;
    procedure Run; override;
    procedure ProcessMessages; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

constructor TMyCustomTransport.Create(AOwner: TComponent);
begin
  inherited;
  FInternalComponent := TMyCommunicationLib.Create;
end;

destructor TMyCustomTransport.Destroy;
begin
  Stop;
  FInternalComponent.Free;
  inherited;
end;

procedure TMyCustomTransport.Start;
begin
  FInternalComponent.StartListener;
  FRunning := True;
end;

// Implement other required methods...

Performance Optimization

  1. Named Pipes
  2. Adjust thread pool size based on expected load
  3. Use LimitWriteQueues to prevent memory issues
  4. Consider pipe buffer sizes

  5. SSE

  6. Implement message compression
  7. Use HTTP/2 for better multiplexing
  8. Optimize JSON message formats

Security Considerations

  1. Named Pipes
  2. Implement proper ACLs for pipes
  3. Validate client credentials

  4. SSE

  5. Always use TLS 1.2+
  6. Implement authentication
  7. Validate Origin headers

  8. STDIO

  9. Sanitize all input
  10. Implement rate limiting

Troubleshooting

Common Issues

Connection Problems

  • Named Pipes:
  • Error 231 (Pipe busy): Increase pipe instances or add retry logic
  • Error 233 (No process): Remote end disconnected

  • SSE:

  • CORS issues: Verify Access-Control-* headers
  • SSL errors: Check certificate chain and dates

Performance Issues

  • High latency:
  • Check network conditions (SSE)
  • Verify buffer sizes (Pipes)

  • Throughput limits:

  • Adjust thread pool sizes
  • Optimize message processing

Memory Problems

  • Growing queues:
  • Implement queue limits
  • Monitor with GetCount methods

Debugging Tips

  1. Enable Logging

    procedure TMyForm.LogMessage(const Msg: string);
    begin
      Memo1.Lines.Add(FormatDateTime('hh:nn:ss.zzz', Now) + ' - ' + Msg);
    end;
    
    // For SSE
    SSETransport.OnLog := LogMessage;
    
    // For Pipes
    PipesLogProc := LogMessage;
    

  2. Diagnostic Tools

  3. Use Wireshark for SSE traffic
  4. Windows Pipe Monitor for named pipes
  5. Process Explorer for handle checks

  6. Error Recovery

    procedure TMyForm.HandleTransportError(E: Exception);
    begin
      LogMessage('ERROR: ' + E.Message);
      if E is EIdSocketError then
        case EIdSocketError(E).LastError of
          WSAECONNRESET: ReconnectTransport;
          // Handle other specific errors
        end;
    end;