@mcp-layer/test-server 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +138 -0
- package/package.json +40 -0
- package/src/bin.js +14 -0
- package/src/config.js +12 -0
- package/src/data/manual.js +22 -0
- package/src/data/notes.js +72 -0
- package/src/data/references.js +20 -0
- package/src/http.js +6 -0
- package/src/index.js +54 -0
- package/src/prompts/index.js +9 -0
- package/src/prompts/welcome.js +63 -0
- package/src/resources/index.js +14 -0
- package/src/resources/manual.js +43 -0
- package/src/resources/notes.js +104 -0
- package/src/resources/ui.js +58 -0
- package/src/shared/capabilities.js +18 -0
- package/src/subscriptions/resources.js +70 -0
- package/src/tools/add.js +44 -0
- package/src/tools/annotated.js +44 -0
- package/src/tools/batch.js +43 -0
- package/src/tools/booking.js +107 -0
- package/src/tools/dashboard.js +53 -0
- package/src/tools/echo.js +45 -0
- package/src/tools/files.js +79 -0
- package/src/tools/index.js +37 -0
- package/src/tools/logs.js +56 -0
- package/src/tools/note-update.js +56 -0
- package/src/tools/present.js +76 -0
- package/src/tools/progress.js +85 -0
- package/src/tools/rebalance.js +49 -0
- package/src/tools/roots.js +98 -0
- package/src/tools/summaries.js +96 -0
- package/src/transport/http.js +77 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const html = [
|
|
2
|
+
'<!doctype html>',
|
|
3
|
+
'<html lang="en">',
|
|
4
|
+
' <head>',
|
|
5
|
+
' <meta charset="utf-8" />',
|
|
6
|
+
' <title>MCP Dashboard</title>',
|
|
7
|
+
' </head>',
|
|
8
|
+
' <body>',
|
|
9
|
+
' <main>',
|
|
10
|
+
' <h1>Dashboard</h1>',
|
|
11
|
+
' <p>UI resource served via ui:// scheme.</p>',
|
|
12
|
+
' </main>',
|
|
13
|
+
' </body>',
|
|
14
|
+
'</html>',
|
|
15
|
+
''
|
|
16
|
+
].join('\n');
|
|
17
|
+
|
|
18
|
+
const uri = 'ui://dashboard/app.html';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register the MCP App UI resource.
|
|
22
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
23
|
+
*/
|
|
24
|
+
export function registerUi(server) {
|
|
25
|
+
/**
|
|
26
|
+
* Return HTML for the dashboard UI.
|
|
27
|
+
* @param {URL} url
|
|
28
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').ReadResourceResult>}
|
|
29
|
+
*/
|
|
30
|
+
async function ui(url) {
|
|
31
|
+
return {
|
|
32
|
+
contents: [
|
|
33
|
+
{
|
|
34
|
+
uri: url.href,
|
|
35
|
+
mimeType: 'text/html',
|
|
36
|
+
text: html
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
server.registerResource(
|
|
43
|
+
'dashboard-ui',
|
|
44
|
+
uri,
|
|
45
|
+
{
|
|
46
|
+
title: 'Dashboard UI',
|
|
47
|
+
description: 'MCP App UI for the dashboard tool.',
|
|
48
|
+
mimeType: 'text/html',
|
|
49
|
+
_meta: {
|
|
50
|
+
ui: {
|
|
51
|
+
csp: "default-src 'self'",
|
|
52
|
+
permissions: ['clipboard-read']
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
ui
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a capability checker bound to the current server connection.
|
|
3
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
4
|
+
* @returns {(capability: 'sampling' | 'elicitation' | 'roots') => boolean}
|
|
5
|
+
*/
|
|
6
|
+
export function createCapabilityChecker(server) {
|
|
7
|
+
/**
|
|
8
|
+
* Determine whether the connected client declared the requested capability.
|
|
9
|
+
* @param {'sampling' | 'elicitation' | 'roots'} capability
|
|
10
|
+
* @returns {boolean}
|
|
11
|
+
*/
|
|
12
|
+
function hasCapability(capability) {
|
|
13
|
+
const caps = server.server.getClientCapabilities();
|
|
14
|
+
return Boolean(caps && caps[capability]);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return hasCapability;
|
|
18
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ErrorCode, McpError, SubscribeRequestSchema, UnsubscribeRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configure basic resource subscriptions on the underlying server transport.
|
|
5
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
6
|
+
* @param {{ isSubscribable: (uri: string) => boolean }} options
|
|
7
|
+
* @returns {{ notifyResourceUpdated: (uri: string) => Promise<void> }}
|
|
8
|
+
*/
|
|
9
|
+
export function registerResourceSubscriptions(server, options) {
|
|
10
|
+
const subscribers = new Map();
|
|
11
|
+
|
|
12
|
+
server.server.assertCanSetRequestHandler(SubscribeRequestSchema.shape.method.value);
|
|
13
|
+
server.server.assertCanSetRequestHandler(UnsubscribeRequestSchema.shape.method.value);
|
|
14
|
+
server.server.registerCapabilities({
|
|
15
|
+
resources: {
|
|
16
|
+
subscribe: true
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
server.server.setRequestHandler(SubscribeRequestSchema, async (request, extra) => {
|
|
21
|
+
const uri = request.params.uri;
|
|
22
|
+
if (!options.isSubscribable(uri)) {
|
|
23
|
+
throw new McpError(ErrorCode.InvalidParams, `Cannot subscribe to ${uri}`);
|
|
24
|
+
}
|
|
25
|
+
const sessionId = extra.sessionId ?? 'stdio';
|
|
26
|
+
const existing = subscribers.get(sessionId) ?? new Set();
|
|
27
|
+
existing.add(uri);
|
|
28
|
+
subscribers.set(sessionId, existing);
|
|
29
|
+
return {};
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
server.server.setRequestHandler(UnsubscribeRequestSchema, async (request, extra) => {
|
|
33
|
+
const sessionId = extra.sessionId ?? 'stdio';
|
|
34
|
+
if (!sessionId) {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
const set = subscribers.get(sessionId);
|
|
38
|
+
if (set) {
|
|
39
|
+
set.delete(request.params.uri);
|
|
40
|
+
if (set.size === 0) {
|
|
41
|
+
subscribers.delete(sessionId);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
server.server.onclose = () => {
|
|
48
|
+
subscribers.clear();
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Notify subscribed clients that a resource has been updated.
|
|
53
|
+
* @param {string} uri
|
|
54
|
+
* @returns {Promise<void>}
|
|
55
|
+
*/
|
|
56
|
+
async function notifyResourceUpdated(uri) {
|
|
57
|
+
let hasAudience = false;
|
|
58
|
+
for (const set of subscribers.values()) {
|
|
59
|
+
if (set.has(uri)) {
|
|
60
|
+
hasAudience = true;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (hasAudience) {
|
|
65
|
+
await server.server.sendResourceUpdated({ uri });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { notifyResourceUpdated };
|
|
70
|
+
}
|
package/src/tools/add.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Register the add tool returning structured totals.
|
|
5
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
6
|
+
* @returns {ReturnType<import('@modelcontextprotocol/sdk/server/mcp.js').McpServer['registerTool']>}
|
|
7
|
+
*/
|
|
8
|
+
export function registerAdd(server) {
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
first: z.number(),
|
|
11
|
+
second: z.number()
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Sum two numbers to demonstrate structured responses.
|
|
16
|
+
* @param {{ first: number, second: number }} args
|
|
17
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>}
|
|
18
|
+
*/
|
|
19
|
+
async function addTool(args) {
|
|
20
|
+
const total = args.first + args.second;
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: 'text',
|
|
25
|
+
text: `Total: ${total}`
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
structuredContent: { total }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return server.registerTool(
|
|
33
|
+
'add',
|
|
34
|
+
{
|
|
35
|
+
title: 'Add',
|
|
36
|
+
description: 'Combine two numbers and return the sum.',
|
|
37
|
+
inputSchema,
|
|
38
|
+
outputSchema: {
|
|
39
|
+
total: z.number()
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
addTool
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Register a tool that exercises annotations and _meta without output schema.
|
|
5
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
6
|
+
* @returns {ReturnType<import('@modelcontextprotocol/sdk/server/mcp.js').McpServer['registerTool']>}
|
|
7
|
+
*/
|
|
8
|
+
export function registerAnnotated(server) {
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
label: z.string().min(1, 'Label is required')
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Return a plain text response for annotation coverage.
|
|
15
|
+
* @param {{ label: string }} args
|
|
16
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>}
|
|
17
|
+
*/
|
|
18
|
+
async function annotatedTool(args) {
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: 'text',
|
|
23
|
+
text: `Annotated tool saw ${args.label}.`
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return server.registerTool(
|
|
30
|
+
'annotated',
|
|
31
|
+
{
|
|
32
|
+
description: 'Tool used to exercise annotation/title fallback and _meta extraction.',
|
|
33
|
+
inputSchema,
|
|
34
|
+
annotations: {
|
|
35
|
+
title: 'Annotated Tool',
|
|
36
|
+
readOnlyHint: true
|
|
37
|
+
},
|
|
38
|
+
_meta: {
|
|
39
|
+
owner: 'mcp-layer-schema'
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
annotatedTool
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Register a tool that accepts array/object inputs.
|
|
5
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
6
|
+
* @returns {ReturnType<import('@modelcontextprotocol/sdk/server/mcp.js').McpServer['registerTool']>}
|
|
7
|
+
*/
|
|
8
|
+
export function registerBatch(server) {
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
items: z.array(z.string()).min(1, 'Provide at least one item'),
|
|
11
|
+
meta: z.object({ tag: z.string().min(1, 'Tag is required') })
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Summarize array/object inputs.
|
|
16
|
+
* @param {{ items: string[], meta: { tag: string } }} args
|
|
17
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>}
|
|
18
|
+
*/
|
|
19
|
+
async function batchTool(args) {
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
type: 'text',
|
|
24
|
+
text: `Batch ${args.meta.tag} contains ${args.items.length} items.`
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
structuredContent: {
|
|
28
|
+
count: args.items.length,
|
|
29
|
+
tag: args.meta.tag
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return server.registerTool(
|
|
35
|
+
'batch',
|
|
36
|
+
{
|
|
37
|
+
title: 'Batch',
|
|
38
|
+
description: 'Accepts array and object inputs for CLI parsing tests.',
|
|
39
|
+
inputSchema
|
|
40
|
+
},
|
|
41
|
+
batchTool
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Register the booking tool that triggers elicitation workflows.
|
|
5
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
6
|
+
* @param {{ hasCapability: (capability: 'elicitation') => boolean }} capabilities
|
|
7
|
+
*/
|
|
8
|
+
export function registerBooking(server, capabilities) {
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
restaurant: z.string().min(1),
|
|
11
|
+
date: z.string().min(1),
|
|
12
|
+
guests: z.number().int().min(1).max(12)
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Demonstrate elicitation by asking for alternate booking dates.
|
|
17
|
+
* @param {{ restaurant: string, date: string, guests: number }} args
|
|
18
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>}
|
|
19
|
+
*/
|
|
20
|
+
async function bookingTool(args) {
|
|
21
|
+
const baseMessage = `No tables available at ${args.restaurant} on ${args.date}.`;
|
|
22
|
+
if (!capabilities.hasCapability('elicitation')) {
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: 'text',
|
|
27
|
+
text: `${baseMessage} Client did not declare elicitation capability.`
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
structuredContent: {
|
|
31
|
+
confirmed: false,
|
|
32
|
+
alternateDate: null,
|
|
33
|
+
message: `${baseMessage} Client lacks elicitation support.`
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const result = await server.server.elicitInput({
|
|
40
|
+
message: `${baseMessage} Provide an alternate date to continue.`,
|
|
41
|
+
requestedSchema: {
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: {
|
|
44
|
+
confirmAlternate: {
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
title: 'Confirm alternate date',
|
|
47
|
+
description: 'Confirm whether we should book an alternate date.'
|
|
48
|
+
},
|
|
49
|
+
alternateDate: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
title: 'Preferred alternate date',
|
|
52
|
+
description: 'ISO-8601 date string for the alternate booking.'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
required: ['confirmAlternate']
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const confirmed = result.action === 'accept' && Boolean(result.content?.confirmAlternate);
|
|
60
|
+
const alternate = confirmed ? result.content?.alternateDate ?? args.date : null;
|
|
61
|
+
const message = confirmed ? `Reservation confirmed for ${alternate ?? args.date}.` : `${baseMessage} Request declined.`;
|
|
62
|
+
return {
|
|
63
|
+
content: [
|
|
64
|
+
{
|
|
65
|
+
type: 'text',
|
|
66
|
+
text: message
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
structuredContent: {
|
|
70
|
+
confirmed,
|
|
71
|
+
alternateDate: alternate,
|
|
72
|
+
message
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
} catch (error) {
|
|
76
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
77
|
+
return {
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: 'text',
|
|
81
|
+
text: message
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
structuredContent: {
|
|
85
|
+
confirmed: false,
|
|
86
|
+
alternateDate: null,
|
|
87
|
+
message
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
server.registerTool(
|
|
94
|
+
'booking',
|
|
95
|
+
{
|
|
96
|
+
title: 'Booking',
|
|
97
|
+
description: 'Trigger elicitation/create to confirm alternate dates.',
|
|
98
|
+
inputSchema,
|
|
99
|
+
outputSchema: {
|
|
100
|
+
confirmed: z.boolean(),
|
|
101
|
+
alternateDate: z.string().nullable(),
|
|
102
|
+
message: z.string()
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
bookingTool
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
const uri = 'ui://dashboard/app.html';
|
|
4
|
+
const csp = "default-src 'self'";
|
|
5
|
+
const permissions = ['clipboard-read'];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Register a tool that declares an MCP App UI resource.
|
|
9
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
10
|
+
* @returns {ReturnType<import('@modelcontextprotocol/sdk/server/mcp.js').McpServer['registerTool']>}
|
|
11
|
+
*/
|
|
12
|
+
export function registerDashboard(server) {
|
|
13
|
+
const inputSchema = {
|
|
14
|
+
name: z.string().min(1, 'Name is required')
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Return a simple payload while the host renders the UI resource.
|
|
19
|
+
* @param {{ name: string }} args
|
|
20
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>}
|
|
21
|
+
*/
|
|
22
|
+
async function dashboardTool(args) {
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: 'text',
|
|
27
|
+
text: `Dashboard ready for ${args.name}.`
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
structuredContent: {
|
|
31
|
+
name: args.name,
|
|
32
|
+
resourceUri: uri
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return server.registerTool(
|
|
38
|
+
'dashboard',
|
|
39
|
+
{
|
|
40
|
+
title: 'Dashboard',
|
|
41
|
+
description: 'Return a dashboard with an MCP App UI resource.',
|
|
42
|
+
inputSchema,
|
|
43
|
+
_meta: {
|
|
44
|
+
ui: {
|
|
45
|
+
resourceUri: uri,
|
|
46
|
+
csp,
|
|
47
|
+
permissions
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
dashboardTool
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Register the echo tool that optionally uppercases responses.
|
|
5
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
6
|
+
* @returns {ReturnType<import('@modelcontextprotocol/sdk/server/mcp.js').McpServer['registerTool']>}
|
|
7
|
+
*/
|
|
8
|
+
export function registerEcho(server) {
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
text: z.string().min(1, 'Text must be provided'),
|
|
11
|
+
loud: z.boolean().default(false)
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Repeat supplied text and optionally uppercase the response.
|
|
16
|
+
* @param {{ text: string, loud: boolean }} args
|
|
17
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>}
|
|
18
|
+
*/
|
|
19
|
+
async function echoTool(args) {
|
|
20
|
+
const text = args.loud ? args.text.toUpperCase() : args.text;
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: 'text',
|
|
25
|
+
text
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
structuredContent: { text, loud: args.loud }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return server.registerTool(
|
|
33
|
+
'echo',
|
|
34
|
+
{
|
|
35
|
+
title: 'Echo',
|
|
36
|
+
description: 'Repeat supplied text; uppercase when loud is true.',
|
|
37
|
+
inputSchema,
|
|
38
|
+
outputSchema: {
|
|
39
|
+
text: z.string(),
|
|
40
|
+
loud: z.boolean()
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
echoTool
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Register the files tool that emits ResourceLinks referencing shared assets.
|
|
5
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
6
|
+
* @param {{ references: Array<{ uri: string, name: string, description: string, mimeType: string }> }} context
|
|
7
|
+
*/
|
|
8
|
+
export function registerFiles(server, context) {
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
filter: z.string().min(1).default('*'),
|
|
11
|
+
limit: z.number().int().min(1).max(context.references.length).default(context.references.length)
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Emit ResourceLinks referencing manual and note resources.
|
|
16
|
+
* @param {{ filter: string, limit: number }} args
|
|
17
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>}
|
|
18
|
+
*/
|
|
19
|
+
async function filesTool(args) {
|
|
20
|
+
const term = args.filter === '*' ? '' : args.filter.toLowerCase();
|
|
21
|
+
const matches = context.references
|
|
22
|
+
.filter(function filterReferences(entry) {
|
|
23
|
+
return entry.name.toLowerCase().includes(term);
|
|
24
|
+
})
|
|
25
|
+
.slice(0, args.limit);
|
|
26
|
+
|
|
27
|
+
const payload = {
|
|
28
|
+
count: matches.length,
|
|
29
|
+
files: matches.map(function mapMatches(entry) {
|
|
30
|
+
return {
|
|
31
|
+
uri: entry.uri,
|
|
32
|
+
name: entry.name,
|
|
33
|
+
description: entry.description,
|
|
34
|
+
mimeType: entry.mimeType
|
|
35
|
+
};
|
|
36
|
+
})
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: 'text',
|
|
43
|
+
text: `Found ${payload.count} references.`
|
|
44
|
+
},
|
|
45
|
+
...matches.map(function linkReferences(entry) {
|
|
46
|
+
return {
|
|
47
|
+
type: 'resource_link',
|
|
48
|
+
uri: entry.uri,
|
|
49
|
+
name: entry.name,
|
|
50
|
+
description: entry.description,
|
|
51
|
+
mimeType: entry.mimeType
|
|
52
|
+
};
|
|
53
|
+
})
|
|
54
|
+
],
|
|
55
|
+
structuredContent: payload
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
server.registerTool(
|
|
60
|
+
'files',
|
|
61
|
+
{
|
|
62
|
+
title: 'Files',
|
|
63
|
+
description: 'List ResourceLinks for manual and note resources.',
|
|
64
|
+
inputSchema,
|
|
65
|
+
outputSchema: {
|
|
66
|
+
count: z.number().int(),
|
|
67
|
+
files: z.array(
|
|
68
|
+
z.object({
|
|
69
|
+
uri: z.string(),
|
|
70
|
+
name: z.string(),
|
|
71
|
+
description: z.string(),
|
|
72
|
+
mimeType: z.string()
|
|
73
|
+
})
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
filesTool
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { registerAdd } from './add.js';
|
|
2
|
+
import { registerAnnotated } from './annotated.js';
|
|
3
|
+
import { registerBatch } from './batch.js';
|
|
4
|
+
import { registerBooking } from './booking.js';
|
|
5
|
+
import { registerDashboard } from './dashboard.js';
|
|
6
|
+
import { registerEcho } from './echo.js';
|
|
7
|
+
import { registerFiles } from './files.js';
|
|
8
|
+
import { registerLogs } from './logs.js';
|
|
9
|
+
import { registerNoteUpdate } from './note-update.js';
|
|
10
|
+
import { registerProgress } from './progress.js';
|
|
11
|
+
import { registerPresent } from './present.js';
|
|
12
|
+
import { registerRebalance } from './rebalance.js';
|
|
13
|
+
import { registerRoots } from './roots.js';
|
|
14
|
+
import { registerSummaries } from './summaries.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Register all server tools.
|
|
18
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
19
|
+
* @param {{ references: Array<{ uri: string, name: string, description: string, mimeType: string }> }} context
|
|
20
|
+
* @param {{ hasCapability: (capability: 'sampling' | 'elicitation' | 'roots') => boolean }} capabilities
|
|
21
|
+
*/
|
|
22
|
+
export function registerTools(server, context, capabilities, notifier) {
|
|
23
|
+
const echoHandle = registerEcho(server);
|
|
24
|
+
const addHandle = registerAdd(server);
|
|
25
|
+
registerBatch(server);
|
|
26
|
+
registerAnnotated(server);
|
|
27
|
+
registerDashboard(server);
|
|
28
|
+
registerFiles(server, context);
|
|
29
|
+
registerSummaries(server, capabilities);
|
|
30
|
+
registerBooking(server, capabilities);
|
|
31
|
+
registerRoots(server, capabilities);
|
|
32
|
+
registerNoteUpdate(server, context, notifier);
|
|
33
|
+
registerLogs(server);
|
|
34
|
+
registerPresent(server);
|
|
35
|
+
registerProgress(server);
|
|
36
|
+
registerRebalance(server, { echo: echoHandle, add: addHandle });
|
|
37
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { LoggingLevelSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
const levels = LoggingLevelSchema.options;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Register the logs tool that emits notifications/message entries.
|
|
8
|
+
* @param {import('@modelcontextprotocol/sdk/server/mcp.js').McpServer} server
|
|
9
|
+
*/
|
|
10
|
+
export function registerLogs(server) {
|
|
11
|
+
const inputSchema = {
|
|
12
|
+
level: z.enum(levels),
|
|
13
|
+
message: z.string().min(1),
|
|
14
|
+
logger: z.string().default('diagnostics')
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Emit a logging notification honoring the client's configured level filter.
|
|
19
|
+
* @param {{ level: typeof levels[number], message: string, logger: string }} args
|
|
20
|
+
* @returns {Promise<import('@modelcontextprotocol/sdk/types.js').CallToolResult>}
|
|
21
|
+
*/
|
|
22
|
+
async function logsTool(args) {
|
|
23
|
+
await server.sendLoggingMessage({
|
|
24
|
+
level: args.level,
|
|
25
|
+
logger: args.logger,
|
|
26
|
+
data: args.message
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: 'text',
|
|
33
|
+
text: `Logged ${args.level} message.`
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
structuredContent: {
|
|
37
|
+
level: args.level,
|
|
38
|
+
logger: args.logger
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
server.registerTool(
|
|
44
|
+
'logs',
|
|
45
|
+
{
|
|
46
|
+
title: 'Logs',
|
|
47
|
+
description: 'Send notifications/message payloads at the requested level.',
|
|
48
|
+
inputSchema,
|
|
49
|
+
outputSchema: {
|
|
50
|
+
level: z.enum(levels),
|
|
51
|
+
logger: z.string()
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
logsTool
|
|
55
|
+
);
|
|
56
|
+
}
|