You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor: address reviewer feedback and clean up discovery caching
- Make DiscoveryState class final
- Cache DiscoveryState objects directly instead of arrays (no serialization needed)
- Rename exportDiscoveryState/importDiscoveryState to getDiscoveryState/setDiscoveryState
- Add getDiscoveryState method to ReferenceRegistryInterface
- Remove TTL parameter from CachedDiscoverer (no expiration by default)
- Remove unused methods from DiscoveryState (toArray, fromArray, merge)
- Simplify ServerBuilder to handle decoration internally
- Make Discoverer.applyDiscoveryState() internal (no longer public API)
- Simplify documentation to focus on user perspective
- Remove unnecessary development comments
- Update all tests to work with new architecture
- All tests pass, PHPStan clean, code formatting applied
This document explains the discovery caching feature in the PHP MCP SDK, which improves performance by caching the results of file system operations and reflection during MCP element discovery.
3
+
This document explains how to use the discovery caching feature in the PHP MCP SDK to improve performance.
4
4
5
5
## Overview
6
6
7
-
The discovery caching system allows you to cache the results of MCP element discovery to avoid repeated file system scanning and reflection operations. This is particularly useful in:
7
+
The discovery caching system caches the results of MCP element discovery to avoid repeated file system scanning and reflection operations. This is particularly useful in:
8
8
9
9
-**Development environments** where the server is restarted frequently
10
10
-**Production environments** where discovery happens on every request
11
11
-**Large codebases** with many MCP elements to discover
12
12
13
-
## Architecture
14
-
15
-
The caching system is built around a state-based approach that eliminates the need for reflection to access private registry state:
16
-
17
-
### Core Components
18
-
19
-
1.**`DiscoveryState`** - A value object that encapsulates all discovered MCP capabilities
20
-
2.**`CachedDiscoverer`** - A decorator that wraps the `Discoverer` and provides caching functionality
21
-
3.**`Registry`** - Enhanced with `exportDiscoveryState()` and `importDiscoveryState()` methods
22
-
4.**`ServerBuilder`** - Updated with `withCache()` method for easy cache configuration
23
-
24
-
### Key Benefits
25
-
26
-
-**No Reflection Required**: Uses clean public APIs instead of accessing private state
27
-
-**State-Based**: Encapsulates discovered elements in a dedicated state object
28
-
-**PSR-16 Compatible**: Works with any PSR-16 SimpleCache implementation
29
-
-**Backward Compatible**: Existing code continues to work without changes
30
-
31
13
## Usage
32
14
33
15
### Basic Setup
@@ -49,112 +31,30 @@ $server = Server::make()
49
31
The caching system works with any PSR-16 SimpleCache implementation. Popular options include:
50
32
51
33
#### Symfony Cache
34
+
52
35
```php
53
36
use Symfony\Component\Cache\Adapter\ArrayAdapter;
54
37
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
55
-
use Symfony\Component\Cache\Adapter\RedisAdapter;
56
38
use Symfony\Component\Cache\Psr16Cache;
57
39
58
40
// In-memory cache (development)
59
41
$cache = new Psr16Cache(new ArrayAdapter());
60
42
61
43
// Filesystem cache (production)
62
-
$cache = new Psr16Cache(new FilesystemAdapter('cache', 0, __DIR__ . '/var/cache'));
63
-
64
-
// Redis cache (distributed)
65
-
$cache = new Psr16Cache(new RedisAdapter($redisClient));
44
+
$cache = new Psr16Cache(new FilesystemAdapter('mcp-discovery', 0, '/var/cache'));
66
45
```
67
46
68
47
#### Other PSR-16 Implementations
48
+
69
49
```php
70
50
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
71
51
use Doctrine\Common\Cache\ArrayCache;
72
52
73
-
// Doctrine cache
74
-
$doctrineCache = new ArrayCache();
75
-
$cache = DoctrineProvider::wrap($doctrineCache);
76
-
```
77
-
78
-
## Configuration
79
-
80
-
### Cache TTL (Time To Live)
81
-
82
-
The default cache TTL is 1 hour (3600 seconds). You can customize this when creating the `CachedDiscoverer`:
83
-
84
-
```php
85
-
use Mcp\Capability\Discovery\CachedDiscoverer;
86
-
use Mcp\Capability\Discovery\Discoverer;
87
-
88
-
$discoverer = new Discoverer($registry, $logger);
89
-
$cachedDiscoverer = new CachedDiscoverer(
90
-
$discoverer,
91
-
$cache,
92
-
$logger,
93
-
7200 // 2 hours TTL
94
-
);
95
-
```
96
-
97
-
### Cache Key Generation
98
-
99
-
Cache keys are automatically generated based on:
100
-
- Base path for discovery
101
-
- Directories to scan
102
-
- Exclude directories
103
-
- File modification times (implicitly through file system state)
104
-
105
-
This ensures that cache invalidation happens automatically when files change.
106
-
107
-
## Advanced Usage
108
-
109
-
### Manual Cache Management
110
-
111
-
```php
112
-
use Mcp\Capability\Discovery\CachedDiscoverer;
113
-
114
-
$cachedDiscoverer = new CachedDiscoverer($discoverer, $cache, $logger);
->withServerInfo('Cached Calculator', '1.0.0', 'Calculator with cached discovery')
234
-
->withDiscovery(__DIR__, ['.'])
235
-
->withLogger(logger())
236
-
->withCache($cache) // Enable discovery caching
237
-
->build();
238
-
239
-
// Connect and start serving
240
-
$server->connect(new StdioTransport());
241
-
```
242
-
243
-
## Migration Guide
244
-
245
-
### From Non-Cached to Cached
246
-
247
-
1.**Add cache dependency**:
248
-
```bash
249
-
composer require symfony/cache
250
-
```
251
-
252
-
2.**Update server configuration**:
253
-
```php
254
-
// Before
255
-
$server = Server::make()
256
-
->withDiscovery(__DIR__, ['.'])
257
-
->build();
258
-
259
-
// After
260
-
$server = Server::make()
261
-
->withDiscovery(__DIR__, ['.'])
262
-
->withCache(new Psr16Cache(new ArrayAdapter()))
263
-
->build();
264
-
```
265
-
266
-
3.**No other changes required** - the API remains the same!
267
-
268
-
## API Reference
269
-
270
-
### DiscoveryState
271
-
272
-
```php
273
-
class DiscoveryState
274
-
{
275
-
public function __construct(
276
-
array $tools = [],
277
-
array $resources = [],
278
-
array $prompts = [],
279
-
array $resourceTemplates = []
280
-
);
281
-
282
-
public function getTools(): array;
283
-
public function getResources(): array;
284
-
public function getPrompts(): array;
285
-
public function getResourceTemplates(): array;
286
-
public function isEmpty(): bool;
287
-
public function getElementCount(): int;
288
-
public function getElementCounts(): array;
289
-
public function merge(DiscoveryState $other): DiscoveryState;
290
-
public function toArray(): array;
291
-
public static function fromArray(array $data): DiscoveryState;
292
-
}
293
-
```
294
-
295
-
### CachedDiscoverer
296
-
297
-
```php
298
-
class CachedDiscoverer
299
-
{
300
-
public function __construct(
301
-
Discoverer $discoverer,
302
-
CacheInterface $cache,
303
-
LoggerInterface $logger,
304
-
int $cacheTtl = 3600
305
-
);
306
-
307
-
public function discover(string $basePath, array $directories, array $excludeDirs = []): DiscoveryState;
308
-
public function clearCache(): void;
309
-
}
310
-
```
311
-
312
-
### ServerBuilder
313
-
314
-
```php
315
-
class ServerBuilder
316
-
{
317
-
public function withCache(CacheInterface $cache): self;
318
-
// ... other methods
319
-
}
320
-
```
321
-
322
-
## Conclusion
323
-
324
-
Discovery caching provides significant performance improvements for MCP servers, especially in development environments and production deployments with frequent restarts. The state-based architecture ensures clean separation of concerns while maintaining backward compatibility with existing code.
325
107
326
-
For more examples, see the `examples/10-cached-discovery-stdio/` directory in the SDK.
108
+
- Use filesystem cache instead of in-memory cache for large codebases
109
+
- Consider using a dedicated cache server (Redis, Memcached) for high-traffic applications
0 commit comments