@spacelr/mcp 0.0.5 → 0.0.6
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.mjs +964 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2555,6 +2555,957 @@ function registerEmailTemplateTools(server, api) {
|
|
|
2555
2555
|
);
|
|
2556
2556
|
}
|
|
2557
2557
|
|
|
2558
|
+
// libs/mcp-server/src/tools/cronJobs.ts
|
|
2559
|
+
import { z as z9 } from "zod";
|
|
2560
|
+
function registerCronJobTools(server, api) {
|
|
2561
|
+
server.registerTool(
|
|
2562
|
+
"cron_jobs_list",
|
|
2563
|
+
{
|
|
2564
|
+
description: "List all cron jobs for a project",
|
|
2565
|
+
inputSchema: {
|
|
2566
|
+
projectId: z9.string()
|
|
2567
|
+
}
|
|
2568
|
+
},
|
|
2569
|
+
async ({ projectId }) => {
|
|
2570
|
+
try {
|
|
2571
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/cron-jobs`);
|
|
2572
|
+
return {
|
|
2573
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2574
|
+
};
|
|
2575
|
+
} catch (error) {
|
|
2576
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2577
|
+
return {
|
|
2578
|
+
content: [{ type: "text", text: `Failed to list cron jobs: ${message}` }],
|
|
2579
|
+
isError: true
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
);
|
|
2584
|
+
server.registerTool(
|
|
2585
|
+
"cron_jobs_get",
|
|
2586
|
+
{
|
|
2587
|
+
description: "Get a single cron job by ID",
|
|
2588
|
+
inputSchema: {
|
|
2589
|
+
projectId: z9.string(),
|
|
2590
|
+
jobId: z9.string()
|
|
2591
|
+
}
|
|
2592
|
+
},
|
|
2593
|
+
async ({ projectId, jobId }) => {
|
|
2594
|
+
try {
|
|
2595
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/cron-jobs/${encodeURIComponent(jobId)}`);
|
|
2596
|
+
return {
|
|
2597
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2598
|
+
};
|
|
2599
|
+
} catch (error) {
|
|
2600
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2601
|
+
return {
|
|
2602
|
+
content: [{ type: "text", text: `Failed to get cron job: ${message}` }],
|
|
2603
|
+
isError: true
|
|
2604
|
+
};
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
);
|
|
2608
|
+
server.registerTool(
|
|
2609
|
+
"cron_jobs_create",
|
|
2610
|
+
{
|
|
2611
|
+
description: 'Create a new cron job. When type is "webhook", url is required. When type is "function", functionId is required. cronExpression uses 5-field cron format (e.g. "0 0 * * *").',
|
|
2612
|
+
inputSchema: {
|
|
2613
|
+
projectId: z9.string(),
|
|
2614
|
+
name: z9.string(),
|
|
2615
|
+
cronExpression: z9.string().regex(/^(\S+\s){4}\S+$/),
|
|
2616
|
+
timezone: z9.string().optional(),
|
|
2617
|
+
type: z9.enum(["webhook", "function"]).optional(),
|
|
2618
|
+
functionId: z9.string().optional(),
|
|
2619
|
+
url: z9.string().url().optional(),
|
|
2620
|
+
secret: z9.string().optional(),
|
|
2621
|
+
payload: z9.record(z9.string(), z9.unknown()).optional(),
|
|
2622
|
+
retryAttempts: z9.number().int().min(0).max(10).optional(),
|
|
2623
|
+
timeout: z9.number().int().min(1e3).max(12e4).optional(),
|
|
2624
|
+
enabled: z9.boolean().optional()
|
|
2625
|
+
}
|
|
2626
|
+
},
|
|
2627
|
+
async ({ projectId, name, cronExpression, timezone, type, functionId, url, secret, payload, retryAttempts, timeout, enabled }) => {
|
|
2628
|
+
try {
|
|
2629
|
+
const body = { name, cronExpression };
|
|
2630
|
+
if (timezone !== void 0) body.timezone = timezone;
|
|
2631
|
+
if (type !== void 0) body.type = type;
|
|
2632
|
+
if (functionId !== void 0) body.functionId = functionId;
|
|
2633
|
+
if (url !== void 0) body.url = url;
|
|
2634
|
+
if (secret !== void 0) body.secret = secret;
|
|
2635
|
+
if (payload !== void 0) body.payload = payload;
|
|
2636
|
+
if (retryAttempts !== void 0) body.retryAttempts = retryAttempts;
|
|
2637
|
+
if (timeout !== void 0) body.timeout = timeout;
|
|
2638
|
+
if (enabled !== void 0) body.enabled = enabled;
|
|
2639
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/cron-jobs`, { body });
|
|
2640
|
+
return {
|
|
2641
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2642
|
+
};
|
|
2643
|
+
} catch (error) {
|
|
2644
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2645
|
+
return {
|
|
2646
|
+
content: [{ type: "text", text: `Failed to create cron job: ${message}` }],
|
|
2647
|
+
isError: true
|
|
2648
|
+
};
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
);
|
|
2652
|
+
server.registerTool(
|
|
2653
|
+
"cron_jobs_update",
|
|
2654
|
+
{
|
|
2655
|
+
description: "Update an existing cron job",
|
|
2656
|
+
inputSchema: {
|
|
2657
|
+
projectId: z9.string(),
|
|
2658
|
+
jobId: z9.string(),
|
|
2659
|
+
name: z9.string().optional(),
|
|
2660
|
+
cronExpression: z9.string().regex(/^(\S+\s){4}\S+$/).optional(),
|
|
2661
|
+
timezone: z9.string().optional(),
|
|
2662
|
+
type: z9.enum(["webhook", "function"]).optional(),
|
|
2663
|
+
functionId: z9.string().optional(),
|
|
2664
|
+
url: z9.string().url().optional(),
|
|
2665
|
+
secret: z9.string().optional(),
|
|
2666
|
+
payload: z9.record(z9.string(), z9.unknown()).optional(),
|
|
2667
|
+
retryAttempts: z9.number().int().min(0).max(10).optional(),
|
|
2668
|
+
timeout: z9.number().int().min(1e3).max(12e4).optional(),
|
|
2669
|
+
enabled: z9.boolean().optional()
|
|
2670
|
+
}
|
|
2671
|
+
},
|
|
2672
|
+
async ({ projectId, jobId, name, cronExpression, timezone, type, functionId, url, secret, payload, retryAttempts, timeout, enabled }) => {
|
|
2673
|
+
try {
|
|
2674
|
+
const body = {};
|
|
2675
|
+
if (name !== void 0) body.name = name;
|
|
2676
|
+
if (cronExpression !== void 0) body.cronExpression = cronExpression;
|
|
2677
|
+
if (timezone !== void 0) body.timezone = timezone;
|
|
2678
|
+
if (type !== void 0) body.type = type;
|
|
2679
|
+
if (functionId !== void 0) body.functionId = functionId;
|
|
2680
|
+
if (url !== void 0) body.url = url;
|
|
2681
|
+
if (secret !== void 0) body.secret = secret;
|
|
2682
|
+
if (payload !== void 0) body.payload = payload;
|
|
2683
|
+
if (retryAttempts !== void 0) body.retryAttempts = retryAttempts;
|
|
2684
|
+
if (timeout !== void 0) body.timeout = timeout;
|
|
2685
|
+
if (enabled !== void 0) body.enabled = enabled;
|
|
2686
|
+
if (Object.keys(body).length === 0) {
|
|
2687
|
+
return {
|
|
2688
|
+
content: [{ type: "text", text: "At least one field must be provided" }],
|
|
2689
|
+
isError: true
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
const result = await api.patch(`/projects/${encodeURIComponent(projectId)}/cron-jobs/${encodeURIComponent(jobId)}`, { body });
|
|
2693
|
+
return {
|
|
2694
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2695
|
+
};
|
|
2696
|
+
} catch (error) {
|
|
2697
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2698
|
+
return {
|
|
2699
|
+
content: [{ type: "text", text: `Failed to update cron job: ${message}` }],
|
|
2700
|
+
isError: true
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
);
|
|
2705
|
+
server.registerTool(
|
|
2706
|
+
"cron_jobs_delete",
|
|
2707
|
+
{
|
|
2708
|
+
description: "Delete a cron job",
|
|
2709
|
+
inputSchema: {
|
|
2710
|
+
projectId: z9.string(),
|
|
2711
|
+
jobId: z9.string()
|
|
2712
|
+
}
|
|
2713
|
+
},
|
|
2714
|
+
async ({ projectId, jobId }) => {
|
|
2715
|
+
try {
|
|
2716
|
+
const result = await api.delete(`/projects/${encodeURIComponent(projectId)}/cron-jobs/${encodeURIComponent(jobId)}`);
|
|
2717
|
+
return {
|
|
2718
|
+
content: [{ type: "text", text: result ? JSON.stringify(result, null, 2) : "Cron job deleted" }]
|
|
2719
|
+
};
|
|
2720
|
+
} catch (error) {
|
|
2721
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2722
|
+
return {
|
|
2723
|
+
content: [{ type: "text", text: `Failed to delete cron job: ${message}` }],
|
|
2724
|
+
isError: true
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
);
|
|
2729
|
+
server.registerTool(
|
|
2730
|
+
"cron_jobs_trigger",
|
|
2731
|
+
{
|
|
2732
|
+
description: "Manually trigger a cron job execution",
|
|
2733
|
+
inputSchema: {
|
|
2734
|
+
projectId: z9.string(),
|
|
2735
|
+
jobId: z9.string()
|
|
2736
|
+
}
|
|
2737
|
+
},
|
|
2738
|
+
async ({ projectId, jobId }) => {
|
|
2739
|
+
try {
|
|
2740
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/cron-jobs/${encodeURIComponent(jobId)}/trigger`);
|
|
2741
|
+
return {
|
|
2742
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2743
|
+
};
|
|
2744
|
+
} catch (error) {
|
|
2745
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2746
|
+
return {
|
|
2747
|
+
content: [{ type: "text", text: `Failed to trigger cron job: ${message}` }],
|
|
2748
|
+
isError: true
|
|
2749
|
+
};
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
);
|
|
2753
|
+
server.registerTool(
|
|
2754
|
+
"cron_jobs_toggle",
|
|
2755
|
+
{
|
|
2756
|
+
description: "Toggle a cron job enabled/disabled",
|
|
2757
|
+
inputSchema: {
|
|
2758
|
+
projectId: z9.string(),
|
|
2759
|
+
jobId: z9.string(),
|
|
2760
|
+
enabled: z9.boolean()
|
|
2761
|
+
}
|
|
2762
|
+
},
|
|
2763
|
+
async ({ projectId, jobId, enabled }) => {
|
|
2764
|
+
try {
|
|
2765
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/cron-jobs/${encodeURIComponent(jobId)}/toggle`, { body: { enabled } });
|
|
2766
|
+
return {
|
|
2767
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2768
|
+
};
|
|
2769
|
+
} catch (error) {
|
|
2770
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2771
|
+
return {
|
|
2772
|
+
content: [{ type: "text", text: `Failed to toggle cron job: ${message}` }],
|
|
2773
|
+
isError: true
|
|
2774
|
+
};
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
);
|
|
2778
|
+
server.registerTool(
|
|
2779
|
+
"cron_jobs_executions",
|
|
2780
|
+
{
|
|
2781
|
+
description: "List execution history for a cron job",
|
|
2782
|
+
inputSchema: {
|
|
2783
|
+
projectId: z9.string(),
|
|
2784
|
+
jobId: z9.string(),
|
|
2785
|
+
limit: z9.number().int().min(1).max(100).optional(),
|
|
2786
|
+
offset: z9.number().int().min(0).optional()
|
|
2787
|
+
}
|
|
2788
|
+
},
|
|
2789
|
+
async ({ projectId, jobId, limit, offset }) => {
|
|
2790
|
+
try {
|
|
2791
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/cron-jobs/${encodeURIComponent(jobId)}/executions`, { params: { limit, offset } });
|
|
2792
|
+
return {
|
|
2793
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2794
|
+
};
|
|
2795
|
+
} catch (error) {
|
|
2796
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2797
|
+
return {
|
|
2798
|
+
content: [{ type: "text", text: `Failed to list cron job executions: ${message}` }],
|
|
2799
|
+
isError: true
|
|
2800
|
+
};
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
);
|
|
2804
|
+
server.registerTool(
|
|
2805
|
+
"cron_jobs_list_all",
|
|
2806
|
+
{
|
|
2807
|
+
description: "List all cron jobs across projects (admin overview)",
|
|
2808
|
+
inputSchema: {
|
|
2809
|
+
projectId: z9.string().optional()
|
|
2810
|
+
}
|
|
2811
|
+
},
|
|
2812
|
+
async ({ projectId }) => {
|
|
2813
|
+
try {
|
|
2814
|
+
const result = await api.get("/cron/jobs", { params: { projectId } });
|
|
2815
|
+
return {
|
|
2816
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2817
|
+
};
|
|
2818
|
+
} catch (error) {
|
|
2819
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2820
|
+
return {
|
|
2821
|
+
content: [{ type: "text", text: `Failed to list all cron jobs: ${message}` }],
|
|
2822
|
+
isError: true
|
|
2823
|
+
};
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
);
|
|
2827
|
+
server.registerTool(
|
|
2828
|
+
"cron_jobs_status",
|
|
2829
|
+
{
|
|
2830
|
+
description: "Get cron queue status",
|
|
2831
|
+
inputSchema: {}
|
|
2832
|
+
},
|
|
2833
|
+
async () => {
|
|
2834
|
+
try {
|
|
2835
|
+
const result = await api.get("/cron/status");
|
|
2836
|
+
return {
|
|
2837
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2838
|
+
};
|
|
2839
|
+
} catch (error) {
|
|
2840
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2841
|
+
return {
|
|
2842
|
+
content: [{ type: "text", text: `Failed to get cron status: ${message}` }],
|
|
2843
|
+
isError: true
|
|
2844
|
+
};
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
);
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
// libs/mcp-server/src/tools/webhooks.ts
|
|
2851
|
+
import { z as z10 } from "zod";
|
|
2852
|
+
var WEBHOOK_EVENT_TYPES = [
|
|
2853
|
+
"user.created",
|
|
2854
|
+
"user.updated",
|
|
2855
|
+
"user.deleted",
|
|
2856
|
+
"user.login",
|
|
2857
|
+
"user.email_verified",
|
|
2858
|
+
"user.password_reset_requested",
|
|
2859
|
+
"user.password_reset",
|
|
2860
|
+
"user.2fa_verified",
|
|
2861
|
+
"database.insert",
|
|
2862
|
+
"database.update",
|
|
2863
|
+
"database.delete",
|
|
2864
|
+
"storage.upload",
|
|
2865
|
+
"storage.delete",
|
|
2866
|
+
"project.created",
|
|
2867
|
+
"project.updated"
|
|
2868
|
+
];
|
|
2869
|
+
function registerWebhookTools(server, api) {
|
|
2870
|
+
server.registerTool(
|
|
2871
|
+
"webhooks_list",
|
|
2872
|
+
{
|
|
2873
|
+
description: "List all webhooks for a project",
|
|
2874
|
+
inputSchema: {
|
|
2875
|
+
projectId: z10.string()
|
|
2876
|
+
}
|
|
2877
|
+
},
|
|
2878
|
+
async ({ projectId }) => {
|
|
2879
|
+
try {
|
|
2880
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/webhooks`);
|
|
2881
|
+
return {
|
|
2882
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2883
|
+
};
|
|
2884
|
+
} catch (error) {
|
|
2885
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2886
|
+
return {
|
|
2887
|
+
content: [{ type: "text", text: `Failed to list webhooks: ${message}` }],
|
|
2888
|
+
isError: true
|
|
2889
|
+
};
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
);
|
|
2893
|
+
server.registerTool(
|
|
2894
|
+
"webhooks_get",
|
|
2895
|
+
{
|
|
2896
|
+
description: "Get a single webhook by ID",
|
|
2897
|
+
inputSchema: {
|
|
2898
|
+
projectId: z10.string(),
|
|
2899
|
+
webhookId: z10.string()
|
|
2900
|
+
}
|
|
2901
|
+
},
|
|
2902
|
+
async ({ projectId, webhookId }) => {
|
|
2903
|
+
try {
|
|
2904
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/webhooks/${encodeURIComponent(webhookId)}`);
|
|
2905
|
+
return {
|
|
2906
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2907
|
+
};
|
|
2908
|
+
} catch (error) {
|
|
2909
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2910
|
+
return {
|
|
2911
|
+
content: [{ type: "text", text: `Failed to get webhook: ${message}` }],
|
|
2912
|
+
isError: true
|
|
2913
|
+
};
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
);
|
|
2917
|
+
server.registerTool(
|
|
2918
|
+
"webhooks_create",
|
|
2919
|
+
{
|
|
2920
|
+
description: "Create a new webhook for a project. WARNING: The response includes a secret that will be visible in the conversation context. Events include: user.created, user.updated, user.deleted, user.login, user.email_verified, user.password_reset_requested, user.password_reset, user.2fa_verified, database.insert, database.update, database.delete, storage.upload, storage.delete, project.created, project.updated.",
|
|
2921
|
+
inputSchema: {
|
|
2922
|
+
projectId: z10.string(),
|
|
2923
|
+
url: z10.string().url(),
|
|
2924
|
+
events: z10.array(z10.enum(WEBHOOK_EVENT_TYPES)).min(1),
|
|
2925
|
+
description: z10.string().optional(),
|
|
2926
|
+
headers: z10.record(z10.string(), z10.string()).optional(),
|
|
2927
|
+
active: z10.boolean().optional()
|
|
2928
|
+
}
|
|
2929
|
+
},
|
|
2930
|
+
async ({ projectId, url, events, description, headers, active }) => {
|
|
2931
|
+
try {
|
|
2932
|
+
const body = { url, events };
|
|
2933
|
+
if (description !== void 0) body.description = description;
|
|
2934
|
+
if (headers !== void 0) body.headers = headers;
|
|
2935
|
+
if (active !== void 0) body.active = active;
|
|
2936
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/webhooks`, { body });
|
|
2937
|
+
return {
|
|
2938
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2939
|
+
};
|
|
2940
|
+
} catch (error) {
|
|
2941
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2942
|
+
return {
|
|
2943
|
+
content: [{ type: "text", text: `Failed to create webhook: ${message}` }],
|
|
2944
|
+
isError: true
|
|
2945
|
+
};
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
);
|
|
2949
|
+
server.registerTool(
|
|
2950
|
+
"webhooks_update",
|
|
2951
|
+
{
|
|
2952
|
+
description: "Update an existing webhook",
|
|
2953
|
+
inputSchema: {
|
|
2954
|
+
projectId: z10.string(),
|
|
2955
|
+
webhookId: z10.string(),
|
|
2956
|
+
url: z10.string().url().optional(),
|
|
2957
|
+
events: z10.array(z10.enum(WEBHOOK_EVENT_TYPES)).min(1).optional(),
|
|
2958
|
+
description: z10.string().optional(),
|
|
2959
|
+
headers: z10.record(z10.string(), z10.string()).optional(),
|
|
2960
|
+
active: z10.boolean().optional()
|
|
2961
|
+
}
|
|
2962
|
+
},
|
|
2963
|
+
async ({ projectId, webhookId, url, events, description, headers, active }) => {
|
|
2964
|
+
try {
|
|
2965
|
+
const body = {};
|
|
2966
|
+
if (url !== void 0) body.url = url;
|
|
2967
|
+
if (events !== void 0) body.events = events;
|
|
2968
|
+
if (description !== void 0) body.description = description;
|
|
2969
|
+
if (headers !== void 0) body.headers = headers;
|
|
2970
|
+
if (active !== void 0) body.active = active;
|
|
2971
|
+
if (Object.keys(body).length === 0) {
|
|
2972
|
+
return {
|
|
2973
|
+
content: [{ type: "text", text: "At least one field must be provided" }],
|
|
2974
|
+
isError: true
|
|
2975
|
+
};
|
|
2976
|
+
}
|
|
2977
|
+
const result = await api.patch(`/projects/${encodeURIComponent(projectId)}/webhooks/${encodeURIComponent(webhookId)}`, { body });
|
|
2978
|
+
return {
|
|
2979
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
2980
|
+
};
|
|
2981
|
+
} catch (error) {
|
|
2982
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2983
|
+
return {
|
|
2984
|
+
content: [{ type: "text", text: `Failed to update webhook: ${message}` }],
|
|
2985
|
+
isError: true
|
|
2986
|
+
};
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
);
|
|
2990
|
+
server.registerTool(
|
|
2991
|
+
"webhooks_delete",
|
|
2992
|
+
{
|
|
2993
|
+
description: "Delete a webhook",
|
|
2994
|
+
inputSchema: {
|
|
2995
|
+
projectId: z10.string(),
|
|
2996
|
+
webhookId: z10.string()
|
|
2997
|
+
}
|
|
2998
|
+
},
|
|
2999
|
+
async ({ projectId, webhookId }) => {
|
|
3000
|
+
try {
|
|
3001
|
+
const result = await api.delete(`/projects/${encodeURIComponent(projectId)}/webhooks/${encodeURIComponent(webhookId)}`);
|
|
3002
|
+
return {
|
|
3003
|
+
content: [{ type: "text", text: result ? JSON.stringify(result, null, 2) : "Webhook deleted" }]
|
|
3004
|
+
};
|
|
3005
|
+
} catch (error) {
|
|
3006
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3007
|
+
return {
|
|
3008
|
+
content: [{ type: "text", text: `Failed to delete webhook: ${message}` }],
|
|
3009
|
+
isError: true
|
|
3010
|
+
};
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
);
|
|
3014
|
+
server.registerTool(
|
|
3015
|
+
"webhooks_test",
|
|
3016
|
+
{
|
|
3017
|
+
description: "Send a test ping to a webhook",
|
|
3018
|
+
inputSchema: {
|
|
3019
|
+
projectId: z10.string(),
|
|
3020
|
+
webhookId: z10.string()
|
|
3021
|
+
}
|
|
3022
|
+
},
|
|
3023
|
+
async ({ projectId, webhookId }) => {
|
|
3024
|
+
try {
|
|
3025
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/webhooks/${encodeURIComponent(webhookId)}/test`);
|
|
3026
|
+
return {
|
|
3027
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3028
|
+
};
|
|
3029
|
+
} catch (error) {
|
|
3030
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3031
|
+
return {
|
|
3032
|
+
content: [{ type: "text", text: `Failed to test webhook: ${message}` }],
|
|
3033
|
+
isError: true
|
|
3034
|
+
};
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
);
|
|
3038
|
+
server.registerTool(
|
|
3039
|
+
"webhooks_deliveries",
|
|
3040
|
+
{
|
|
3041
|
+
description: "List webhook delivery logs for a project",
|
|
3042
|
+
inputSchema: {
|
|
3043
|
+
projectId: z10.string(),
|
|
3044
|
+
webhookId: z10.string().optional(),
|
|
3045
|
+
limit: z10.number().int().min(1).max(100).optional(),
|
|
3046
|
+
offset: z10.number().int().min(0).optional()
|
|
3047
|
+
}
|
|
3048
|
+
},
|
|
3049
|
+
async ({ projectId, webhookId, limit, offset }) => {
|
|
3050
|
+
try {
|
|
3051
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/webhook-deliveries`, { params: { webhookId, limit, offset } });
|
|
3052
|
+
return {
|
|
3053
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3054
|
+
};
|
|
3055
|
+
} catch (error) {
|
|
3056
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3057
|
+
return {
|
|
3058
|
+
content: [{ type: "text", text: `Failed to list webhook deliveries: ${message}` }],
|
|
3059
|
+
isError: true
|
|
3060
|
+
};
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
);
|
|
3064
|
+
server.registerTool(
|
|
3065
|
+
"webhooks_delivery_retry",
|
|
3066
|
+
{
|
|
3067
|
+
description: "Retry a failed webhook delivery",
|
|
3068
|
+
inputSchema: {
|
|
3069
|
+
projectId: z10.string(),
|
|
3070
|
+
deliveryId: z10.string()
|
|
3071
|
+
}
|
|
3072
|
+
},
|
|
3073
|
+
async ({ projectId, deliveryId }) => {
|
|
3074
|
+
try {
|
|
3075
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/webhook-deliveries/${encodeURIComponent(deliveryId)}/retry`);
|
|
3076
|
+
return {
|
|
3077
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3078
|
+
};
|
|
3079
|
+
} catch (error) {
|
|
3080
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3081
|
+
return {
|
|
3082
|
+
content: [{ type: "text", text: `Failed to retry webhook delivery: ${message}` }],
|
|
3083
|
+
isError: true
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
);
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
// libs/mcp-server/src/tools/notifications.ts
|
|
3091
|
+
import { z as z11 } from "zod";
|
|
3092
|
+
function registerNotificationTools(server, api) {
|
|
3093
|
+
server.registerTool(
|
|
3094
|
+
"notification_templates_list",
|
|
3095
|
+
{
|
|
3096
|
+
description: "List all notification templates for a project (includes system defaults)",
|
|
3097
|
+
inputSchema: {
|
|
3098
|
+
projectId: z11.string()
|
|
3099
|
+
}
|
|
3100
|
+
},
|
|
3101
|
+
async ({ projectId }) => {
|
|
3102
|
+
try {
|
|
3103
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/notification-templates`);
|
|
3104
|
+
return {
|
|
3105
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3106
|
+
};
|
|
3107
|
+
} catch (error) {
|
|
3108
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3109
|
+
return {
|
|
3110
|
+
content: [{ type: "text", text: `Failed to list notification templates: ${message}` }],
|
|
3111
|
+
isError: true
|
|
3112
|
+
};
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
);
|
|
3116
|
+
server.registerTool(
|
|
3117
|
+
"notification_templates_get",
|
|
3118
|
+
{
|
|
3119
|
+
description: "Get a single notification template by ID",
|
|
3120
|
+
inputSchema: {
|
|
3121
|
+
id: z11.string()
|
|
3122
|
+
}
|
|
3123
|
+
},
|
|
3124
|
+
async ({ id }) => {
|
|
3125
|
+
try {
|
|
3126
|
+
const result = await api.get(`/notification-templates/${encodeURIComponent(id)}`);
|
|
3127
|
+
return {
|
|
3128
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3129
|
+
};
|
|
3130
|
+
} catch (error) {
|
|
3131
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3132
|
+
return {
|
|
3133
|
+
content: [{ type: "text", text: `Failed to get notification template: ${message}` }],
|
|
3134
|
+
isError: true
|
|
3135
|
+
};
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
);
|
|
3139
|
+
server.registerTool(
|
|
3140
|
+
"notification_templates_create",
|
|
3141
|
+
{
|
|
3142
|
+
description: "Create a new project-specific notification template. Variables use Handlebars syntax in titleTemplate and bodyTemplate.",
|
|
3143
|
+
inputSchema: {
|
|
3144
|
+
projectId: z11.string(),
|
|
3145
|
+
type: z11.string(),
|
|
3146
|
+
name: z11.string(),
|
|
3147
|
+
titleTemplate: z11.string(),
|
|
3148
|
+
bodyTemplate: z11.string(),
|
|
3149
|
+
icon: z11.string().optional(),
|
|
3150
|
+
defaultUrl: z11.string().optional(),
|
|
3151
|
+
variables: z11.array(z11.string()).optional(),
|
|
3152
|
+
isActive: z11.boolean().optional()
|
|
3153
|
+
}
|
|
3154
|
+
},
|
|
3155
|
+
async ({ projectId, type, name, titleTemplate, bodyTemplate, icon, defaultUrl, variables, isActive }) => {
|
|
3156
|
+
try {
|
|
3157
|
+
const body = { projectId, type, name, titleTemplate, bodyTemplate };
|
|
3158
|
+
if (icon !== void 0) body.icon = icon;
|
|
3159
|
+
if (defaultUrl !== void 0) body.defaultUrl = defaultUrl;
|
|
3160
|
+
if (variables !== void 0) body.variables = variables;
|
|
3161
|
+
if (isActive !== void 0) body.isActive = isActive;
|
|
3162
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/notification-templates`, { body });
|
|
3163
|
+
return {
|
|
3164
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3165
|
+
};
|
|
3166
|
+
} catch (error) {
|
|
3167
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3168
|
+
return {
|
|
3169
|
+
content: [{ type: "text", text: `Failed to create notification template: ${message}` }],
|
|
3170
|
+
isError: true
|
|
3171
|
+
};
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
);
|
|
3175
|
+
server.registerTool(
|
|
3176
|
+
"notification_templates_update",
|
|
3177
|
+
{
|
|
3178
|
+
description: "Update an existing notification template",
|
|
3179
|
+
inputSchema: {
|
|
3180
|
+
id: z11.string(),
|
|
3181
|
+
name: z11.string().optional(),
|
|
3182
|
+
titleTemplate: z11.string().optional(),
|
|
3183
|
+
bodyTemplate: z11.string().optional(),
|
|
3184
|
+
icon: z11.string().optional(),
|
|
3185
|
+
defaultUrl: z11.string().optional(),
|
|
3186
|
+
variables: z11.array(z11.string()).optional(),
|
|
3187
|
+
isActive: z11.boolean().optional()
|
|
3188
|
+
}
|
|
3189
|
+
},
|
|
3190
|
+
async ({ id, name, titleTemplate, bodyTemplate, icon, defaultUrl, variables, isActive }) => {
|
|
3191
|
+
try {
|
|
3192
|
+
const body = {};
|
|
3193
|
+
if (name !== void 0) body.name = name;
|
|
3194
|
+
if (titleTemplate !== void 0) body.titleTemplate = titleTemplate;
|
|
3195
|
+
if (bodyTemplate !== void 0) body.bodyTemplate = bodyTemplate;
|
|
3196
|
+
if (icon !== void 0) body.icon = icon;
|
|
3197
|
+
if (defaultUrl !== void 0) body.defaultUrl = defaultUrl;
|
|
3198
|
+
if (variables !== void 0) body.variables = variables;
|
|
3199
|
+
if (isActive !== void 0) body.isActive = isActive;
|
|
3200
|
+
if (Object.keys(body).length === 0) {
|
|
3201
|
+
return {
|
|
3202
|
+
content: [{ type: "text", text: "At least one field must be provided" }],
|
|
3203
|
+
isError: true
|
|
3204
|
+
};
|
|
3205
|
+
}
|
|
3206
|
+
const result = await api.patch(`/notification-templates/${encodeURIComponent(id)}`, { body });
|
|
3207
|
+
return {
|
|
3208
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3209
|
+
};
|
|
3210
|
+
} catch (error) {
|
|
3211
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3212
|
+
return {
|
|
3213
|
+
content: [{ type: "text", text: `Failed to update notification template: ${message}` }],
|
|
3214
|
+
isError: true
|
|
3215
|
+
};
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
);
|
|
3219
|
+
server.registerTool(
|
|
3220
|
+
"notification_templates_delete",
|
|
3221
|
+
{
|
|
3222
|
+
description: "Delete a project notification template override (reverts to system default)",
|
|
3223
|
+
inputSchema: {
|
|
3224
|
+
id: z11.string()
|
|
3225
|
+
}
|
|
3226
|
+
},
|
|
3227
|
+
async ({ id }) => {
|
|
3228
|
+
try {
|
|
3229
|
+
const result = await api.delete(`/notification-templates/${encodeURIComponent(id)}`);
|
|
3230
|
+
return {
|
|
3231
|
+
content: [{ type: "text", text: result ? JSON.stringify(result, null, 2) : "Notification template deleted" }]
|
|
3232
|
+
};
|
|
3233
|
+
} catch (error) {
|
|
3234
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3235
|
+
return {
|
|
3236
|
+
content: [{ type: "text", text: `Failed to delete notification template: ${message}` }],
|
|
3237
|
+
isError: true
|
|
3238
|
+
};
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
);
|
|
3242
|
+
server.registerTool(
|
|
3243
|
+
"notification_templates_preview",
|
|
3244
|
+
{
|
|
3245
|
+
description: "Preview a compiled notification template with Handlebars variables applied",
|
|
3246
|
+
inputSchema: {
|
|
3247
|
+
titleTemplate: z11.string(),
|
|
3248
|
+
bodyTemplate: z11.string(),
|
|
3249
|
+
variables: z11.record(z11.string(), z11.string())
|
|
3250
|
+
}
|
|
3251
|
+
},
|
|
3252
|
+
async ({ titleTemplate, bodyTemplate, variables }) => {
|
|
3253
|
+
try {
|
|
3254
|
+
const result = await api.post("/notification-templates/preview", { body: { titleTemplate, bodyTemplate, variables } });
|
|
3255
|
+
return {
|
|
3256
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3257
|
+
};
|
|
3258
|
+
} catch (error) {
|
|
3259
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3260
|
+
return {
|
|
3261
|
+
content: [{ type: "text", text: `Failed to preview notification template: ${message}` }],
|
|
3262
|
+
isError: true
|
|
3263
|
+
};
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
);
|
|
3267
|
+
server.registerTool(
|
|
3268
|
+
"notification_config_get",
|
|
3269
|
+
{
|
|
3270
|
+
description: "Get push notification provider configuration for a project (VAPID, FCM, APNS). WARNING: Response may include sensitive credentials that will be visible in the conversation context.",
|
|
3271
|
+
inputSchema: {
|
|
3272
|
+
projectId: z11.string()
|
|
3273
|
+
}
|
|
3274
|
+
},
|
|
3275
|
+
async ({ projectId }) => {
|
|
3276
|
+
try {
|
|
3277
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/notification-config`);
|
|
3278
|
+
return {
|
|
3279
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3280
|
+
};
|
|
3281
|
+
} catch (error) {
|
|
3282
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3283
|
+
return {
|
|
3284
|
+
content: [{ type: "text", text: `Failed to get notification config: ${message}` }],
|
|
3285
|
+
isError: true
|
|
3286
|
+
};
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
);
|
|
3290
|
+
server.registerTool(
|
|
3291
|
+
"notification_config_update",
|
|
3292
|
+
{
|
|
3293
|
+
description: "Update push notification provider configuration. Supports VAPID, FCM, and APNS providers. WARNING: privateKey and serviceAccountJson values are sensitive credentials that will be visible in the conversation context.",
|
|
3294
|
+
inputSchema: {
|
|
3295
|
+
projectId: z11.string(),
|
|
3296
|
+
vapid: z11.object({
|
|
3297
|
+
publicKey: z11.string().optional(),
|
|
3298
|
+
privateKey: z11.string().optional(),
|
|
3299
|
+
subject: z11.string().optional(),
|
|
3300
|
+
enabled: z11.boolean().optional()
|
|
3301
|
+
}).optional(),
|
|
3302
|
+
fcm: z11.object({
|
|
3303
|
+
serviceAccountJson: z11.string().optional(),
|
|
3304
|
+
enabled: z11.boolean().optional()
|
|
3305
|
+
}).optional(),
|
|
3306
|
+
apns: z11.object({
|
|
3307
|
+
keyId: z11.string().optional(),
|
|
3308
|
+
teamId: z11.string().optional(),
|
|
3309
|
+
privateKey: z11.string().optional(),
|
|
3310
|
+
bundleId: z11.string().optional(),
|
|
3311
|
+
production: z11.boolean().optional(),
|
|
3312
|
+
enabled: z11.boolean().optional()
|
|
3313
|
+
}).optional()
|
|
3314
|
+
}
|
|
3315
|
+
},
|
|
3316
|
+
async ({ projectId, vapid, fcm, apns }) => {
|
|
3317
|
+
try {
|
|
3318
|
+
const body = {};
|
|
3319
|
+
if (vapid !== void 0) body.vapid = vapid;
|
|
3320
|
+
if (fcm !== void 0) body.fcm = fcm;
|
|
3321
|
+
if (apns !== void 0) body.apns = apns;
|
|
3322
|
+
if (Object.keys(body).length === 0) {
|
|
3323
|
+
return {
|
|
3324
|
+
content: [{ type: "text", text: "At least one provider config must be provided" }],
|
|
3325
|
+
isError: true
|
|
3326
|
+
};
|
|
3327
|
+
}
|
|
3328
|
+
const result = await api.patch(`/projects/${encodeURIComponent(projectId)}/notification-config`, { body });
|
|
3329
|
+
return {
|
|
3330
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3331
|
+
};
|
|
3332
|
+
} catch (error) {
|
|
3333
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3334
|
+
return {
|
|
3335
|
+
content: [{ type: "text", text: `Failed to update notification config: ${message}` }],
|
|
3336
|
+
isError: true
|
|
3337
|
+
};
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
);
|
|
3341
|
+
server.registerTool(
|
|
3342
|
+
"notification_config_delete",
|
|
3343
|
+
{
|
|
3344
|
+
description: "Delete push notification provider configuration. Specify a provider to delete only that one, or omit to delete all.",
|
|
3345
|
+
inputSchema: {
|
|
3346
|
+
projectId: z11.string(),
|
|
3347
|
+
provider: z11.enum(["vapid", "fcm", "apns"]).optional()
|
|
3348
|
+
}
|
|
3349
|
+
},
|
|
3350
|
+
async ({ projectId, provider }) => {
|
|
3351
|
+
try {
|
|
3352
|
+
const result = await api.delete(`/projects/${encodeURIComponent(projectId)}/notification-config`, { params: { provider } });
|
|
3353
|
+
return {
|
|
3354
|
+
content: [{ type: "text", text: result ? JSON.stringify(result, null, 2) : "Notification config deleted" }]
|
|
3355
|
+
};
|
|
3356
|
+
} catch (error) {
|
|
3357
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3358
|
+
return {
|
|
3359
|
+
content: [{ type: "text", text: `Failed to delete notification config: ${message}` }],
|
|
3360
|
+
isError: true
|
|
3361
|
+
};
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
);
|
|
3365
|
+
server.registerTool(
|
|
3366
|
+
"notification_config_generate_vapid",
|
|
3367
|
+
{
|
|
3368
|
+
description: "Generate a new VAPID key pair for web push notifications. WARNING: The private key will be visible in the conversation context.",
|
|
3369
|
+
inputSchema: {}
|
|
3370
|
+
},
|
|
3371
|
+
async () => {
|
|
3372
|
+
try {
|
|
3373
|
+
const result = await api.post("/notification-config/generate-vapid-keys");
|
|
3374
|
+
return {
|
|
3375
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3376
|
+
};
|
|
3377
|
+
} catch (error) {
|
|
3378
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3379
|
+
return {
|
|
3380
|
+
content: [{ type: "text", text: `Failed to generate VAPID keys: ${message}` }],
|
|
3381
|
+
isError: true
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
);
|
|
3386
|
+
server.registerTool(
|
|
3387
|
+
"notifications_send",
|
|
3388
|
+
{
|
|
3389
|
+
description: "Send a push notification to selected users",
|
|
3390
|
+
inputSchema: {
|
|
3391
|
+
projectId: z11.string(),
|
|
3392
|
+
userIds: z11.array(z11.string()).min(1),
|
|
3393
|
+
title: z11.string(),
|
|
3394
|
+
body: z11.string(),
|
|
3395
|
+
icon: z11.string().optional(),
|
|
3396
|
+
url: z11.string().optional()
|
|
3397
|
+
}
|
|
3398
|
+
},
|
|
3399
|
+
async ({ projectId, userIds, title, body: notifBody, icon, url }) => {
|
|
3400
|
+
try {
|
|
3401
|
+
const reqBody = { userIds, title, body: notifBody };
|
|
3402
|
+
if (icon !== void 0) reqBody.icon = icon;
|
|
3403
|
+
if (url !== void 0) reqBody.url = url;
|
|
3404
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/notifications/send`, { body: reqBody });
|
|
3405
|
+
return {
|
|
3406
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3407
|
+
};
|
|
3408
|
+
} catch (error) {
|
|
3409
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3410
|
+
return {
|
|
3411
|
+
content: [{ type: "text", text: `Failed to send notification: ${message}` }],
|
|
3412
|
+
isError: true
|
|
3413
|
+
};
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
);
|
|
3417
|
+
server.registerTool(
|
|
3418
|
+
"notifications_broadcast",
|
|
3419
|
+
{
|
|
3420
|
+
description: "Broadcast a push notification to all subscribed users in a project",
|
|
3421
|
+
inputSchema: {
|
|
3422
|
+
projectId: z11.string(),
|
|
3423
|
+
title: z11.string(),
|
|
3424
|
+
body: z11.string(),
|
|
3425
|
+
icon: z11.string().optional(),
|
|
3426
|
+
url: z11.string().optional()
|
|
3427
|
+
}
|
|
3428
|
+
},
|
|
3429
|
+
async ({ projectId, title, body: notifBody, icon, url }) => {
|
|
3430
|
+
try {
|
|
3431
|
+
const reqBody = { title, body: notifBody };
|
|
3432
|
+
if (icon !== void 0) reqBody.icon = icon;
|
|
3433
|
+
if (url !== void 0) reqBody.url = url;
|
|
3434
|
+
const result = await api.post(`/projects/${encodeURIComponent(projectId)}/notifications/broadcast`, { body: reqBody });
|
|
3435
|
+
return {
|
|
3436
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3437
|
+
};
|
|
3438
|
+
} catch (error) {
|
|
3439
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3440
|
+
return {
|
|
3441
|
+
content: [{ type: "text", text: `Failed to broadcast notification: ${message}` }],
|
|
3442
|
+
isError: true
|
|
3443
|
+
};
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
);
|
|
3447
|
+
}
|
|
3448
|
+
|
|
3449
|
+
// libs/mcp-server/src/tools/auditLogs.ts
|
|
3450
|
+
import { z as z12 } from "zod";
|
|
3451
|
+
function registerAuditLogTools(server, api) {
|
|
3452
|
+
server.registerTool(
|
|
3453
|
+
"audit_logs_list",
|
|
3454
|
+
{
|
|
3455
|
+
description: "List audit logs for a project. Filter by entity type, action, and date range.",
|
|
3456
|
+
inputSchema: {
|
|
3457
|
+
projectId: z12.string(),
|
|
3458
|
+
entityType: z12.enum(["user", "client", "project", "auth", "database", "storage"]).optional(),
|
|
3459
|
+
action: z12.string().optional(),
|
|
3460
|
+
startDate: z12.string().datetime().optional(),
|
|
3461
|
+
endDate: z12.string().datetime().optional(),
|
|
3462
|
+
limit: z12.number().int().min(1).max(100).optional(),
|
|
3463
|
+
offset: z12.number().int().min(0).optional()
|
|
3464
|
+
}
|
|
3465
|
+
},
|
|
3466
|
+
async ({ projectId, entityType, action, startDate, endDate, limit, offset }) => {
|
|
3467
|
+
try {
|
|
3468
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/audit-logs`, {
|
|
3469
|
+
params: { entityType, action, startDate, endDate, limit, offset }
|
|
3470
|
+
});
|
|
3471
|
+
return {
|
|
3472
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3473
|
+
};
|
|
3474
|
+
} catch (error) {
|
|
3475
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3476
|
+
return {
|
|
3477
|
+
content: [{ type: "text", text: `Failed to list audit logs: ${message}` }],
|
|
3478
|
+
isError: true
|
|
3479
|
+
};
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
);
|
|
3483
|
+
server.registerTool(
|
|
3484
|
+
"audit_logs_get",
|
|
3485
|
+
{
|
|
3486
|
+
description: "Get a single audit log entry by ID",
|
|
3487
|
+
inputSchema: {
|
|
3488
|
+
projectId: z12.string(),
|
|
3489
|
+
logId: z12.string()
|
|
3490
|
+
}
|
|
3491
|
+
},
|
|
3492
|
+
async ({ projectId, logId }) => {
|
|
3493
|
+
try {
|
|
3494
|
+
const result = await api.get(`/projects/${encodeURIComponent(projectId)}/audit-logs/${encodeURIComponent(logId)}`);
|
|
3495
|
+
return {
|
|
3496
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
3497
|
+
};
|
|
3498
|
+
} catch (error) {
|
|
3499
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3500
|
+
return {
|
|
3501
|
+
content: [{ type: "text", text: `Failed to get audit log: ${message}` }],
|
|
3502
|
+
isError: true
|
|
3503
|
+
};
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
);
|
|
3507
|
+
}
|
|
3508
|
+
|
|
2558
3509
|
// libs/mcp-server/src/tools/index.ts
|
|
2559
3510
|
function registerAllTools(server, api) {
|
|
2560
3511
|
registerAuthTools(server, api);
|
|
@@ -2565,10 +3516,14 @@ function registerAllTools(server, api) {
|
|
|
2565
3516
|
registerStorageTools(server, api);
|
|
2566
3517
|
registerFunctionTools(server, api);
|
|
2567
3518
|
registerEmailTemplateTools(server, api);
|
|
3519
|
+
registerCronJobTools(server, api);
|
|
3520
|
+
registerWebhookTools(server, api);
|
|
3521
|
+
registerNotificationTools(server, api);
|
|
3522
|
+
registerAuditLogTools(server, api);
|
|
2568
3523
|
}
|
|
2569
3524
|
|
|
2570
3525
|
// libs/mcp-server/src/prompts/database.ts
|
|
2571
|
-
import { z as
|
|
3526
|
+
import { z as z13 } from "zod";
|
|
2572
3527
|
function registerDatabasePrompts(server) {
|
|
2573
3528
|
server.registerPrompt(
|
|
2574
3529
|
"setup-collection",
|
|
@@ -2576,9 +3531,9 @@ function registerDatabasePrompts(server) {
|
|
|
2576
3531
|
title: "Setup Database Collection",
|
|
2577
3532
|
description: "Guide for creating a new database collection with proper security rules. Collections MUST have rules defined before data can be inserted.",
|
|
2578
3533
|
argsSchema: {
|
|
2579
|
-
projectId:
|
|
2580
|
-
collectionName:
|
|
2581
|
-
access:
|
|
3534
|
+
projectId: z13.string().describe("Project ID"),
|
|
3535
|
+
collectionName: z13.string().describe("Name of the collection to create"),
|
|
3536
|
+
access: z13.enum(["public-read", "authenticated", "admin-only"]).optional().describe("Access level (default: admin-only)")
|
|
2582
3537
|
}
|
|
2583
3538
|
},
|
|
2584
3539
|
async ({ projectId, collectionName, access }) => {
|
|
@@ -2643,7 +3598,7 @@ function registerDatabasePrompts(server) {
|
|
|
2643
3598
|
title: "Database Workflow Guide",
|
|
2644
3599
|
description: "Explains how the Spacelr database system works: rules-first approach, collection lifecycle, and security model.",
|
|
2645
3600
|
argsSchema: {
|
|
2646
|
-
projectId:
|
|
3601
|
+
projectId: z13.string().describe("Project ID")
|
|
2647
3602
|
}
|
|
2648
3603
|
},
|
|
2649
3604
|
async ({ projectId }) => {
|
|
@@ -2692,7 +3647,7 @@ function registerDatabasePrompts(server) {
|
|
|
2692
3647
|
}
|
|
2693
3648
|
|
|
2694
3649
|
// libs/mcp-server/src/prompts/functions.ts
|
|
2695
|
-
import { z as
|
|
3650
|
+
import { z as z14 } from "zod";
|
|
2696
3651
|
function registerFunctionPrompts(server) {
|
|
2697
3652
|
server.registerPrompt(
|
|
2698
3653
|
"deploy-function",
|
|
@@ -2700,9 +3655,9 @@ function registerFunctionPrompts(server) {
|
|
|
2700
3655
|
title: "Deploy a Serverless Function",
|
|
2701
3656
|
description: "Step-by-step guide for creating, deploying, and testing a serverless function. Covers the full lifecycle from creation to execution.",
|
|
2702
3657
|
argsSchema: {
|
|
2703
|
-
projectId:
|
|
2704
|
-
name:
|
|
2705
|
-
useCase:
|
|
3658
|
+
projectId: z14.string().describe("Project ID"),
|
|
3659
|
+
name: z14.string().describe("Function name"),
|
|
3660
|
+
useCase: z14.string().optional().describe('What the function should do (e.g. "fetch data from API and store in DB")')
|
|
2706
3661
|
}
|
|
2707
3662
|
},
|
|
2708
3663
|
async ({ projectId, name, useCase }) => {
|