feat: TikTok and Snapchat integrations

TikTok: getUserProfile, getUserVideos, createVideo (PULL_FROM_URL),
getVideoStatus via Content Posting API v2. Full multi-tenant credential
isolation and audit logging on write operations.

Snapchat: getMe (Login Kit), getAdAccounts (Marketing API). createSnap
throws with a clear explanation that Creative Kit is mobile-only — no
server-side posting API exists.

Platform type, validPlatforms list, and /api/connections endpoint all
updated to include tiktok and snapchat. Architecture diagram updated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Garfield
2026-05-08 11:38:32 -04:00
parent 7ada43a1d7
commit 6c7e56769e
6 changed files with 416 additions and 3 deletions

View File

@@ -9,6 +9,8 @@ import { getMe as getTelegramMe, sendMessage as sendTelegramMessage, sendPhoto a
import { getMe as getDiscordMe, getGuilds, getChannels, sendMessage as sendDiscordMessage, getMessages as getDiscordMessages } from './clients/discord.js';
import { getProfile as getInstagramProfile, getMedia as getInstagramMedia, createPost as createInstagramPost } from './clients/instagram.js';
import { searchTweets, getUserProfile, getUserTweets, createTweet } from './clients/twitter.js';
import { getUserProfile as getTikTokProfile, getUserVideos, createVideo, getVideoStatus } from './clients/tiktok.js';
import { getMe as getSnapchatMe, createSnap, getAdAccounts } from './clients/snapchat.js';
const ACCOUNT_PARAM = {
account: {
@@ -517,6 +519,97 @@ export const tools: Tool[] = [
},
},
},
// ── TikTok tools ─────────────────────────────────────────────
{
name: 'tiktok_get_profile',
description:
'Get the TikTok user profile including follower count, following count, likes, and video count.',
inputSchema: {
type: 'object',
properties: {
account: { type: 'string', description: 'Which TikTok account to use (default: "default")' },
},
},
},
{
name: 'tiktok_get_videos',
description:
'List recent videos from the authenticated TikTok account with view, like, comment, and share counts.',
inputSchema: {
type: 'object',
properties: {
max_count: { type: 'number', description: 'Max videos to return (default: 10, max: 20)' },
account: { type: 'string', description: 'Which TikTok account to use (default: "default")' },
},
},
},
{
name: 'tiktok_create_video',
description:
'Post a video to TikTok by providing a publicly accessible video URL. Returns a publish_id to check status.',
inputSchema: {
type: 'object',
required: ['video_url'],
properties: {
video_url: { type: 'string', description: 'Publicly accessible URL of the video to post' },
title: { type: 'string', description: 'Video title (max 150 chars)' },
description: { type: 'string', description: 'Video description / caption' },
account: { type: 'string', description: 'Which TikTok account to use (default: "default")' },
},
},
},
{
name: 'tiktok_get_video_status',
description:
'Check the processing status of a TikTok video upload using the publish_id returned by tiktok_create_video.',
inputSchema: {
type: 'object',
required: ['publish_id'],
properties: {
publish_id: { type: 'string', description: 'Publish ID returned by tiktok_create_video' },
account: { type: 'string', description: 'Which TikTok account to use (default: "default")' },
},
},
},
// ── Snapchat tools ───────────────────────────────────────────
{
name: 'snapchat_get_me',
description:
'Get the authenticated Snapchat user profile (display name, bitmoji avatar). Uses Snapchat Login Kit.',
inputSchema: {
type: 'object',
properties: {
account: { type: 'string', description: 'Which Snapchat account to use (default: "default")' },
},
},
},
{
name: 'snapchat_create_snap',
description:
'[NOT SUPPORTED] Snapchat Creative Kit is a mobile-only SDK — posting Snaps from a server is not possible. Use the iOS/Android Creative Kit SDK instead.',
inputSchema: {
type: 'object',
properties: {
image_url: { type: 'string', description: 'Image URL (not usable server-side)' },
video_url: { type: 'string', description: 'Video URL (not usable server-side)' },
caption: { type: 'string', description: 'Caption text (not usable server-side)' },
account: { type: 'string', description: 'Which Snapchat account to use (default: "default")' },
},
},
},
{
name: 'snapchat_get_ad_accounts',
description:
'List Snapchat Ads Manager ad accounts. Use when the user wants to manage Snapchat advertising campaigns.',
inputSchema: {
type: 'object',
properties: {
account: { type: 'string', description: 'Which Snapchat account to use (default: "default")' },
},
},
},
];
function acct(args: Record<string, unknown>): Account {
@@ -779,6 +872,58 @@ export async function handleToolCall(
}, customer);
break;
// ── TikTok ─────────────────────────────────────────────────
case 'tiktok_get_profile':
result = await getTikTokProfile({
account: args.account as string | undefined,
}, customer);
break;
case 'tiktok_get_videos':
result = await getUserVideos({
max_count: (args.max_count as number) ?? 10,
account: args.account as string | undefined,
}, customer);
break;
case 'tiktok_create_video':
result = await createVideo({
video_url: args.video_url as string,
title: args.title as string | undefined,
description: args.description as string | undefined,
account: args.account as string | undefined,
}, customer);
break;
case 'tiktok_get_video_status':
result = await getVideoStatus({
publish_id: args.publish_id as string,
account: args.account as string | undefined,
}, customer);
break;
// ── Snapchat ────────────────────────────────────────────────
case 'snapchat_get_me':
result = await getSnapchatMe({
account: args.account as string | undefined,
}, customer);
break;
case 'snapchat_create_snap':
result = await createSnap({
image_url: args.image_url as string | undefined,
video_url: args.video_url as string | undefined,
caption: args.caption as string | undefined,
account: args.account as string | undefined,
}, customer);
break;
case 'snapchat_get_ad_accounts':
result = await getAdAccounts({
account: args.account as string | undefined,
}, customer);
break;
// Legacy Yahoo-prefixed names — keep working for any cached Claude sessions
case 'yahoo_get_profile':
result = await getProfile('yahoo');