@zeph-to/mcp-server 0.2.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/README.md +242 -0
- package/dist/api-client.d.ts +54 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +106 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +17 -0
- package/dist/error-format.d.ts +8 -0
- package/dist/error-format.d.ts.map +1 -0
- package/dist/error-format.js +49 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/poll.d.ts +10 -0
- package/dist/poll.d.ts.map +1 -0
- package/dist/poll.js +43 -0
- package/dist/resources/channels.d.ts +4 -0
- package/dist/resources/channels.d.ts.map +1 -0
- package/dist/resources/channels.js +24 -0
- package/dist/resources/devices.d.ts +4 -0
- package/dist/resources/devices.d.ts.map +1 -0
- package/dist/resources/devices.js +24 -0
- package/dist/tools/broadcast.d.ts +4 -0
- package/dist/tools/broadcast.d.ts.map +1 -0
- package/dist/tools/broadcast.js +36 -0
- package/dist/tools/clipboard.d.ts +5 -0
- package/dist/tools/clipboard.d.ts.map +1 -0
- package/dist/tools/clipboard.js +28 -0
- package/dist/tools/dismiss.d.ts +5 -0
- package/dist/tools/dismiss.d.ts.map +1 -0
- package/dist/tools/dismiss.js +37 -0
- package/dist/tools/file.d.ts +5 -0
- package/dist/tools/file.d.ts.map +1 -0
- package/dist/tools/file.js +59 -0
- package/dist/tools/input.d.ts +5 -0
- package/dist/tools/input.d.ts.map +1 -0
- package/dist/tools/input.js +46 -0
- package/dist/tools/list.d.ts +4 -0
- package/dist/tools/list.d.ts.map +1 -0
- package/dist/tools/list.js +38 -0
- package/dist/tools/notify.d.ts +5 -0
- package/dist/tools/notify.d.ts.map +1 -0
- package/dist/tools/notify.js +36 -0
- package/dist/tools/prompt.d.ts +5 -0
- package/dist/tools/prompt.d.ts.map +1 -0
- package/dist/tools/prompt.js +59 -0
- package/dist/types.d.ts +94 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/package.json +33 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices.d.ts","sourceRoot":"","sources":["../../src/resources/devices.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,eAAO,MAAM,uBAAuB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,SAuB/E,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDevicesResource = void 0;
|
|
4
|
+
const registerDevicesResource = (server, client) => {
|
|
5
|
+
server.registerResource('devices', 'zeph://devices', {
|
|
6
|
+
title: 'Connected Devices',
|
|
7
|
+
description: 'List of user devices connected to Zeph with online status',
|
|
8
|
+
mimeType: 'application/json',
|
|
9
|
+
}, async (uri) => {
|
|
10
|
+
try {
|
|
11
|
+
const response = await client.listDevices();
|
|
12
|
+
return {
|
|
13
|
+
contents: [{ uri: uri.href, text: JSON.stringify(response.data, null, 2) }],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
const message = err instanceof Error ? err.message : 'Failed to fetch devices';
|
|
18
|
+
return {
|
|
19
|
+
contents: [{ uri: uri.href, text: JSON.stringify({ error: message }) }],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
exports.registerDevicesResource = registerDevicesResource;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../src/tools/broadcast.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,eAAO,MAAM,qBAAqB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,SAiC7E,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerBroadcastTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const error_format_js_1 = require("../error-format.js");
|
|
6
|
+
const registerBroadcastTool = (server, client) => {
|
|
7
|
+
server.registerTool('zeph_broadcast', {
|
|
8
|
+
description: 'Send a push notification to all subscribers of a channel. Use zeph://channels resource to find available channels.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
channelId: zod_1.z.string().describe('Channel ID to broadcast to (e.g., "ch_...")'),
|
|
11
|
+
title: zod_1.z.string().describe('Notification title'),
|
|
12
|
+
body: zod_1.z.string().optional().describe('Notification body text'),
|
|
13
|
+
url: zod_1.z.string().url().optional().describe('URL to open. When provided, the push becomes a link type.'),
|
|
14
|
+
priority: zod_1.z
|
|
15
|
+
.enum(['low', 'normal', 'high', 'urgent'])
|
|
16
|
+
.default('normal')
|
|
17
|
+
.describe('Notification priority'),
|
|
18
|
+
},
|
|
19
|
+
}, async ({ channelId, title, body, url, priority }) => {
|
|
20
|
+
try {
|
|
21
|
+
const result = await client.sendPush({
|
|
22
|
+
title,
|
|
23
|
+
body,
|
|
24
|
+
url,
|
|
25
|
+
type: url ? 'link' : 'note',
|
|
26
|
+
priority,
|
|
27
|
+
channelId,
|
|
28
|
+
});
|
|
29
|
+
return (0, error_format_js_1.textResult)({ pushId: result.data.pushId, channelId });
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
exports.registerBroadcastTool = registerBroadcastTool;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ZephApiClient } from '../api-client.js';
|
|
3
|
+
import type { McpServerConfig } from '../config.js';
|
|
4
|
+
export declare const registerClipboardTool: (server: McpServer, client: ZephApiClient, config: McpServerConfig) => void;
|
|
5
|
+
//# sourceMappingURL=clipboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../src/tools/clipboard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,eAAO,MAAM,qBAAqB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,EAAE,QAAQ,eAAe,SAyBtG,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerClipboardTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const error_format_js_1 = require("../error-format.js");
|
|
6
|
+
const registerClipboardTool = (server, client, config) => {
|
|
7
|
+
server.registerTool('zeph_clipboard', {
|
|
8
|
+
description: 'Copy text to the user\'s device clipboard. The text will appear in their clipboard history and can be pasted immediately.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
text: zod_1.z.string().describe('Text to copy to clipboard'),
|
|
11
|
+
targetDeviceId: zod_1.z.string().optional().describe('Target device ID. Omit to use configured default or send to all devices.'),
|
|
12
|
+
},
|
|
13
|
+
}, async ({ text, targetDeviceId }) => {
|
|
14
|
+
try {
|
|
15
|
+
const result = await client.sendPush({
|
|
16
|
+
title: 'Clipboard',
|
|
17
|
+
body: text,
|
|
18
|
+
type: 'clipboard',
|
|
19
|
+
targetDeviceId: targetDeviceId ?? config.deviceId,
|
|
20
|
+
});
|
|
21
|
+
return (0, error_format_js_1.textResult)({ pushId: result.data.pushId });
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
exports.registerClipboardTool = registerClipboardTool;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ZephApiClient } from '../api-client.js';
|
|
3
|
+
export declare const registerDismissTool: (server: McpServer, client: ZephApiClient) => void;
|
|
4
|
+
export declare const registerDismissAllTool: (server: McpServer, client: ZephApiClient) => void;
|
|
5
|
+
//# sourceMappingURL=dismiss.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dismiss.d.ts","sourceRoot":"","sources":["../../src/tools/dismiss.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,eAAO,MAAM,mBAAmB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,SAmB3E,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,SAiB9E,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDismissAllTool = exports.registerDismissTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const error_format_js_1 = require("../error-format.js");
|
|
6
|
+
const registerDismissTool = (server, client) => {
|
|
7
|
+
server.registerTool('zeph_dismiss', {
|
|
8
|
+
description: 'Dismiss (mark as read) a specific push notification by ID. Use after processing a notification to clear it from the user\'s feed.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
pushId: zod_1.z.string().describe('Push ID to dismiss (e.g., "push_01HX...")'),
|
|
11
|
+
},
|
|
12
|
+
}, async ({ pushId }) => {
|
|
13
|
+
try {
|
|
14
|
+
await client.dismissPush(pushId);
|
|
15
|
+
return (0, error_format_js_1.textResult)({ dismissed: true, pushId });
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
exports.registerDismissTool = registerDismissTool;
|
|
23
|
+
const registerDismissAllTool = (server, client) => {
|
|
24
|
+
server.registerTool('zeph_dismiss_all', {
|
|
25
|
+
description: 'Dismiss all push notifications at once. Clears the entire notification feed.',
|
|
26
|
+
inputSchema: {},
|
|
27
|
+
}, async () => {
|
|
28
|
+
try {
|
|
29
|
+
const result = await client.dismissAllPushes();
|
|
30
|
+
return (0, error_format_js_1.textResult)({ dismissed: result.data.dismissed, badge: result.data.badge ?? 0 });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
exports.registerDismissAllTool = registerDismissAllTool;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ZephApiClient } from '../api-client.js';
|
|
3
|
+
import type { McpServerConfig } from '../config.js';
|
|
4
|
+
export declare const registerFileTool: (server: McpServer, client: ZephApiClient, config: McpServerConfig) => void;
|
|
5
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/tools/file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,eAAO,MAAM,gBAAgB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,EAAE,QAAQ,eAAe,SAyCjG,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerFileTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const error_format_js_1 = require("../error-format.js");
|
|
6
|
+
const registerFileTool = (server, client, config) => {
|
|
7
|
+
server.registerTool('zeph_file', {
|
|
8
|
+
description: 'Send a text file to the user\'s device. The content is uploaded and delivered as a file push. Use for logs, reports, code snippets, or any text content.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
fileName: zod_1.z.string().describe('File name with extension (e.g., "report.txt", "output.json")'),
|
|
11
|
+
content: zod_1.z.string().describe('Text content of the file'),
|
|
12
|
+
title: zod_1.z.string().optional().describe('Notification title (defaults to fileName)'),
|
|
13
|
+
targetDeviceId: zod_1.z.string().optional().describe('Target device ID. Omit to use configured default or send to all devices.'),
|
|
14
|
+
},
|
|
15
|
+
}, async ({ fileName, content, title, targetDeviceId }) => {
|
|
16
|
+
try {
|
|
17
|
+
const fileType = inferMimeType(fileName);
|
|
18
|
+
const fileSize = new TextEncoder().encode(content).byteLength;
|
|
19
|
+
// Step 1: Request upload URL
|
|
20
|
+
const upload = await client.requestUpload({ fileName, fileType, fileSize });
|
|
21
|
+
// Step 2: Upload content to S3
|
|
22
|
+
await client.uploadToS3(upload.data.uploadUrl, content, fileType);
|
|
23
|
+
// Step 3: Send file push
|
|
24
|
+
const result = await client.sendPush({
|
|
25
|
+
title: title ?? fileName,
|
|
26
|
+
type: 'file',
|
|
27
|
+
fileKey: upload.data.fileKey,
|
|
28
|
+
fileName,
|
|
29
|
+
fileSize,
|
|
30
|
+
fileType,
|
|
31
|
+
targetDeviceId: targetDeviceId ?? config.deviceId,
|
|
32
|
+
});
|
|
33
|
+
return (0, error_format_js_1.textResult)({ pushId: result.data.pushId, fileKey: upload.data.fileKey, fileSize });
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
exports.registerFileTool = registerFileTool;
|
|
41
|
+
const inferMimeType = (fileName) => {
|
|
42
|
+
const ext = fileName.split('.').pop()?.toLowerCase();
|
|
43
|
+
const map = {
|
|
44
|
+
txt: 'text/plain',
|
|
45
|
+
json: 'application/json',
|
|
46
|
+
csv: 'text/csv',
|
|
47
|
+
md: 'text/markdown',
|
|
48
|
+
html: 'text/html',
|
|
49
|
+
xml: 'text/xml',
|
|
50
|
+
yaml: 'text/yaml',
|
|
51
|
+
yml: 'text/yaml',
|
|
52
|
+
log: 'text/plain',
|
|
53
|
+
ts: 'text/typescript',
|
|
54
|
+
js: 'text/javascript',
|
|
55
|
+
py: 'text/x-python',
|
|
56
|
+
sh: 'text/x-shellscript',
|
|
57
|
+
};
|
|
58
|
+
return map[ext ?? ''] ?? 'text/plain';
|
|
59
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ZephApiClient } from '../api-client.js';
|
|
3
|
+
import type { McpServerConfig } from '../config.js';
|
|
4
|
+
export declare const registerInputTool: (server: McpServer, client: ZephApiClient, config: McpServerConfig) => void;
|
|
5
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/tools/input.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,eAAO,MAAM,iBAAiB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,EAAE,QAAQ,eAAe,SAkDlG,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerInputTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const error_format_js_1 = require("../error-format.js");
|
|
6
|
+
const poll_js_1 = require("../poll.js");
|
|
7
|
+
const registerInputTool = (server, client, config) => {
|
|
8
|
+
server.registerTool('zeph_input', {
|
|
9
|
+
description: 'Request text input from the user via push notification. The tool blocks until the user responds or the timeout is reached. Requires ZEPH_HOOK_ID environment variable.',
|
|
10
|
+
inputSchema: {
|
|
11
|
+
title: zod_1.z.string().describe('Input request title'),
|
|
12
|
+
body: zod_1.z.string().optional().describe('Instructions or context'),
|
|
13
|
+
placeholder: zod_1.z.string().optional().describe('Input placeholder hint'),
|
|
14
|
+
inputType: zod_1.z
|
|
15
|
+
.enum(['text', 'password', 'multiline'])
|
|
16
|
+
.default('text')
|
|
17
|
+
.describe('Input field type'),
|
|
18
|
+
timeout: zod_1.z
|
|
19
|
+
.number()
|
|
20
|
+
.min(10)
|
|
21
|
+
.max(600)
|
|
22
|
+
.default(120)
|
|
23
|
+
.describe('Seconds to wait for response (default: 120)'),
|
|
24
|
+
},
|
|
25
|
+
}, async ({ title, body, placeholder, inputType, timeout }, ctx) => {
|
|
26
|
+
if (!config.hookId)
|
|
27
|
+
return (0, error_format_js_1.hookNotConfiguredError)();
|
|
28
|
+
try {
|
|
29
|
+
const trigger = await client.triggerHook(config.hookId, {
|
|
30
|
+
title,
|
|
31
|
+
body,
|
|
32
|
+
timeout,
|
|
33
|
+
hookType: 'input',
|
|
34
|
+
metadata: { placeholder, inputType },
|
|
35
|
+
});
|
|
36
|
+
const event = await (0, poll_js_1.pollForResponse)(client, config.hookId, trigger.data.eventId, timeout, ctx);
|
|
37
|
+
if (!event)
|
|
38
|
+
return (0, error_format_js_1.timeoutError)(timeout, 'Try again with a longer timeout');
|
|
39
|
+
return (0, error_format_js_1.textResult)({ value: event.data.response?.value ?? '', timedOut: false });
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
exports.registerInputTool = registerInputTool;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,eAAO,MAAM,gBAAgB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,SAmCxE,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerListTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const error_format_js_1 = require("../error-format.js");
|
|
6
|
+
const registerListTool = (server, client) => {
|
|
7
|
+
server.registerTool('zeph_list', {
|
|
8
|
+
description: 'List recent push notifications. Use this to check notification history, avoid duplicates, or reference previous messages.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
limit: zod_1.z
|
|
11
|
+
.number()
|
|
12
|
+
.min(1)
|
|
13
|
+
.max(20)
|
|
14
|
+
.default(5)
|
|
15
|
+
.describe('Number of pushes to return (default: 5, max: 20)'),
|
|
16
|
+
type: zod_1.z
|
|
17
|
+
.enum(['note', 'link', 'file', 'clipboard', 'hook'])
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Filter by push type'),
|
|
20
|
+
},
|
|
21
|
+
}, async ({ limit, type }) => {
|
|
22
|
+
try {
|
|
23
|
+
const result = await client.listPushes({ limit, type });
|
|
24
|
+
const summary = result.data.map((p) => ({
|
|
25
|
+
pushId: p.pushId,
|
|
26
|
+
type: p.type,
|
|
27
|
+
title: p.title,
|
|
28
|
+
body: p.body?.slice(0, 100),
|
|
29
|
+
createdAt: p.createdAt,
|
|
30
|
+
}));
|
|
31
|
+
return (0, error_format_js_1.textResult)({ pushes: summary, total: summary.length, hasMore: result.pagination.hasMore });
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
exports.registerListTool = registerListTool;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ZephApiClient } from '../api-client.js';
|
|
3
|
+
import type { McpServerConfig } from '../config.js';
|
|
4
|
+
export declare const registerNotifyTool: (server: McpServer, client: ZephApiClient, config: McpServerConfig) => void;
|
|
5
|
+
//# sourceMappingURL=notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/tools/notify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,eAAO,MAAM,kBAAkB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,EAAE,QAAQ,eAAe,SAiCnG,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerNotifyTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const error_format_js_1 = require("../error-format.js");
|
|
6
|
+
const registerNotifyTool = (server, client, config) => {
|
|
7
|
+
server.registerTool('zeph_notify', {
|
|
8
|
+
description: 'Send a one-way push notification to the user\'s devices. Use this to inform the user about task completion, errors, or status updates.',
|
|
9
|
+
inputSchema: {
|
|
10
|
+
title: zod_1.z.string().describe('Notification title'),
|
|
11
|
+
body: zod_1.z.string().optional().describe('Notification body text'),
|
|
12
|
+
url: zod_1.z.string().url().optional().describe('URL to open on the device. When provided, the push becomes a link type.'),
|
|
13
|
+
priority: zod_1.z
|
|
14
|
+
.enum(['low', 'normal', 'high', 'urgent'])
|
|
15
|
+
.default('normal')
|
|
16
|
+
.describe('Notification priority. Use "urgent" for critical alerts, "low" for background info.'),
|
|
17
|
+
targetDeviceId: zod_1.z.string().optional().describe('Target device ID. Omit to use configured default or send to all devices.'),
|
|
18
|
+
},
|
|
19
|
+
}, async ({ title, body, url, priority, targetDeviceId }) => {
|
|
20
|
+
try {
|
|
21
|
+
const result = await client.sendPush({
|
|
22
|
+
title,
|
|
23
|
+
body,
|
|
24
|
+
url,
|
|
25
|
+
type: url ? 'link' : 'note',
|
|
26
|
+
priority,
|
|
27
|
+
targetDeviceId: targetDeviceId ?? config.deviceId,
|
|
28
|
+
});
|
|
29
|
+
return (0, error_format_js_1.textResult)({ pushId: result.data.pushId });
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
exports.registerNotifyTool = registerNotifyTool;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { ZephApiClient } from '../api-client.js';
|
|
3
|
+
import type { McpServerConfig } from '../config.js';
|
|
4
|
+
export declare const registerPromptTool: (server: McpServer, client: ZephApiClient, config: McpServerConfig) => void;
|
|
5
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/tools/prompt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,eAAO,MAAM,kBAAkB,GAAI,QAAQ,SAAS,EAAE,QAAQ,aAAa,EAAE,QAAQ,eAAe,SAiEnG,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerPromptTool = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const error_format_js_1 = require("../error-format.js");
|
|
6
|
+
const poll_js_1 = require("../poll.js");
|
|
7
|
+
const registerPromptTool = (server, client, config) => {
|
|
8
|
+
server.registerTool('zeph_prompt', {
|
|
9
|
+
description: 'Ask the user to choose from predefined options via push notification. The tool blocks until the user responds or the timeout is reached. Requires ZEPH_HOOK_ID environment variable.',
|
|
10
|
+
inputSchema: {
|
|
11
|
+
title: zod_1.z.string().describe('Question or request title'),
|
|
12
|
+
body: zod_1.z.string().optional().describe('Detailed description'),
|
|
13
|
+
actions: zod_1.z
|
|
14
|
+
.array(zod_1.z.object({
|
|
15
|
+
id: zod_1.z.string().describe('Unique action identifier'),
|
|
16
|
+
label: zod_1.z.string().describe('Display label for the button'),
|
|
17
|
+
style: zod_1.z.enum(['primary', 'secondary', 'danger']).default('secondary')
|
|
18
|
+
.describe('Button style (default: secondary)'),
|
|
19
|
+
}))
|
|
20
|
+
.min(2)
|
|
21
|
+
.max(4)
|
|
22
|
+
.describe('Choice options (2-4 items)'),
|
|
23
|
+
timeout: zod_1.z
|
|
24
|
+
.number()
|
|
25
|
+
.min(10)
|
|
26
|
+
.max(300)
|
|
27
|
+
.default(120)
|
|
28
|
+
.describe('Seconds to wait for response (default: 120)'),
|
|
29
|
+
fallback: zod_1.z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('Action ID to auto-select on timeout'),
|
|
33
|
+
},
|
|
34
|
+
}, async ({ title, body, actions, timeout, fallback }, ctx) => {
|
|
35
|
+
if (!config.hookId)
|
|
36
|
+
return (0, error_format_js_1.hookNotConfiguredError)();
|
|
37
|
+
try {
|
|
38
|
+
const trigger = await client.triggerHook(config.hookId, {
|
|
39
|
+
title,
|
|
40
|
+
body,
|
|
41
|
+
actions,
|
|
42
|
+
timeout,
|
|
43
|
+
fallback,
|
|
44
|
+
hookType: 'interactive',
|
|
45
|
+
});
|
|
46
|
+
const event = await (0, poll_js_1.pollForResponse)(client, config.hookId, trigger.data.eventId, timeout, ctx);
|
|
47
|
+
if (!event) {
|
|
48
|
+
if (fallback)
|
|
49
|
+
return (0, error_format_js_1.textResult)({ actionId: fallback, timedOut: true });
|
|
50
|
+
return (0, error_format_js_1.timeoutError)(timeout, 'Try again or use zeph_notify for one-way communication');
|
|
51
|
+
}
|
|
52
|
+
return (0, error_format_js_1.textResult)({ actionId: event.data.response?.actionId, timedOut: false });
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
return (0, error_format_js_1.formatToolError)(err);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
exports.registerPromptTool = registerPromptTool;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export interface ApiErrorBody {
|
|
2
|
+
error: {
|
|
3
|
+
code: string;
|
|
4
|
+
message: string;
|
|
5
|
+
status: number;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export interface PushResponse {
|
|
9
|
+
data: {
|
|
10
|
+
pushId: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface HookTriggerResponse {
|
|
14
|
+
data: {
|
|
15
|
+
pushId: string;
|
|
16
|
+
eventId: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface HookEventResponse {
|
|
20
|
+
data: {
|
|
21
|
+
eventId: string;
|
|
22
|
+
status: 'pending' | 'responded' | 'timed_out' | 'cancelled';
|
|
23
|
+
response?: {
|
|
24
|
+
actionId?: string;
|
|
25
|
+
value?: string;
|
|
26
|
+
respondedDeviceId?: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface DeviceRecord {
|
|
31
|
+
deviceId: string;
|
|
32
|
+
nickname?: string;
|
|
33
|
+
type?: string;
|
|
34
|
+
model?: string;
|
|
35
|
+
isOnline?: boolean;
|
|
36
|
+
lastSeenAt?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface DevicesResponse {
|
|
39
|
+
data: DeviceRecord[];
|
|
40
|
+
}
|
|
41
|
+
export interface PushRecord {
|
|
42
|
+
pushId: string;
|
|
43
|
+
type: string;
|
|
44
|
+
title?: string;
|
|
45
|
+
body?: string;
|
|
46
|
+
url?: string;
|
|
47
|
+
priority?: string;
|
|
48
|
+
senderDeviceId?: string;
|
|
49
|
+
targetDeviceId?: string;
|
|
50
|
+
channelId?: string;
|
|
51
|
+
fileKey?: string;
|
|
52
|
+
fileName?: string;
|
|
53
|
+
fileSize?: number;
|
|
54
|
+
createdAt: string;
|
|
55
|
+
}
|
|
56
|
+
export interface PushListResponse {
|
|
57
|
+
data: PushRecord[];
|
|
58
|
+
pagination: {
|
|
59
|
+
cursor?: string;
|
|
60
|
+
hasMore: boolean;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export interface DismissResponse {
|
|
64
|
+
data: {
|
|
65
|
+
dismissed: boolean | number;
|
|
66
|
+
badge?: number;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export interface ChannelRecord {
|
|
70
|
+
channelId: string;
|
|
71
|
+
tag: string;
|
|
72
|
+
name: string;
|
|
73
|
+
description?: string;
|
|
74
|
+
ownerId: string;
|
|
75
|
+
subscriberCount: number;
|
|
76
|
+
isPublic: boolean;
|
|
77
|
+
}
|
|
78
|
+
export interface ChannelsResponse {
|
|
79
|
+
data: ChannelRecord[];
|
|
80
|
+
}
|
|
81
|
+
export interface UploadRequestResponse {
|
|
82
|
+
data: {
|
|
83
|
+
fileId: string;
|
|
84
|
+
fileKey: string;
|
|
85
|
+
uploadUrl: string;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export interface ToolError {
|
|
89
|
+
error: string;
|
|
90
|
+
message: string;
|
|
91
|
+
retryAfter?: number;
|
|
92
|
+
suggestion?: string;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zeph-to/mcp-server",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Zeph MCP server — AI agent notifications, prompts, and input via MCP protocol",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"zeph-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=18.0.0"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"!dist/**/*.tsbuildinfo"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p tsconfig.lib.json",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
23
|
+
"zod": "^3.25.1"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/tak-bro/encl",
|
|
28
|
+
"directory": "libs/mcp-server"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/tak-bro/encl/tree/main/libs/mcp-server",
|
|
31
|
+
"keywords": ["zeph", "mcp", "ai", "notification", "prompt", "model-context-protocol"],
|
|
32
|
+
"license": "MIT"
|
|
33
|
+
}
|