Resources provide access to static data that clients can read.
use Mcp\Capability\Attribute\McpResource;
class ConfigProvider
{
/**
* Provides the current application configuration.
*/
#[McpResource(uri: 'config://app/settings', name: 'app_settings')]
public function getSettings(): array
{
return [
'version' => '1.0.0',
'debug' => false,
'features' => ['auth', 'logging']
];
}
}uri(required): Unique resource identifier. Must comply with RFC 3986.name(optional): Short resource identifier. Defaults to method name if not provided.title(optional): Human-readable display title shown in client UI. Distinct fromname.description(optional): Resource description. Falls back to the docblock (summary plus long description).mimeType(optional): MIME type of the resource content.size(optional): Size in bytes if known.annotations(optional): Additional metadata.icons(optional): Array ofIconobjects for visual representation.meta(optional): Arbitrary key-value pairs for custom metadata.
Standard Protocol URI Schemes: https:// (web resources), file:// (filesystem), git:// (version control).
Custom schemes: config://, data://, db://, api:// or any RFC 3986 compliant scheme.
Resource handlers can return various data types that are automatically formatted into appropriate MCP resource content types.
// String content - converted to text resource
public function getTextFile(): string
{
return "File content here";
}
// Array content - converted to JSON
public function getConfig(): array
{
return ['debug' => true, 'version' => '1.0'];
}
// Stream resource - read and converted to blob.
// `resource` is not a PHP type declaration, so the return type is left off.
/** @return resource */
public function getImageStream()
{
return fopen('image.png', 'r');
}
// SplFileInfo - file content with MIME type detection
public function getFileInfo(): \SplFileInfo
{
return new \SplFileInfo('document.pdf');
}Explicit resource content types
use Mcp\Schema\Content\{TextResourceContents, BlobResourceContents};
public function getExplicitText(): TextResourceContents
{
return new TextResourceContents(
uri: 'config://app/settings',
mimeType: 'application/json',
text: json_encode(['setting' => 'value'])
);
}
public function getExplicitBlob(): BlobResourceContents
{
return new BlobResourceContents(
uri: 'file://image.png',
mimeType: 'image/png',
blob: base64_encode(file_get_contents('image.png'))
);
}Special Array Formats
// Array with 'text' key - used as text content
public function getTextArray(): array
{
return ['text' => 'Content here', 'mimeType' => 'text/plain'];
}
// Array with 'blob' key - used as blob content
public function getBlobArray(): array
{
return ['blob' => base64_encode($data), 'mimeType' => 'image/png'];
}
// Multiple resource contents
public function getMultipleResources(): array
{
return [
new TextResourceContents('file://readme.txt', 'text/plain', 'README content'),
new TextResourceContents('file://config.json', 'application/json', '{"key": "value"}')
];
}Resource handlers can throw any exception, but the type determines how it's handled:
ResourceReadException: Converted to JSON-RPC error response with the actual exception message- Any other exception: Converted to JSON-RPC error response, but with a generic error message
use Mcp\Capability\Attribute\McpResourceTemplate;
use Mcp\Exception\ResourceReadException;
// A URI with variables is a resource *template*; `#[McpResource]` registers a
// fixed URI and would never receive `$path`. Note a variable matches a single
// segment, so `$path` here cannot contain `/`.
#[McpResourceTemplate(uriTemplate: 'file://{path}')]
public function getFile(string $path): string
{
if (!file_exists($path)) {
throw new ResourceReadException("File not found: {$path}");
}
if (!is_readable($path)) {
throw new ResourceReadException("File not readable: {$path}");
}
return file_get_contents($path);
}Recommendation: Use ResourceReadException when you want to communicate specific errors to clients. Any other exception will still be converted to JSON-RPC compliant errors but with generic error messages.