From 42c3967d8b04f2a95550102967f65763719fceb5 Mon Sep 17 00:00:00 2001 From: ihrpr Date: Mon, 16 Jun 2025 14:23:17 +0100 Subject: [PATCH] add to readme --- README.md | 111 ++++++++++++++++++++++++++++++++++++++++- src/server/mcp.test.ts | 28 +++++++---- 2 files changed, 128 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ff6c482f..63acfb06 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,33 @@ server.registerResource( }] }) ); + +// Resource with context-aware completion +server.registerResource( + "repository", + new ResourceTemplate("github://repos/{owner}/{repo}", { + list: undefined, + complete: { + // Provide intelligent completions based on previously resolved parameters + repo: (value, context) => { + if (context?.arguments?.["owner"] === "org1") { + return ["project1", "project2", "project3"].filter(r => r.startsWith(value)); + } + return ["default-repo"].filter(r => r.startsWith(value)); + } + } + }), + { + title: "GitHub Repository", + description: "Repository information" + }, + async (uri, { owner, repo }) => ({ + contents: [{ + uri: uri.href, + text: `Repository: ${owner}/${repo}` + }] + }) +); ``` ### Tools @@ -233,12 +260,14 @@ Tools can return `ResourceLink` objects to reference resources without embedding Prompts are reusable templates that help LLMs interact with your server effectively: ```typescript +import { completable } from "@modelcontextprotocol/sdk/server/completable.js"; + server.registerPrompt( "review-code", { title: "Code Review", description: "Review code for best practices and potential issues", - arguments: { code: z.string() } + argsSchema: { code: z.string() } }, ({ code }) => ({ messages: [{ @@ -250,6 +279,35 @@ server.registerPrompt( }] }) ); + +// Prompt with context-aware completion +server.registerPrompt( + "team-greeting", + { + title: "Team Greeting", + description: "Generate a greeting for team members", + argsSchema: { + // Completable arguments can use context for intelligent suggestions + name: completable(z.string(), (value, context) => { + if (context?.arguments?.["department"] === "engineering") { + return ["Alice", "Bob", "Charlie"].filter(n => n.startsWith(value)); + } else if (context?.arguments?.["department"] === "sales") { + return ["David", "Eve", "Frank"].filter(n => n.startsWith(value)); + } + return ["Guest"].filter(n => n.startsWith(value)); + }) + } + }, + ({ name }) => ({ + messages: [{ + role: "assistant", + content: { + type: "text", + text: `Hello ${name}, welcome to the team!` + } + }] + }) +); ``` ### Display Names and Metadata @@ -637,6 +695,57 @@ server.registerTool( ## Advanced Usage +### Context-Aware Completions + +MCP supports intelligent completions that can use previously resolved values as context. This is useful for creating dependent parameter completions where later parameters depend on earlier ones: + +```typescript +import { completable } from "@modelcontextprotocol/sdk/server/completable.js"; + +// For resource templates +server.registerResource( + "database-query", + new ResourceTemplate("db://{database}/{table}/{query}", { + list: undefined, + complete: { + // Table completions depend on the selected database + table: (value, context) => { + const database = context?.arguments?.["database"]; + if (database === "users_db") { + return ["profiles", "sessions", "preferences"].filter(t => t.startsWith(value)); + } else if (database === "products_db") { + return ["items", "categories", "inventory"].filter(t => t.startsWith(value)); + } + return []; + } + } + }), + metadata, + handler +); + +// For prompts with completable arguments +server.registerPrompt( + "api-request", + { + argsSchema: { + endpoint: z.string(), + // Method completions can be context-aware + method: completable(z.string(), (value, context) => { + const endpoint = context?.arguments?.["endpoint"]; + if (endpoint?.includes("/readonly/")) { + return ["GET"].filter(m => m.startsWith(value.toUpperCase())); + } + return ["GET", "POST", "PUT", "DELETE"].filter(m => m.startsWith(value.toUpperCase())); + }) + } + }, + handler +); +``` + +The context object contains an `arguments` field with previously resolved parameter values, allowing you to provide more intelligent and contextual completions. + ### Dynamic Servers If you want to offer an initial set of tools/prompts/resources, but later add additional ones based on user action or external state change, you can add/update/remove them _after_ the Server is connected. This will automatically emit the corresponding `listChanged` notifications: diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index 23600db4..685987bf 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -3747,7 +3747,7 @@ describe("Tool title precedence", () => { version: "1.0", }); - mcpServer.resource( + mcpServer.registerResource( "test", new ResourceTemplate("github://repos/{owner}/{repo}", { list: undefined, @@ -3762,6 +3762,10 @@ describe("Tool title precedence", () => { }, }, }), + { + title: "GitHub Repository", + description: "Repository information" + }, async () => ({ contents: [ { @@ -3865,17 +3869,21 @@ describe("Tool title precedence", () => { version: "1.0", }); - mcpServer.prompt( + mcpServer.registerPrompt( "test-prompt", { - name: completable(z.string(), (value, context) => { - if (context?.arguments?.["category"] === "developers") { - return ["Alice", "Bob", "Charlie"].filter(n => n.startsWith(value)); - } else if (context?.arguments?.["category"] === "managers") { - return ["David", "Eve", "Frank"].filter(n => n.startsWith(value)); - } - return ["Guest"].filter(n => n.startsWith(value)); - }), + title: "Team Greeting", + description: "Generate a greeting for team members", + argsSchema: { + name: completable(z.string(), (value, context) => { + if (context?.arguments?.["category"] === "developers") { + return ["Alice", "Bob", "Charlie"].filter(n => n.startsWith(value)); + } else if (context?.arguments?.["category"] === "managers") { + return ["David", "Eve", "Frank"].filter(n => n.startsWith(value)); + } + return ["Guest"].filter(n => n.startsWith(value)); + }), + } }, async ({ name }) => ({ messages: [