The MCP server supports the protocol versions 2026-07-28, 2025-11-25, 2025-06-18 and 2025-03-26 at the same time. No configuration is needed, the server detects the protocol era of every request and answers in the same era.
initialize, receives an Mcp-Session-Id and uses that session on every following request. This flow works exactly as in previous releases, see Sessions.initialize and no session. Every request is self contained and carries the protocol version, the client information and the client capabilities in params._meta. The server processes each request statelessly, so no Mcp-Session-Id header is created or echoed.
A request is treated as modern when its _meta contains io.modelcontextprotocol/protocolVersion with a modern (or unknown) version. An initialize request, or a request without that field, follows the legacy flow. Inside any event handler you can check the era of the current request using aSession.Request.Era (aimcpeModern or aimcpeLegacy) and aSession.Request.ProtocolVersion.
A 2026-07-28 client calls server/discover to learn which versions the server supports, its capabilities, its extensions and optional instructions. The server answers automatically using the values of MCPOptions.ServerInfo, MCPOptions.Instructions and MCPOptions.Extensions, plus the capabilities built from the registered tools, prompts and resources. The discover result is cacheable.
Modern requests supported by the server: server/discover, tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read, resources/templates/list, completion/complete, subscriptions/listen, the tasks/* methods and the notifications notifications/progress and notifications/cancelled. Methods that only exist in the legacy era (ping, logging/setLevel, resources/subscribe, resources/unsubscribe, ...) return error -32601.
When a modern request arrives over HTTP, the server validates that the headers match the JSON body before the request is dispatched:
_meta.io.modelcontextprotocol/protocolVersion.method.params.name (or params.uri for resources, or the task id for tasks/*). Base64 encoded values are decoded before the comparison and control characters are rejected.tools/call requests when the tool declares x-mcp-header properties (see below).
A modern GET or DELETE request to the MCP endpoint returns HTTP 405, because the 2026-07-28 transport only uses POST. The Origin validation of the endpoint applies to modern requests too.
| Code | HTTP status | Meaning |
|---|---|---|
-32020 | 400 | Header mismatch. An MCP header does not match the value in the request body. |
-32021 | 400 | Missing required client capability. The request needs a capability the client did not declare in _meta (for example elicitation or the tasks extension). |
-32022 | 400 | Unsupported protocol version. The error data contains the list of supported versions so the client can retry with one of them. |
-32601 | 404 | Method not found, including legacy only methods called in the modern era. |
-32602 | 200 | Invalid params. Raise it from your handler, for example when a resource is not found. |
To return a JSON-RPC error from any request handler, raise a TsgcAI_MCP_Exception. The error -32021 is sent automatically when a feature needs a client capability that the request did not declare, for example a multi round-trip request asking for elicitation, or a tool that requires the tasks extension.
procedure TMainForm.MCPServerMCPRequestResource(Sender: TObject;
const aSession: TsgcAI_MCP_Session; const aRequest: TsgcAI_MCP_Request_ResourcesRead;
const aResponse: TsgcAI_MCP_Response_ResourcesRead);
begin
if aRequest.Params.Uri <> 'file:///readme.txt' then
raise TsgcAI_MCP_Exception.Create(CS_AI_MCP_INVALID_PARAMS, 'Resource not found');
...
end;
Your handlers can check the client capabilities too. HasClientCapability(aSession, aCapability) returns True when the client declared the capability (in _meta for a 2026-07-28 request, in initialize for a legacy session), and CheckClientCapability(aSession, aCapability) raises the error -32021 when it is missing.
if MCPServer.HasClientCapability(aSession, 'roots') then
aResponse.InputRequired.AddRoots('roots');
// fails the request with -32021 if the client cannot sample
MCPServer.CheckClientCapability(aSession, 'sampling');
Modern list results and the discover result can be cached by the client. Configure the cache hints with MCPOptions.Cache:
aimcpcsPrivate (default) or aimcpcsPublic, sent as cacheScope.ttlMs. By default 60000.
MCPOptions.Instructions is a free text sent in the server/discover result to tell the model how to use the server. MCPOptions.Extensions is a raw JSON object with the extensions advertised in server/discover; the tasks extension is added automatically when MCPOptions.Tasks.Enabled is True.
MCPServer.MCPOptions.ServerInfo.Name := 'sgc-mcp-server';
MCPServer.MCPOptions.ServerInfo.Version := '1.0.0';
MCPServer.MCPOptions.Instructions := 'Use the weather tools to answer forecast questions.';
MCPServer.MCPOptions.Cache.Scope := aimcpcsPublic;
MCPServer.MCPOptions.Cache.TTLMs := 300000;
MCPServer.MCPOptions.Extensions := '{"com.example/audit":{}}';
A 2026-07-28 tool can ask the client to mirror some arguments of tools/call as HTTP headers, so proxies and gateways can route the request without parsing the body. Set the XMCPHeader property of the input schema property; it is published in tools/list as x-mcp-header and the client sends the argument as the header Mcp-Param-{XMCPHeader}. When the tool uses RawInputSchema, add "x-mcp-header" directly to the property in the JSON schema. The server checks that the header value matches the argument and answers -32020 if not.
procedure TMainForm.FormCreate(Sender: TObject);
var
oTool: TsgcAI_MCP_Tool;
oProperty: TsgcAI_MCP_Tool_InputSchema_Property;
begin
oTool := MCPServer.Tools.AddTool('get_forecast', 'Returns the weather forecast');
oProperty := TsgcAI_MCP_Tool_InputSchema_Property.Create;
oProperty.Name := 'region';
oProperty._Type := aimcpjtString;
oProperty.Description := 'Region code';
oProperty.XMCPHeader := 'Region'; // client sends Mcp-Param-Region
oTool.InputSchema.Properties.AddProperty(oProperty);
end;