@hasna/skills 0.1.32 → 0.1.34

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.
Files changed (95) hide show
  1. package/README.md +1 -16
  2. package/bin/index.js +57 -14
  3. package/bin/mcp.js +57 -13
  4. package/dist/cli/commands/runtime.d.ts +1 -1
  5. package/dist/index.js +51 -5
  6. package/dist/lib/skill-validation.d.ts +2 -0
  7. package/package.json +1 -1
  8. package/skills/ad-creative-pack/package.json +4 -7
  9. package/skills/api-docs-portal/package.json +5 -3
  10. package/skills/audio/package.json +4 -22
  11. package/skills/audio-transcript-pack/package.json +3 -2
  12. package/skills/blog-article/package.json +5 -21
  13. package/skills/brand-kit/package.json +4 -7
  14. package/skills/brand-photo-shoot/package.json +3 -2
  15. package/skills/browse/README.md +13 -256
  16. package/skills/browse/SKILL.md +24 -45
  17. package/skills/browse/package.json +4 -33
  18. package/skills/contract-review-report/package.json +3 -2
  19. package/skills/customer-feedback-report/package.json +3 -2
  20. package/skills/deepresearch/CLAUDE.md +6 -39
  21. package/skills/deepresearch/README.md +15 -150
  22. package/skills/deepresearch/SKILL.md +23 -32
  23. package/skills/deepresearch/package.json +4 -37
  24. package/skills/domainpurchase/SKILL.md +14 -31
  25. package/skills/domainpurchase/package.json +3 -8
  26. package/skills/email-sequence/package.json +4 -7
  27. package/skills/generate-book-cover/package.json +5 -23
  28. package/skills/icon-pack/package.json +4 -22
  29. package/skills/image/README.md +13 -183
  30. package/skills/image/package.json +4 -22
  31. package/skills/invoice-reconciliation/package.json +3 -2
  32. package/skills/landing-page-pack/package.json +4 -7
  33. package/skills/logo-design/package.json +4 -2
  34. package/skills/managemcp/CLAUDE.md +9 -43
  35. package/skills/managemcp/README.md +12 -198
  36. package/skills/managemcp/package.json +2 -10
  37. package/skills/managemcp/tsconfig.json +1 -3
  38. package/skills/market-research-report/package.json +5 -4
  39. package/skills/meeting-pack/package.json +3 -2
  40. package/skills/migration-plan-pack/package.json +3 -2
  41. package/skills/music/package.json +4 -20
  42. package/skills/music-album/package.json +3 -2
  43. package/skills/one-page-website/package.json +3 -2
  44. package/skills/pdf-read/package.json +5 -23
  45. package/skills/pdf-to-dataset/package.json +5 -4
  46. package/skills/pdf-to-markdown/package.json +5 -4
  47. package/skills/performance-audit-report/package.json +3 -2
  48. package/skills/photo-album/package.json +4 -2
  49. package/skills/pitch-deck/package.json +5 -3
  50. package/skills/playlist-maker/package.json +4 -2
  51. package/skills/product-mockup/package.json +3 -2
  52. package/skills/proposal-pack/package.json +5 -4
  53. package/skills/read-pdf/package.json +4 -29
  54. package/skills/remove-background/package.json +5 -21
  55. package/skills/repo-onboarding-report/package.json +3 -2
  56. package/skills/sdk-generator/package.json +3 -2
  57. package/skills/security-audit-report/package.json +5 -4
  58. package/skills/seo-content-pack/package.json +5 -3
  59. package/skills/short-video-pack/package.json +3 -2
  60. package/skills/slide-deck-generator/package.json +3 -2
  61. package/skills/sms/README.md +18 -56
  62. package/skills/sms/package.json +1 -3
  63. package/skills/sms/tsconfig.json +1 -2
  64. package/skills/social-content-calendar/package.json +4 -7
  65. package/skills/test-suite-generator/package.json +5 -4
  66. package/skills/transcript/package.json +4 -23
  67. package/skills/video/package.json +4 -24
  68. package/skills/video-highlight-pack/package.json +3 -2
  69. package/skills/voiceover-jingle-pack/package.json +3 -2
  70. package/skills/webcrawling/CLAUDE.md +6 -17
  71. package/skills/webcrawling/README.md +13 -66
  72. package/skills/webcrawling/package.json +4 -32
  73. package/skills/browse/.env.example +0 -14
  74. package/skills/deepresearch/.env.example +0 -9
  75. package/skills/domainpurchase/.env.example +0 -7
  76. package/skills/domainpurchase/src/lib/api-client.ts +0 -571
  77. package/skills/domainpurchase/src/lib/config.ts +0 -209
  78. package/skills/domainpurchase/src/lib/installer.ts +0 -165
  79. package/skills/image/.env.example +0 -12
  80. package/skills/image/PROJECT_OVERVIEW.md +0 -216
  81. package/skills/image/QUICKSTART.md +0 -111
  82. package/skills/managemcp/.env.example +0 -16
  83. package/skills/managemcp/scripts/migrate.ts +0 -57
  84. package/skills/managemcp/scripts/seed.ts +0 -58
  85. package/skills/managemcp/src/db/index.ts +0 -37
  86. package/skills/managemcp/src/lib/api-client.ts +0 -108
  87. package/skills/managemcp/src/lib/config.ts +0 -34
  88. package/skills/managemcp/src/lib/installer.ts +0 -140
  89. package/skills/managemcp/src/lib/service-dir.ts +0 -119
  90. package/skills/sms/scripts/buy-number.ts +0 -63
  91. package/skills/sms/scripts/test-send.ts +0 -67
  92. package/skills/sms/src/server.ts +0 -351
  93. package/skills/sms/src/sse-server.ts +0 -279
  94. package/skills/transcript/.env.example +0 -10
  95. package/skills/webcrawling/.env.example +0 -2
@@ -1,351 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * MCP SMS HTTP Server
4
- * Provides SMS functionality for AI agents via HTTP API using Twilio
5
- */
6
-
7
- import twilio from "twilio";
8
-
9
- // Configuration
10
- const CONFIG = {
11
- port: parseInt(process.env.PORT || "3848"),
12
- accountSid: process.env.TWILIO_ACCOUNT_SID || "",
13
- authToken: process.env.TWILIO_AUTH_TOKEN || "",
14
- apiKey: process.env.MCP_SMS_API_KEY || "",
15
- };
16
-
17
- // Twilio Client
18
- const twilioClient = twilio(CONFIG.accountSid, CONFIG.authToken);
19
-
20
- // Helper: Capitalize first letter
21
- function capitalize(str: string): string {
22
- return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
23
- }
24
-
25
- // Helper: Get display name for agent - "[Name] (AI Agent)"
26
- function getDisplayName(agentName: string): string {
27
- return `${capitalize(agentName)} (AI Agent)`;
28
- }
29
-
30
- // Helper: Validate API key
31
- function validateApiKey(request: Request): boolean {
32
- if (!CONFIG.apiKey) return true;
33
- const authHeader = request.headers.get("Authorization");
34
- if (!authHeader) return false;
35
- const [type, key] = authHeader.split(" ");
36
- return type === "Bearer" && key === CONFIG.apiKey;
37
- }
38
-
39
- // Helper: JSON response
40
- function jsonResponse(data: any, status = 200): Response {
41
- return new Response(JSON.stringify(data, null, 2), {
42
- status,
43
- headers: { "Content-Type": "application/json" },
44
- });
45
- }
46
-
47
- // Helper: Error response
48
- function errorResponse(message: string, status = 400): Response {
49
- return jsonResponse({ success: false, error: message }, status);
50
- }
51
-
52
- // Helper: Format phone number to E.164
53
- function formatPhoneNumber(phone: string): string {
54
- const digits = phone.replace(/\D/g, "");
55
- if (digits.length === 10) {
56
- return `+1${digits}`;
57
- }
58
- if (digits.length === 11 && digits.startsWith("1")) {
59
- return `+${digits}`;
60
- }
61
- if (!phone.startsWith("+")) {
62
- return `+${digits}`;
63
- }
64
- return phone;
65
- }
66
-
67
- // Send SMS
68
- async function sendSms(params: {
69
- agent_name: string;
70
- from_number: string;
71
- to: string;
72
- body: string;
73
- }): Promise<{ success: boolean; message_sid?: string; error?: string }> {
74
- try {
75
- const message = await twilioClient.messages.create({
76
- body: params.body,
77
- from: formatPhoneNumber(params.from_number),
78
- to: formatPhoneNumber(params.to),
79
- });
80
-
81
- return {
82
- success: true,
83
- message_sid: message.sid,
84
- };
85
- } catch (error: any) {
86
- return {
87
- success: false,
88
- error: error.message,
89
- };
90
- }
91
- }
92
-
93
- // List messages
94
- async function listMessages(params: {
95
- agent_name: string;
96
- phone_number: string;
97
- limit?: number;
98
- direction?: "inbound" | "outbound";
99
- }): Promise<any> {
100
- try {
101
- const options: any = {
102
- limit: params.limit || 20,
103
- };
104
-
105
- if (params.direction === "inbound") {
106
- options.to = formatPhoneNumber(params.phone_number);
107
- } else if (params.direction === "outbound") {
108
- options.from = formatPhoneNumber(params.phone_number);
109
- }
110
-
111
- const messages = await twilioClient.messages.list(options);
112
-
113
- return {
114
- success: true,
115
- count: messages.length,
116
- messages: messages.map((m) => ({
117
- sid: m.sid,
118
- from: m.from,
119
- to: m.to,
120
- body: m.body,
121
- status: m.status,
122
- direction: m.direction,
123
- date_sent: m.dateSent?.toISOString(),
124
- date_created: m.dateCreated?.toISOString(),
125
- })),
126
- };
127
- } catch (error: any) {
128
- return {
129
- success: false,
130
- error: error.message,
131
- };
132
- }
133
- }
134
-
135
- // Get message
136
- async function getMessage(messageSid: string): Promise<any> {
137
- try {
138
- const message = await twilioClient.messages(messageSid).fetch();
139
-
140
- return {
141
- success: true,
142
- sid: message.sid,
143
- from: message.from,
144
- to: message.to,
145
- body: message.body,
146
- status: message.status,
147
- direction: message.direction,
148
- date_sent: message.dateSent?.toISOString(),
149
- date_created: message.dateCreated?.toISOString(),
150
- price: message.price,
151
- price_unit: message.priceUnit,
152
- };
153
- } catch (error: any) {
154
- return {
155
- success: false,
156
- error: error.message,
157
- };
158
- }
159
- }
160
-
161
- // List phone numbers
162
- async function listPhoneNumbers(): Promise<any> {
163
- try {
164
- const numbers = await twilioClient.incomingPhoneNumbers.list();
165
-
166
- return {
167
- success: true,
168
- count: numbers.length,
169
- phone_numbers: numbers.map((n) => ({
170
- sid: n.sid,
171
- phone_number: n.phoneNumber,
172
- friendly_name: n.friendlyName,
173
- capabilities: n.capabilities,
174
- date_created: n.dateCreated?.toISOString(),
175
- })),
176
- };
177
- } catch (error: any) {
178
- return {
179
- success: false,
180
- error: error.message,
181
- };
182
- }
183
- }
184
-
185
- // Buy phone number
186
- async function buyPhoneNumber(params: {
187
- area_code?: string;
188
- friendly_name?: string;
189
- }): Promise<any> {
190
- try {
191
- // Search for available numbers
192
- const searchOptions: any = {
193
- limit: 1,
194
- };
195
-
196
- if (params.area_code) {
197
- searchOptions.areaCode = params.area_code;
198
- }
199
-
200
- const availableNumbers =
201
- await twilioClient.availablePhoneNumbers("US").local.list(searchOptions);
202
-
203
- if (availableNumbers.length === 0) {
204
- return {
205
- success: false,
206
- error: "No available phone numbers found",
207
- };
208
- }
209
-
210
- // Purchase the number
211
- const purchased = await twilioClient.incomingPhoneNumbers.create({
212
- phoneNumber: availableNumbers[0].phoneNumber,
213
- friendlyName: params.friendly_name || "MCP SMS Agent",
214
- });
215
-
216
- return {
217
- success: true,
218
- phone_number: purchased.phoneNumber,
219
- sid: purchased.sid,
220
- friendly_name: purchased.friendlyName,
221
- };
222
- } catch (error: any) {
223
- return {
224
- success: false,
225
- error: error.message,
226
- };
227
- }
228
- }
229
-
230
- // HTTP Server
231
- const PATH_PREFIX = "/sms";
232
-
233
- const server = Bun.serve({
234
- port: CONFIG.port,
235
- async fetch(request) {
236
- const url = new URL(request.url);
237
- let path = url.pathname;
238
- const method = request.method;
239
-
240
- // Strip path prefix if present (for ALB routing)
241
- if (path.startsWith(PATH_PREFIX)) {
242
- path = path.slice(PATH_PREFIX.length) || "/";
243
- }
244
-
245
- // Health check
246
- if (path === "/health" && method === "GET") {
247
- return jsonResponse({ status: "ok", version: "1.0.0" });
248
- }
249
-
250
- // API key validation for all other routes
251
- if (!validateApiKey(request)) {
252
- return errorResponse("Unauthorized", 401);
253
- }
254
-
255
- try {
256
- // POST /send - Send SMS
257
- if (path === "/send" && method === "POST") {
258
- const body = await request.json();
259
-
260
- if (!body.agent_name || !body.from_number || !body.to || !body.body) {
261
- return errorResponse(
262
- "Missing required fields: agent_name, from_number, to, body"
263
- );
264
- }
265
-
266
- const result = await sendSms(body);
267
- return jsonResponse({
268
- ...result,
269
- agent: getDisplayName(body.agent_name),
270
- from: formatPhoneNumber(body.from_number),
271
- to: formatPhoneNumber(body.to),
272
- });
273
- }
274
-
275
- // GET /messages/:phone - List messages for a phone number
276
- if (path.startsWith("/messages/") && method === "GET") {
277
- const parts = path.split("/");
278
- const phoneNumber = decodeURIComponent(parts[2]);
279
- const agentName = url.searchParams.get("agent") || "unknown";
280
- const limit = parseInt(url.searchParams.get("limit") || "20");
281
- const direction = url.searchParams.get("direction") as
282
- | "inbound"
283
- | "outbound"
284
- | undefined;
285
-
286
- if (!phoneNumber) {
287
- return errorResponse("Phone number required");
288
- }
289
-
290
- const result = await listMessages({
291
- agent_name: agentName,
292
- phone_number: phoneNumber,
293
- limit,
294
- direction,
295
- });
296
- return jsonResponse(result);
297
- }
298
-
299
- // GET /message/:sid - Get specific message
300
- if (path.startsWith("/message/") && method === "GET") {
301
- const messageSid = path.split("/")[2];
302
-
303
- if (!messageSid) {
304
- return errorResponse("Message SID required");
305
- }
306
-
307
- const result = await getMessage(messageSid);
308
- return jsonResponse(result);
309
- }
310
-
311
- // GET /numbers - List phone numbers
312
- if (path === "/numbers" && method === "GET") {
313
- const result = await listPhoneNumbers();
314
- return jsonResponse(result);
315
- }
316
-
317
- // POST /numbers/buy - Buy a phone number
318
- if (path === "/numbers/buy" && method === "POST") {
319
- const body = await request.json();
320
- const result = await buyPhoneNumber({
321
- area_code: body.area_code,
322
- friendly_name: body.friendly_name,
323
- });
324
- return jsonResponse(result);
325
- }
326
-
327
- // GET /agent/:name - Get agent info
328
- if (path.startsWith("/agent/") && method === "GET") {
329
- const agentName = path.split("/")[2];
330
-
331
- if (!agentName) {
332
- return errorResponse("Agent name required");
333
- }
334
-
335
- return jsonResponse({
336
- success: true,
337
- agent_name: agentName,
338
- display_name: getDisplayName(agentName),
339
- });
340
- }
341
-
342
- return errorResponse("Not found", 404);
343
- } catch (error: any) {
344
- console.error("Error:", error);
345
- return errorResponse(error.message, 500);
346
- }
347
- },
348
- });
349
-
350
- console.log(`MCP SMS Server running on http://localhost:${CONFIG.port}`);
351
- console.log(`API Key: ${CONFIG.apiKey ? "configured" : "not configured (open access)"}`);
@@ -1,279 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * MCP SMS SSE Server
4
- * Provides SMS functionality for AI agents via SSE transport using Twilio
5
- */
6
-
7
- import express from "express";
8
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9
- import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
10
- import { z } from "zod";
11
- import twilio from "twilio";
12
-
13
- // Configuration
14
- const CONFIG = {
15
- port: parseInt(process.env.PORT || "3848"),
16
- accountSid: process.env.TWILIO_ACCOUNT_SID || "",
17
- authToken: process.env.TWILIO_AUTH_TOKEN || "",
18
- apiKey: process.env.MCP_SMS_API_KEY || "",
19
- };
20
-
21
- // Twilio Client
22
- const twilioClient = twilio(CONFIG.accountSid, CONFIG.authToken);
23
-
24
- // Helper functions
25
- function capitalize(str: string): string {
26
- return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
27
- }
28
-
29
- function getDisplayName(agentName: string): string {
30
- return `${capitalize(agentName)} (AI Agent)`;
31
- }
32
-
33
- function formatPhoneNumber(phone: string): string {
34
- const digits = phone.replace(/\D/g, "");
35
- if (digits.length === 10) return `+1${digits}`;
36
- if (digits.length === 11 && digits.startsWith("1")) return `+${digits}`;
37
- if (!phone.startsWith("+")) return `+${digits}`;
38
- return phone;
39
- }
40
-
41
- // Create MCP Server with tools
42
- function createMcpServer(): McpServer {
43
- const server = new McpServer({
44
- name: "mcp-sms",
45
- version: "1.0.0",
46
- });
47
-
48
- // Tool: Send SMS
49
- server.tool(
50
- "send_sms",
51
- "Send an SMS message from an AI agent",
52
- {
53
- agent_name: z.string().describe("Name of the AI agent sending the SMS"),
54
- from_number: z.string().describe("Twilio phone number to send from"),
55
- to: z.string().describe("Recipient phone number"),
56
- body: z.string().describe("SMS message body (max 1600 characters)"),
57
- },
58
- async ({ agent_name, from_number, to, body }) => {
59
- try {
60
- const message = await twilioClient.messages.create({
61
- body,
62
- from: formatPhoneNumber(from_number),
63
- to: formatPhoneNumber(to),
64
- });
65
-
66
- return {
67
- content: [{
68
- type: "text",
69
- text: JSON.stringify({
70
- success: true,
71
- message_sid: message.sid,
72
- agent: getDisplayName(agent_name),
73
- from: formatPhoneNumber(from_number),
74
- to: formatPhoneNumber(to),
75
- status: message.status,
76
- }, null, 2),
77
- }],
78
- };
79
- } catch (error: any) {
80
- return {
81
- content: [{ type: "text", text: JSON.stringify({ success: false, error: error.message }, null, 2) }],
82
- isError: true,
83
- };
84
- }
85
- }
86
- );
87
-
88
- // Tool: List Messages
89
- server.tool(
90
- "list_messages",
91
- "List SMS messages for a phone number",
92
- {
93
- agent_name: z.string().describe("Name of the AI agent"),
94
- phone_number: z.string().describe("Phone number to list messages for"),
95
- limit: z.number().optional().default(20).describe("Maximum number of messages"),
96
- direction: z.enum(["inbound", "outbound"]).optional().describe("Filter by message direction"),
97
- },
98
- async ({ agent_name, phone_number, limit, direction }) => {
99
- try {
100
- const options: any = { limit };
101
- if (direction === "inbound") options.to = formatPhoneNumber(phone_number);
102
- else if (direction === "outbound") options.from = formatPhoneNumber(phone_number);
103
-
104
- const messages = await twilioClient.messages.list(options);
105
-
106
- return {
107
- content: [{
108
- type: "text",
109
- text: JSON.stringify({
110
- success: true,
111
- agent: getDisplayName(agent_name),
112
- count: messages.length,
113
- messages: messages.map((m) => ({
114
- sid: m.sid,
115
- from: m.from,
116
- to: m.to,
117
- body: m.body,
118
- status: m.status,
119
- direction: m.direction,
120
- date_sent: m.dateSent?.toISOString(),
121
- })),
122
- }, null, 2),
123
- }],
124
- };
125
- } catch (error: any) {
126
- return {
127
- content: [{ type: "text", text: JSON.stringify({ success: false, error: error.message }, null, 2) }],
128
- isError: true,
129
- };
130
- }
131
- }
132
- );
133
-
134
- // Tool: Read Message
135
- server.tool(
136
- "read_message",
137
- "Read a specific SMS message by SID",
138
- {
139
- message_sid: z.string().describe("The Twilio message SID"),
140
- },
141
- async ({ message_sid }) => {
142
- try {
143
- const message = await twilioClient.messages(message_sid).fetch();
144
-
145
- return {
146
- content: [{
147
- type: "text",
148
- text: JSON.stringify({
149
- success: true,
150
- sid: message.sid,
151
- from: message.from,
152
- to: message.to,
153
- body: message.body,
154
- status: message.status,
155
- direction: message.direction,
156
- date_sent: message.dateSent?.toISOString(),
157
- date_created: message.dateCreated?.toISOString(),
158
- price: message.price,
159
- price_unit: message.priceUnit,
160
- }, null, 2),
161
- }],
162
- };
163
- } catch (error: any) {
164
- return {
165
- content: [{ type: "text", text: JSON.stringify({ success: false, error: error.message }, null, 2) }],
166
- isError: true,
167
- };
168
- }
169
- }
170
- );
171
-
172
- // Tool: List Phone Numbers
173
- server.tool(
174
- "list_phone_numbers",
175
- "List all Twilio phone numbers in the account",
176
- {},
177
- async () => {
178
- try {
179
- const numbers = await twilioClient.incomingPhoneNumbers.list();
180
-
181
- return {
182
- content: [{
183
- type: "text",
184
- text: JSON.stringify({
185
- success: true,
186
- count: numbers.length,
187
- phone_numbers: numbers.map((n) => ({
188
- sid: n.sid,
189
- phone_number: n.phoneNumber,
190
- friendly_name: n.friendlyName,
191
- capabilities: n.capabilities,
192
- })),
193
- }, null, 2),
194
- }],
195
- };
196
- } catch (error: any) {
197
- return {
198
- content: [{ type: "text", text: JSON.stringify({ success: false, error: error.message }, null, 2) }],
199
- isError: true,
200
- };
201
- }
202
- }
203
- );
204
-
205
- // Tool: Get Agent Info
206
- server.tool(
207
- "get_agent_info",
208
- "Get SMS configuration info for an AI agent",
209
- {
210
- agent_name: z.string().describe("Name of the AI agent"),
211
- },
212
- async ({ agent_name }) => {
213
- return {
214
- content: [{
215
- type: "text",
216
- text: JSON.stringify({
217
- agent_name,
218
- display_name: getDisplayName(agent_name),
219
- }, null, 2),
220
- }],
221
- };
222
- }
223
- );
224
-
225
- return server;
226
- }
227
-
228
- // Validate API key middleware
229
- function validateApiKey(req: express.Request, res: express.Response, next: express.NextFunction) {
230
- if (!CONFIG.apiKey) return next();
231
- const authHeader = req.headers.authorization;
232
- if (!authHeader) return res.status(401).json({ error: "Unauthorized" });
233
- const [type, key] = authHeader.split(" ");
234
- if (type !== "Bearer" || key !== CONFIG.apiKey) return res.status(401).json({ error: "Unauthorized" });
235
- next();
236
- }
237
-
238
- // Express app
239
- const app = express();
240
- // Don't use express.json() globally - SSEServerTransport needs raw stream
241
- // app.use(express.json());
242
-
243
- const transports: { [sessionId: string]: SSEServerTransport } = {};
244
-
245
- app.get("/health", (req, res) => {
246
- res.json({ status: "ok", version: "1.0.0", transport: "sse" });
247
- });
248
-
249
- app.get("/sse", validateApiKey, async (req, res) => {
250
- console.log("SSE connection request received");
251
- const transport = new SSEServerTransport("/mcp/sms/messages", res);
252
- transports[transport.sessionId] = transport;
253
- console.log("SSE session started:", transport.sessionId);
254
-
255
- res.on("close", () => {
256
- console.log("SSE session closed:", transport.sessionId);
257
- delete transports[transport.sessionId];
258
- });
259
-
260
- const server = createMcpServer();
261
- await server.connect(transport);
262
- });
263
-
264
- app.post("/messages", validateApiKey, async (req, res) => {
265
- const sessionId = req.query.sessionId as string;
266
- const transport = transports[sessionId];
267
-
268
- if (transport) {
269
- await transport.handlePostMessage(req, res);
270
- } else {
271
- res.status(400).json({ error: "No transport found for sessionId" });
272
- }
273
- });
274
-
275
- app.listen(CONFIG.port, () => {
276
- console.log(`MCP SMS SSE Server running on http://localhost:${CONFIG.port}`);
277
- console.log(`SSE endpoint: http://localhost:${CONFIG.port}/sse`);
278
- console.log(`API Key: ${CONFIG.apiKey ? "configured" : "not configured"}`);
279
- });
@@ -1,10 +0,0 @@
1
- # At least one provider API key is required
2
-
3
- # ElevenLabs - Highest accuracy (96.7%), 3GB files, speaker diarization
4
- ELEVENLABS_API_KEY=your_elevenlabs_key
5
-
6
- # OpenAI Whisper - Industry standard, 25MB limit (auto-chunking for larger)
7
- OPENAI_API_KEY=your_openai_key
8
-
9
- # Google Gemini - Cost-effective, 2GB files, generous free tier
10
- GOOGLE_API_KEY=your_google_key
@@ -1,2 +0,0 @@
1
- # Firecrawl API key (required)
2
- FIRECRAWL_API_KEY=fc-your-api-key-here