Skip to content

Session Management

MCPConnect provides built-in session management for maintaining stateful interactions across multiple requests. Sessions are thread-safe, automatically managed, and can store both generic JSON data or fully typed custom objects.

Configuring Session Support

Add session configuration to your server setup:

pascal
uses
  MCPConnect.Configuration.Session,
  MCPConnect.Configuration.MCP,
  MCPConnect.Session.Core;

FJRPCServer
  .Plugin.Configure<ISessionConfig>
    .SetLocation(TSessionIdLocation.Header)  // or Cookie
    .SetHeaderName('Mcp-Session-Id')         // Default for MCP
    .SetTimeout(30)                           // Minutes
    .SetSessionClass(TSessionData)            // Or your custom class
  .ApplyConfig

  .Plugin.Configure<IMCPConfig>
    .Server
      .SetName('delphi-mcp-server')
      .SetVersion('2.0.0')
      .SetCapabilities([Tools])
    .BackToMCP
    .Tools
      .RegisterClass(TShoppingCartTool)
    .BackToMCP;

Session Behavior by Transport

TransportBehavior
HTTP (WebBroker/Indy)Session ID passed via header or cookie. Server returns Mcp-Session-Id header on first request.
STDIOImplicit session per connection — no session ID needed.

Using Sessions in Your Tools

Sessions are automatically injected into your tool classes using the [Context] attribute.

Option 1: Generic JSON Storage (TSessionData)

pascal
type
  TShoppingCartTool = class
  private
    [Context]
    FSession: TSessionData;  // Automatically injected
  public
    [McpTool('cart_add', 'Add item to shopping cart')]
    function AddToCart(
      [McpParam('item_id')] const AItemId: string;
      [McpParam('quantity')] AQuantity: Integer
    ): string;
  end;

function TShoppingCartTool.AddToCart(const AItemId: string;
  AQuantity: Integer): string;
var
  LCart: TJSONObject;
begin
  if not FSession.Data.TryGetValue<TJSONObject>('cart', LCart) then
  begin
    LCart := TJSONObject.Create;
    FSession.Data.AddPair('cart', LCart);
  end;
  LCart.AddPair(AItemId, TJSONNumber.Create(AQuantity));
  Result := Format('Added %d x %s to cart', [AQuantity, AItemId]);
end;

Option 2: Custom Typed Session

For better type safety, create a custom session class that extends TSessionBase:

pascal
type
  TCartItem = class
  private
    FItemId: string;
    FQuantity: Integer;
  public
    property ItemId: string read FItemId write FItemId;
    property Quantity: Integer read FQuantity write FQuantity;
  end;

  TShoppingSession = class(TSessionBase)
  private
    FCart: TObjectDictionary<string, TCartItem>;
  public
    property Cart: TObjectDictionary<string, TCartItem> read FCart;
    constructor Create;
    destructor Destroy; override;
  end;

constructor TShoppingSession.Create;
begin
  inherited;
  FCart := TObjectDictionary<string, TCartItem>.Create([doOwnsValues]);
end;

// In your tool class:
type
  TShoppingCartTool = class
  private
    [Context]
    FSession: TShoppingSession;  // Typed session — fully type-safe
  public
    [McpTool('cart_add', 'Add item to cart')]
    function AddToCart(const AItemId: string; AQuantity: Integer): string;
  end;

function TShoppingCartTool.AddToCart(const AItemId: string;
  AQuantity: Integer): string;
var
  LItem: TCartItem;
begin
  if FSession.Cart.TryGetValue(AItemId, LItem) then
    LItem.Quantity := LItem.Quantity + AQuantity
  else
  begin
    LItem := TCartItem.Create;
    LItem.ItemId := AItemId;
    LItem.Quantity := AQuantity;
    FSession.Cart.Add(AItemId, LItem);
  end;
  Result := Format('Added %d x %s', [AQuantity, AItemId]);
end;

Register your custom session class in the configuration:

pascal
.SetSessionClass(TShoppingSession)