Class Definition
export abstract class ResourceContext<
Params extends Record<string, string> = Record<string, string>,
Out = unknown,
> extends ExecutionContextBase<Out>
Type Parameters
| Parameter | Description |
|---|---|
Params | URI template parameters type |
Out | Output type |
Properties
| Property | Type | Description |
|---|---|---|
metadata | ResourceMetadata | ResourceTemplateMetadata | Resource metadata |
uri | string | The actual resource URI being read |
params | Params | Extracted URI template parameters |
output | Out | undefined | Resource content (after execution) |
resourceName | string | Resource name |
resourceId | string | Resource ID |
Abstract Method
execute(uri, params)
The main execution method that must be implemented.abstract execute(uri: string, params: Params): Promise<Out>
Return Format
Resources must returnReadResourceResult:
interface ReadResourceResult {
contents: Array<{
uri: string;
mimeType?: string;
text?: string; // Text content
blob?: string; // Base64-encoded binary
}>;
}
Methods
respond(value)
Set output and end execution immediately.respond(value: Out): never
async execute(uri: string, params: Params) {
const cached = await this.cache.get(uri);
if (cached) {
this.respond(cached); // Ends execution
}
// Continue with fetch...
}
outputHistory
History of output changes during execution.get outputHistory(): ReadonlyArray<Out>
Static Resource Example
import { Resource, ResourceContext } from '@frontmcp/sdk';
@Resource({
name: 'app-config',
uri: 'config://app',
mimeType: 'application/json',
description: 'Application configuration',
})
class AppConfigResource extends ResourceContext {
async execute(uri: string) {
const config = this.get(ConfigService);
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify({
version: config.get('APP_VERSION'),
environment: config.get('NODE_ENV'),
features: config.getObject('FEATURES'),
}, null, 2),
}],
};
}
}
Template Resource Example
import { ResourceTemplate, ResourceContext } from '@frontmcp/sdk';
@ResourceTemplate({
name: 'user-profile',
uriTemplate: 'users://{userId}/profile',
mimeType: 'application/json',
description: 'User profile by ID',
})
class UserProfileResource extends ResourceContext<{ userId: string }> {
async execute(uri: string, params: { userId: string }) {
this.mark('fetching');
const userService = this.get(UserServiceToken);
const user = await userService.findById(params.userId);
if (!user) {
this.fail(new ResourceNotFoundError(uri));
}
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify({
id: user.id,
name: user.name,
email: user.email,
createdAt: user.createdAt,
}),
}],
};
}
}
Binary Content Example
import { Resource, ResourceContext } from '@frontmcp/sdk';
import { readFile } from '@frontmcp/utils';
@Resource({
name: 'logo',
uri: 'assets://logo.png',
mimeType: 'image/png',
})
class LogoResource extends ResourceContext {
async execute(uri: string) {
const logoPath = this.get(ConfigService).get('LOGO_PATH');
const buffer = await readFile(logoPath);
return {
contents: [{
uri,
mimeType: 'image/png',
blob: buffer.toString('base64'),
}],
};
}
}
Multiple Parameters Example
import { ResourceTemplate, ResourceContext } from '@frontmcp/sdk';
interface RepoFileParams {
owner: string;
repo: string;
branch: string;
path: string;
}
@ResourceTemplate({
name: 'github-file',
uriTemplate: 'github://{owner}/{repo}/{branch}/{path}',
mimeType: 'text/plain',
description: 'File from GitHub repository',
})
class GitHubFileResource extends ResourceContext<RepoFileParams> {
async execute(uri: string, params: RepoFileParams) {
const { owner, repo, branch, path } = params;
this.logger.info('Fetching GitHub file', { owner, repo, branch, path });
const response = await this.fetch(
`https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${path}`
);
if (!response.ok) {
if (response.status === 404) {
this.fail(new ResourceNotFoundError(uri));
}
this.fail(new ResourceReadError(uri, new Error(`HTTP ${response.status}`)));
}
const content = await response.text();
const mimeType = this.detectMimeType(path);
return {
contents: [{
uri,
mimeType,
text: content,
}],
};
}
private detectMimeType(path: string): string {
if (path.endsWith('.json')) return 'application/json';
if (path.endsWith('.md')) return 'text/markdown';
if (path.endsWith('.ts') || path.endsWith('.js')) return 'text/javascript';
return 'text/plain';
}
}
Full Example with Error Handling
import { ResourceTemplate, ResourceContext, App, FrontMcp } from '@frontmcp/sdk';
import { ResourceNotFoundError, ResourceReadError } from '@frontmcp/sdk';
@ResourceTemplate({
name: 'document',
uriTemplate: 'docs://{category}/{documentId}',
title: 'Document',
description: 'Fetch documents by category and ID',
mimeType: 'application/json',
})
class DocumentResource extends ResourceContext<{ category: string; documentId: string }> {
async execute(uri: string, params: { category: string; documentId: string }) {
const { category, documentId } = params;
this.mark('validation');
if (!this.isValidCategory(category)) {
this.fail(new InvalidResourceUriError(uri, `Invalid category: ${category}`));
}
this.mark('fetching');
const docService = this.get(DocumentServiceToken);
try {
const doc = await docService.find(category, documentId);
if (!doc) {
this.fail(new ResourceNotFoundError(uri));
}
this.mark('serializing');
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify({
id: doc.id,
title: doc.title,
category,
content: doc.content,
metadata: {
author: doc.author,
createdAt: doc.createdAt,
updatedAt: doc.updatedAt,
},
}, null, 2),
}],
};
} catch (error) {
this.logger.error('Failed to read document', { uri, error });
this.fail(new ResourceReadError(uri, error as Error));
}
}
private isValidCategory(category: string): boolean {
return ['guides', 'api', 'tutorials'].includes(category);
}
}
@App({
name: 'docs',
resources: [DocumentResource],
})
class DocsApp {}
@FrontMcp({
info: { name: 'Documentation Server', version: '1.0.0' },
apps: [DocsApp],
})
export default class DocServer {}
Related
@Resource
Resource decorator
@ResourceTemplate
Template decorator
ResourceRegistry
Resource registry
Resource Errors
Resource errors