@rafaylabs/animation-mcp 1.0.0 → 1.0.1
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/bin/cli.js +1 -1
- package/dist/api/catalog-client.d.ts +9 -1
- package/dist/api/catalog-client.js +14 -3
- package/dist/index.js +8 -3
- package/dist/tools/schemas.d.ts +3 -0
- package/dist/tools/schemas.js +1 -0
- package/dist/tools/search.d.ts +6 -0
- package/dist/tools/search.js +11 -3
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ async function main() {
|
|
|
24
24
|
if (!ok) process.exitCode = 1;
|
|
25
25
|
} else if (command === '--help' || command === '-h' || command === 'help') {
|
|
26
26
|
console.log(`
|
|
27
|
-
RafayLabs Animation MCP v1.0.
|
|
27
|
+
RafayLabs Animation MCP v1.0.1
|
|
28
28
|
AI-driven on-brand Lottie animations and framework code generator.
|
|
29
29
|
|
|
30
30
|
Usage:
|
|
@@ -5,6 +5,7 @@ export interface CatalogSearchParams {
|
|
|
5
5
|
loop?: boolean;
|
|
6
6
|
max_size_kb?: number;
|
|
7
7
|
limit?: number;
|
|
8
|
+
page?: number;
|
|
8
9
|
}
|
|
9
10
|
export interface CatalogSearchResultItem {
|
|
10
11
|
id: string;
|
|
@@ -17,10 +18,17 @@ export interface CatalogSearchResultItem {
|
|
|
17
18
|
match_score: number;
|
|
18
19
|
themeable_score: number;
|
|
19
20
|
}
|
|
21
|
+
export interface CatalogSearchResult {
|
|
22
|
+
results: CatalogSearchResultItem[];
|
|
23
|
+
total: number;
|
|
24
|
+
page: number;
|
|
25
|
+
totalPages: number;
|
|
26
|
+
hasMore: boolean;
|
|
27
|
+
}
|
|
20
28
|
/**
|
|
21
29
|
* Searches the 11K+ hosted Lottie animation catalogue
|
|
22
30
|
*/
|
|
23
|
-
export declare function searchCatalog(params: CatalogSearchParams): Promise<
|
|
31
|
+
export declare function searchCatalog(params: CatalogSearchParams): Promise<CatalogSearchResult>;
|
|
24
32
|
/**
|
|
25
33
|
* Downloads and caches a Lottie JSON animation from the catalogue by ID
|
|
26
34
|
*/
|
|
@@ -10,7 +10,8 @@ const CACHE_DIR = path.join(os.homedir(), '.animation-mcp', 'cache');
|
|
|
10
10
|
*/
|
|
11
11
|
export async function searchCatalog(params) {
|
|
12
12
|
const limit = Math.min(params.limit || 5, 20);
|
|
13
|
-
const
|
|
13
|
+
const page = Math.max(1, Math.floor(params.page || 1));
|
|
14
|
+
const qs = new URLSearchParams({ search: params.query, limit: String(limit), page: String(page) });
|
|
14
15
|
if (params.category)
|
|
15
16
|
qs.set('category', params.category);
|
|
16
17
|
const res = await serverFetch(`/api/mcp/search?${qs.toString()}`);
|
|
@@ -19,7 +20,7 @@ export async function searchCatalog(params) {
|
|
|
19
20
|
}
|
|
20
21
|
const data = (await res.json());
|
|
21
22
|
const items = data.items || data.animations || [];
|
|
22
|
-
|
|
23
|
+
const results = items.map((item, idx) => {
|
|
23
24
|
const sizeBytes = item.file_size_bytes || item.size_bytes || 25000;
|
|
24
25
|
return {
|
|
25
26
|
id: String(item.id || item.slug),
|
|
@@ -29,10 +30,20 @@ export async function searchCatalog(params) {
|
|
|
29
30
|
preview_url: item.thumbnail_webp_url || item.preview_url || null,
|
|
30
31
|
duration_seconds: Number(item.duration_seconds || item.duration || 2.0),
|
|
31
32
|
size_kb: `${(sizeBytes / 1024).toFixed(1)} KB`,
|
|
32
|
-
|
|
33
|
+
// Real relevance from the server (0..1); older servers do not send it, so fall back to rank order.
|
|
34
|
+
match_score: typeof item.match_score === 'number' ? item.match_score : Number(Math.max(0, 1.0 - idx * 0.08).toFixed(2)),
|
|
33
35
|
themeable_score: 0.95,
|
|
34
36
|
};
|
|
35
37
|
});
|
|
38
|
+
const total = Number(data.total ?? results.length);
|
|
39
|
+
const totalPages = Number(data.totalPages ?? 1);
|
|
40
|
+
return {
|
|
41
|
+
results,
|
|
42
|
+
total,
|
|
43
|
+
page: Number(data.page ?? page),
|
|
44
|
+
totalPages,
|
|
45
|
+
hasMore: typeof data.has_more === 'boolean' ? data.has_more : page < totalPages,
|
|
46
|
+
};
|
|
36
47
|
}
|
|
37
48
|
/**
|
|
38
49
|
* Downloads and caches a Lottie JSON animation from the catalogue by ID
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { SearchAnimationsArgsSchema, GetAnimationArgsSchema, ApplyThemeArgsSchem
|
|
|
14
14
|
export async function startMcpServer() {
|
|
15
15
|
const server = new Server({
|
|
16
16
|
name: 'rafaylabs-animation-mcp',
|
|
17
|
-
version: '1.0.
|
|
17
|
+
version: '1.0.1',
|
|
18
18
|
}, {
|
|
19
19
|
capabilities: {
|
|
20
20
|
tools: {},
|
|
@@ -26,7 +26,7 @@ export async function startMcpServer() {
|
|
|
26
26
|
tools: [
|
|
27
27
|
{
|
|
28
28
|
name: 'search_animations',
|
|
29
|
-
description: 'Search the RafayLabs catalogue of 11,000+ production Lottie animations using plain language (e.g. "success checkmark with confetti", "pulsing order delivery truck", "loading skeleton shimmer"). Returns short structured JSON with preview URLs,
|
|
29
|
+
description: 'Search the RafayLabs catalogue of 11,000+ production Lottie animations using plain language (e.g. "success checkmark with confetti", "pulsing order delivery truck", "loading skeleton shimmer"). Results are ranked by relevance (match_score 0-1, 1 = closest). Returns short structured JSON with preview URLs, size, category, totalMatches and has_more. If nothing fits, call again with the next page or with different keywords. Never returns raw Lottie JSON to save context window.',
|
|
30
30
|
inputSchema: {
|
|
31
31
|
type: 'object',
|
|
32
32
|
properties: {
|
|
@@ -52,9 +52,14 @@ export async function startMcpServer() {
|
|
|
52
52
|
},
|
|
53
53
|
limit: {
|
|
54
54
|
type: 'number',
|
|
55
|
-
description: '
|
|
55
|
+
description: 'Results per page, 1-20 (default 5)',
|
|
56
56
|
default: 5,
|
|
57
57
|
},
|
|
58
|
+
page: {
|
|
59
|
+
type: 'number',
|
|
60
|
+
description: 'Page of results (default 1). Use the next page when has_more is true and nothing fits yet',
|
|
61
|
+
default: 1,
|
|
62
|
+
},
|
|
58
63
|
},
|
|
59
64
|
required: ['query'],
|
|
60
65
|
},
|
package/dist/tools/schemas.d.ts
CHANGED
|
@@ -6,8 +6,10 @@ export declare const SearchAnimationsArgsSchema: z.ZodObject<{
|
|
|
6
6
|
loop: z.ZodOptional<z.ZodBoolean>;
|
|
7
7
|
max_size_kb: z.ZodOptional<z.ZodNumber>;
|
|
8
8
|
limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
9
|
+
page: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
9
10
|
}, "strip", z.ZodTypeAny, {
|
|
10
11
|
limit: number;
|
|
12
|
+
page: number;
|
|
11
13
|
query: string;
|
|
12
14
|
category?: string | undefined;
|
|
13
15
|
style?: string | undefined;
|
|
@@ -16,6 +18,7 @@ export declare const SearchAnimationsArgsSchema: z.ZodObject<{
|
|
|
16
18
|
}, {
|
|
17
19
|
query: string;
|
|
18
20
|
limit?: number | undefined;
|
|
21
|
+
page?: number | undefined;
|
|
19
22
|
category?: string | undefined;
|
|
20
23
|
style?: string | undefined;
|
|
21
24
|
loop?: boolean | undefined;
|
package/dist/tools/schemas.js
CHANGED
|
@@ -6,6 +6,7 @@ export const SearchAnimationsArgsSchema = z.object({
|
|
|
6
6
|
loop: z.boolean().optional(),
|
|
7
7
|
max_size_kb: z.number().positive().optional(),
|
|
8
8
|
limit: z.number().int().min(1).max(20).optional().default(5),
|
|
9
|
+
page: z.number().int().min(1).max(50).optional().default(1),
|
|
9
10
|
});
|
|
10
11
|
export const GetAnimationArgsSchema = z.object({
|
|
11
12
|
id: z.string().regex(/^[A-Za-z0-9_-]{1,128}$/, 'Animation ID may only contain letters, numbers, - and _'),
|
package/dist/tools/search.d.ts
CHANGED
|
@@ -7,8 +7,10 @@ export declare const SearchAnimationsSchema: z.ZodObject<{
|
|
|
7
7
|
loop: z.ZodOptional<z.ZodBoolean>;
|
|
8
8
|
max_size_kb: z.ZodOptional<z.ZodNumber>;
|
|
9
9
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
page: z.ZodDefault<z.ZodNumber>;
|
|
10
11
|
}, "strip", z.ZodTypeAny, {
|
|
11
12
|
limit: number;
|
|
13
|
+
page: number;
|
|
12
14
|
query: string;
|
|
13
15
|
category?: string | undefined;
|
|
14
16
|
style?: string | undefined;
|
|
@@ -17,6 +19,7 @@ export declare const SearchAnimationsSchema: z.ZodObject<{
|
|
|
17
19
|
}, {
|
|
18
20
|
query: string;
|
|
19
21
|
limit?: number | undefined;
|
|
22
|
+
page?: number | undefined;
|
|
20
23
|
category?: string | undefined;
|
|
21
24
|
style?: string | undefined;
|
|
22
25
|
loop?: boolean | undefined;
|
|
@@ -26,4 +29,7 @@ export type SearchAnimationsInput = z.infer<typeof SearchAnimationsSchema>;
|
|
|
26
29
|
export declare function handleSearchAnimations(input: SearchAnimationsInput): Promise<{
|
|
27
30
|
results: CatalogSearchResultItem[];
|
|
28
31
|
totalMatches: number;
|
|
32
|
+
page: number;
|
|
33
|
+
totalPages: number;
|
|
34
|
+
has_more: boolean;
|
|
29
35
|
}>;
|
package/dist/tools/search.js
CHANGED
|
@@ -6,17 +6,25 @@ export const SearchAnimationsSchema = z.object({
|
|
|
6
6
|
category: z.string().optional().describe('Animation category: success, loading, error, empty state, onboarding, ecommerce'),
|
|
7
7
|
loop: z.boolean().optional().describe('Whether the animation should continuously loop'),
|
|
8
8
|
max_size_kb: z.number().optional().describe('Maximum allowed file size in KB'),
|
|
9
|
-
limit: z.number().min(1).max(20).default(5).describe('
|
|
9
|
+
limit: z.number().min(1).max(20).default(5).describe('Results per page, 1-20 (default 5)'),
|
|
10
|
+
page: z.number().int().min(1).max(50).default(1).describe('Page of results (default 1). Ask for the next page when has_more is true and nothing fits yet'),
|
|
10
11
|
});
|
|
11
12
|
export async function handleSearchAnimations(input) {
|
|
12
13
|
// Sign-in, plan and daily limits are enforced by the server; it answers 401/429 with a clear message.
|
|
13
|
-
const
|
|
14
|
+
const found = await searchCatalog({
|
|
14
15
|
query: input.query,
|
|
15
16
|
category: input.category,
|
|
16
17
|
style: input.style,
|
|
17
18
|
loop: input.loop,
|
|
18
19
|
max_size_kb: input.max_size_kb,
|
|
19
20
|
limit: input.limit,
|
|
21
|
+
page: input.page,
|
|
20
22
|
});
|
|
21
|
-
return {
|
|
23
|
+
return {
|
|
24
|
+
results: found.results,
|
|
25
|
+
totalMatches: found.total,
|
|
26
|
+
page: found.page,
|
|
27
|
+
totalPages: found.totalPages,
|
|
28
|
+
has_more: found.hasMore,
|
|
29
|
+
};
|
|
22
30
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rafaylabs/animation-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "On-brand Lottie animations and framework code inside your AI coding assistant (Cursor, Claude Code, Windsurf, VS Code)",
|
|
6
6
|
"main": "dist/index.js",
|