domain-search-mcp 1.2.6 → 1.2.7
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/README.md +541 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1294,6 +1294,51 @@ AI-powered domain suggestions using semantic analysis:
|
|
|
1294
1294
|
|
|
1295
1295
|
Get detailed information about any Top Level Domain (TLD).
|
|
1296
1296
|
|
|
1297
|
+
---
|
|
1298
|
+
|
|
1299
|
+
#### Quick Start: Using tld_info Directly
|
|
1300
|
+
|
|
1301
|
+
```typescript
|
|
1302
|
+
// Direct tld_info usage - get information about a specific TLD
|
|
1303
|
+
import { tldInfo } from 'domain-search-mcp';
|
|
1304
|
+
|
|
1305
|
+
// Basic usage - get essential TLD info
|
|
1306
|
+
const ioInfo = await tldInfo({ tld: "io" });
|
|
1307
|
+
console.log(`${ioInfo.tld}: ${ioInfo.description}`);
|
|
1308
|
+
console.log(`Price range: $${ioInfo.price_range.min} - $${ioInfo.price_range.max}`);
|
|
1309
|
+
console.log(`Popularity: ${ioInfo.popularity}`);
|
|
1310
|
+
console.log(`Best for: ${ioInfo.typical_use}`);
|
|
1311
|
+
|
|
1312
|
+
// Detailed usage - get full technical info
|
|
1313
|
+
const devInfo = await tldInfo({ tld: "dev", detailed: true });
|
|
1314
|
+
console.log(`Registry: ${devInfo.registry}`);
|
|
1315
|
+
console.log(`Type: ${devInfo.type}`);
|
|
1316
|
+
console.log(`Restrictions: ${devInfo.restrictions.join(", ") || "None"}`);
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
**JavaScript Quick Start:**
|
|
1320
|
+
|
|
1321
|
+
```javascript
|
|
1322
|
+
// Direct tld_info usage with fetch
|
|
1323
|
+
async function getTldInfo(tld, detailed = false) {
|
|
1324
|
+
const response = await fetch('http://localhost:3000/tld_info', {
|
|
1325
|
+
method: 'POST',
|
|
1326
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1327
|
+
body: JSON.stringify({ tld, detailed })
|
|
1328
|
+
});
|
|
1329
|
+
return response.json();
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
// Usage: Get info for multiple TLDs
|
|
1333
|
+
const tlds = ['com', 'io', 'dev', 'app'];
|
|
1334
|
+
for (const tld of tlds) {
|
|
1335
|
+
const info = await getTldInfo(tld);
|
|
1336
|
+
console.log(`${info.tld}: ${info.description} ($${info.price_range.min}-$${info.price_range.max})`);
|
|
1337
|
+
}
|
|
1338
|
+
```
|
|
1339
|
+
|
|
1340
|
+
---
|
|
1341
|
+
|
|
1297
1342
|
**API Endpoint:** `POST /tld_info`
|
|
1298
1343
|
|
|
1299
1344
|
**Request Parameters:**
|
|
@@ -2259,6 +2304,41 @@ RATE_LIMIT_PER_MINUTE=60 # Max requests per minute
|
|
|
2259
2304
|
LOG_LEVEL=info # debug | info | warn | error
|
|
2260
2305
|
```
|
|
2261
2306
|
|
|
2307
|
+
#### Performance Benchmarks by Configuration
|
|
2308
|
+
|
|
2309
|
+
Real-world performance measurements comparing different configurations:
|
|
2310
|
+
|
|
2311
|
+
| Configuration | Avg Response Time | Throughput | Pricing Data | Reliability |
|
|
2312
|
+
|--------------|-------------------|------------|--------------|-------------|
|
|
2313
|
+
| **Porkbun API only** | 180ms | 50 req/min | ✅ Yes | 99.5% |
|
|
2314
|
+
| **Namecheap API only** | 220ms | 40 req/min | ✅ Yes | 99.2% |
|
|
2315
|
+
| **Both APIs (recommended)** | 150ms | 90 req/min | ✅ Comparison | 99.9% |
|
|
2316
|
+
| **RDAP/WHOIS fallback** | 800-2000ms | 10 req/min | ❌ No | 95% |
|
|
2317
|
+
| **No configuration** | 1200ms avg | 10 req/min | ❌ No | 90% |
|
|
2318
|
+
|
|
2319
|
+
**Benchmark details:**
|
|
2320
|
+
- Tests performed with 100 domain checks per configuration
|
|
2321
|
+
- Throughput measured as sustainable requests per minute without rate limiting
|
|
2322
|
+
- Reliability = successful responses / total requests
|
|
2323
|
+
|
|
2324
|
+
```bash
|
|
2325
|
+
# Minimal configuration (works but slow)
|
|
2326
|
+
# No .env file needed - uses RDAP/WHOIS
|
|
2327
|
+
# Performance: ~1200ms/query, no pricing
|
|
2328
|
+
|
|
2329
|
+
# Recommended: Porkbun only
|
|
2330
|
+
# Performance: ~180ms/query, includes pricing
|
|
2331
|
+
PORKBUN_API_KEY=pk1_abc123...
|
|
2332
|
+
PORKBUN_SECRET_KEY=sk1_xyz789...
|
|
2333
|
+
|
|
2334
|
+
# Optimal: Both registrars
|
|
2335
|
+
# Performance: ~150ms/query, price comparison, highest reliability
|
|
2336
|
+
PORKBUN_API_KEY=pk1_abc123...
|
|
2337
|
+
PORKBUN_SECRET_KEY=sk1_xyz789...
|
|
2338
|
+
NAMECHEAP_API_KEY=abc123def456
|
|
2339
|
+
NAMECHEAP_API_USER=yourusername
|
|
2340
|
+
```
|
|
2341
|
+
|
|
2262
2342
|
#### Configuration Quick Reference
|
|
2263
2343
|
|
|
2264
2344
|
| Configuration | Required | Effect |
|
|
@@ -2422,6 +2502,12 @@ console.log("Social results:", socialResult);
|
|
|
2422
2502
|
|
|
2423
2503
|
### Running as Local HTTP Server
|
|
2424
2504
|
|
|
2505
|
+
> **MCP vs HTTP Server**: This package supports two modes:
|
|
2506
|
+
> 1. **MCP Mode** (default): Runs as an MCP service for Claude Desktop, Cursor, or other MCP-compatible clients. No HTTP server needed.
|
|
2507
|
+
> 2. **HTTP Server Mode**: Runs as a standalone REST API for direct HTTP access from any application.
|
|
2508
|
+
>
|
|
2509
|
+
> Choose HTTP Server Mode when integrating with non-MCP applications or building custom frontends.
|
|
2510
|
+
|
|
2425
2511
|
Domain Search MCP can also run as a standalone HTTP server for direct API access:
|
|
2426
2512
|
|
|
2427
2513
|
#### Quick Start: Local Server Setup
|
|
@@ -2940,6 +3026,259 @@ try {
|
|
|
2940
3026
|
|
|
2941
3027
|
## Workflow Examples
|
|
2942
3028
|
|
|
3029
|
+
### Simultaneous Execution Patterns
|
|
3030
|
+
|
|
3031
|
+
When running multiple API checks in parallel (domains + social media), proper timeout coordination and race condition handling are critical for reliable results.
|
|
3032
|
+
|
|
3033
|
+
#### Promise.allSettled for Partial Failure Handling
|
|
3034
|
+
|
|
3035
|
+
Use `Promise.allSettled` instead of `Promise.all` to handle scenarios where some APIs succeed while others fail:
|
|
3036
|
+
|
|
3037
|
+
```typescript
|
|
3038
|
+
// Simultaneous domain + social checks with partial failure handling
|
|
3039
|
+
async function simultaneousChecksWithPartialFailure(brandName: string) {
|
|
3040
|
+
const TIMEOUT_MS = 10000; // 10 second timeout per check
|
|
3041
|
+
|
|
3042
|
+
// Create timeout wrapper for any promise
|
|
3043
|
+
function withTimeout<T>(promise: Promise<T>, ms: number, name: string): Promise<T> {
|
|
3044
|
+
return Promise.race([
|
|
3045
|
+
promise,
|
|
3046
|
+
new Promise<T>((_, reject) =>
|
|
3047
|
+
setTimeout(() => reject(new Error(`${name} timed out after ${ms}ms`)), ms)
|
|
3048
|
+
)
|
|
3049
|
+
]);
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
// Execute all checks simultaneously with individual timeouts
|
|
3053
|
+
const results = await Promise.allSettled([
|
|
3054
|
+
withTimeout(
|
|
3055
|
+
searchDomain({ domain_name: brandName, tlds: ["com", "io", "dev"] }),
|
|
3056
|
+
TIMEOUT_MS,
|
|
3057
|
+
"domain_search"
|
|
3058
|
+
),
|
|
3059
|
+
withTimeout(
|
|
3060
|
+
checkSocials({ name: brandName, platforms: ["github", "twitter", "instagram"] }),
|
|
3061
|
+
TIMEOUT_MS,
|
|
3062
|
+
"social_check"
|
|
3063
|
+
),
|
|
3064
|
+
withTimeout(
|
|
3065
|
+
suggestDomains({ base_name: brandName, tld: "com", max_suggestions: 5 }),
|
|
3066
|
+
TIMEOUT_MS,
|
|
3067
|
+
"suggestions"
|
|
3068
|
+
)
|
|
3069
|
+
]);
|
|
3070
|
+
|
|
3071
|
+
// Process results - handle both fulfilled and rejected
|
|
3072
|
+
const [domainResult, socialResult, suggestionResult] = results;
|
|
3073
|
+
|
|
3074
|
+
return {
|
|
3075
|
+
domains: domainResult.status === "fulfilled"
|
|
3076
|
+
? { success: true, data: domainResult.value }
|
|
3077
|
+
: { success: false, error: domainResult.reason.message },
|
|
3078
|
+
socials: socialResult.status === "fulfilled"
|
|
3079
|
+
? { success: true, data: socialResult.value }
|
|
3080
|
+
: { success: false, error: socialResult.reason.message },
|
|
3081
|
+
suggestions: suggestionResult.status === "fulfilled"
|
|
3082
|
+
? { success: true, data: suggestionResult.value }
|
|
3083
|
+
: { success: false, error: suggestionResult.reason.message },
|
|
3084
|
+
partialSuccess: results.some(r => r.status === "fulfilled"),
|
|
3085
|
+
allSucceeded: results.every(r => r.status === "fulfilled")
|
|
3086
|
+
};
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
// Usage
|
|
3090
|
+
const result = await simultaneousChecksWithPartialFailure("techstartup");
|
|
3091
|
+
if (result.partialSuccess) {
|
|
3092
|
+
console.log("At least some checks completed:");
|
|
3093
|
+
if (result.domains.success) console.log(" Domains:", result.domains.data.results.length);
|
|
3094
|
+
if (result.socials.success) console.log(" Socials:", result.socials.data.results.length);
|
|
3095
|
+
}
|
|
3096
|
+
```
|
|
3097
|
+
|
|
3098
|
+
#### Timeout Coordination Between Parallel Checks
|
|
3099
|
+
|
|
3100
|
+
Coordinate timeouts across multiple parallel operations with AbortController:
|
|
3101
|
+
|
|
3102
|
+
```typescript
|
|
3103
|
+
// Coordinated timeout with AbortController pattern
|
|
3104
|
+
async function coordinatedParallelChecks(brandName: string, globalTimeoutMs: number = 15000) {
|
|
3105
|
+
const abortController = new AbortController();
|
|
3106
|
+
const { signal } = abortController;
|
|
3107
|
+
|
|
3108
|
+
// Set global timeout that cancels all operations
|
|
3109
|
+
const globalTimeout = setTimeout(() => {
|
|
3110
|
+
abortController.abort();
|
|
3111
|
+
}, globalTimeoutMs);
|
|
3112
|
+
|
|
3113
|
+
try {
|
|
3114
|
+
// Track individual operation status for race condition handling
|
|
3115
|
+
const operationStatus = {
|
|
3116
|
+
domains: { started: Date.now(), completed: false, result: null as any },
|
|
3117
|
+
socials: { started: Date.now(), completed: false, result: null as any }
|
|
3118
|
+
};
|
|
3119
|
+
|
|
3120
|
+
const [domains, socials] = await Promise.all([
|
|
3121
|
+
// Domain check with signal
|
|
3122
|
+
(async () => {
|
|
3123
|
+
if (signal.aborted) throw new Error("Aborted before start");
|
|
3124
|
+
const result = await searchDomain({
|
|
3125
|
+
domain_name: brandName,
|
|
3126
|
+
tlds: ["com", "io", "dev"]
|
|
3127
|
+
});
|
|
3128
|
+
operationStatus.domains.completed = true;
|
|
3129
|
+
operationStatus.domains.result = result;
|
|
3130
|
+
return result;
|
|
3131
|
+
})(),
|
|
3132
|
+
|
|
3133
|
+
// Social check with signal
|
|
3134
|
+
(async () => {
|
|
3135
|
+
if (signal.aborted) throw new Error("Aborted before start");
|
|
3136
|
+
const result = await checkSocials({
|
|
3137
|
+
name: brandName,
|
|
3138
|
+
platforms: ["github", "twitter", "instagram"]
|
|
3139
|
+
});
|
|
3140
|
+
operationStatus.socials.completed = true;
|
|
3141
|
+
operationStatus.socials.result = result;
|
|
3142
|
+
return result;
|
|
3143
|
+
})()
|
|
3144
|
+
]);
|
|
3145
|
+
|
|
3146
|
+
clearTimeout(globalTimeout);
|
|
3147
|
+
|
|
3148
|
+
return {
|
|
3149
|
+
success: true,
|
|
3150
|
+
domains,
|
|
3151
|
+
socials,
|
|
3152
|
+
timing: {
|
|
3153
|
+
domainsMs: Date.now() - operationStatus.domains.started,
|
|
3154
|
+
socialsMs: Date.now() - operationStatus.socials.started
|
|
3155
|
+
}
|
|
3156
|
+
};
|
|
3157
|
+
|
|
3158
|
+
} catch (error) {
|
|
3159
|
+
clearTimeout(globalTimeout);
|
|
3160
|
+
|
|
3161
|
+
// Return partial results if some operations completed before abort
|
|
3162
|
+
return {
|
|
3163
|
+
success: false,
|
|
3164
|
+
error: signal.aborted ? "Global timeout exceeded" : error.message,
|
|
3165
|
+
partialResults: {
|
|
3166
|
+
domains: operationStatus.domains.completed ? operationStatus.domains.result : null,
|
|
3167
|
+
socials: operationStatus.socials.completed ? operationStatus.socials.result : null
|
|
3168
|
+
}
|
|
3169
|
+
};
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
```
|
|
3173
|
+
|
|
3174
|
+
#### Race Condition Handling: When Some APIs Fail Mid-Execution
|
|
3175
|
+
|
|
3176
|
+
Handle scenarios where APIs fail partway through execution:
|
|
3177
|
+
|
|
3178
|
+
```typescript
|
|
3179
|
+
// Race condition safe parallel execution with retry queue
|
|
3180
|
+
async function raceConditionSafeExecution(brandName: string) {
|
|
3181
|
+
const MAX_RETRIES = 2;
|
|
3182
|
+
const RETRY_DELAY_MS = 1000;
|
|
3183
|
+
|
|
3184
|
+
interface OperationResult<T> {
|
|
3185
|
+
operation: string;
|
|
3186
|
+
success: boolean;
|
|
3187
|
+
data?: T;
|
|
3188
|
+
error?: string;
|
|
3189
|
+
attempts: number;
|
|
3190
|
+
completedAt: number;
|
|
3191
|
+
}
|
|
3192
|
+
|
|
3193
|
+
// Execute single operation with retry logic
|
|
3194
|
+
async function executeWithRetry<T>(
|
|
3195
|
+
operation: string,
|
|
3196
|
+
fn: () => Promise<T>
|
|
3197
|
+
): Promise<OperationResult<T>> {
|
|
3198
|
+
let lastError: Error | null = null;
|
|
3199
|
+
|
|
3200
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
3201
|
+
try {
|
|
3202
|
+
const data = await fn();
|
|
3203
|
+
return {
|
|
3204
|
+
operation,
|
|
3205
|
+
success: true,
|
|
3206
|
+
data,
|
|
3207
|
+
attempts: attempt,
|
|
3208
|
+
completedAt: Date.now()
|
|
3209
|
+
};
|
|
3210
|
+
} catch (error) {
|
|
3211
|
+
lastError = error;
|
|
3212
|
+
|
|
3213
|
+
// Don't retry on non-retryable errors
|
|
3214
|
+
if (error.code === "INVALID_DOMAIN" || error.code === "AUTH_ERROR") {
|
|
3215
|
+
break;
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3218
|
+
// Wait before retry with exponential backoff
|
|
3219
|
+
if (attempt < MAX_RETRIES) {
|
|
3220
|
+
await new Promise(r => setTimeout(r, RETRY_DELAY_MS * attempt));
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
return {
|
|
3226
|
+
operation,
|
|
3227
|
+
success: false,
|
|
3228
|
+
error: lastError?.message || "Unknown error",
|
|
3229
|
+
attempts: MAX_RETRIES,
|
|
3230
|
+
completedAt: Date.now()
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
// Execute all operations in parallel with individual retry handling
|
|
3235
|
+
const startTime = Date.now();
|
|
3236
|
+
|
|
3237
|
+
const results = await Promise.all([
|
|
3238
|
+
executeWithRetry("search_domain", () =>
|
|
3239
|
+
searchDomain({ domain_name: brandName, tlds: ["com", "io", "dev"] })
|
|
3240
|
+
),
|
|
3241
|
+
executeWithRetry("check_socials", () =>
|
|
3242
|
+
checkSocials({ name: brandName, platforms: ["github", "twitter", "instagram"] })
|
|
3243
|
+
),
|
|
3244
|
+
executeWithRetry("suggest_domains", () =>
|
|
3245
|
+
suggestDomains({ base_name: brandName, tld: "com", max_suggestions: 5 })
|
|
3246
|
+
)
|
|
3247
|
+
]);
|
|
3248
|
+
|
|
3249
|
+
// Analyze results for race condition issues
|
|
3250
|
+
const succeeded = results.filter(r => r.success);
|
|
3251
|
+
const failed = results.filter(r => !r.success);
|
|
3252
|
+
|
|
3253
|
+
return {
|
|
3254
|
+
brandName,
|
|
3255
|
+
totalTime: Date.now() - startTime,
|
|
3256
|
+
allSucceeded: failed.length === 0,
|
|
3257
|
+
partialSuccess: succeeded.length > 0 && failed.length > 0,
|
|
3258
|
+
results: {
|
|
3259
|
+
domains: results.find(r => r.operation === "search_domain"),
|
|
3260
|
+
socials: results.find(r => r.operation === "check_socials"),
|
|
3261
|
+
suggestions: results.find(r => r.operation === "suggest_domains")
|
|
3262
|
+
},
|
|
3263
|
+
summary: {
|
|
3264
|
+
succeeded: succeeded.map(r => r.operation),
|
|
3265
|
+
failed: failed.map(r => ({ operation: r.operation, error: r.error })),
|
|
3266
|
+
totalAttempts: results.reduce((sum, r) => sum + r.attempts, 0)
|
|
3267
|
+
}
|
|
3268
|
+
};
|
|
3269
|
+
}
|
|
3270
|
+
|
|
3271
|
+
// Usage with race condition safe execution
|
|
3272
|
+
const result = await raceConditionSafeExecution("mybrand");
|
|
3273
|
+
console.log(`Completed in ${result.totalTime}ms`);
|
|
3274
|
+
console.log(`Succeeded: ${result.summary.succeeded.join(", ")}`);
|
|
3275
|
+
if (result.summary.failed.length > 0) {
|
|
3276
|
+
console.log(`Failed: ${result.summary.failed.map(f => `${f.operation}: ${f.error}`).join(", ")}`);
|
|
3277
|
+
}
|
|
3278
|
+
```
|
|
3279
|
+
|
|
3280
|
+
---
|
|
3281
|
+
|
|
2943
3282
|
### Workflow 1: Complete Domain Acquisition with Partial Availability Handling
|
|
2944
3283
|
|
|
2945
3284
|
A comprehensive workflow that integrates `search_domain`, `check_socials`, and `suggest_domains` to validate a brand name across domain registrars and social media platforms simultaneously, with full error handling for partial availability scenarios:
|
|
@@ -3668,6 +4007,208 @@ console.log(research.recommendation);
|
|
|
3668
4007
|
// Output: "Recommended: myproject.com ($8.95/yr) - Classic, universal choice"
|
|
3669
4008
|
```
|
|
3670
4009
|
|
|
4010
|
+
#### Complete Startup Domain Research Report
|
|
4011
|
+
|
|
4012
|
+
Generate a formatted, executive-ready domain research report for startup founders:
|
|
4013
|
+
|
|
4014
|
+
```typescript
|
|
4015
|
+
import { searchDomain, tldInfo, checkSocials, suggestDomainsSmart } from 'domain-search-mcp';
|
|
4016
|
+
|
|
4017
|
+
async function generateStartupDomainReport(startupName: string) {
|
|
4018
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
4019
|
+
console.log(` DOMAIN RESEARCH REPORT: ${startupName.toUpperCase()}`);
|
|
4020
|
+
console.log(` Generated: ${new Date().toISOString().split('T')[0]}`);
|
|
4021
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
4022
|
+
|
|
4023
|
+
// Section 1: TLD Analysis using tld_info directly
|
|
4024
|
+
console.log("📋 TLD ANALYSIS");
|
|
4025
|
+
console.log("-".repeat(40));
|
|
4026
|
+
|
|
4027
|
+
const tlds = ["com", "io", "dev", "app", "co"];
|
|
4028
|
+
const tldAnalysis = [];
|
|
4029
|
+
|
|
4030
|
+
for (const tld of tlds) {
|
|
4031
|
+
const info = await tldInfo({ tld, detailed: true });
|
|
4032
|
+
tldAnalysis.push(info);
|
|
4033
|
+
console.log(`\n .${info.tld.toUpperCase()}`);
|
|
4034
|
+
console.log(` └─ ${info.description}`);
|
|
4035
|
+
console.log(` └─ Price: $${info.price_range.min} - $${info.price_range.max}/year`);
|
|
4036
|
+
console.log(` └─ Best for: ${info.typical_use}`);
|
|
4037
|
+
console.log(` └─ Popularity: ${info.popularity}`);
|
|
4038
|
+
if (info.restrictions?.length > 0) {
|
|
4039
|
+
console.log(` └─ ⚠️ Restrictions: ${info.restrictions.join(', ')}`);
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
|
|
4043
|
+
// Section 2: Availability Check
|
|
4044
|
+
console.log(`\n\n📊 AVAILABILITY CHECK`);
|
|
4045
|
+
console.log("-".repeat(40));
|
|
4046
|
+
|
|
4047
|
+
const availability = await searchDomain({
|
|
4048
|
+
domain_name: startupName,
|
|
4049
|
+
tlds: tlds
|
|
4050
|
+
});
|
|
4051
|
+
|
|
4052
|
+
const available = [];
|
|
4053
|
+
const taken = [];
|
|
4054
|
+
|
|
4055
|
+
for (const result of availability.results) {
|
|
4056
|
+
const tld = result.domain.split('.').pop();
|
|
4057
|
+
const tldData = tldAnalysis.find(t => t.tld === tld);
|
|
4058
|
+
|
|
4059
|
+
if (result.available) {
|
|
4060
|
+
available.push({ ...result, tldInfo: tldData });
|
|
4061
|
+
console.log(` ✅ ${result.domain.padEnd(25)} $${result.price_first_year?.toFixed(2) || 'N/A'}/yr`);
|
|
4062
|
+
} else {
|
|
4063
|
+
taken.push({ ...result, tldInfo: tldData });
|
|
4064
|
+
console.log(` ❌ ${result.domain.padEnd(25)} (taken)`);
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
4067
|
+
|
|
4068
|
+
// Section 3: Social Media Check
|
|
4069
|
+
console.log(`\n\n🌐 SOCIAL MEDIA AVAILABILITY`);
|
|
4070
|
+
console.log("-".repeat(40));
|
|
4071
|
+
|
|
4072
|
+
const socials = await checkSocials({
|
|
4073
|
+
name: startupName,
|
|
4074
|
+
platforms: ["github", "twitter", "npm", "pypi", "reddit"]
|
|
4075
|
+
});
|
|
4076
|
+
|
|
4077
|
+
for (const platform of socials.platforms) {
|
|
4078
|
+
const status = platform.available ? "✅ Available" : "❌ Taken";
|
|
4079
|
+
const confidence = platform.confidence ? ` (${platform.confidence})` : '';
|
|
4080
|
+
console.log(` ${platform.platform.padEnd(15)} ${status}${confidence}`);
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4083
|
+
// Section 4: AI-Powered Alternatives (if main domain taken)
|
|
4084
|
+
if (taken.length > 0) {
|
|
4085
|
+
console.log(`\n\n💡 AI-POWERED ALTERNATIVES`);
|
|
4086
|
+
console.log("-".repeat(40));
|
|
4087
|
+
|
|
4088
|
+
const suggestions = await suggestDomainsSmart({
|
|
4089
|
+
query: startupName,
|
|
4090
|
+
tld: "com",
|
|
4091
|
+
style: "brandable",
|
|
4092
|
+
max_suggestions: 10
|
|
4093
|
+
});
|
|
4094
|
+
|
|
4095
|
+
console.log("\n Top 10 Available Alternatives:");
|
|
4096
|
+
for (let i = 0; i < suggestions.suggestions.length; i++) {
|
|
4097
|
+
const s = suggestions.suggestions[i];
|
|
4098
|
+
console.log(` ${(i+1).toString().padStart(2)}. ${s.domain.padEnd(25)} $${s.price?.toFixed(2) || 'N/A'}/yr`);
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
|
|
4102
|
+
// Section 5: Recommendation Summary
|
|
4103
|
+
console.log(`\n\n📌 RECOMMENDATION`);
|
|
4104
|
+
console.log("-".repeat(40));
|
|
4105
|
+
|
|
4106
|
+
if (available.length > 0) {
|
|
4107
|
+
// Sort by price to find best value
|
|
4108
|
+
const bestValue = available.sort((a, b) =>
|
|
4109
|
+
(a.price_first_year || 999) - (b.price_first_year || 999)
|
|
4110
|
+
)[0];
|
|
4111
|
+
|
|
4112
|
+
// Find tech-focused option
|
|
4113
|
+
const techOption = available.find(a =>
|
|
4114
|
+
['io', 'dev', 'app'].includes(a.domain.split('.').pop())
|
|
4115
|
+
);
|
|
4116
|
+
|
|
4117
|
+
console.log(`\n 🏆 BEST VALUE: ${bestValue.domain}`);
|
|
4118
|
+
console.log(` Price: $${bestValue.price_first_year}/year`);
|
|
4119
|
+
console.log(` Why: ${bestValue.tldInfo?.recommendation || 'Lowest cost option'}`);
|
|
4120
|
+
|
|
4121
|
+
if (techOption && techOption.domain !== bestValue.domain) {
|
|
4122
|
+
console.log(`\n 💻 TECH STARTUP PICK: ${techOption.domain}`);
|
|
4123
|
+
console.log(` Price: $${techOption.price_first_year}/year`);
|
|
4124
|
+
console.log(` Why: ${techOption.tldInfo?.recommendation || 'Popular with tech startups'}`);
|
|
4125
|
+
}
|
|
4126
|
+
} else {
|
|
4127
|
+
console.log("\n ⚠️ Primary domain unavailable across all TLDs.");
|
|
4128
|
+
console.log(" → Consider alternatives listed above");
|
|
4129
|
+
console.log(" → Check social media availability for brand consistency");
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
console.log(`\n${'='.repeat(60)}\n`);
|
|
4133
|
+
|
|
4134
|
+
return {
|
|
4135
|
+
startupName,
|
|
4136
|
+
generatedAt: new Date().toISOString(),
|
|
4137
|
+
tldAnalysis,
|
|
4138
|
+
availability: { available, taken },
|
|
4139
|
+
socialMedia: socials.platforms,
|
|
4140
|
+
recommendations: available.length > 0
|
|
4141
|
+
? available.sort((a, b) => (a.price_first_year || 999) - (b.price_first_year || 999))
|
|
4142
|
+
: []
|
|
4143
|
+
};
|
|
4144
|
+
}
|
|
4145
|
+
|
|
4146
|
+
// Generate report for a startup
|
|
4147
|
+
const report = await generateStartupDomainReport("nexaflow");
|
|
4148
|
+
```
|
|
4149
|
+
|
|
4150
|
+
**Sample Output:**
|
|
4151
|
+
```
|
|
4152
|
+
============================================================
|
|
4153
|
+
DOMAIN RESEARCH REPORT: NEXAFLOW
|
|
4154
|
+
Generated: 2024-01-15
|
|
4155
|
+
============================================================
|
|
4156
|
+
|
|
4157
|
+
📋 TLD ANALYSIS
|
|
4158
|
+
----------------------------------------
|
|
4159
|
+
|
|
4160
|
+
.COM
|
|
4161
|
+
└─ The original and most recognized domain extension
|
|
4162
|
+
└─ Price: $8.95 - $12.95/year
|
|
4163
|
+
└─ Best for: Any business or personal website
|
|
4164
|
+
└─ Popularity: Very High
|
|
4165
|
+
|
|
4166
|
+
.IO
|
|
4167
|
+
└─ Popular with tech startups and SaaS companies
|
|
4168
|
+
└─ Price: $32.95 - $44.95/year
|
|
4169
|
+
└─ Best for: Tech startups, APIs, developer tools
|
|
4170
|
+
└─ Popularity: High
|
|
4171
|
+
|
|
4172
|
+
.DEV
|
|
4173
|
+
└─ Google-operated TLD for developers
|
|
4174
|
+
└─ Price: $12.95 - $16.95/year
|
|
4175
|
+
└─ Best for: Developer portfolios, open source projects
|
|
4176
|
+
└─ Popularity: Medium
|
|
4177
|
+
└─ ⚠️ Restrictions: Requires HTTPS
|
|
4178
|
+
|
|
4179
|
+
|
|
4180
|
+
📊 AVAILABILITY CHECK
|
|
4181
|
+
----------------------------------------
|
|
4182
|
+
✅ nexaflow.com $9.95/yr
|
|
4183
|
+
❌ nexaflow.io (taken)
|
|
4184
|
+
✅ nexaflow.dev $14.95/yr
|
|
4185
|
+
✅ nexaflow.app $14.95/yr
|
|
4186
|
+
✅ nexaflow.co $29.95/yr
|
|
4187
|
+
|
|
4188
|
+
|
|
4189
|
+
🌐 SOCIAL MEDIA AVAILABILITY
|
|
4190
|
+
----------------------------------------
|
|
4191
|
+
github ✅ Available (high)
|
|
4192
|
+
twitter ❌ Taken (high)
|
|
4193
|
+
npm ✅ Available (high)
|
|
4194
|
+
pypi ✅ Available (high)
|
|
4195
|
+
reddit ✅ Available (high)
|
|
4196
|
+
|
|
4197
|
+
|
|
4198
|
+
📌 RECOMMENDATION
|
|
4199
|
+
----------------------------------------
|
|
4200
|
+
|
|
4201
|
+
🏆 BEST VALUE: nexaflow.com
|
|
4202
|
+
Price: $9.95/year
|
|
4203
|
+
Why: Classic, universal choice - trusted by all audiences
|
|
4204
|
+
|
|
4205
|
+
💻 TECH STARTUP PICK: nexaflow.dev
|
|
4206
|
+
Price: $14.95/year
|
|
4207
|
+
Why: Signals technical focus, requires HTTPS
|
|
4208
|
+
|
|
4209
|
+
============================================================
|
|
4210
|
+
```
|
|
4211
|
+
|
|
3671
4212
|
### Workflow 7: Validate 50 Domains with Result Aggregation
|
|
3672
4213
|
|
|
3673
4214
|
End-to-end workflow for validating exactly 50 domain names with comprehensive result handling:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domain-search-mcp",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "Fast domain availability aggregator MCP server. Check availability across Porkbun, Namecheap, RDAP, and WHOIS. Compare pricing. Get suggestions.",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"types": "dist/server.d.ts",
|