[WIP] Refactor everything server to be more modular and use recommended APIs.

Adding the get-resource-reference tool

* Updated architecture.md

* In prompts/resource.ts
  - Refactor/extracted the prompt argument completers into exported functions in resources/templates.ts
  - Refactor/extracted BLOB_TYPE, TEXT_TYPE, and resourceTypes into exported constants in resources/templates.ts as RESOURCE_TYPE_BLOB, RESOURCE_TYPE_TEXT, and RESOURCE_TYPES
  - In resources/templates.ts
    - refactor renamed index to resourceId throughout for consistency with prompts and tool references
* Added tools/get-resource-reference.ts
  - Registers the 'get-resource-reference' tool with the provided McpServer instance.
  - uses enum and number schema for tools to provide resourceType and resourceId arguments. Completables don't work for tool arguments.
  - Returns the corresponding dynamic resource
* In tools/index.ts
  - imported registerGetResourceReferenceTool
  - in registerTools
    - called registerGetResourceReferenceTool
This commit is contained in:
cliffhall
2025-12-09 17:47:38 -05:00
parent 328a990163
commit 320e3d8b25
4 changed files with 253 additions and 76 deletions

View File

@@ -0,0 +1,98 @@
import { z } from "zod";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import {
textResource,
textResourceUri,
blobResourceUri,
blobResource,
RESOURCE_TYPE_BLOB,
RESOURCE_TYPE_TEXT,
RESOURCE_TYPES,
} from "../resources/templates.js";
// Tool input schema
const GetResourceReferenceSchema = z.object({
resourceType: z
.enum([RESOURCE_TYPE_TEXT, RESOURCE_TYPE_BLOB])
.default(RESOURCE_TYPE_TEXT),
resourceId: z
.number()
.default(1)
.describe("ID of the text resource to fetch"),
});
// Tool configuration
const name = "get-resource-reference";
const config = {
title: "Get Resource Reference Tool",
description: "Adds two numbers",
inputSchema: GetResourceReferenceSchema,
};
/**
* Registers the 'get-resource-reference' tool with the provided McpServer instance.
*
* The registered tool validates and processes arguments for retrieving a resource
* reference. Supported resource types include predefined `RESOURCE_TYPE_TEXT` and
* `RESOURCE_TYPE_BLOB`. The retrieved resource's reference will include the resource
* ID, type, and its associated URI.
*
* The tool performs the following operations:
* 1. Validates the `resourceType` argument to ensure it matches a supported type.
* 2. Validates the `resourceId` argument to ensure it is a finite positive integer.
* 3. Constructs a URI for the resource based on its type (text or blob).
* 4. Retrieves the resource and returns it in a structured response object.
*
* @param {McpServer} server - The server instance where the tool is registered.
*/
export const registerGetResourceReferenceTool = (server: McpServer) => {
server.registerTool(name, config, async (args): Promise<CallToolResult> => {
// Validate resource type argument
const { resourceType } = args;
if (!RESOURCE_TYPES.includes(resourceType)) {
throw new Error(
`Invalid resourceType: ${args?.resourceType}. Must be ${RESOURCE_TYPE_TEXT} or ${RESOURCE_TYPE_BLOB}.`
);
}
// Validate resourceId argument
const resourceId = Number(args?.resourceId);
if (
!Number.isFinite(resourceId) ||
!Number.isInteger(resourceId) ||
resourceId < 1
) {
throw new Error(
`Invalid resourceId: ${args?.resourceId}. Must be a finite positive integer.`
);
}
// Get resource based on the resource type
const uri =
resourceType === RESOURCE_TYPE_TEXT
? textResourceUri(resourceId)
: blobResourceUri(resourceId);
const resource =
resourceType === RESOURCE_TYPE_TEXT
? textResource(uri, resourceId)
: blobResource(uri, resourceId);
return {
content: [
{
type: "text",
text: `Returning resource reference for Resource ${resourceId}:`,
},
{
type: "resource",
resource: resource,
},
{
type: "text",
text: `You can access this resource using the URI: ${resource.uri}`,
},
],
};
});
};