aso-mcp 1.0.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.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +227 -0
  3. package/build/cache/sqlite-cache.d.ts +10 -0
  4. package/build/cache/sqlite-cache.d.ts.map +1 -0
  5. package/build/cache/sqlite-cache.js +51 -0
  6. package/build/cache/sqlite-cache.js.map +1 -0
  7. package/build/data-sources/app-store-connect.d.ts +12 -0
  8. package/build/data-sources/app-store-connect.d.ts.map +1 -0
  9. package/build/data-sources/app-store-connect.js +415 -0
  10. package/build/data-sources/app-store-connect.js.map +1 -0
  11. package/build/data-sources/app-store.d.ts +7 -0
  12. package/build/data-sources/app-store.d.ts.map +1 -0
  13. package/build/data-sources/app-store.js +28 -0
  14. package/build/data-sources/app-store.js.map +1 -0
  15. package/build/data-sources/aso-scoring.d.ts +15 -0
  16. package/build/data-sources/aso-scoring.d.ts.map +1 -0
  17. package/build/data-sources/aso-scoring.js +140 -0
  18. package/build/data-sources/aso-scoring.js.map +1 -0
  19. package/build/data-sources/custom-scoring.d.ts +52 -0
  20. package/build/data-sources/custom-scoring.d.ts.map +1 -0
  21. package/build/data-sources/custom-scoring.js +83 -0
  22. package/build/data-sources/custom-scoring.js.map +1 -0
  23. package/build/server.d.ts +3 -0
  24. package/build/server.d.ts.map +1 -0
  25. package/build/server.js +69 -0
  26. package/build/server.js.map +1 -0
  27. package/build/tools/analyze-competitors.d.ts +3 -0
  28. package/build/tools/analyze-competitors.d.ts.map +1 -0
  29. package/build/tools/analyze-competitors.js +112 -0
  30. package/build/tools/analyze-competitors.js.map +1 -0
  31. package/build/tools/analyze-reviews.d.ts +3 -0
  32. package/build/tools/analyze-reviews.d.ts.map +1 -0
  33. package/build/tools/analyze-reviews.js +188 -0
  34. package/build/tools/analyze-reviews.js.map +1 -0
  35. package/build/tools/clear-cache.d.ts +3 -0
  36. package/build/tools/clear-cache.d.ts.map +1 -0
  37. package/build/tools/clear-cache.js +32 -0
  38. package/build/tools/clear-cache.js.map +1 -0
  39. package/build/tools/connect-get-app.d.ts +3 -0
  40. package/build/tools/connect-get-app.d.ts.map +1 -0
  41. package/build/tools/connect-get-app.js +56 -0
  42. package/build/tools/connect-get-app.js.map +1 -0
  43. package/build/tools/connect-get-metadata.d.ts +3 -0
  44. package/build/tools/connect-get-metadata.d.ts.map +1 -0
  45. package/build/tools/connect-get-metadata.js +73 -0
  46. package/build/tools/connect-get-metadata.js.map +1 -0
  47. package/build/tools/connect-list-localizations.d.ts +3 -0
  48. package/build/tools/connect-list-localizations.d.ts.map +1 -0
  49. package/build/tools/connect-list-localizations.js +55 -0
  50. package/build/tools/connect-list-localizations.js.map +1 -0
  51. package/build/tools/connect-setup.d.ts +3 -0
  52. package/build/tools/connect-setup.d.ts.map +1 -0
  53. package/build/tools/connect-setup.js +47 -0
  54. package/build/tools/connect-setup.js.map +1 -0
  55. package/build/tools/connect-update-metadata.d.ts +3 -0
  56. package/build/tools/connect-update-metadata.d.ts.map +1 -0
  57. package/build/tools/connect-update-metadata.js +176 -0
  58. package/build/tools/connect-update-metadata.js.map +1 -0
  59. package/build/tools/discover-keywords.d.ts +3 -0
  60. package/build/tools/discover-keywords.d.ts.map +1 -0
  61. package/build/tools/discover-keywords.js +195 -0
  62. package/build/tools/discover-keywords.js.map +1 -0
  63. package/build/tools/generate-aso-brief.d.ts +3 -0
  64. package/build/tools/generate-aso-brief.d.ts.map +1 -0
  65. package/build/tools/generate-aso-brief.js +295 -0
  66. package/build/tools/generate-aso-brief.js.map +1 -0
  67. package/build/tools/get-app-details.d.ts +3 -0
  68. package/build/tools/get-app-details.d.ts.map +1 -0
  69. package/build/tools/get-app-details.js +89 -0
  70. package/build/tools/get-app-details.js.map +1 -0
  71. package/build/tools/get-aso-report.d.ts +3 -0
  72. package/build/tools/get-aso-report.d.ts.map +1 -0
  73. package/build/tools/get-aso-report.js +168 -0
  74. package/build/tools/get-aso-report.js.map +1 -0
  75. package/build/tools/keyword-gap.d.ts +3 -0
  76. package/build/tools/keyword-gap.d.ts.map +1 -0
  77. package/build/tools/keyword-gap.js +116 -0
  78. package/build/tools/keyword-gap.js.map +1 -0
  79. package/build/tools/localized-keywords.d.ts +3 -0
  80. package/build/tools/localized-keywords.d.ts.map +1 -0
  81. package/build/tools/localized-keywords.js +107 -0
  82. package/build/tools/localized-keywords.js.map +1 -0
  83. package/build/tools/optimize-metadata.d.ts +3 -0
  84. package/build/tools/optimize-metadata.d.ts.map +1 -0
  85. package/build/tools/optimize-metadata.js +156 -0
  86. package/build/tools/optimize-metadata.js.map +1 -0
  87. package/build/tools/search-keywords.d.ts +3 -0
  88. package/build/tools/search-keywords.d.ts.map +1 -0
  89. package/build/tools/search-keywords.js +65 -0
  90. package/build/tools/search-keywords.js.map +1 -0
  91. package/build/tools/suggest-keywords.d.ts +3 -0
  92. package/build/tools/suggest-keywords.d.ts.map +1 -0
  93. package/build/tools/suggest-keywords.js +71 -0
  94. package/build/tools/suggest-keywords.js.map +1 -0
  95. package/build/tools/track-ranking.d.ts +3 -0
  96. package/build/tools/track-ranking.d.ts.map +1 -0
  97. package/build/tools/track-ranking.js +94 -0
  98. package/build/tools/track-ranking.js.map +1 -0
  99. package/build/types/index.d.ts +151 -0
  100. package/build/types/index.d.ts.map +1 -0
  101. package/build/types/index.js +2 -0
  102. package/build/types/index.js.map +1 -0
  103. package/build/utils/constants.d.ts +40 -0
  104. package/build/utils/constants.d.ts.map +1 -0
  105. package/build/utils/constants.js +35 -0
  106. package/build/utils/constants.js.map +1 -0
  107. package/build/utils/formatters.d.ts +9 -0
  108. package/build/utils/formatters.d.ts.map +1 -0
  109. package/build/utils/formatters.js +37 -0
  110. package/build/utils/formatters.js.map +1 -0
  111. package/build/utils/localization.d.ts +7 -0
  112. package/build/utils/localization.d.ts.map +1 -0
  113. package/build/utils/localization.js +63 -0
  114. package/build/utils/localization.js.map +1 -0
  115. package/build/utils/rate-limiter.d.ts +7 -0
  116. package/build/utils/rate-limiter.d.ts.map +1 -0
  117. package/build/utils/rate-limiter.js +23 -0
  118. package/build/utils/rate-limiter.js.map +1 -0
  119. package/package.json +60 -0
@@ -0,0 +1,195 @@
1
+ import { z } from "zod";
2
+ import { searchApps, getSuggestions } from "../data-sources/app-store.js";
3
+ import { batchGetScores } from "../data-sources/aso-scoring.js";
4
+ import { getFromCache, setCache } from "../cache/sqlite-cache.js";
5
+ import { CACHE_TTL } from "../utils/constants.js";
6
+ import { extractTitleKeywords, calculateOpportunityScore, } from "../data-sources/custom-scoring.js";
7
+ export function registerDiscoverKeywords(server) {
8
+ server.tool("discover_keywords", "Performs keyword discovery from scratch for a new app. Scans top apps based on category, niche definition, and feature list, builds a keyword pool, and scores each keyword. The first step of the ASO process.", {
9
+ category: z
10
+ .string()
11
+ .describe("App Store category (e.g. 'Health & Fitness', 'Productivity', 'Education')"),
12
+ niche: z
13
+ .string()
14
+ .describe("App's niche definition (e.g. 'calorie tracking and diet planning', 'to-do list and task management')"),
15
+ features: z
16
+ .array(z.string())
17
+ .describe("App's main features (e.g. ['calorie counter', 'barcode scanner', 'water tracking', 'diet plan'])"),
18
+ country: z
19
+ .string()
20
+ .default("tr")
21
+ .describe("Target country code"),
22
+ maxResults: z
23
+ .number()
24
+ .default(50)
25
+ .describe("Maximum number of keywords"),
26
+ }, async ({ category, niche, features, country, maxResults }) => {
27
+ const cacheKey = `discover:${category}:${niche}:${features.join(",")}:${country}`;
28
+ const cached = getFromCache(cacheKey);
29
+ if (cached) {
30
+ return { content: [{ type: "text", text: cached }] };
31
+ }
32
+ try {
33
+ // ─── 1. Build search terms ───
34
+ const searchTerms = [
35
+ ...niche.split(/\s+ve\s+|\s+and\s+|,\s*/).map((t) => t.trim()).filter(Boolean),
36
+ ...features.slice(0, 8),
37
+ category,
38
+ ];
39
+ const uniqueTerms = [...new Set(searchTerms)];
40
+ // ─── 2. Search App Store for each term, collect top apps ───
41
+ const allApps = new Map();
42
+ const termAppMap = {};
43
+ for (const term of uniqueTerms.slice(0, 10)) {
44
+ try {
45
+ const apps = await searchApps(term, country, 10);
46
+ termAppMap[term] = [];
47
+ for (const app of apps) {
48
+ const a = app;
49
+ const key = a.appId || String(a.id);
50
+ if (!allApps.has(key)) {
51
+ allApps.set(key, a);
52
+ }
53
+ termAppMap[term].push(a.title);
54
+ }
55
+ }
56
+ catch {
57
+ // continue
58
+ }
59
+ }
60
+ // ─── 3. Extract keywords from top apps' title + description ───
61
+ const rawKeywords = new Map();
62
+ for (const [key, app] of allApps) {
63
+ const titleKws = extractTitleKeywords(app.title || "");
64
+ const descKws = extractTitleKeywords((app.description || "").slice(0, 300));
65
+ const allKws = [...new Set([...titleKws, ...descKws])];
66
+ for (const kw of allKws) {
67
+ if (kw.length < 2)
68
+ continue;
69
+ const existing = rawKeywords.get(kw);
70
+ if (existing) {
71
+ existing.count++;
72
+ if (!existing.sources.includes(app.title)) {
73
+ existing.sources.push(app.title);
74
+ }
75
+ }
76
+ else {
77
+ rawKeywords.set(kw, { count: 1, sources: [app.title] });
78
+ }
79
+ }
80
+ }
81
+ // ─── 4. App Store autocomplete suggestions ───
82
+ for (const term of uniqueTerms.slice(0, 5)) {
83
+ try {
84
+ const suggestions = await getSuggestions(term);
85
+ if (Array.isArray(suggestions)) {
86
+ for (const s of suggestions) {
87
+ const text = typeof s === "string" ? s : s?.term || "";
88
+ if (text && !rawKeywords.has(text.toLowerCase())) {
89
+ rawKeywords.set(text.toLowerCase(), {
90
+ count: 1,
91
+ sources: ["autocomplete"],
92
+ });
93
+ }
94
+ }
95
+ }
96
+ }
97
+ catch {
98
+ // continue
99
+ }
100
+ }
101
+ // ─── 5. Add feature keywords ───
102
+ for (const feature of features) {
103
+ const featureWords = extractTitleKeywords(feature);
104
+ for (const fw of featureWords) {
105
+ if (!rawKeywords.has(fw)) {
106
+ rawKeywords.set(fw, { count: 1, sources: ["app-feature"] });
107
+ }
108
+ }
109
+ // Also add the feature itself
110
+ const featureLower = feature.toLowerCase().trim();
111
+ if (!rawKeywords.has(featureLower)) {
112
+ rawKeywords.set(featureLower, { count: 1, sources: ["app-feature"] });
113
+ }
114
+ }
115
+ // ─── 6. Sort by frequency, score top keywords (in parallel) ───
116
+ const sortedKeywords = [...rawKeywords.entries()]
117
+ .sort((a, b) => b[1].count - a[1].count)
118
+ .slice(0, maxResults);
119
+ const batchScores = await batchGetScores(sortedKeywords.map(([kw]) => kw), country);
120
+ const scoreMap = new Map(batchScores.map((s) => [s.keyword, s]));
121
+ const scoredKeywords = [];
122
+ for (const [kw, data] of sortedKeywords) {
123
+ const scores = scoreMap.get(kw) || { traffic: 0, difficulty: 0 };
124
+ const oppScore = calculateOpportunityScore(scores.traffic, scores.difficulty);
125
+ let tier;
126
+ if (oppScore >= 7)
127
+ tier = "A — High opportunity";
128
+ else if (oppScore >= 5)
129
+ tier = "B — Medium opportunity";
130
+ else if (oppScore >= 3)
131
+ tier = "C — Low opportunity";
132
+ else
133
+ tier = "D — Weak";
134
+ scoredKeywords.push({
135
+ keyword: kw,
136
+ traffic: scores.traffic,
137
+ difficulty: scores.difficulty,
138
+ opportunityScore: Math.round(oppScore * 10) / 10,
139
+ frequency: data.count,
140
+ sources: data.sources.slice(0, 3),
141
+ tier,
142
+ });
143
+ }
144
+ // Sort by opportunity
145
+ scoredKeywords.sort((a, b) => b.opportunityScore - a.opportunityScore);
146
+ // ─── 7. Summary statistics ───
147
+ const tierA = scoredKeywords.filter((k) => k.tier.startsWith("A"));
148
+ const tierB = scoredKeywords.filter((k) => k.tier.startsWith("B"));
149
+ const result = {
150
+ category,
151
+ niche,
152
+ country,
153
+ features,
154
+ totalAppsAnalyzed: allApps.size,
155
+ totalKeywordsFound: scoredKeywords.length,
156
+ summary: {
157
+ tierA: tierA.length,
158
+ tierB: tierB.length,
159
+ topOpportunities: tierA.slice(0, 10).map((k) => k.keyword),
160
+ avgTraffic: scoredKeywords.length > 0
161
+ ? Math.round((scoredKeywords.reduce((s, k) => s + k.traffic, 0) /
162
+ scoredKeywords.length) *
163
+ 10) / 10
164
+ : 0,
165
+ avgDifficulty: scoredKeywords.length > 0
166
+ ? Math.round((scoredKeywords.reduce((s, k) => s + k.difficulty, 0) /
167
+ scoredKeywords.length) *
168
+ 10) / 10
169
+ : 0,
170
+ },
171
+ keywords: scoredKeywords,
172
+ searchTermsUsed: uniqueTerms,
173
+ topCompetitors: [...allApps.values()]
174
+ .sort((a, b) => (b.reviews || 0) - (a.reviews || 0))
175
+ .slice(0, 5)
176
+ .map((a) => ({
177
+ title: a.title,
178
+ developer: a.developer,
179
+ rating: a.score || 0,
180
+ reviews: a.reviews || 0,
181
+ })),
182
+ };
183
+ const resultText = JSON.stringify(result, null, 2);
184
+ setCache(cacheKey, resultText, CACHE_TTL.KEYWORD_SCORES);
185
+ return { content: [{ type: "text", text: resultText }] };
186
+ }
187
+ catch (error) {
188
+ return {
189
+ content: [{ type: "text", text: `Error: ${error.message}` }],
190
+ isError: true,
191
+ };
192
+ }
193
+ });
194
+ }
195
+ //# sourceMappingURL=discover-keywords.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover-keywords.js","sourceRoot":"","sources":["../../src/tools/discover-keywords.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGenerateAsoBrief(server: McpServer): void;
3
+ //# sourceMappingURL=generate-aso-brief.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-aso-brief.d.ts","sourceRoot":"","sources":["../../src/tools/generate-aso-brief.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAapE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,QAuVzD"}
@@ -0,0 +1,295 @@
1
+ import { z } from "zod";
2
+ import { searchApps, getAppDetails, getSuggestions } from "../data-sources/app-store.js";
3
+ import { getScores, batchGetScores } from "../data-sources/aso-scoring.js";
4
+ import { getFromCache, setCache } from "../cache/sqlite-cache.js";
5
+ import { CACHE_TTL, CHAR_LIMITS } from "../utils/constants.js";
6
+ import { getCountryName } from "../utils/localization.js";
7
+ import { extractTitleKeywords, calculateCompetitiveScore, calculateOpportunityScore, } from "../data-sources/custom-scoring.js";
8
+ export function registerGenerateAsoBrief(server) {
9
+ server.tool("generate_aso_brief", "Generates a complete ASO brief for a new app. Based on the app's name, category, features, and target audience, it provides: a scored keyword pool, competitor pattern analysis, structured suggestions for title/subtitle/keyword field, and character limits. A ready-made brief for AI to directly produce ASO content.", {
10
+ appName: z
11
+ .string()
12
+ .describe("App name"),
13
+ category: z
14
+ .string()
15
+ .describe("App Store category (e.g. 'Health & Fitness', 'Productivity')"),
16
+ features: z
17
+ .array(z.string())
18
+ .describe("App's main features"),
19
+ targetAudience: z
20
+ .string()
21
+ .describe("Target audience description (e.g. 'women on a diet aged 25-40', 'college students')"),
22
+ countries: z
23
+ .array(z.string())
24
+ .default(["tr"])
25
+ .describe("Target countries"),
26
+ competitorAppIds: z
27
+ .array(z.string())
28
+ .default([])
29
+ .describe("Known competitor app IDs (optional)"),
30
+ }, async ({ appName, category, features, targetAudience, countries, competitorAppIds }) => {
31
+ const cacheKey = `brief:${appName}:${category}:${countries.join(",")}`;
32
+ const cached = getFromCache(cacheKey);
33
+ if (cached) {
34
+ return { content: [{ type: "text", text: cached }] };
35
+ }
36
+ try {
37
+ const primaryCountry = countries[0] || "tr";
38
+ // ─── 1. Keyword discovery ───
39
+ // Search terms: features + category + niche combinations
40
+ const searchTerms = [
41
+ ...features.slice(0, 6),
42
+ category,
43
+ ...features.slice(0, 3).map((f) => `${f} app`),
44
+ ];
45
+ const keywordPool = new Map();
46
+ // Feature and category based search
47
+ for (const term of searchTerms.slice(0, 8)) {
48
+ try {
49
+ const apps = await searchApps(term, primaryCountry, 8);
50
+ for (const app of apps) {
51
+ const a = app;
52
+ const kws = extractTitleKeywords(a.title || "");
53
+ for (const kw of kws) {
54
+ if (!keywordPool.has(kw)) {
55
+ keywordPool.set(kw, { traffic: 0, difficulty: 0, source: "competitor-title" });
56
+ }
57
+ }
58
+ }
59
+ }
60
+ catch {
61
+ // continue
62
+ }
63
+ }
64
+ // Autocomplete suggestions
65
+ for (const term of features.slice(0, 4)) {
66
+ try {
67
+ const suggestions = await getSuggestions(term);
68
+ if (Array.isArray(suggestions)) {
69
+ for (const s of suggestions) {
70
+ const text = (typeof s === "string" ? s : s?.term || "").toLowerCase();
71
+ if (text && !keywordPool.has(text)) {
72
+ keywordPool.set(text, { traffic: 0, difficulty: 0, source: "autocomplete" });
73
+ }
74
+ }
75
+ }
76
+ }
77
+ catch {
78
+ // continue
79
+ }
80
+ }
81
+ // Add features themselves
82
+ for (const f of features) {
83
+ const fl = f.toLowerCase().trim();
84
+ if (!keywordPool.has(fl)) {
85
+ keywordPool.set(fl, { traffic: 0, difficulty: 0, source: "app-feature" });
86
+ }
87
+ }
88
+ // Score keywords (in parallel)
89
+ const poolEntries = [...keywordPool.entries()].slice(0, 40);
90
+ const batchScores = await batchGetScores(poolEntries.map(([kw]) => kw), primaryCountry);
91
+ const scoreMap = new Map(batchScores.map((s) => [s.keyword, s]));
92
+ const scoredPool = [];
93
+ for (const [kw, data] of poolEntries) {
94
+ const scores = scoreMap.get(kw) || { traffic: 0, difficulty: 0 };
95
+ const opp = calculateOpportunityScore(scores.traffic, scores.difficulty);
96
+ scoredPool.push({
97
+ keyword: kw,
98
+ traffic: scores.traffic,
99
+ difficulty: scores.difficulty,
100
+ opportunityScore: Math.round(opp * 10) / 10,
101
+ source: data.source,
102
+ });
103
+ }
104
+ scoredPool.sort((a, b) => b.opportunityScore - a.opportunityScore);
105
+ // ─── 2. Competitor analysis ───
106
+ const competitorData = [];
107
+ // Known competitors
108
+ for (const cId of competitorAppIds.slice(0, 3)) {
109
+ try {
110
+ const comp = await getAppDetails(cId, primaryCountry);
111
+ competitorData.push({
112
+ title: comp.title || "",
113
+ subtitle: comp.subtitle || "",
114
+ developer: comp.developer || "",
115
+ rating: comp.score || 0,
116
+ reviews: comp.reviews || 0,
117
+ titleKeywords: extractTitleKeywords(comp.title || ""),
118
+ titleLength: (comp.title || "").length,
119
+ });
120
+ }
121
+ catch {
122
+ // continue
123
+ }
124
+ }
125
+ // Also add top search results as competitors
126
+ if (competitorData.length < 5) {
127
+ try {
128
+ const topApps = await searchApps(features[0] || category, primaryCountry, 5);
129
+ for (const app of topApps) {
130
+ const a = app;
131
+ if (competitorData.length >= 5)
132
+ break;
133
+ if (competitorData.some((c) => c.title === a.title))
134
+ continue;
135
+ competitorData.push({
136
+ title: a.title || "",
137
+ subtitle: "",
138
+ developer: a.developer || "",
139
+ rating: a.score || 0,
140
+ reviews: a.reviews || 0,
141
+ titleKeywords: extractTitleKeywords(a.title || ""),
142
+ titleLength: (a.title || "").length,
143
+ });
144
+ }
145
+ }
146
+ catch {
147
+ // continue
148
+ }
149
+ }
150
+ // Competitor keyword patterns
151
+ const competitorKeywordFreq = {};
152
+ for (const comp of competitorData) {
153
+ for (const kw of comp.titleKeywords) {
154
+ competitorKeywordFreq[kw] = (competitorKeywordFreq[kw] || 0) + 1;
155
+ }
156
+ }
157
+ const commonCompetitorKeywords = Object.entries(competitorKeywordFreq)
158
+ .filter(([, count]) => count >= 2)
159
+ .sort((a, b) => b[1] - a[1])
160
+ .map(([kw]) => kw);
161
+ const avgCompetitorTitleLength = competitorData.length > 0
162
+ ? Math.round(competitorData.reduce((s, c) => s + c.titleLength, 0) /
163
+ competitorData.length)
164
+ : 0;
165
+ // ─── 3. Competition level ───
166
+ const competitiveScore = calculateCompetitiveScore(competitorData.map((c) => ({
167
+ rating: c.rating,
168
+ reviews: c.reviews,
169
+ free: true,
170
+ })));
171
+ // ─── 4. Title/Subtitle/Keyword field suggestions ───
172
+ const topKeywords = scoredPool
173
+ .filter((k) => k.traffic > 0)
174
+ .slice(0, 20);
175
+ // Highest traffic keywords for title
176
+ const titleCandidates = topKeywords
177
+ .slice(0, 5)
178
+ .map((k) => k.keyword);
179
+ // Next keywords for subtitle
180
+ const subtitleCandidates = topKeywords
181
+ .slice(3, 10)
182
+ .map((k) => k.keyword);
183
+ // Remaining for keyword field
184
+ const usedInTitleSubtitle = new Set([
185
+ ...titleCandidates,
186
+ ...subtitleCandidates,
187
+ ]);
188
+ const keywordFieldCandidates = topKeywords
189
+ .filter((k) => !usedInTitleSubtitle.has(k.keyword))
190
+ .map((k) => k.keyword);
191
+ // ─── 5. Multi-market analysis ───
192
+ const marketAnalysis = [];
193
+ for (const c of countries) {
194
+ if (c === primaryCountry) {
195
+ marketAnalysis.push({
196
+ country: c,
197
+ countryName: getCountryName(c),
198
+ topKeywords: topKeywords.slice(0, 10).map((k) => ({
199
+ keyword: k.keyword,
200
+ traffic: k.traffic,
201
+ difficulty: k.difficulty,
202
+ })),
203
+ });
204
+ continue;
205
+ }
206
+ const marketKws = [];
207
+ for (const kw of topKeywords.slice(0, 8)) {
208
+ try {
209
+ const scores = await getScores(kw.keyword, c);
210
+ marketKws.push({
211
+ keyword: kw.keyword,
212
+ traffic: scores.traffic,
213
+ difficulty: scores.difficulty,
214
+ });
215
+ }
216
+ catch {
217
+ marketKws.push({ keyword: kw.keyword, traffic: 0, difficulty: 0 });
218
+ }
219
+ }
220
+ marketAnalysis.push({
221
+ country: c,
222
+ countryName: getCountryName(c),
223
+ topKeywords: marketKws,
224
+ });
225
+ }
226
+ // ─── 6. Build brief ───
227
+ const result = {
228
+ appName,
229
+ category,
230
+ targetAudience,
231
+ features,
232
+ countries: countries.map((c) => ({ code: c, name: getCountryName(c) })),
233
+ primaryCountry,
234
+ competitiveAnalysis: {
235
+ competitiveScore: Math.round(competitiveScore * 10) / 10,
236
+ level: competitiveScore > 7
237
+ ? "High competition"
238
+ : competitiveScore > 4
239
+ ? "Medium competition"
240
+ : "Low competition",
241
+ competitors: competitorData,
242
+ commonCompetitorKeywords,
243
+ avgCompetitorTitleLength,
244
+ },
245
+ keywordPool: {
246
+ total: scoredPool.length,
247
+ topOpportunities: scoredPool.filter((k) => k.opportunityScore >= 6).slice(0, 15),
248
+ allKeywords: scoredPool,
249
+ },
250
+ metadataGuidelines: {
251
+ title: {
252
+ maxLength: CHAR_LIMITS.TITLE,
253
+ recommendation: `"${appName}" + highest traffic keyword. Competitors use ${avgCompetitorTitleLength} chars on average.`,
254
+ candidateKeywords: titleCandidates,
255
+ pattern: `${appName} - [keyword1] [keyword2]`,
256
+ examples: competitorData.slice(0, 3).map((c) => c.title),
257
+ },
258
+ subtitle: {
259
+ maxLength: CHAR_LIMITS.SUBTITLE,
260
+ recommendation: "Use high traffic keywords that are not in the title.",
261
+ candidateKeywords: subtitleCandidates,
262
+ },
263
+ keywordField: {
264
+ maxLength: CHAR_LIMITS.KEYWORD_FIELD,
265
+ recommendation: "Separate keywords not in title and subtitle with commas. Do not use spaces.",
266
+ candidateKeywords: keywordFieldCandidates,
267
+ },
268
+ description: {
269
+ recommendation: "First 3 sentences are critical — place the most important keywords here. Apple now also uses the description for keyword analysis.",
270
+ mustIncludeKeywords: topKeywords.slice(0, 8).map((k) => k.keyword),
271
+ },
272
+ },
273
+ marketAnalysis,
274
+ actionPlan: [
275
+ `1. Create title: "${appName}" + [${titleCandidates.slice(0, 2).join(", ")}] (max ${CHAR_LIMITS.TITLE} chars)`,
276
+ `2. Create subtitle: [${subtitleCandidates.slice(0, 3).join(", ")}] (max ${CHAR_LIMITS.SUBTITLE} chars)`,
277
+ `3. Fill keyword field: ${keywordFieldCandidates.slice(0, 5).join(",")} (max ${CHAR_LIMITS.KEYWORD_FIELD} chars, comma-separated)`,
278
+ `4. Write description: Use [${topKeywords.slice(0, 3).map((k) => k.keyword).join(", ")}] keywords in the first 3 sentences`,
279
+ `5. ${countries.length > 1 ? `Localize for ${countries.length} markets` : "Optimize for single market"}`,
280
+ `6. Follow competitor patterns: ${commonCompetitorKeywords.slice(0, 5).join(", ") || "unique space"}`,
281
+ ],
282
+ };
283
+ const resultText = JSON.stringify(result, null, 2);
284
+ setCache(cacheKey, resultText, CACHE_TTL.KEYWORD_SCORES);
285
+ return { content: [{ type: "text", text: resultText }] };
286
+ }
287
+ catch (error) {
288
+ return {
289
+ content: [{ type: "text", text: `Error: ${error.message}` }],
290
+ isError: true,
291
+ };
292
+ }
293
+ });
294
+ }
295
+ //# sourceMappingURL=generate-aso-brief.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-aso-brief.js","sourceRoot":"","sources":["../../src/tools/generate-aso-brief.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGetAppDetails(server: McpServer): void;
3
+ //# sourceMappingURL=get-app-details.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-app-details.d.ts","sourceRoot":"","sources":["../../src/tools/get-app-details.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QA8FtD"}
@@ -0,0 +1,89 @@
1
+ import { z } from "zod";
2
+ import { getAppDetails, getSimilarApps } from "../data-sources/app-store.js";
3
+ import { getFromCache, setCache } from "../cache/sqlite-cache.js";
4
+ import { CACHE_TTL, CHAR_LIMITS } from "../utils/constants.js";
5
+ export function registerGetAppDetails(server) {
6
+ server.tool("get_app_details", "Retrieves all ASO-relevant information for a single app: title, description, rating, reviews, similar apps, and metadata analysis.", {
7
+ appId: z
8
+ .string()
9
+ .describe("App Store app ID or bundle ID (e.g. '324684580' or 'com.spotify.client')"),
10
+ country: z
11
+ .string()
12
+ .default("tr")
13
+ .describe("Country code (tr, us, de, gb, fr...)"),
14
+ includeSimilar: z
15
+ .boolean()
16
+ .default(true)
17
+ .describe("Also fetch similar apps"),
18
+ }, async ({ appId, country, includeSimilar }) => {
19
+ const cacheKey = `app:${appId}:${country}:${includeSimilar}`;
20
+ const cached = getFromCache(cacheKey);
21
+ if (cached) {
22
+ return { content: [{ type: "text", text: cached }] };
23
+ }
24
+ try {
25
+ const app = await getAppDetails(appId, country);
26
+ let similarApps = [];
27
+ if (includeSimilar && app.id) {
28
+ try {
29
+ similarApps = await getSimilarApps(app.id, country);
30
+ }
31
+ catch {
32
+ // Continue if similar apps cannot be fetched
33
+ }
34
+ }
35
+ const titleLength = (app.title || "").length;
36
+ const descriptionWords = (app.description || "")
37
+ .split(/\s+/)
38
+ .filter(Boolean).length;
39
+ const result = {
40
+ app: {
41
+ id: app.id,
42
+ appId: app.appId,
43
+ title: app.title,
44
+ url: app.url,
45
+ description: app.description,
46
+ developer: app.developer,
47
+ developerId: app.developerId,
48
+ score: app.score,
49
+ reviews: app.reviews,
50
+ ratings: app.ratings,
51
+ histogram: app.histogram,
52
+ price: app.price,
53
+ free: app.free,
54
+ currency: app.currency,
55
+ genre: app.genre,
56
+ genreId: app.genreId,
57
+ icon: app.icon,
58
+ released: app.released,
59
+ updated: app.updated,
60
+ version: app.version,
61
+ size: app.size,
62
+ },
63
+ metadataAnalysis: {
64
+ titleLength,
65
+ titleLimitRemaining: CHAR_LIMITS.TITLE - titleLength,
66
+ titleOptimal: titleLength <= CHAR_LIMITS.TITLE,
67
+ descriptionWordCount: descriptionWords,
68
+ },
69
+ similarApps: similarApps.slice(0, 10).map((s) => ({
70
+ title: s.title,
71
+ developer: s.developer,
72
+ rating: s.score,
73
+ reviews: s.reviews,
74
+ url: s.url,
75
+ })),
76
+ };
77
+ const resultText = JSON.stringify(result, null, 2);
78
+ setCache(cacheKey, resultText, CACHE_TTL.APP_DETAILS);
79
+ return { content: [{ type: "text", text: resultText }] };
80
+ }
81
+ catch (error) {
82
+ return {
83
+ content: [{ type: "text", text: `Error: ${error.message}` }],
84
+ isError: true,
85
+ };
86
+ }
87
+ });
88
+ }
89
+ //# sourceMappingURL=get-app-details.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-app-details.js","sourceRoot":"","sources":["../../src/tools/get-app-details.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGetAsoReport(server: McpServer): void;
3
+ //# sourceMappingURL=get-aso-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-aso-report.d.ts","sourceRoot":"","sources":["../../src/tools/get-aso-report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmBpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,QAkMrD"}