feat: Introduce MCP Resource Types and Service Methods
This commit is contained in:
parent
85a61a7c96
commit
89166a79d4
|
|
@ -33,7 +33,11 @@ import type {
|
|||
MCPConnection,
|
||||
MCPPhaseCallback,
|
||||
MCPConnectionLog,
|
||||
MCPServerInfo
|
||||
MCPServerInfo,
|
||||
MCPResource,
|
||||
MCPResourceTemplate,
|
||||
MCPResourceContent,
|
||||
MCPReadResourceResult
|
||||
} from '$lib/types';
|
||||
import { MCPConnectionPhase, MCPLogLevel, MCPTransportType } from '$lib/enums';
|
||||
import { DEFAULT_MCP_CONFIG } from '$lib/constants/mcp';
|
||||
|
|
@ -435,4 +439,176 @@ export class MCPService {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Resources Operations
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* List resources from a connection.
|
||||
* @param connection - The MCP connection to use
|
||||
* @param cursor - Optional pagination cursor
|
||||
* @returns Array of available resources and optional next cursor
|
||||
*/
|
||||
static async listResources(
|
||||
connection: MCPConnection,
|
||||
cursor?: string
|
||||
): Promise<{ resources: MCPResource[]; nextCursor?: string }> {
|
||||
try {
|
||||
const result = await connection.client.listResources(cursor ? { cursor } : undefined);
|
||||
return {
|
||||
resources: (result.resources ?? []) as MCPResource[],
|
||||
nextCursor: result.nextCursor
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(`[MCPService][${connection.serverName}] Failed to list resources:`, error);
|
||||
return { resources: [] };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List all resources from a connection (handles pagination automatically).
|
||||
* @param connection - The MCP connection to use
|
||||
* @returns Array of all available resources
|
||||
*/
|
||||
static async listAllResources(connection: MCPConnection): Promise<MCPResource[]> {
|
||||
const allResources: MCPResource[] = [];
|
||||
let cursor: string | undefined;
|
||||
|
||||
do {
|
||||
const result = await this.listResources(connection, cursor);
|
||||
allResources.push(...result.resources);
|
||||
cursor = result.nextCursor;
|
||||
} while (cursor);
|
||||
|
||||
return allResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* List resource templates from a connection.
|
||||
* @param connection - The MCP connection to use
|
||||
* @param cursor - Optional pagination cursor
|
||||
* @returns Array of available resource templates and optional next cursor
|
||||
*/
|
||||
static async listResourceTemplates(
|
||||
connection: MCPConnection,
|
||||
cursor?: string
|
||||
): Promise<{ resourceTemplates: MCPResourceTemplate[]; nextCursor?: string }> {
|
||||
try {
|
||||
const result = await connection.client.listResourceTemplates(cursor ? { cursor } : undefined);
|
||||
return {
|
||||
resourceTemplates: (result.resourceTemplates ?? []) as MCPResourceTemplate[],
|
||||
nextCursor: result.nextCursor
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`[MCPService][${connection.serverName}] Failed to list resource templates:`,
|
||||
error
|
||||
);
|
||||
return { resourceTemplates: [] };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List all resource templates from a connection (handles pagination automatically).
|
||||
* @param connection - The MCP connection to use
|
||||
* @returns Array of all available resource templates
|
||||
*/
|
||||
static async listAllResourceTemplates(connection: MCPConnection): Promise<MCPResourceTemplate[]> {
|
||||
const allTemplates: MCPResourceTemplate[] = [];
|
||||
let cursor: string | undefined;
|
||||
|
||||
do {
|
||||
const result = await this.listResourceTemplates(connection, cursor);
|
||||
allTemplates.push(...result.resourceTemplates);
|
||||
cursor = result.nextCursor;
|
||||
} while (cursor);
|
||||
|
||||
return allTemplates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the contents of a resource.
|
||||
* @param connection - The MCP connection to use
|
||||
* @param uri - The URI of the resource to read
|
||||
* @returns The resource contents
|
||||
*/
|
||||
static async readResource(
|
||||
connection: MCPConnection,
|
||||
uri: string
|
||||
): Promise<MCPReadResourceResult> {
|
||||
try {
|
||||
const result = await connection.client.readResource({ uri });
|
||||
return {
|
||||
contents: (result.contents ?? []) as MCPResourceContent[],
|
||||
_meta: result._meta
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`[MCPService][${connection.serverName}] Failed to read resource:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to updates for a resource.
|
||||
* The server will send notifications/resources/updated when the resource changes.
|
||||
* @param connection - The MCP connection to use
|
||||
* @param uri - The URI of the resource to subscribe to
|
||||
*/
|
||||
static async subscribeResource(connection: MCPConnection, uri: string): Promise<void> {
|
||||
try {
|
||||
await connection.client.subscribeResource({ uri });
|
||||
console.log(`[MCPService][${connection.serverName}] Subscribed to resource: ${uri}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[MCPService][${connection.serverName}] Failed to subscribe to resource:`,
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from updates for a resource.
|
||||
* @param connection - The MCP connection to use
|
||||
* @param uri - The URI of the resource to unsubscribe from
|
||||
*/
|
||||
static async unsubscribeResource(connection: MCPConnection, uri: string): Promise<void> {
|
||||
try {
|
||||
await connection.client.unsubscribeResource({ uri });
|
||||
console.log(`[MCPService][${connection.serverName}] Unsubscribed from resource: ${uri}`);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[MCPService][${connection.serverName}] Failed to unsubscribe from resource:`,
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a connection supports resources.
|
||||
* Per MCP spec: presence of the `resources` key (even as empty object {}) indicates support.
|
||||
* Empty object means resources are supported but no sub-features (subscribe, listChanged).
|
||||
* @param connection - The MCP connection to check
|
||||
* @returns Whether the server supports resources
|
||||
*/
|
||||
static supportsResources(connection: MCPConnection): boolean {
|
||||
// Per MCP spec: "Servers that support resources MUST declare the resources capability"
|
||||
// The presence of the key indicates support, even if it's an empty object
|
||||
return connection.serverCapabilities?.resources !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a connection supports resource subscriptions.
|
||||
* @param connection - The MCP connection to check
|
||||
* @returns Whether the server supports resource subscriptions
|
||||
*/
|
||||
static supportsResourceSubscriptions(connection: MCPConnection): boolean {
|
||||
return !!connection.serverCapabilities?.resources?.subscribe;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,22 @@ export type {
|
|||
Tool,
|
||||
Prompt,
|
||||
GetPromptResult,
|
||||
PromptMessage
|
||||
PromptMessage,
|
||||
MCPProgressState,
|
||||
MCPResourceAnnotations,
|
||||
MCPResourceIcon,
|
||||
MCPResource,
|
||||
MCPResourceTemplate,
|
||||
MCPTextResourceContent,
|
||||
MCPBlobResourceContent,
|
||||
MCPResourceContent,
|
||||
MCPReadResourceResult,
|
||||
MCPResourceInfo,
|
||||
MCPResourceTemplateInfo,
|
||||
MCPCachedResource,
|
||||
MCPResourceAttachment,
|
||||
MCPResourceSubscription,
|
||||
MCPServerResources
|
||||
} from './mcp';
|
||||
|
||||
// Agentic types
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ export type HealthCheckState =
|
|||
*/
|
||||
export interface HealthCheckParams {
|
||||
id: string;
|
||||
enabled: boolean;
|
||||
url: string;
|
||||
requestTimeoutSeconds: number;
|
||||
headers?: string;
|
||||
|
|
@ -249,3 +250,167 @@ export interface ToolExecutionResult {
|
|||
content: string;
|
||||
isError: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress tracking state for a specific operation
|
||||
*/
|
||||
export interface MCPProgressState {
|
||||
progressToken: string | number;
|
||||
serverName: string;
|
||||
progress: number;
|
||||
total?: number;
|
||||
message?: string;
|
||||
startTime: Date;
|
||||
lastUpdate: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource annotations for audience and priority hints
|
||||
*/
|
||||
export interface MCPResourceAnnotations {
|
||||
audience?: ('user' | 'assistant')[];
|
||||
priority?: number;
|
||||
lastModified?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon definition for resources
|
||||
*/
|
||||
export interface MCPResourceIcon {
|
||||
src: string;
|
||||
mimeType?: string;
|
||||
sizes?: string[];
|
||||
theme?: 'light' | 'dark';
|
||||
}
|
||||
|
||||
/**
|
||||
* A known resource that the server is capable of reading
|
||||
*/
|
||||
export interface MCPResource {
|
||||
uri: string;
|
||||
name: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
mimeType?: string;
|
||||
annotations?: MCPResourceAnnotations;
|
||||
icons?: MCPResourceIcon[];
|
||||
_meta?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A template for dynamically generating resource URIs
|
||||
*/
|
||||
export interface MCPResourceTemplate {
|
||||
uriTemplate: string;
|
||||
name: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
mimeType?: string;
|
||||
annotations?: MCPResourceAnnotations;
|
||||
icons?: MCPResourceIcon[];
|
||||
_meta?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text content from a resource
|
||||
*/
|
||||
export interface MCPTextResourceContent {
|
||||
uri: string;
|
||||
mimeType?: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binary (blob) content from a resource
|
||||
*/
|
||||
export interface MCPBlobResourceContent {
|
||||
uri: string;
|
||||
mimeType?: string;
|
||||
/** Base64-encoded binary data */
|
||||
blob: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union type for resource content
|
||||
*/
|
||||
export type MCPResourceContent = MCPTextResourceContent | MCPBlobResourceContent;
|
||||
|
||||
/**
|
||||
* Result from reading a resource
|
||||
*/
|
||||
export interface MCPReadResourceResult {
|
||||
contents: MCPResourceContent[];
|
||||
_meta?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource information for display in UI
|
||||
*/
|
||||
export interface MCPResourceInfo {
|
||||
uri: string;
|
||||
name: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
mimeType?: string;
|
||||
serverName: string;
|
||||
annotations?: MCPResourceAnnotations;
|
||||
icons?: MCPResourceIcon[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource template information for display in UI
|
||||
*/
|
||||
export interface MCPResourceTemplateInfo {
|
||||
uriTemplate: string;
|
||||
name: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
mimeType?: string;
|
||||
serverName: string;
|
||||
annotations?: MCPResourceAnnotations;
|
||||
icons?: MCPResourceIcon[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached resource content with metadata
|
||||
*/
|
||||
export interface MCPCachedResource {
|
||||
resource: MCPResourceInfo;
|
||||
content: MCPResourceContent[];
|
||||
fetchedAt: Date;
|
||||
/** Whether this resource has an active subscription */
|
||||
subscribed?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource attachment for chat context
|
||||
*/
|
||||
export interface MCPResourceAttachment {
|
||||
id: string;
|
||||
resource: MCPResourceInfo;
|
||||
content?: MCPResourceContent[];
|
||||
loading?: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* State for resource subscriptions
|
||||
*/
|
||||
export interface MCPResourceSubscription {
|
||||
uri: string;
|
||||
serverName: string;
|
||||
subscribedAt: Date;
|
||||
lastUpdate?: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregated resources state per server
|
||||
*/
|
||||
export interface MCPServerResources {
|
||||
serverName: string;
|
||||
resources: MCPResource[];
|
||||
templates: MCPResourceTemplate[];
|
||||
lastFetched?: Date;
|
||||
loading: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue