feat(session): implement PSR-16 cache based session storage (#114)
This commit is contained in:
parent
7190bee153
commit
f41ea86608
3 changed files with 125 additions and 5 deletions
27
README.md
27
README.md
|
|
@ -190,23 +190,42 @@ $response = $server->run($transport);
|
|||
By default, the SDK uses in-memory sessions. You can configure different session stores:
|
||||
|
||||
```php
|
||||
use Mcp\Server\Session\InMemorySessionStore;
|
||||
use Mcp\Server\Session\FileSessionStore;
|
||||
use Mcp\Server\Session\InMemorySessionStore;
|
||||
use Mcp\Server\Session\Psr16StoreSession;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
|
||||
// Use default in-memory sessions (TTL only)
|
||||
// Use default in-memory sessions with custom TTL
|
||||
$server = Server::builder()
|
||||
->setSession(ttl: 7200) // 2 hours
|
||||
->build();
|
||||
|
||||
// Use file-based sessions
|
||||
// Override with file-based storage
|
||||
$server = Server::builder()
|
||||
->setSession(new FileSessionStore(__DIR__ . '/sessions'))
|
||||
->build();
|
||||
|
||||
// Use in-memory with custom TTL
|
||||
// Override with in-memory storage and custom TTL
|
||||
$server = Server::builder()
|
||||
->setSession(new InMemorySessionStore(3600))
|
||||
->build();
|
||||
|
||||
// Override with PSR-16 cache-based storage
|
||||
// Requires psr/simple-cache and symfony/cache (or any other PSR-16 implementation)
|
||||
// composer require psr/simple-cache symfony/cache
|
||||
$redisAdapter = new RedisAdapter(
|
||||
RedisAdapter::createConnection('redis://localhost:6379'),
|
||||
'mcp_sessions'
|
||||
);
|
||||
|
||||
$server = Server::builder()
|
||||
->setSession(new Psr16StoreSession(
|
||||
cache: new Psr16Cache($redisAdapter),
|
||||
prefix: 'mcp-',
|
||||
ttl: 3600
|
||||
))
|
||||
->build();
|
||||
```
|
||||
|
||||
### Discovery Caching
|
||||
|
|
|
|||
|
|
@ -139,6 +139,9 @@ Configure session storage and lifecycle. By default, the SDK uses `InMemorySessi
|
|||
```php
|
||||
use Mcp\Server\Session\FileSessionStore;
|
||||
use Mcp\Server\Session\InMemorySessionStore;
|
||||
use Mcp\Server\Session\Psr16StoreSession;
|
||||
use Symfony\Component\Cache\Psr16Cache;
|
||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
|
||||
// Use default in-memory sessions with custom TTL
|
||||
$server = Server::builder()
|
||||
|
|
@ -147,18 +150,35 @@ $server = Server::builder()
|
|||
|
||||
// Override with file-based storage
|
||||
$server = Server::builder()
|
||||
->setSession(new FileSessionStore('/tmp/mcp-sessions'))
|
||||
->setSession(new FileSessionStore(__DIR__ . '/sessions'))
|
||||
->build();
|
||||
|
||||
// Override with in-memory storage and custom TTL
|
||||
$server = Server::builder()
|
||||
->setSession(new InMemorySessionStore(3600))
|
||||
->build();
|
||||
|
||||
// Override with PSR-16 cache-based storage
|
||||
// Requires psr/simple-cache and symfony/cache (or any other PSR-16 implementation)
|
||||
// composer require psr/simple-cache symfony/cache
|
||||
$redisAdapter = new RedisAdapter(
|
||||
RedisAdapter::createConnection('redis://localhost:6379'),
|
||||
'mcp_sessions'
|
||||
);
|
||||
|
||||
$server = Server::builder()
|
||||
->setSession(new Psr16StoreSession(
|
||||
cache: new Psr16Cache($redisAdapter),
|
||||
prefix: 'mcp-',
|
||||
ttl: 3600
|
||||
))
|
||||
->build();
|
||||
```
|
||||
|
||||
**Available Session Stores:**
|
||||
- `InMemorySessionStore`: Fast in-memory storage (default)
|
||||
- `FileSessionStore`: Persistent file-based storage
|
||||
- `Psr16StoreSession`: PSR-16 compliant cache-based storage
|
||||
|
||||
**Custom Session Stores:**
|
||||
|
||||
|
|
|
|||
81
src/Server/Session/Psr16StoreSession.php
Normal file
81
src/Server/Session/Psr16StoreSession.php
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the official PHP MCP SDK.
|
||||
*
|
||||
* A collaboration between Symfony and the PHP Foundation.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Mcp\Server\Session;
|
||||
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
/**
|
||||
* @author luoyue <1569097443@qq.com>
|
||||
*
|
||||
* PSR-16 compliant cache-based session store.
|
||||
*
|
||||
* This implementation uses any PSR-16 compliant cache as the storage backend
|
||||
* for session data. Each session is stored with a prefixed key using the session ID.
|
||||
*/
|
||||
class Psr16StoreSession implements SessionStoreInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CacheInterface $cache,
|
||||
private readonly string $prefix = 'mcp-',
|
||||
private readonly int $ttl = 3600,
|
||||
) {
|
||||
}
|
||||
|
||||
public function exists(Uuid $id): bool
|
||||
{
|
||||
try {
|
||||
return $this->cache->has($this->getKey($id));
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function read(Uuid $id): string|false
|
||||
{
|
||||
try {
|
||||
return $this->cache->get($this->getKey($id), false);
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function write(Uuid $id, string $data): bool
|
||||
{
|
||||
try {
|
||||
return $this->cache->set($this->getKey($id), $data, $this->ttl);
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function destroy(Uuid $id): bool
|
||||
{
|
||||
try {
|
||||
return $this->cache->delete($this->getKey($id));
|
||||
} catch (\Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function gc(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
private function getKey(Uuid $id): string
|
||||
{
|
||||
return $this->prefix.$id;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue