@meetlark/mcp-server 1.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/README.md +74 -0
- package/bin/cli.ts +8 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +10 -0
- package/dist/chunk-AFREFQH7.js +14238 -0
- package/dist/src/index.d.ts +26 -0
- package/dist/src/index.js +8 -0
- package/package.json +23 -0
- package/server.json +12 -0
- package/smithery.yaml +12 -0
- package/src/client.ts +96 -0
- package/src/config.ts +2 -0
- package/src/index.ts +3 -0
- package/src/server.ts +28 -0
- package/src/tools/close-poll.ts +75 -0
- package/src/tools/create-poll.ts +84 -0
- package/src/tools/get-admin.ts +64 -0
- package/src/tools/get-results.ts +64 -0
- package/src/tools/index.ts +6 -0
- package/src/tools/reopen-poll.ts +75 -0
- package/src/tools/vote.ts +88 -0
- package/test/cli.test.ts +44 -0
- package/test/client.test.ts +234 -0
- package/test/route.test.ts +112 -0
- package/test/server.test.ts +87 -0
- package/test/setup.test.ts +27 -0
- package/test/tools.test.ts +265 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +8 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
|
|
3
|
+
declare function createMeetLarkServer(apiUrl?: string): McpServer;
|
|
4
|
+
|
|
5
|
+
interface MeetLarkError {
|
|
6
|
+
status: number;
|
|
7
|
+
code: string;
|
|
8
|
+
message: string;
|
|
9
|
+
}
|
|
10
|
+
interface MeetLarkResult<T> {
|
|
11
|
+
data?: T;
|
|
12
|
+
error?: MeetLarkError;
|
|
13
|
+
}
|
|
14
|
+
declare class MeetLarkClient {
|
|
15
|
+
private apiUrl;
|
|
16
|
+
constructor(apiUrl?: string);
|
|
17
|
+
private request;
|
|
18
|
+
createPoll(data: Record<string, unknown>): Promise<MeetLarkResult<unknown>>;
|
|
19
|
+
getResults(participateToken: string): Promise<MeetLarkResult<unknown>>;
|
|
20
|
+
vote(participateToken: string, data: Record<string, unknown>): Promise<MeetLarkResult<unknown>>;
|
|
21
|
+
getAdminView(adminToken: string): Promise<MeetLarkResult<unknown>>;
|
|
22
|
+
closePoll(adminToken: string): Promise<MeetLarkResult<unknown>>;
|
|
23
|
+
reopenPoll(adminToken: string): Promise<MeetLarkResult<unknown>>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { MeetLarkClient, type MeetLarkError, type MeetLarkResult, createMeetLarkServer };
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@meetlark/mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"meetlark-mcp": "./dist/bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/src/index.js",
|
|
9
|
+
"types": "./dist/src/index.d.ts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"test": "node --test --import tsx test/*.test.ts",
|
|
13
|
+
"dev": "tsup --watch"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@modelcontextprotocol/sdk": "^1.26.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"tsup": "^8.5.1",
|
|
20
|
+
"tsx": "^4.21.0",
|
|
21
|
+
"typescript": "5.9.3"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
|
|
3
|
+
"name": "ai.meetlark/mcp-server",
|
|
4
|
+
"description": "Agent-first scheduling poll service. Create polls, collect availability votes, find times that work for groups. No accounts needed.",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"remotes": [
|
|
7
|
+
{
|
|
8
|
+
"type": "sse",
|
|
9
|
+
"url": "https://meetlark.ai/mcp"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
package/smithery.yaml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
name: meetlark-mcp-server
|
|
2
|
+
description: Agent-first scheduling poll service. Create polls, collect availability votes, find times that work for groups. No accounts needed.
|
|
3
|
+
tags:
|
|
4
|
+
- scheduling
|
|
5
|
+
- polls
|
|
6
|
+
- mcp
|
|
7
|
+
command:
|
|
8
|
+
type: stdio
|
|
9
|
+
command: npx
|
|
10
|
+
args:
|
|
11
|
+
- -y
|
|
12
|
+
- "@meetlark/mcp-server"
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { MEETLARK_API_URL } from "./config.js";
|
|
2
|
+
|
|
3
|
+
export interface MeetLarkError {
|
|
4
|
+
status: number;
|
|
5
|
+
code: string;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface MeetLarkResult<T> {
|
|
10
|
+
data?: T;
|
|
11
|
+
error?: MeetLarkError;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class MeetLarkClient {
|
|
15
|
+
private apiUrl: string;
|
|
16
|
+
|
|
17
|
+
constructor(apiUrl?: string) {
|
|
18
|
+
this.apiUrl = apiUrl ?? MEETLARK_API_URL;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private async request<T>(
|
|
22
|
+
path: string,
|
|
23
|
+
options?: RequestInit,
|
|
24
|
+
): Promise<MeetLarkResult<T>> {
|
|
25
|
+
let response: Response;
|
|
26
|
+
try {
|
|
27
|
+
response = await fetch(`${this.apiUrl}${path}`, {
|
|
28
|
+
...options,
|
|
29
|
+
headers: {
|
|
30
|
+
"Content-Type": "application/json",
|
|
31
|
+
...options?.headers,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return {
|
|
36
|
+
error: {
|
|
37
|
+
status: 0,
|
|
38
|
+
code: "network_error",
|
|
39
|
+
message:
|
|
40
|
+
err instanceof Error ? err.message : "Network request failed",
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const body = await response.json();
|
|
46
|
+
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
return {
|
|
49
|
+
error: {
|
|
50
|
+
status: response.status,
|
|
51
|
+
code: body.error?.code ?? "unknown_error",
|
|
52
|
+
message: body.error?.message ?? response.statusText,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { data: body.data };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async createPoll(data: Record<string, unknown>): Promise<MeetLarkResult<unknown>> {
|
|
61
|
+
return this.request("/api/v1/polls?autoVerify=true", {
|
|
62
|
+
method: "POST",
|
|
63
|
+
body: JSON.stringify(data),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async getResults(participateToken: string): Promise<MeetLarkResult<unknown>> {
|
|
68
|
+
return this.request(`/api/v1/vote/participate/${participateToken}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async vote(
|
|
72
|
+
participateToken: string,
|
|
73
|
+
data: Record<string, unknown>,
|
|
74
|
+
): Promise<MeetLarkResult<unknown>> {
|
|
75
|
+
return this.request(`/api/v1/vote/participate/${participateToken}`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
body: JSON.stringify(data),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async getAdminView(adminToken: string): Promise<MeetLarkResult<unknown>> {
|
|
82
|
+
return this.request(`/api/v1/polls/admin/${adminToken}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async closePoll(adminToken: string): Promise<MeetLarkResult<unknown>> {
|
|
86
|
+
return this.request(`/api/v1/polls/admin/${adminToken}/close`, {
|
|
87
|
+
method: "POST",
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async reopenPoll(adminToken: string): Promise<MeetLarkResult<unknown>> {
|
|
92
|
+
return this.request(`/api/v1/polls/admin/${adminToken}/reopen`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
package/src/config.ts
ADDED
package/src/index.ts
ADDED
package/src/server.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { MeetLarkClient } from "./client.js";
|
|
3
|
+
import {
|
|
4
|
+
registerCreatePoll,
|
|
5
|
+
registerGetResults,
|
|
6
|
+
registerVote,
|
|
7
|
+
registerGetAdmin,
|
|
8
|
+
registerClosePoll,
|
|
9
|
+
registerReopenPoll,
|
|
10
|
+
} from "./tools/index.js";
|
|
11
|
+
|
|
12
|
+
export function createMeetLarkServer(apiUrl?: string): McpServer {
|
|
13
|
+
const server = new McpServer({
|
|
14
|
+
name: "meetlark",
|
|
15
|
+
version: "1.0.0",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const client = new MeetLarkClient(apiUrl);
|
|
19
|
+
|
|
20
|
+
registerCreatePoll(server, client);
|
|
21
|
+
registerGetResults(server, client);
|
|
22
|
+
registerVote(server, client);
|
|
23
|
+
registerGetAdmin(server, client);
|
|
24
|
+
registerClosePoll(server, client);
|
|
25
|
+
registerReopenPoll(server, client);
|
|
26
|
+
|
|
27
|
+
return server;
|
|
28
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import type { MeetLarkClient } from "../client.js";
|
|
4
|
+
|
|
5
|
+
export function registerClosePoll(server: McpServer, client: MeetLarkClient) {
|
|
6
|
+
server.registerTool("meetlark_close_poll", {
|
|
7
|
+
description:
|
|
8
|
+
"Close a poll to stop accepting new votes. " +
|
|
9
|
+
"Use the admin token from poll creation.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
adminToken: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("The adm_xxx token from poll creation"),
|
|
14
|
+
},
|
|
15
|
+
}, async (args) => {
|
|
16
|
+
const result = await client.closePoll(args.adminToken);
|
|
17
|
+
|
|
18
|
+
if (result.error) {
|
|
19
|
+
if (result.error.code === "poll_not_found") {
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
type: "text" as const,
|
|
24
|
+
text: "Poll not found. The admin token may be invalid.",
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (result.error.code === "poll_already_closed") {
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "text" as const,
|
|
36
|
+
text: "This poll is already closed.",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (result.error.code === "network_error") {
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "text" as const,
|
|
48
|
+
text: "Could not connect to MeetLark API.",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text" as const,
|
|
59
|
+
text: result.error.message,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text" as const,
|
|
70
|
+
text: JSON.stringify(result.data),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import type { MeetLarkClient } from "../client.js";
|
|
4
|
+
|
|
5
|
+
export function registerCreatePoll(server: McpServer, client: MeetLarkClient) {
|
|
6
|
+
server.registerTool("meetlark_create_poll", {
|
|
7
|
+
description:
|
|
8
|
+
"Create a scheduling poll to find a time that works for a group. " +
|
|
9
|
+
"Returns an admin URL (keep private) and a participation URL " +
|
|
10
|
+
"(share with participants). The creator's email must be verified -- " +
|
|
11
|
+
"if not yet verified, a verification email is sent automatically. " +
|
|
12
|
+
"Ask the user to check their inbox and click the link, then retry.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
title: z.string().describe("What is this poll for?"),
|
|
15
|
+
description: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Additional context for participants"),
|
|
19
|
+
timeSlots: z
|
|
20
|
+
.array(
|
|
21
|
+
z.object({
|
|
22
|
+
date: z.string().describe("Date in YYYY-MM-DD format"),
|
|
23
|
+
startTime: z.string().describe("Start time in HH:MM format"),
|
|
24
|
+
endTime: z.string().describe("End time in HH:MM format"),
|
|
25
|
+
}),
|
|
26
|
+
)
|
|
27
|
+
.describe("Available time slots to vote on"),
|
|
28
|
+
creatorEmail: z
|
|
29
|
+
.string()
|
|
30
|
+
.describe("Email address of the poll creator"),
|
|
31
|
+
creatorName: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Name of the poll creator"),
|
|
35
|
+
},
|
|
36
|
+
}, async (args) => {
|
|
37
|
+
const result = await client.createPoll(args);
|
|
38
|
+
|
|
39
|
+
if (result.error) {
|
|
40
|
+
if (result.error.code === "email_not_verified") {
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: "text" as const,
|
|
45
|
+
text: `Email verification required. A verification email has been sent to ${(args as Record<string, unknown>).creatorEmail}. Ask the user to click the link in the email, then try creating the poll again.`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (result.error.code === "network_error") {
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: "text" as const,
|
|
57
|
+
text: `Could not connect to MeetLark API.`,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text" as const,
|
|
68
|
+
text: result.error.message,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
isError: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text" as const,
|
|
79
|
+
text: JSON.stringify(result.data),
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import type { MeetLarkClient } from "../client.js";
|
|
4
|
+
|
|
5
|
+
export function registerGetAdmin(server: McpServer, client: MeetLarkClient) {
|
|
6
|
+
server.registerTool("meetlark_get_admin_view", {
|
|
7
|
+
description:
|
|
8
|
+
"Get full poll details and results using the admin token. " +
|
|
9
|
+
"Includes all participant data, vote counts, and poll " +
|
|
10
|
+
"management info. Use the admin token from poll creation.",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
adminToken: z
|
|
13
|
+
.string()
|
|
14
|
+
.describe("The adm_xxx token from poll creation"),
|
|
15
|
+
},
|
|
16
|
+
}, async (args) => {
|
|
17
|
+
const result = await client.getAdminView(args.adminToken);
|
|
18
|
+
|
|
19
|
+
if (result.error) {
|
|
20
|
+
if (result.error.code === "poll_not_found") {
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: "text" as const,
|
|
25
|
+
text: "Poll not found. The admin token may be invalid.",
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (result.error.code === "network_error") {
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: "text" as const,
|
|
37
|
+
text: "Could not connect to MeetLark API.",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
isError: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "text" as const,
|
|
48
|
+
text: result.error.message,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text" as const,
|
|
59
|
+
text: JSON.stringify(result.data),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import type { MeetLarkClient } from "../client.js";
|
|
4
|
+
|
|
5
|
+
export function registerGetResults(server: McpServer, client: MeetLarkClient) {
|
|
6
|
+
server.registerTool("meetlark_get_results", {
|
|
7
|
+
description:
|
|
8
|
+
"View current poll results including all votes cast so far. " +
|
|
9
|
+
"Shows the poll details and time slots. Use the participation " +
|
|
10
|
+
"token from the poll's participate URL.",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
participateToken: z
|
|
13
|
+
.string()
|
|
14
|
+
.describe("The prt_xxx token from the participation URL"),
|
|
15
|
+
},
|
|
16
|
+
}, async (args) => {
|
|
17
|
+
const result = await client.getResults(args.participateToken);
|
|
18
|
+
|
|
19
|
+
if (result.error) {
|
|
20
|
+
if (result.error.code === "participate_token_not_found") {
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: "text" as const,
|
|
25
|
+
text: "Token not found. The participation link may be invalid or expired.",
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (result.error.code === "network_error") {
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: "text" as const,
|
|
37
|
+
text: "Could not connect to MeetLark API.",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
isError: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "text" as const,
|
|
48
|
+
text: result.error.message,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text" as const,
|
|
59
|
+
text: JSON.stringify(result.data),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { registerCreatePoll } from "./create-poll.js";
|
|
2
|
+
export { registerGetResults } from "./get-results.js";
|
|
3
|
+
export { registerVote } from "./vote.js";
|
|
4
|
+
export { registerGetAdmin } from "./get-admin.js";
|
|
5
|
+
export { registerClosePoll } from "./close-poll.js";
|
|
6
|
+
export { registerReopenPoll } from "./reopen-poll.js";
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import type { MeetLarkClient } from "../client.js";
|
|
4
|
+
|
|
5
|
+
export function registerReopenPoll(server: McpServer, client: MeetLarkClient) {
|
|
6
|
+
server.registerTool("meetlark_reopen_poll", {
|
|
7
|
+
description:
|
|
8
|
+
"Reopen a previously closed poll to accept votes again. " +
|
|
9
|
+
"Use the admin token from poll creation.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
adminToken: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("The adm_xxx token from poll creation"),
|
|
14
|
+
},
|
|
15
|
+
}, async (args) => {
|
|
16
|
+
const result = await client.reopenPoll(args.adminToken);
|
|
17
|
+
|
|
18
|
+
if (result.error) {
|
|
19
|
+
if (result.error.code === "poll_not_found") {
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
type: "text" as const,
|
|
24
|
+
text: "Poll not found. The admin token may be invalid.",
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (result.error.code === "poll_already_open") {
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "text" as const,
|
|
36
|
+
text: "This poll is already open.",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
isError: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (result.error.code === "network_error") {
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "text" as const,
|
|
48
|
+
text: "Could not connect to MeetLark API.",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text" as const,
|
|
59
|
+
text: result.error.message,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text" as const,
|
|
70
|
+
text: JSON.stringify(result.data),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import type { MeetLarkClient } from "../client.js";
|
|
4
|
+
|
|
5
|
+
export function registerVote(server: McpServer, client: MeetLarkClient) {
|
|
6
|
+
server.registerTool("meetlark_vote", {
|
|
7
|
+
description:
|
|
8
|
+
"Cast a vote on a scheduling poll. Each time slot can be " +
|
|
9
|
+
"voted yes, maybe, or no. Use the participation token from " +
|
|
10
|
+
"the poll's participate URL.",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
participateToken: z
|
|
13
|
+
.string()
|
|
14
|
+
.describe("The prt_xxx token from the participation URL"),
|
|
15
|
+
name: z.string().describe("Name to display in results"),
|
|
16
|
+
votes: z
|
|
17
|
+
.array(
|
|
18
|
+
z.object({
|
|
19
|
+
timeSlotId: z.string().describe("Time slot ID"),
|
|
20
|
+
value: z.enum(["yes", "maybe", "no"]).describe("Vote value"),
|
|
21
|
+
}),
|
|
22
|
+
)
|
|
23
|
+
.describe("Votes for each time slot"),
|
|
24
|
+
},
|
|
25
|
+
}, async (args) => {
|
|
26
|
+
const result = await client.vote(args.participateToken, {
|
|
27
|
+
name: args.name,
|
|
28
|
+
votes: args.votes,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (result.error) {
|
|
32
|
+
if (result.error.code === "participate_token_not_found") {
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: "text" as const,
|
|
37
|
+
text: "Token not found. The participation link may be invalid or expired.",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
isError: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (result.error.code === "poll_closed") {
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: "text" as const,
|
|
49
|
+
text: "This poll is already closed.",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
isError: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (result.error.code === "network_error") {
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: "text" as const,
|
|
61
|
+
text: "Could not connect to MeetLark API.",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
isError: true,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: "text" as const,
|
|
72
|
+
text: result.error.message,
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
isError: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: "text" as const,
|
|
83
|
+
text: JSON.stringify(result.data),
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
}
|