improve readme

This commit is contained in:
ihrpr 2025-06-16 14:36:35 +01:00
commit 0e86a6d139
No known key found for this signature in database
2 changed files with 53 additions and 66 deletions

View file

@ -287,23 +287,30 @@ server.registerPrompt(
title: "Team Greeting",
description: "Generate a greeting for team members",
argsSchema: {
// Completable arguments can use context for intelligent suggestions
department: completable(z.string(), (value) => {
// Department suggestions
return ["engineering", "sales", "marketing", "support"].filter(d => d.startsWith(value));
}),
name: completable(z.string(), (value, context) => {
if (context?.arguments?.["department"] === "engineering") {
// Name suggestions based on selected department
const department = context?.arguments?.["department"];
if (department === "engineering") {
return ["Alice", "Bob", "Charlie"].filter(n => n.startsWith(value));
} else if (context?.arguments?.["department"] === "sales") {
} else if (department === "sales") {
return ["David", "Eve", "Frank"].filter(n => n.startsWith(value));
} else if (department === "marketing") {
return ["Grace", "Henry", "Iris"].filter(n => n.startsWith(value));
}
return ["Guest"].filter(n => n.startsWith(value));
})
}
},
({ name }) => ({
({ department, name }) => ({
messages: [{
role: "assistant",
content: {
type: "text",
text: `Hello ${name}, welcome to the team!`
text: `Hello ${name}, welcome to the ${department} team!`
}
}]
})
@ -695,57 +702,6 @@ 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:

View file

@ -3875,23 +3875,29 @@ describe("Tool title precedence", () => {
title: "Team Greeting",
description: "Generate a greeting for team members",
argsSchema: {
department: completable(z.string(), (value) => {
return ["engineering", "sales", "marketing", "support"].filter(d => d.startsWith(value));
}),
name: completable(z.string(), (value, context) => {
if (context?.arguments?.["category"] === "developers") {
const department = context?.arguments?.["department"];
if (department === "engineering") {
return ["Alice", "Bob", "Charlie"].filter(n => n.startsWith(value));
} else if (context?.arguments?.["category"] === "managers") {
} else if (department === "sales") {
return ["David", "Eve", "Frank"].filter(n => n.startsWith(value));
} else if (department === "marketing") {
return ["Grace", "Henry", "Iris"].filter(n => n.startsWith(value));
}
return ["Guest"].filter(n => n.startsWith(value));
}),
}
},
async ({ name }) => ({
async ({ department, name }) => ({
messages: [
{
role: "assistant",
content: {
type: "text",
text: `Hello ${name}`,
text: `Hello ${name}, welcome to the ${department} team!`,
},
},
],
@ -3906,7 +3912,7 @@ describe("Tool title precedence", () => {
mcpServer.server.connect(serverTransport),
]);
// Test with developers category
// Test with engineering department
const result1 = await client.request(
{
method: "completion/complete",
@ -3921,7 +3927,7 @@ describe("Tool title precedence", () => {
},
context: {
arguments: {
category: "developers",
department: "engineering",
},
},
},
@ -3931,7 +3937,7 @@ describe("Tool title precedence", () => {
expect(result1.completion.values).toEqual(["Alice"]);
// Test with managers category
// Test with sales department
const result2 = await client.request(
{
method: "completion/complete",
@ -3946,7 +3952,7 @@ describe("Tool title precedence", () => {
},
context: {
arguments: {
category: "managers",
department: "sales",
},
},
},
@ -3956,8 +3962,33 @@ describe("Tool title precedence", () => {
expect(result2.completion.values).toEqual(["David"]);
// Test with no resolved context
// Test with marketing department
const result3 = await client.request(
{
method: "completion/complete",
params: {
ref: {
type: "ref/prompt",
name: "test-prompt",
},
argument: {
name: "name",
value: "G",
},
context: {
arguments: {
department: "marketing",
},
},
},
},
CompleteResultSchema,
);
expect(result3.completion.values).toEqual(["Grace"]);
// Test with no resolved context
const result4 = await client.request(
{
method: "completion/complete",
params: {
@ -3974,6 +4005,6 @@ describe("Tool title precedence", () => {
CompleteResultSchema,
);
expect(result3.completion.values).toEqual(["Guest"]);
expect(result4.completion.values).toEqual(["Guest"]);
});
});