TypeScript SDK for implementing the Model Context Protocol, enabling developers to build MCP servers and clients with support for multiple transports, tools, resources, prompts, and authentication
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Resources expose data to LLMs without side effects. Resources are application-driven or user-driven (not model-controlled). Can be static (fixed URIs) or dynamic (URI templates).
server.registerResource(
name: string,
uri: string,
config: {
title?: string;
description?: string;
mimeType?: string;
icons?: Icons;
_meta?: Record<string, unknown>;
},
readCallback: (uri: URL) => Promise<ReadResourceResult> | ReadResourceResult
): RegisteredResource;import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import fs from 'fs/promises';
const server = new McpServer({ name: 'resources-server', version: '1.0.0' });
// Config resource
server.registerResource('config', 'config://app', {
title: 'Application Config',
description: 'Application configuration data',
mimeType: 'application/json'
}, async (uri) => ({
contents: [{
uri: uri.href,
mimeType: 'application/json',
text: JSON.stringify({ setting1: 'value1', setting2: 'value2' })
}]
}));
// File resource
server.registerResource('readme', 'file:///project/README.md', {
title: 'Project README',
description: 'Project documentation',
mimeType: 'text/markdown'
}, async (uri) => ({
contents: [{
uri: uri.href,
mimeType: 'text/markdown',
text: await fs.readFile('/project/README.md', 'utf-8')
}]
}));server.registerResource(
name: string,
template: ResourceTemplate,
config: { title?: string; description?: string; mimeType?: string; icons?: Icons; _meta?: Record<string, unknown>; },
readCallback: (uri: URL, variables: Variables) => Promise<ReadResourceResult> | ReadResourceResult
): RegisteredResourceTemplate;import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
import { UriTemplate, Variables } from '@modelcontextprotocol/sdk/shared/uriTemplate.js';
class ResourceTemplate {
constructor(
uriTemplate: string | UriTemplate,
callbacks: {
list?: (cursor?: string) => Promise<Resource[]> | Resource[];
complete?: {
[variable: string]: (value: string, context?: { arguments?: Record<string, unknown> }) => Promise<string[]> | string[];
};
}
);
get uriTemplate(): UriTemplate;
get listCallback(): ListResourcesCallback | undefined;
completeCallback(variable: string): CompleteResourceTemplateCallback | undefined;
}
// UriTemplate (RFC 6570)
class UriTemplate {
constructor(template: string);
match(uri: string): Variables | undefined; // Extract variables
expand(variables: Variables): string; // Expand template
toString(): string;
}
type Variables = Record<string, string>;// User profile with template
server.registerResource('user-profile',
new ResourceTemplate('users://{userId}/profile', { list: undefined }),
{ title: 'User Profile' },
async (uri, { userId }) => {
const profile = await db.getUserProfile(userId);
return { contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(profile) }] };
}
);
// Repository files with template
server.registerResource('repo-file',
new ResourceTemplate('github://repos/{owner}/{repo}/files/{path}', { list: undefined }),
{ title: 'GitHub Repository File' },
async (uri, { owner, repo, path }) => {
const content = await github.getFile(owner, repo, path);
return { contents: [{ uri: uri.href, mimeType: 'text/plain', text: content }] };
}
);
// Template with listing
server.registerResource('project-files',
new ResourceTemplate('file:///project/{path}', {
list: async (cursor) => {
const files = await listProjectFiles(cursor);
return files.map(file => ({
uri: `file:///project/${file.path}`,
name: file.name,
description: file.description,
mimeType: file.mimeType
}));
}
}),
{ title: 'Project Files' },
async (uri, { path }) => {
const content = await fs.readFile(`/project/${path}`, 'utf-8');
return { contents: [{ uri: uri.href, text: content }] };
}
);
// Template with completion
server.registerResource('repository',
new ResourceTemplate('github://repos/{owner}/{repo}', {
list: undefined,
complete: {
repo: (value, context) => {
const owner = context?.arguments?.['owner'];
if (owner === 'anthropics') {
return ['claude-sdk', 'typescript-sdk', 'python-sdk'].filter(r => r.startsWith(value));
}
return ['default-repo'].filter(r => r.startsWith(value));
}
}
}),
{ title: 'GitHub Repository' },
async (uri, { owner, repo }) => ({
contents: [{ uri: uri.href, text: `Repository: ${owner}/${repo}` }]
})
);interface ReadResourceResult {
contents: ResourceContents[];
_meta?: Record<string, unknown>;
}
type ResourceContents = TextResourceContents | BlobResourceContents;
interface TextResourceContents {
uri: string;
mimeType?: string;
text: string;
}
interface BlobResourceContents {
uri: string;
mimeType?: string;
blob: string; // Base64 encoded
}// Text resource
return {
contents: [{ uri: uri.href, mimeType: 'text/plain', text: 'Resource content here' }]
};
// JSON resource
return {
contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify({ key: 'value' }) }]
};
// Binary resource (image)
return {
contents: [{ uri: uri.href, mimeType: 'image/png', blob: base64EncodedImageData }]
};
// Multiple contents
return {
contents: [
{ uri: 'file:///project/README.md', mimeType: 'text/markdown', text: readmeContent },
{ uri: 'file:///project/LICENSE', mimeType: 'text/plain', text: licenseContent }
]
};interface RegisteredResource {
enable(): void;
disable(): void;
remove(): void;
}
interface RegisteredResourceTemplate {
enable(): void;
disable(): void;
remove(): void;
}const resource = server.registerResource('data', 'app://data', config, callback);
resource.disable();
resource.enable();
resource.remove();Requires server capability declaration:
const server = new McpServer(
{ name: 'my-server', version: '1.0.0' },
{
capabilities: {
resources: {
subscribe: true, // Enable subscriptions
listChanged: true // Enable list change notifications
}
}
}
);server.sendResourceUpdated(params: { uri: string }): Promise<void>;
server.sendResourceListChanged(): Promise<void>;// Notify about specific resource update
await server.sendResourceUpdated({ uri: 'config://app' });
// Notify that resource list changed
await server.sendResourceListChanged();interface Resource {
uri: string;
name: string;
title?: string;
description?: string;
mimeType?: string;
icons?: Icons;
_meta?: Record<string, unknown>;
}
interface ResourceTemplate {
uriTemplate: string;
name: string;
title?: string;
description?: string;
mimeType?: string;
icons?: Icons;
_meta?: Record<string, unknown>;
}
interface ListResourcesResult {
resources: Resource[];
nextCursor?: string;
}
interface ListResourceTemplatesResult {
resourceTemplates: ResourceTemplate[];
nextCursor?: string;
}
interface Icons {
icon?: Icon;
light?: Icon;
dark?: Icon;
}
interface Icon {
src: string;
mimeType?: string;
size?: string;
}server.resource(name: string, uri: string, readCallback: ReadResourceCallback): RegisteredResource;
server.resource(name: string, uri: string, metadata: ResourceMetadata, readCallback: ReadResourceCallback): RegisteredResource;
server.resource(name: string, template: ResourceTemplate, readCallback: ReadResourceTemplateCallback): RegisteredResourceTemplate;
server.resource(name: string, template: ResourceTemplate, metadata: ResourceMetadata, readCallback: ReadResourceTemplateCallback): RegisteredResourceTemplate;Use registerResource for new code.