@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 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,CAgF5C;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,CAwE5C;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,CAyF5C;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6EzD"}
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"}
@@ -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,CAsB5C;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2B5D"}
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"}
@@ -50,6 +50,7 @@ export async function handleCreateContact(params) {
50
50
  email: params.email ?? null,
51
51
  notes: params.notes ?? null,
52
52
  user_id: userId,
53
+ external_source: 'mcp',
53
54
  })
54
55
  .select()
55
56
  .single();
@@ -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.1.4",
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
  },