SharedTempStore as session storage over DatabaseSessionStore
>>> [!note] Migrated issue
<!-- Drupal.org comment -->
<!-- Migrated from issue #3585861. -->
Reported by: [mglaman](https://www.drupal.org/user/2416470)
>>>
<h3 id="summary-problem-motivation">Problem/Motivation</h3>
<p><code>DatabaseSessionStore</code> is the only <code>SessionStoreInterface</code> implementation in <code>mcp_server</code>. It requires a custom <code>mcp_session_queue</code> database table, manages its own <code>expires_at</code> column, and relies on <code>DbSessionManager::gc()</code> being called externally to delete expired rows. Sites that already run Drupal's key-value expiry system (used by <code>SharedTempStore</code>) gain nothing from this parallel infrastructure they pay for an extra table and manual GC wiring that Drupal's tempstore subsystem already provides for free.</p>
<p>This is what we implemented, offering as a suggestion.</p>
<h3 id="summary-proposed-resolution">Proposed resolution</h3>
<p>Add a <code>SharedTempStoreSessionStore</code> class that implements <code>SessionStoreInterface</code> using Drupal's <code>SharedTempStoreFactory</code>. Drupal's tempstore layer handles expiry automatically via its own GC, so <code>gc()</code> becomes a no-op. No custom schema, no cron hook.</p>
<p><strong>PHP</strong></p>
<p>Create <code>src/Session/SharedTempStoreSessionStore.php</code>:</p>
<pre><pre><span style="color: #000000"><span style="color: #0000BB"><?php<br><br></span><span style="color: #007700">declare(</span><span style="color: #0000BB">strict_types</span><span style="color: #007700">=</span><span style="color: #0000BB">1</span><span style="color: #007700">);<br><br>namespace </span><span style="color: #0000BB">Drupal</span><span style="color: #007700">\</span><span style="color: #0000BB">mcp_server</span><span style="color: #007700">\</span><span style="color: #0000BB">Session</span><span style="color: #007700">;<br><br>use </span><span style="color: #0000BB">Drupal</span><span style="color: #007700">\</span><span style="color: #0000BB">Core</span><span style="color: #007700">\</span><span style="color: #0000BB">TempStore</span><span style="color: #007700">\</span><span style="color: #0000BB">SharedTempStore</span><span style="color: #007700">;<br>use </span><span style="color: #0000BB">Drupal</span><span style="color: #007700">\</span><span style="color: #0000BB">Core</span><span style="color: #007700">\</span><span style="color: #0000BB">TempStore</span><span style="color: #007700">\</span><span style="color: #0000BB">SharedTempStoreFactory</span><span style="color: #007700">;<br>use </span><span style="color: #0000BB">Drupal</span><span style="color: #007700">\</span><span style="color: #0000BB">Core</span><span style="color: #007700">\</span><span style="color: #0000BB">TempStore</span><span style="color: #007700">\</span><span style="color: #0000BB">TempStoreException</span><span style="color: #007700">;<br>use </span><span style="color: #0000BB">Mcp</span><span style="color: #007700">\</span><span style="color: #0000BB">Server</span><span style="color: #007700">\</span><span style="color: #0000BB">Session</span><span style="color: #007700">\</span><span style="color: #0000BB">SessionStoreInterface</span><span style="color: #007700">;<br>use </span><span style="color: #0000BB">Symfony</span><span style="color: #007700">\</span><span style="color: #0000BB">Component</span><span style="color: #007700">\</span><span style="color: #0000BB">Uid</span><span style="color: #007700">\</span><span style="color: #0000BB">Uuid</span><span style="color: #007700">;<br><br>final </span><span style="color: #0000BB">readonly </span><span style="color: #007700">class </span><span style="color: #0000BB">SharedTempStoreSessionStore </span><span style="color: #007700">implements </span><span style="color: #0000BB">SessionStoreInterface </span><span style="color: #007700">{<br><br> private const </span><span style="color: #0000BB">string COLLECTION </span><span style="color: #007700">= </span><span style="color: #DD0000">'mcp_sessions'</span><span style="color: #007700">;<br><br> public function </span><span style="color: #0000BB">__construct</span><span style="color: #007700">(<br> private </span><span style="color: #0000BB">SharedTempStoreFactory $tempStoreFactory</span><span style="color: #007700">,<br> ) {}<br><br> public function </span><span style="color: #0000BB">exists</span><span style="color: #007700">(</span><span style="color: #0000BB">Uuid $id</span><span style="color: #007700">): </span><span style="color: #0000BB">bool </span><span style="color: #007700">{<br> return </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">read</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">) !== </span><span style="color: #0000BB">FALSE</span><span style="color: #007700">;<br> }<br><br> public function </span><span style="color: #0000BB">read</span><span style="color: #007700">(</span><span style="color: #0000BB">Uuid $id</span><span style="color: #007700">): </span><span style="color: #0000BB">string</span><span style="color: #007700">|</span><span style="color: #0000BB">false </span><span style="color: #007700">{<br> return </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">store</span><span style="color: #007700">()-></span><span style="color: #0000BB">get</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">-></span><span style="color: #0000BB">toRfc4122</span><span style="color: #007700">()) ?? </span><span style="color: #0000BB">FALSE</span><span style="color: #007700">;<br> }<br><br> public function </span><span style="color: #0000BB">write</span><span style="color: #007700">(</span><span style="color: #0000BB">Uuid $id</span><span style="color: #007700">, </span><span style="color: #0000BB">string $data</span><span style="color: #007700">): </span><span style="color: #0000BB">bool </span><span style="color: #007700">{<br> try {<br> </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">store</span><span style="color: #007700">()-></span><span style="color: #0000BB">set</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">-></span><span style="color: #0000BB">toRfc4122</span><span style="color: #007700">(), </span><span style="color: #0000BB">$data</span><span style="color: #007700">);<br> return </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">;<br> }<br> catch (</span><span style="color: #0000BB">TempStoreException</span><span style="color: #007700">) {<br> return </span><span style="color: #0000BB">FALSE</span><span style="color: #007700">;<br> }<br> }<br><br> public function </span><span style="color: #0000BB">destroy</span><span style="color: #007700">(</span><span style="color: #0000BB">Uuid $id</span><span style="color: #007700">): </span><span style="color: #0000BB">bool </span><span style="color: #007700">{<br> try {<br> </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">store</span><span style="color: #007700">()-></span><span style="color: #0000BB">delete</span><span style="color: #007700">(</span><span style="color: #0000BB">$id</span><span style="color: #007700">-></span><span style="color: #0000BB">toRfc4122</span><span style="color: #007700">());<br> return </span><span style="color: #0000BB">TRUE</span><span style="color: #007700">;<br> }<br> catch (</span><span style="color: #0000BB">TempStoreException</span><span style="color: #007700">) {<br> return </span><span style="color: #0000BB">FALSE</span><span style="color: #007700">;<br> }<br> }<br><br> public function </span><span style="color: #0000BB">gc</span><span style="color: #007700">(): array {<br> return [];<br> }<br><br> private function </span><span style="color: #0000BB">store</span><span style="color: #007700">(): </span><span style="color: #0000BB">SharedTempStore </span><span style="color: #007700">{<br> return </span><span style="color: #0000BB">$this</span><span style="color: #007700">-></span><span style="color: #0000BB">tempStoreFactory</span><span style="color: #007700">-></span><span style="color: #0000BB">get</span><span style="color: #007700">(</span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">COLLECTION</span><span style="color: #007700">);<br> }<br><br>}<br></span><span style="color: #0000BB">?></span></span></pre></pre><h3 id="summary-api-changes">API changes</h3>
<h3 id="summary-ai-usage">AI usage (if applicable)</h3>
<p>[X AI Assisted Issue<br>
This issue was generated with AI assistance, but was reviewed and refined by the creator.</p>
<p>[ ] AI Assisted Code<br>
This code was mainly generated by a human, with AI autocompleting or parts AI generated, but under full human supervision.</p>
<p>[ ] AI Generated Code<br>
This code was mainly generated by an AI with human guidance, and reviewed, tested, and refined by a human.</p>
<p>[ ] Vibe Coded<br>
This code was generated by an AI and has only been functionally tested.</p>
issue