@telitask/mcp-server 0.1.4 → 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/dist/index.js +2 -0
- package/dist/tools/calls.d.ts.map +1 -1
- package/dist/tools/calls.js +3 -0
- package/dist/tools/contacts.d.ts.map +1 -1
- package/dist/tools/contacts.js +1 -0
- package/dist/tools/phone.d.ts +17 -0
- package/dist/tools/phone.d.ts.map +1 -0
- package/dist/tools/phone.js +89 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { runOAuthLogin } from './auth/oauth.js';
|
|
|
6
6
|
import { registerContactTools } from './tools/contacts.js';
|
|
7
7
|
import { registerTaskTools } from './tools/tasks.js';
|
|
8
8
|
import { registerCallTools } from './tools/calls.js';
|
|
9
|
+
import { registerPhoneTools } from './tools/phone.js';
|
|
9
10
|
import { registerResources } from './resources/index.js';
|
|
10
11
|
const DEFAULT_DASHBOARD_URL = 'https://telitask.ai';
|
|
11
12
|
async function runLogin() {
|
|
@@ -58,6 +59,7 @@ async function runServer() {
|
|
|
58
59
|
registerContactTools(server);
|
|
59
60
|
registerTaskTools(server);
|
|
60
61
|
registerCallTools(server);
|
|
62
|
+
registerPhoneTools(server);
|
|
61
63
|
registerResources(server);
|
|
62
64
|
}
|
|
63
65
|
const transport = new StdioServerTransport();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calls.d.ts","sourceRoot":"","sources":["../../src/tools/calls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4JzE,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"calls.d.ts","sourceRoot":"","sources":["../../src/tools/calls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4JzE,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAiF5C;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAyE5C;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAgC5C;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAuC5C;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE;IAC1C,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAwC5C;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CA0F5C;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6EzD"}
|
package/dist/tools/calls.js
CHANGED
|
@@ -144,6 +144,7 @@ export async function handleMakeCall(params) {
|
|
|
144
144
|
callType: 'on_behalf',
|
|
145
145
|
purpose: params.brief,
|
|
146
146
|
contactId: contactResult.id,
|
|
147
|
+
source: 'mcp',
|
|
147
148
|
}),
|
|
148
149
|
});
|
|
149
150
|
if (!response.ok) {
|
|
@@ -235,6 +236,7 @@ export async function handleScheduleCall(params) {
|
|
|
235
236
|
callType,
|
|
236
237
|
purpose: params.brief,
|
|
237
238
|
scheduledAt: params.scheduled_at,
|
|
239
|
+
source: 'mcp',
|
|
238
240
|
...(contactId && { contactId }),
|
|
239
241
|
};
|
|
240
242
|
const response = await fetch(`${voiceServerUrl}/api/scheduled-calls`, {
|
|
@@ -379,6 +381,7 @@ export async function handleCallMe(params) {
|
|
|
379
381
|
personaId,
|
|
380
382
|
phoneNumber: userProfile.phone_number,
|
|
381
383
|
callType: 'direct',
|
|
384
|
+
source: 'mcp',
|
|
382
385
|
};
|
|
383
386
|
if (params.brief)
|
|
384
387
|
body.purpose = params.brief;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contacts.d.ts","sourceRoot":"","sources":["../../src/tools/contacts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAwC5C;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"contacts.d.ts","sourceRoot":"","sources":["../../src/tools/contacts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAwC5C;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAuB5C;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2B5D"}
|
package/dist/tools/contacts.js
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
export declare function handleSendPhoneCode(params: {
|
|
3
|
+
phone_number: string;
|
|
4
|
+
country_code?: string;
|
|
5
|
+
}): Promise<{
|
|
6
|
+
type: 'text';
|
|
7
|
+
text: string;
|
|
8
|
+
}[]>;
|
|
9
|
+
export declare function handleVerifyPhoneCode(params: {
|
|
10
|
+
phone_number: string;
|
|
11
|
+
code: string;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
type: 'text';
|
|
14
|
+
text: string;
|
|
15
|
+
}[]>;
|
|
16
|
+
export declare function registerPhoneTools(server: McpServer): void;
|
|
17
|
+
//# sourceMappingURL=phone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phone.d.ts","sourceRoot":"","sources":["../../src/tools/phone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqBzE,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CA8C5C;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAsB5C;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwB1D"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { parsePhoneNumberFromString } from 'libphonenumber-js';
|
|
3
|
+
import { refreshSessionIfNeeded, getVoiceServerUrl, getAccessToken, } from '../lib/supabase.js';
|
|
4
|
+
/** Map voice server error codes to user-friendly messages */
|
|
5
|
+
const ERROR_MESSAGES = {
|
|
6
|
+
invalid_code: 'Invalid code. Please try again.',
|
|
7
|
+
code_expired: "Code expired. Say 'resend' and I'll send a new one.",
|
|
8
|
+
max_attempts_exceeded: 'Too many failed attempts. Request a new code.',
|
|
9
|
+
phone_already_verified: 'This phone number is already in use by another account.',
|
|
10
|
+
rate_limit_exceeded: 'Too many attempts. Please wait a few minutes.',
|
|
11
|
+
country_not_supported: 'Phone numbers from this country are not currently supported.',
|
|
12
|
+
cooldown: 'Please wait before requesting another code.',
|
|
13
|
+
};
|
|
14
|
+
export async function handleSendPhoneCode(params) {
|
|
15
|
+
await refreshSessionIfNeeded();
|
|
16
|
+
const voiceServerUrl = getVoiceServerUrl();
|
|
17
|
+
const accessToken = getAccessToken();
|
|
18
|
+
// Normalize phone number to E.164
|
|
19
|
+
let e164;
|
|
20
|
+
if (params.phone_number.startsWith('+')) {
|
|
21
|
+
// International format — parse directly
|
|
22
|
+
const parsed = parsePhoneNumberFromString(params.phone_number);
|
|
23
|
+
if (!parsed?.isValid()) {
|
|
24
|
+
return [{ type: 'text', text: 'Could not parse that phone number. Please provide a valid phone number.' }];
|
|
25
|
+
}
|
|
26
|
+
e164 = parsed.format('E.164');
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Local format — need country_code
|
|
30
|
+
if (!params.country_code) {
|
|
31
|
+
return [{ type: 'text', text: "I need your country to verify this number. Which country are you in? (e.g., US, GB, KE)" }];
|
|
32
|
+
}
|
|
33
|
+
const parsed = parsePhoneNumberFromString(params.phone_number, params.country_code);
|
|
34
|
+
if (!parsed?.isValid()) {
|
|
35
|
+
return [{ type: 'text', text: `Could not parse "${params.phone_number}" as a valid phone number for ${params.country_code}.` }];
|
|
36
|
+
}
|
|
37
|
+
e164 = parsed.format('E.164');
|
|
38
|
+
}
|
|
39
|
+
// POST to voice server
|
|
40
|
+
const response = await fetch(`${voiceServerUrl}/api/phone/send-code`, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
headers: {
|
|
43
|
+
'Content-Type': 'application/json',
|
|
44
|
+
Authorization: `Bearer ${accessToken}`,
|
|
45
|
+
},
|
|
46
|
+
body: JSON.stringify({ phoneNumber: e164 }),
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
const body = await response.json().catch(() => ({}));
|
|
50
|
+
const errorKey = body.error ?? 'unknown';
|
|
51
|
+
const message = ERROR_MESSAGES[errorKey] ?? body.message ?? 'Failed to send verification code. Please try again.';
|
|
52
|
+
return [{ type: 'text', text: message }];
|
|
53
|
+
}
|
|
54
|
+
return [{ type: 'text', text: `Verification code sent to ${e164}. What's the 6-digit code?` }];
|
|
55
|
+
}
|
|
56
|
+
export async function handleVerifyPhoneCode(params) {
|
|
57
|
+
await refreshSessionIfNeeded();
|
|
58
|
+
const voiceServerUrl = getVoiceServerUrl();
|
|
59
|
+
const accessToken = getAccessToken();
|
|
60
|
+
const response = await fetch(`${voiceServerUrl}/api/phone/verify-code`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
Authorization: `Bearer ${accessToken}`,
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify({ phoneNumber: params.phone_number, code: params.code }),
|
|
67
|
+
});
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
const body = await response.json().catch(() => ({}));
|
|
70
|
+
const errorKey = body.error ?? 'unknown';
|
|
71
|
+
const message = ERROR_MESSAGES[errorKey] ?? body.message ?? 'Failed to verify code. Please try again.';
|
|
72
|
+
return [{ type: 'text', text: message }];
|
|
73
|
+
}
|
|
74
|
+
return [{ type: 'text', text: `Phone number verified: ${params.phone_number}` }];
|
|
75
|
+
}
|
|
76
|
+
export function registerPhoneTools(server) {
|
|
77
|
+
server.tool('send_phone_code', "Send a verification code to a phone number. Accepts local format (e.g., '0712345678') with a country_code, or international format (e.g., '+254712345678'). Use this when the user wants to add or verify their phone number.", {
|
|
78
|
+
phone_number: z.string().describe("Phone number in local or international format (e.g., '0712345678' or '+254712345678')"),
|
|
79
|
+
country_code: z.string().optional().describe("ISO 3166-1 alpha-2 country code (e.g., 'KE', 'US'). Required when phone_number is in local format."),
|
|
80
|
+
}, async ({ phone_number, country_code }) => ({
|
|
81
|
+
content: await handleSendPhoneCode({ phone_number, country_code }),
|
|
82
|
+
}));
|
|
83
|
+
server.tool('verify_phone_code', 'Verify a phone number with the 6-digit code sent via SMS. Use the E.164 phone number from the previous send_phone_code step.', {
|
|
84
|
+
phone_number: z.string().describe("Phone number in E.164 format (e.g., '+254712345678') — use the number returned by send_phone_code"),
|
|
85
|
+
code: z.string().describe('The 6-digit verification code from the SMS'),
|
|
86
|
+
}, async ({ phone_number, code }) => ({
|
|
87
|
+
content: await handleVerifyPhoneCode({ phone_number, code }),
|
|
88
|
+
}));
|
|
89
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telitask/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "TeliTask MCP server — manage contacts, tasks, and calls from AI assistants",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
50
50
|
"@supabase/supabase-js": "^2.49.4",
|
|
51
|
+
"libphonenumber-js": "^1.12.36",
|
|
51
52
|
"open": "^10.1.0",
|
|
52
53
|
"zod": "^3.24.2"
|
|
53
54
|
},
|