Problem/Motivation

Some MCP servers will need a persistent MCP session as multiple actions maintain some form of context. An example of this is Playwright MCP, where you may navigate to a page, fill out a form, then take a screenshot. This requires maintaining the MCP Session header across multiple tools.

Proposed resolution

Whilst maintaining the session ID is going to be the responsibility of the caller, we need a mechanism in MCP Client to actually support it. I'm deliberately keeping the scope of implementation narrow here, but I think using context is a good mechanism as it gives flexibility for the caller to solve in a number of different ways, whether via code or via LLM input.

Remaining tasks

Decide if this is the right approach...

User interface changes

Additional optional context, visible in tool explorer etc.

API changes

  1. Automatically add a new context for session name (unique for the session, but human readable rather than UUID).
  2. Update the factory to create and maintain optionally named clients for a session.

Data model changes

N/A

Issue fork mcp_client-3565713

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

andrewbelcher created an issue. See original summary.

andrewbelcher’s picture

Status: Active » Needs review
andrewbelcher’s picture

Assigned: andrewbelcher » Unassigned
marcus_johansson’s picture

Status: Needs review » Needs work

For me it looks like a good solution - this will only solve persistancy over one PHP connection/thread, correct?

If so, we probably need to solve it over many in the future, using Symfony Messenger or some underlying connector. We have the chatbot for instance, calling each agent loop in a new request, and this would break in this case.

Code wise I just wrote two NITs. When fixed or commented on its RTBC for me.

robertoperuzzo’s picture

Assigned: Unassigned » robertoperuzzo
robertoperuzzo’s picture

Reviewing this issue I was concerning about one thing.

Looking at line 641 of McpServerForm, the save() method synchronously calls $client->listTools() (when "Fetch tools on save" is checked), which, based on the code in SwissNL library, uses async operations with Deferred/await pattern. This creates a blocking async call during a synchronous form save operation.

The problem:

  • Line 641: $tools_data = $client->listTools(); - This blocks the entire HTTP request until the MCP server responds
  • If the MCP server is slow, unreachable, or the connection hangs, the user's form save request will timeout or be delayed significantly
  • The async/await pattern in listTools() still blocks the PHP execution context while waiting for the response

The impact:

  • Poor UX: Users wait indefinitely for form saves
  • Potential PHP timeouts on slow MCP servers
  • Form submissions could fail unexpectedly

Recommended fix: Move tool fetching to a queued job or make it truly async (e.g., AJAX after save). The current try-catch (lines 671-682) helps but doesn't solve the blocking issue.

I think, we need to complete the issue #3557648: Create Get/Update Tools Button before, so we can remove the "Fetch tools on save" checkbox from the form and get/Update the tools list using Ajax.

robertoperuzzo’s picture

Assigned: robertoperuzzo » Unassigned