@mcpflo/server-everything 0.0.1
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/README.md +84 -0
- package/dist/createServer.js +42 -0
- package/dist/docs/architecture.md +19 -0
- package/dist/docs/extension.md +20 -0
- package/dist/docs/features.md +23 -0
- package/dist/docs/how-it-works.md +22 -0
- package/dist/docs/instructions.md +16 -0
- package/dist/docs/startup.md +20 -0
- package/dist/docs/structure.md +21 -0
- package/dist/index.js +10 -0
- package/dist/prompts/args.js +19 -0
- package/dist/prompts/completions.js +32 -0
- package/dist/prompts/index.js +19 -0
- package/dist/prompts/resource.js +35 -0
- package/dist/prompts/simple.js +16 -0
- package/dist/resources/docsDir.js +18 -0
- package/dist/resources/file-resources.js +52 -0
- package/dist/resources/index.js +24 -0
- package/dist/resources/session.js +34 -0
- package/dist/resources/subscriptions.js +38 -0
- package/dist/resources/templates.js +91 -0
- package/dist/server/logging.js +45 -0
- package/dist/server/roots.js +44 -0
- package/dist/tools/add.js +12 -0
- package/dist/tools/annotated-message.js +67 -0
- package/dist/tools/echo.js +12 -0
- package/dist/tools/get-resource-links.js +36 -0
- package/dist/tools/get-resource-reference.js +32 -0
- package/dist/tools/get-roots-list.js +51 -0
- package/dist/tools/get-structured-content.js +35 -0
- package/dist/tools/get-tiny-image.js +23 -0
- package/dist/tools/gzip-file-as-resource.js +115 -0
- package/dist/tools/index.js +63 -0
- package/dist/tools/print-env.js +10 -0
- package/dist/tools/simulate-research-query.js +173 -0
- package/dist/tools/toggle-simulated-logging.js +33 -0
- package/dist/tools/toggle-subscriber-updates.js +33 -0
- package/dist/tools/trigger-elicitation-request-async.js +136 -0
- package/dist/tools/trigger-elicitation-request.js +167 -0
- package/dist/tools/trigger-long-running-operation.js +36 -0
- package/dist/tools/trigger-sampling-request-async.js +112 -0
- package/dist/tools/trigger-sampling-request.js +39 -0
- package/dist/tools/trigger-url-elicitation.js +0 -0
- package/package.json +36 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resourceIdForPromptCompleter = exports.resourceTypeCompleter = exports.RESOURCE_TYPES = exports.RESOURCE_TYPE_BLOB = exports.RESOURCE_TYPE_TEXT = void 0;
|
|
4
|
+
exports.textResourceUri = textResourceUri;
|
|
5
|
+
exports.blobResourceUri = blobResourceUri;
|
|
6
|
+
exports.textResource = textResource;
|
|
7
|
+
exports.blobResource = blobResource;
|
|
8
|
+
exports.registerResourceTemplates = registerResourceTemplates;
|
|
9
|
+
const zod_1 = require("zod");
|
|
10
|
+
const completable_js_1 = require("@modelcontextprotocol/sdk/server/completable.js");
|
|
11
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
12
|
+
exports.RESOURCE_TYPE_TEXT = 'text';
|
|
13
|
+
exports.RESOURCE_TYPE_BLOB = 'blob';
|
|
14
|
+
exports.RESOURCE_TYPES = [exports.RESOURCE_TYPE_TEXT, exports.RESOURCE_TYPE_BLOB];
|
|
15
|
+
function textResourceUri(id) {
|
|
16
|
+
return `mcpflo://static/resource/text/${id}`;
|
|
17
|
+
}
|
|
18
|
+
function blobResourceUri(id) {
|
|
19
|
+
return `mcpflo://static/resource/blob/${id}`;
|
|
20
|
+
}
|
|
21
|
+
function textResource(uri, id) {
|
|
22
|
+
return {
|
|
23
|
+
uri,
|
|
24
|
+
mimeType: 'text/plain',
|
|
25
|
+
text: `Resource ${id}: this is a plaintext demo/test fixture resource.`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function blobResource(uri, id) {
|
|
29
|
+
const text = `Resource ${id}: this is a binary demo/test fixture resource.`;
|
|
30
|
+
return {
|
|
31
|
+
uri,
|
|
32
|
+
mimeType: 'application/octet-stream',
|
|
33
|
+
blob: Buffer.from(text, 'utf-8').toString('base64')
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
exports.resourceTypeCompleter = (0, completable_js_1.completable)(zod_1.z.enum(exports.RESOURCE_TYPES).describe('Type of resource: text or blob'), (value) => exports.RESOURCE_TYPES.filter((t) => t.startsWith(value)));
|
|
37
|
+
// resourceId stays a plain completable string, not a coerced number: prompt
|
|
38
|
+
// argument values always arrive as strings over the wire, and completion
|
|
39
|
+
// candidates need to be strings too — the numeric conversion happens where
|
|
40
|
+
// the value is actually used (see prompts/resource.ts), same as the
|
|
41
|
+
// reference's own handler-side Number(...) conversion.
|
|
42
|
+
exports.resourceIdForPromptCompleter = (0, completable_js_1.completable)(zod_1.z.string().describe('ID of the resource'), (value) => ['1', '2', '3', '4', '5'].filter((id) => id.startsWith(value)));
|
|
43
|
+
// Distinct namespace from the static mcpflo://static/resource/... URIs above,
|
|
44
|
+
// since these are genuinely different: dynamic MCP resource *templates*
|
|
45
|
+
// (resources/templates/list), content regenerated with a live timestamp on
|
|
46
|
+
// every read, deliberately excluded from resources/list (list: undefined).
|
|
47
|
+
const DYNAMIC_TEXT_URI_TEMPLATE = 'mcpflo://dynamic/text/{resourceId}';
|
|
48
|
+
const DYNAMIC_BLOB_URI_TEMPLATE = 'mcpflo://dynamic/blob/{resourceId}';
|
|
49
|
+
const resourceIdForResourceTemplateCompleter = (value) => {
|
|
50
|
+
const resourceId = Number(value);
|
|
51
|
+
return Number.isInteger(resourceId) && resourceId > 0 ? [value] : [];
|
|
52
|
+
};
|
|
53
|
+
function parseResourceId(variables) {
|
|
54
|
+
const raw = Array.isArray(variables.resourceId) ? variables.resourceId[0] : variables.resourceId;
|
|
55
|
+
const resourceId = Number(raw);
|
|
56
|
+
if (!Number.isFinite(resourceId) || !Number.isInteger(resourceId) || resourceId < 1) {
|
|
57
|
+
throw new Error(`Invalid resourceId: ${raw}. Must be a finite positive integer.`);
|
|
58
|
+
}
|
|
59
|
+
return resourceId;
|
|
60
|
+
}
|
|
61
|
+
function dynamicTextContent(uri, resourceId) {
|
|
62
|
+
return {
|
|
63
|
+
uri: uri.toString(),
|
|
64
|
+
mimeType: 'text/plain',
|
|
65
|
+
text: `Resource ${resourceId}: dynamically generated plaintext resource, created at ${new Date().toISOString()}.`
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function dynamicBlobContent(uri, resourceId) {
|
|
69
|
+
const text = `Resource ${resourceId}: dynamically generated binary resource, created at ${new Date().toISOString()}.`;
|
|
70
|
+
return {
|
|
71
|
+
uri: uri.toString(),
|
|
72
|
+
mimeType: 'application/octet-stream',
|
|
73
|
+
blob: Buffer.from(text, 'utf-8').toString('base64')
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function registerResourceTemplates(server) {
|
|
77
|
+
server.registerResource('Dynamic Text Resource', new mcp_js_1.ResourceTemplate(DYNAMIC_TEXT_URI_TEMPLATE, {
|
|
78
|
+
list: undefined,
|
|
79
|
+
complete: { resourceId: resourceIdForResourceTemplateCompleter }
|
|
80
|
+
}), {
|
|
81
|
+
mimeType: 'text/plain',
|
|
82
|
+
description: 'Plaintext dynamic resource fabricated from the {resourceId} variable, which must be a positive integer. Demo/test fixture.'
|
|
83
|
+
}, async (uri, variables) => ({ contents: [dynamicTextContent(uri, parseResourceId(variables))] }));
|
|
84
|
+
server.registerResource('Dynamic Blob Resource', new mcp_js_1.ResourceTemplate(DYNAMIC_BLOB_URI_TEMPLATE, {
|
|
85
|
+
list: undefined,
|
|
86
|
+
complete: { resourceId: resourceIdForResourceTemplateCompleter }
|
|
87
|
+
}), {
|
|
88
|
+
mimeType: 'application/octet-stream',
|
|
89
|
+
description: 'Binary (base64) dynamic resource fabricated from the {resourceId} variable, which must be a positive integer. Demo/test fixture.'
|
|
90
|
+
}, async (uri, variables) => ({ contents: [dynamicBlobContent(uri, parseResourceId(variables))] }));
|
|
91
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerLoggingCapability = registerLoggingCapability;
|
|
4
|
+
exports.beginSimulatedLogging = beginSimulatedLogging;
|
|
5
|
+
exports.stopSimulatedLogging = stopSimulatedLogging;
|
|
6
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
7
|
+
// RFC 5424 severity, lowest number = most severe.
|
|
8
|
+
const LEVEL_SEVERITY = {
|
|
9
|
+
emergency: 0,
|
|
10
|
+
alert: 1,
|
|
11
|
+
critical: 2,
|
|
12
|
+
error: 3,
|
|
13
|
+
warning: 4,
|
|
14
|
+
notice: 5,
|
|
15
|
+
info: 6,
|
|
16
|
+
debug: 7
|
|
17
|
+
};
|
|
18
|
+
const RANDOM_LEVELS = Object.keys(LEVEL_SEVERITY);
|
|
19
|
+
const INTERVAL_MS = 5000;
|
|
20
|
+
const sessionLevels = new Map();
|
|
21
|
+
const sessionTimers = new Map();
|
|
22
|
+
function registerLoggingCapability(server) {
|
|
23
|
+
server.server.setRequestHandler(types_js_1.SetLevelRequestSchema, async (request, extra) => {
|
|
24
|
+
sessionLevels.set(extra.sessionId, request.params.level);
|
|
25
|
+
return {};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function beginSimulatedLogging(server, sessionId) {
|
|
29
|
+
const timer = setInterval(() => {
|
|
30
|
+
const level = RANDOM_LEVELS[Math.floor(Math.random() * RANDOM_LEVELS.length)];
|
|
31
|
+
const minLevel = sessionLevels.get(sessionId) ?? 'debug';
|
|
32
|
+
if (LEVEL_SEVERITY[level] > LEVEL_SEVERITY[minLevel])
|
|
33
|
+
return;
|
|
34
|
+
server.server
|
|
35
|
+
.sendLoggingMessage({ level, logger: 'simulated-logging', data: `Simulated ${level} message at ${new Date().toISOString()}` }, sessionId)
|
|
36
|
+
.catch(() => { });
|
|
37
|
+
}, INTERVAL_MS);
|
|
38
|
+
sessionTimers.set(sessionId, timer);
|
|
39
|
+
}
|
|
40
|
+
function stopSimulatedLogging(sessionId) {
|
|
41
|
+
const timer = sessionTimers.get(sessionId);
|
|
42
|
+
if (timer)
|
|
43
|
+
clearInterval(timer);
|
|
44
|
+
sessionTimers.delete(sessionId);
|
|
45
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.syncRoots = syncRoots;
|
|
4
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
5
|
+
// Track roots by session id. stdio is single-session (sessionId always
|
|
6
|
+
// undefined), so setNotificationHandler below only ever gets called once for
|
|
7
|
+
// the life of the process — if this server ever grew a multi-session
|
|
8
|
+
// transport, the notification handler would need per-session dispatch
|
|
9
|
+
// instead of relying on setNotificationHandler's single global registration.
|
|
10
|
+
const roots = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Gets the latest client roots list for the session, requesting and caching
|
|
13
|
+
* it on first use, then keeping the cache fresh via roots/list_changed.
|
|
14
|
+
* Idempotent: only requests roots from the client once per session.
|
|
15
|
+
*/
|
|
16
|
+
async function syncRoots(server, sessionId) {
|
|
17
|
+
const clientCapabilities = server.server.getClientCapabilities() ?? {};
|
|
18
|
+
if (clientCapabilities.roots === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
const requestRoots = async () => {
|
|
21
|
+
try {
|
|
22
|
+
const response = await server.server.listRoots();
|
|
23
|
+
if (response && 'roots' in response) {
|
|
24
|
+
roots.set(sessionId, response.roots);
|
|
25
|
+
await server.sendLoggingMessage({
|
|
26
|
+
level: 'info',
|
|
27
|
+
logger: 'everything-server',
|
|
28
|
+
data: `Roots updated: ${response.roots.length} root(s) received from client`
|
|
29
|
+
}, sessionId);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
await server.sendLoggingMessage({ level: 'info', logger: 'everything-server', data: 'Client returned no roots set' }, sessionId);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error(`Failed to request roots from client ${sessionId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
if (!roots.has(sessionId)) {
|
|
40
|
+
server.server.setNotificationHandler(types_js_1.RootsListChangedNotificationSchema, requestRoots);
|
|
41
|
+
await requestRoots();
|
|
42
|
+
}
|
|
43
|
+
return roots.get(sessionId);
|
|
44
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerAdd = registerAdd;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
function registerAdd(server) {
|
|
6
|
+
server.registerTool('add', {
|
|
7
|
+
description: 'Adds two numbers. Demo/test fixture.',
|
|
8
|
+
inputSchema: { a: zod_1.z.number(), b: zod_1.z.number() }
|
|
9
|
+
}, async ({ a, b }) => ({
|
|
10
|
+
content: [{ type: 'text', text: `${a} + ${b} = ${a + b}` }]
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerAnnotatedMessage = registerAnnotatedMessage;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const get_tiny_image_1 = require("./get-tiny-image");
|
|
6
|
+
const AnnotatedMessageSchema = {
|
|
7
|
+
messageType: zod_1.z
|
|
8
|
+
.enum(['error', 'success', 'debug'])
|
|
9
|
+
.describe('Type of message to demonstrate different annotation patterns'),
|
|
10
|
+
includeImage: zod_1.z.boolean().default(false).describe('Whether to include an example image')
|
|
11
|
+
};
|
|
12
|
+
function registerAnnotatedMessage(server) {
|
|
13
|
+
server.registerTool('annotated-message', {
|
|
14
|
+
description: 'Returns content with audience/priority annotations. Demo/test fixture.',
|
|
15
|
+
inputSchema: AnnotatedMessageSchema,
|
|
16
|
+
annotations: {
|
|
17
|
+
readOnlyHint: true,
|
|
18
|
+
destructiveHint: false,
|
|
19
|
+
idempotentHint: true,
|
|
20
|
+
openWorldHint: false
|
|
21
|
+
}
|
|
22
|
+
}, async ({ messageType, includeImage }) => {
|
|
23
|
+
const content = [];
|
|
24
|
+
if (messageType === 'error') {
|
|
25
|
+
content.push({
|
|
26
|
+
type: 'text',
|
|
27
|
+
text: 'Error: Operation failed',
|
|
28
|
+
annotations: {
|
|
29
|
+
priority: 1.0,
|
|
30
|
+
audience: ['user', 'assistant']
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
else if (messageType === 'success') {
|
|
35
|
+
content.push({
|
|
36
|
+
type: 'text',
|
|
37
|
+
text: 'Operation completed successfully',
|
|
38
|
+
annotations: {
|
|
39
|
+
priority: 0.7,
|
|
40
|
+
audience: ['user']
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
content.push({
|
|
46
|
+
type: 'text',
|
|
47
|
+
text: 'Debug: Cache hit ratio 0.95, latency 150ms',
|
|
48
|
+
annotations: {
|
|
49
|
+
priority: 0.3,
|
|
50
|
+
audience: ['assistant']
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (includeImage) {
|
|
55
|
+
content.push({
|
|
56
|
+
type: 'image',
|
|
57
|
+
data: get_tiny_image_1.TINY_MCPFLO_IMAGE,
|
|
58
|
+
mimeType: 'image/png',
|
|
59
|
+
annotations: {
|
|
60
|
+
priority: 0.5,
|
|
61
|
+
audience: ['user']
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return { content };
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerEcho = registerEcho;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
function registerEcho(server) {
|
|
6
|
+
server.registerTool('echo', {
|
|
7
|
+
description: 'Echoes the message back. Demo/test fixture.',
|
|
8
|
+
inputSchema: { message: zod_1.z.string() }
|
|
9
|
+
}, async ({ message }) => ({
|
|
10
|
+
content: [{ type: 'text', text: `Echo: ${message}` }]
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerGetResourceLinks = registerGetResourceLinks;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const templates_1 = require("../resources/templates");
|
|
6
|
+
function registerGetResourceLinks(server) {
|
|
7
|
+
server.registerTool('get-resource-links', {
|
|
8
|
+
description: 'Returns up to ten resource links that reference different types of resources. Demo/test fixture.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
count: zod_1.z.number().min(1).max(10).default(3).describe('Number of resource links to return (1-10)')
|
|
11
|
+
},
|
|
12
|
+
annotations: {
|
|
13
|
+
readOnlyHint: true,
|
|
14
|
+
destructiveHint: false,
|
|
15
|
+
idempotentHint: true,
|
|
16
|
+
openWorldHint: false
|
|
17
|
+
}
|
|
18
|
+
}, async ({ count }) => {
|
|
19
|
+
const content = [
|
|
20
|
+
{ type: 'text', text: `Here are ${count} resource links to resources available in this server:` }
|
|
21
|
+
];
|
|
22
|
+
for (let resourceId = 1; resourceId <= count; resourceId++) {
|
|
23
|
+
const isEven = resourceId % 2 === 0;
|
|
24
|
+
const uri = isEven ? (0, templates_1.textResourceUri)(resourceId) : (0, templates_1.blobResourceUri)(resourceId);
|
|
25
|
+
const resource = isEven ? (0, templates_1.textResource)(uri, resourceId) : (0, templates_1.blobResource)(uri, resourceId);
|
|
26
|
+
content.push({
|
|
27
|
+
type: 'resource_link',
|
|
28
|
+
uri: resource.uri,
|
|
29
|
+
name: `${isEven ? 'Text' : 'Blob'} Resource ${resourceId}`,
|
|
30
|
+
description: `Resource ${resourceId}: ${resource.mimeType === 'text/plain' ? 'plaintext resource' : 'binary blob resource'}`,
|
|
31
|
+
mimeType: resource.mimeType
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return { content };
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerGetResourceReference = registerGetResourceReference;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const templates_1 = require("../resources/templates");
|
|
6
|
+
function registerGetResourceReference(server) {
|
|
7
|
+
server.registerTool('get-resource-reference', {
|
|
8
|
+
description: 'Returns a resource reference that can be used by MCP clients. Demo/test fixture.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
resourceType: zod_1.z.enum([templates_1.RESOURCE_TYPE_TEXT, templates_1.RESOURCE_TYPE_BLOB]).default(templates_1.RESOURCE_TYPE_TEXT),
|
|
11
|
+
resourceId: zod_1.z.number().int().positive().default(1).describe('ID of the resource to fetch')
|
|
12
|
+
},
|
|
13
|
+
annotations: {
|
|
14
|
+
readOnlyHint: true,
|
|
15
|
+
destructiveHint: false,
|
|
16
|
+
idempotentHint: true,
|
|
17
|
+
openWorldHint: false
|
|
18
|
+
}
|
|
19
|
+
}, async ({ resourceType, resourceId }) => {
|
|
20
|
+
const uri = resourceType === templates_1.RESOURCE_TYPE_TEXT ? (0, templates_1.textResourceUri)(resourceId) : (0, templates_1.blobResourceUri)(resourceId);
|
|
21
|
+
const resource = resourceType === templates_1.RESOURCE_TYPE_TEXT
|
|
22
|
+
? (0, templates_1.textResource)(uri, resourceId)
|
|
23
|
+
: (0, templates_1.blobResource)(uri, resourceId);
|
|
24
|
+
return {
|
|
25
|
+
content: [
|
|
26
|
+
{ type: 'text', text: `Returning resource reference for Resource ${resourceId}:` },
|
|
27
|
+
{ type: 'resource', resource },
|
|
28
|
+
{ type: 'text', text: `You can access this resource using the URI: ${resource.uri}` }
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerGetRootsList = registerGetRootsList;
|
|
4
|
+
const roots_1 = require("../server/roots");
|
|
5
|
+
function registerGetRootsList(server) {
|
|
6
|
+
// Called from server.server.oninitialized (see index.ts), so the client's
|
|
7
|
+
// capabilities are already known here — this is not a registration-time
|
|
8
|
+
// race like it would be if called eagerly at server construction.
|
|
9
|
+
const clientCapabilities = server.server.getClientCapabilities() ?? {};
|
|
10
|
+
if (clientCapabilities.roots === undefined)
|
|
11
|
+
return;
|
|
12
|
+
server.registerTool('get-roots-list', {
|
|
13
|
+
description: "Lists the current MCP roots provided by the client. Demonstrates the roots protocol " +
|
|
14
|
+
"capability even though this server doesn't access files. Demo/test fixture.",
|
|
15
|
+
annotations: {
|
|
16
|
+
readOnlyHint: true,
|
|
17
|
+
destructiveHint: false,
|
|
18
|
+
idempotentHint: true,
|
|
19
|
+
openWorldHint: false
|
|
20
|
+
}
|
|
21
|
+
}, async (extra) => {
|
|
22
|
+
const currentRoots = await (0, roots_1.syncRoots)(server, extra.sessionId);
|
|
23
|
+
if (!currentRoots || currentRoots.length === 0) {
|
|
24
|
+
return {
|
|
25
|
+
content: [
|
|
26
|
+
{
|
|
27
|
+
type: 'text',
|
|
28
|
+
text: 'The client supports roots but no roots are currently configured.\n\n' +
|
|
29
|
+
'This could mean:\n' +
|
|
30
|
+
"1. The client hasn't provided any roots yet\n" +
|
|
31
|
+
'2. The client provided an empty roots list\n' +
|
|
32
|
+
'3. The roots configuration is still being loaded'
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const rootsList = currentRoots
|
|
38
|
+
.map((root, index) => `${index + 1}. ${root.name || 'Unnamed Root'}\n URI: ${root.uri}`)
|
|
39
|
+
.join('\n\n');
|
|
40
|
+
return {
|
|
41
|
+
content: [
|
|
42
|
+
{
|
|
43
|
+
type: 'text',
|
|
44
|
+
text: `Current MCP Roots (${currentRoots.length} total):\n\n${rootsList}\n\n` +
|
|
45
|
+
"Note: This server demonstrates the roots protocol capability but doesn't actually access files. " +
|
|
46
|
+
'The roots are provided by the MCP client and can be used by servers that need file system access.'
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerGetStructuredContent = registerGetStructuredContent;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const LOCATIONS = ['New York', 'Chicago', 'Los Angeles'];
|
|
6
|
+
const WEATHER_BY_LOCATION = {
|
|
7
|
+
'New York': { temperature: 33, conditions: 'Cloudy', humidity: 82 },
|
|
8
|
+
Chicago: { temperature: 36, conditions: 'Light rain / drizzle', humidity: 82 },
|
|
9
|
+
'Los Angeles': { temperature: 73, conditions: 'Sunny / Clear', humidity: 48 }
|
|
10
|
+
};
|
|
11
|
+
function registerGetStructuredContent(server) {
|
|
12
|
+
server.registerTool('get-structured-content', {
|
|
13
|
+
description: 'Returns structured content along with an output schema for client data validation. Demo/test fixture.',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
location: zod_1.z.enum(LOCATIONS).describe('Choose city')
|
|
16
|
+
},
|
|
17
|
+
outputSchema: {
|
|
18
|
+
temperature: zod_1.z.number().describe('Temperature in celsius'),
|
|
19
|
+
conditions: zod_1.z.string().describe('Weather conditions description'),
|
|
20
|
+
humidity: zod_1.z.number().describe('Humidity percentage')
|
|
21
|
+
},
|
|
22
|
+
annotations: {
|
|
23
|
+
readOnlyHint: true,
|
|
24
|
+
destructiveHint: false,
|
|
25
|
+
idempotentHint: true,
|
|
26
|
+
openWorldHint: false
|
|
27
|
+
}
|
|
28
|
+
}, async ({ location }) => {
|
|
29
|
+
const weather = WEATHER_BY_LOCATION[location];
|
|
30
|
+
return {
|
|
31
|
+
content: [{ type: 'text', text: JSON.stringify(weather) }],
|
|
32
|
+
structuredContent: weather
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TINY_MCPFLO_IMAGE = void 0;
|
|
4
|
+
exports.registerGetTinyImage = registerGetTinyImage;
|
|
5
|
+
// Tiny render of MCPFlo's hummingbird logo (resources/icon.png, downscaled to 24x24).
|
|
6
|
+
exports.TINY_MCPFLO_IMAGE = 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAQJlWElmTU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAExAAIAAAA5AAAAcgE7AAIAAAAIAAAArIdpAAQAAAABAAAAtAAAAAAAAABgAAAAAQAAAGAAAAABQ2FudmEgZG9jPURBSE5GXzk3UXprIHVzZXI9VUFISjZZeVdIcDQgYnJhbmQ9QkFISjZhcEd3b1kAAEhhcnNoYWwAAAaQAAAHAAAABDAyMTCRAQAHAAAABAECAwCgAAAHAAAABDAxMDCgAQADAAAAAQABAACgAgAEAAAAAQAAABigAwAEAAAAAQAAABgAAAAAQV6aigAAAAlwSFlzAAAOxAAADsQBlSsOGwAABixpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+NjU1MzU8L2V4aWY6Q29sb3JTcGFjZT4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjEwMjQ8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpFeGlmVmVyc2lvbj4wMjEwPC9leGlmOkV4aWZWZXJzaW9uPgogICAgICAgICA8ZXhpZjpGbGFzaFBpeFZlcnNpb24+MDEwMDwvZXhpZjpGbGFzaFBpeFZlcnNpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4xMDI0PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6Q29tcG9uZW50c0NvbmZpZ3VyYXRpb24+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpPjE8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaT4yPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGk+MzwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpPjA8L3JkZjpsaT4KICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICA8L2V4aWY6Q29tcG9uZW50c0NvbmZpZ3VyYXRpb24+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+Q2FudmEgZG9jPURBSE5GXzk3UXprIHVzZXI9VUFISjZZeVdIcDQgYnJhbmQ9QkFISjZhcEd3b1k8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+OTY8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjk2PC90aWZmOllSZXNvbHV0aW9uPgogICAgICAgICA8ZGM6dGl0bGU+CiAgICAgICAgICAgIDxyZGY6QWx0PgogICAgICAgICAgICAgICA8cmRmOmxpIHhtbDpsYW5nPSJ4LWRlZmF1bHQiPmljb24gLSAxPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOkFsdD4KICAgICAgICAgPC9kYzp0aXRsZT4KICAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpPkhhcnNoYWw8L3JkZjpsaT4KICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgr02MmuAAADn0lEQVRIDd1V3WscVRT/zZ3Z2a/azSatCUmDptRNFKWkVGip+AH+BUJefPZNsH9AwUprSfHF0udCwRcf8uAHvhRBBK3GhxoxWBPS2A83TWk2s8vuZj/ms78zzQyz6Wbf9cCdc+495/zOPefcewf4r5PWL4FSqXQ0CIJTHJPUZzj62nE94OhwlHVd/2V1dfUu5R7qcZybm9OXlpY+1jTtLK0K5D3G+024EVHVyK/Ozs5eWFhY8CJbPRKE27Z9Xil1noaya4jjoOFT7/l+lF6Gvm9tbm4GlmX9KP5C8Ranp6enfN9fJmD+qWrwV8B1pWEsZ6Lc7MILkwDSumqyXK+trKzcEwQVwXied4ZyXux2bUOnDj1l+NEi9S4npq5w7tQLeHkkDynD64cy+KBURDFtHGh13Te4FJIRCeRHdNY8owKmpcEmyEROx7tj2TDNr8stWF0fLnc+yl1/cnqSoDmodgvvHxnHsYNpXFurYavjIqW08Qg3GcCUng6nNExkFKbyOt6bKmC7sYNXDhdQNHVcWK7i2HMpXDwxgpLpoGZV8eZoDqZS+OZBHV/cqcGgDC1I9wugpI4P2gHutz0sVj0cHXLxzmgBnOLESAZnns/go9JBTPEItGwPmpGC0hRuPGziym0rxJRNMsmYkhmEi/pu210aXf+njpNjeRQPZDGhG/jUNFhCH13uxHO7yAYufth0MP9XFY4PRL4xOoW4yZTjEyUGBmcPWx4sI4dCcYiddWD4LhsvJQByRPtpq43Pbj8LzpMY48aCgO4lh2e83OgicBx0Gg0Ekn9YYwPfVzxc/rsJ7qHvziOsgQHkJn93p4Ltx1tMlaeL85SuY6lm4+Kyxd4EYaYRWD+eDJBozVNTkxdp8VET839W0GJTsrRma/FSIYvxXCq+L32AY6xkALbpWeKZxo1HHZz9vYov77MktoPDaYWTh7JsbIzT48hMY0UygN1jlZikGeTujovPV+r443EdWqeO47zzcjH3IXlhQ0oG+Fcetv1ITpVJ6682OtjoAq8WdAzxUu5NexdjI8KJAxiGcZPKZqTox6Vct6wuPrxVxW9VP3xK9laJGA3XdW9G/vFzXalUasPDw7z16u1BmUhZdtjwxW0bTbmNCaKvzC6tr69/Gy3HAWSB7/jPxWJRsj7ORmXFQY7m3iHPtOK6/AkU5V2qks+vra1dIo8jx9rISvjMzMyLfL5PU5xkNgN/mQzepl3ZcZxf75Eo/8/oCWRCf9RkiZi7AAAAAElFTkSuQmCC';
|
|
7
|
+
function registerGetTinyImage(server) {
|
|
8
|
+
server.registerTool('get-tiny-image', {
|
|
9
|
+
description: 'Returns a tiny render of the MCPFlo logo. Demo/test fixture.',
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
idempotentHint: true,
|
|
14
|
+
openWorldHint: false
|
|
15
|
+
}
|
|
16
|
+
}, async () => ({
|
|
17
|
+
content: [
|
|
18
|
+
{ type: 'text', text: "Here's the image you requested:" },
|
|
19
|
+
{ type: 'image', data: exports.TINY_MCPFLO_IMAGE, mimeType: 'image/png' },
|
|
20
|
+
{ type: 'text', text: 'The image above is the MCPFlo hummingbird logo.' }
|
|
21
|
+
]
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerGzipFileAsResource = registerGzipFileAsResource;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const node_zlib_1 = require("node:zlib");
|
|
6
|
+
const session_1 = require("../resources/session");
|
|
7
|
+
const GZIP_MAX_FETCH_SIZE = Number(process.env.GZIP_MAX_FETCH_SIZE ?? String(10 * 1024 * 1024));
|
|
8
|
+
const GZIP_MAX_FETCH_TIME_MILLIS = Number(process.env.GZIP_MAX_FETCH_TIME_MILLIS ?? String(30 * 1000));
|
|
9
|
+
const GZIP_ALLOWED_DOMAINS = (process.env.GZIP_ALLOWED_DOMAINS ?? '')
|
|
10
|
+
.split(',')
|
|
11
|
+
.map((d) => d.trim().toLowerCase())
|
|
12
|
+
.filter((d) => d.length > 0);
|
|
13
|
+
function registerGzipFileAsResource(server) {
|
|
14
|
+
server.registerTool('gzip-file-as-resource', {
|
|
15
|
+
description: "Compresses a single file using gzip compression. Depending upon the selected output type, returns either the compressed data as a gzipped resource or a resource link, allowing it to be downloaded in a subsequent request during the current session. Demo/test fixture.",
|
|
16
|
+
inputSchema: {
|
|
17
|
+
name: zod_1.z.string().describe('Name of the output file').default('README.md.gz'),
|
|
18
|
+
data: zod_1.z
|
|
19
|
+
.url()
|
|
20
|
+
.describe('URL or data URI of the file content to compress')
|
|
21
|
+
.default('https://raw.githubusercontent.com/modelcontextprotocol/servers/refs/heads/main/README.md'),
|
|
22
|
+
outputType: zod_1.z
|
|
23
|
+
.enum(['resourceLink', 'resource'])
|
|
24
|
+
.default('resourceLink')
|
|
25
|
+
.describe("How the resulting gzipped file should be returned. 'resourceLink' returns a link to a resource that can be read later, 'resource' returns a full resource object.")
|
|
26
|
+
},
|
|
27
|
+
annotations: {
|
|
28
|
+
readOnlyHint: false,
|
|
29
|
+
destructiveHint: false,
|
|
30
|
+
idempotentHint: true,
|
|
31
|
+
openWorldHint: true
|
|
32
|
+
}
|
|
33
|
+
}, async ({ name, data: dataUri, outputType }) => {
|
|
34
|
+
const url = validateDataURI(dataUri);
|
|
35
|
+
const response = await fetchSafely(url, {
|
|
36
|
+
maxBytes: GZIP_MAX_FETCH_SIZE,
|
|
37
|
+
timeoutMillis: GZIP_MAX_FETCH_TIME_MILLIS
|
|
38
|
+
});
|
|
39
|
+
const compressedBuffer = (0, node_zlib_1.gzipSync)(Buffer.from(response));
|
|
40
|
+
const uri = (0, session_1.getSessionResourceURI)(name);
|
|
41
|
+
const blob = compressedBuffer.toString('base64');
|
|
42
|
+
const mimeType = 'application/gzip';
|
|
43
|
+
const resource = { uri, name, mimeType };
|
|
44
|
+
const resourceLink = (0, session_1.registerSessionResource)(server, resource, 'blob', blob);
|
|
45
|
+
if (outputType === 'resource') {
|
|
46
|
+
return { content: [{ type: 'resource', resource: { uri, mimeType, blob } }] };
|
|
47
|
+
}
|
|
48
|
+
return { content: [resourceLink] };
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function validateDataURI(dataUri) {
|
|
52
|
+
const url = new URL(dataUri);
|
|
53
|
+
try {
|
|
54
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:' && url.protocol !== 'data:') {
|
|
55
|
+
throw new Error(`Unsupported URL protocol for ${dataUri}. Only http, https, and data URLs are supported.`);
|
|
56
|
+
}
|
|
57
|
+
if (GZIP_ALLOWED_DOMAINS.length > 0 && (url.protocol === 'http:' || url.protocol === 'https:')) {
|
|
58
|
+
const domain = url.hostname;
|
|
59
|
+
const domainAllowed = GZIP_ALLOWED_DOMAINS.some((allowedDomain) => domain === allowedDomain || domain.endsWith(`.${allowedDomain}`));
|
|
60
|
+
if (!domainAllowed) {
|
|
61
|
+
throw new Error(`Domain ${domain} is not in the allowed domains list.`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
throw new Error(`Error processing file ${dataUri}: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
|
+
}
|
|
68
|
+
return url;
|
|
69
|
+
}
|
|
70
|
+
async function fetchSafely(url, { maxBytes, timeoutMillis }) {
|
|
71
|
+
const controller = new AbortController();
|
|
72
|
+
const timeout = setTimeout(() => controller.abort(`Fetching ${url} took more than ${timeoutMillis} ms and was aborted.`), timeoutMillis);
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
75
|
+
if (!response.body) {
|
|
76
|
+
throw new Error('No response body');
|
|
77
|
+
}
|
|
78
|
+
const contentLengthHeader = response.headers.get('content-length');
|
|
79
|
+
if (contentLengthHeader != null) {
|
|
80
|
+
const contentLength = parseInt(contentLengthHeader, 10);
|
|
81
|
+
if (contentLength > maxBytes) {
|
|
82
|
+
throw new Error(`Content-Length for ${url} exceeds max of ${maxBytes}: ${contentLength}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const reader = response.body.getReader();
|
|
86
|
+
const chunks = [];
|
|
87
|
+
let totalSize = 0;
|
|
88
|
+
try {
|
|
89
|
+
while (true) {
|
|
90
|
+
const { done, value } = await reader.read();
|
|
91
|
+
if (done)
|
|
92
|
+
break;
|
|
93
|
+
totalSize += value.length;
|
|
94
|
+
if (totalSize > maxBytes) {
|
|
95
|
+
reader.cancel();
|
|
96
|
+
throw new Error(`Response from ${url} exceeds ${maxBytes} bytes`);
|
|
97
|
+
}
|
|
98
|
+
chunks.push(value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
reader.releaseLock();
|
|
103
|
+
}
|
|
104
|
+
const buffer = new Uint8Array(totalSize);
|
|
105
|
+
let offset = 0;
|
|
106
|
+
for (const chunk of chunks) {
|
|
107
|
+
buffer.set(chunk, offset);
|
|
108
|
+
offset += chunk.length;
|
|
109
|
+
}
|
|
110
|
+
return buffer.buffer;
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
clearTimeout(timeout);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerTools = registerTools;
|
|
4
|
+
exports.registerConditionalTools = registerConditionalTools;
|
|
5
|
+
const echo_1 = require("./echo");
|
|
6
|
+
const add_1 = require("./add");
|
|
7
|
+
const print_env_1 = require("./print-env");
|
|
8
|
+
const get_tiny_image_1 = require("./get-tiny-image");
|
|
9
|
+
const annotated_message_1 = require("./annotated-message");
|
|
10
|
+
const get_resource_reference_1 = require("./get-resource-reference");
|
|
11
|
+
const get_structured_content_1 = require("./get-structured-content");
|
|
12
|
+
const get_resource_links_1 = require("./get-resource-links");
|
|
13
|
+
const gzip_file_as_resource_1 = require("./gzip-file-as-resource");
|
|
14
|
+
const toggle_simulated_logging_1 = require("./toggle-simulated-logging");
|
|
15
|
+
const toggle_subscriber_updates_1 = require("./toggle-subscriber-updates");
|
|
16
|
+
const trigger_long_running_operation_1 = require("./trigger-long-running-operation");
|
|
17
|
+
const simulate_research_query_1 = require("./simulate-research-query");
|
|
18
|
+
const trigger_elicitation_request_async_1 = require("./trigger-elicitation-request-async");
|
|
19
|
+
const trigger_elicitation_request_1 = require("./trigger-elicitation-request");
|
|
20
|
+
const trigger_sampling_request_async_1 = require("./trigger-sampling-request-async");
|
|
21
|
+
const trigger_sampling_request_1 = require("./trigger-sampling-request");
|
|
22
|
+
const trigger_url_elicitation_1 = require("./trigger-url-elicitation");
|
|
23
|
+
const get_roots_list_1 = require("./get-roots-list");
|
|
24
|
+
// Tools with no capability dependency — safe to register immediately at
|
|
25
|
+
// server construction, before any client has connected.
|
|
26
|
+
const registerFns = [
|
|
27
|
+
echo_1.registerEcho,
|
|
28
|
+
add_1.registerAdd,
|
|
29
|
+
print_env_1.registerPrintEnv,
|
|
30
|
+
get_tiny_image_1.registerGetTinyImage,
|
|
31
|
+
annotated_message_1.registerAnnotatedMessage,
|
|
32
|
+
get_resource_reference_1.registerGetResourceReference,
|
|
33
|
+
get_structured_content_1.registerGetStructuredContent,
|
|
34
|
+
get_resource_links_1.registerGetResourceLinks,
|
|
35
|
+
gzip_file_as_resource_1.registerGzipFileAsResource,
|
|
36
|
+
toggle_simulated_logging_1.registerToggleSimulatedLogging,
|
|
37
|
+
toggle_subscriber_updates_1.registerToggleSubscriberUpdates,
|
|
38
|
+
trigger_long_running_operation_1.registerTriggerLongRunningOperation
|
|
39
|
+
];
|
|
40
|
+
function registerTools(server) {
|
|
41
|
+
for (const register of registerFns) {
|
|
42
|
+
register(server);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Tools that depend on a client-declared capability. Registered only from
|
|
46
|
+
// server.server.oninitialized (see index.ts), once the client's actual
|
|
47
|
+
// capabilities are known — registering these eagerly at construction time
|
|
48
|
+
// would mean getClientCapabilities() always reads empty, and either the
|
|
49
|
+
// tool never registers or a flag computed from it is permanently stale.
|
|
50
|
+
const registerConditionalFns = [
|
|
51
|
+
get_roots_list_1.registerGetRootsList,
|
|
52
|
+
trigger_elicitation_request_1.registerTriggerElicitationRequest,
|
|
53
|
+
trigger_url_elicitation_1.registerTriggerUrlElicitation,
|
|
54
|
+
trigger_sampling_request_1.registerTriggerSamplingRequest,
|
|
55
|
+
simulate_research_query_1.registerSimulateResearchQuery,
|
|
56
|
+
trigger_sampling_request_async_1.registerTriggerSamplingRequestAsync,
|
|
57
|
+
trigger_elicitation_request_async_1.registerTriggerElicitationRequestAsync
|
|
58
|
+
];
|
|
59
|
+
function registerConditionalTools(server) {
|
|
60
|
+
for (const register of registerConditionalFns) {
|
|
61
|
+
register(server);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerPrintEnv = registerPrintEnv;
|
|
4
|
+
function registerPrintEnv(server) {
|
|
5
|
+
server.registerTool('print-env', {
|
|
6
|
+
description: 'Dumps the server process environment variables. Demo/test fixture.'
|
|
7
|
+
}, async () => ({
|
|
8
|
+
content: [{ type: 'text', text: JSON.stringify(process.env, null, 2) }]
|
|
9
|
+
}));
|
|
10
|
+
}
|