astro-component-kit 0.4.0 ā 0.5.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.
- package/README.md +139 -27
- package/bin/cli.js +67 -0
- package/bin/installer.js +179 -0
- package/package.json +35 -5
- package/src/components/index.ts +2 -0
- package/src/components/lib/Galaxy3D.astro +249 -137
- package/src/components/lib/app/AppSidebar.astro +249 -0
- package/src/components/lib/app/AppTopbar.astro +284 -0
- package/src/components/lib/app/ArrivalsBoard.astro +176 -0
- package/src/components/lib/app/AuthCard.astro +213 -0
- package/src/components/lib/app/DataTable.astro +346 -0
- package/src/components/lib/app/GuestProfileCard.astro +133 -0
- package/src/components/lib/app/HousekeepingBoard.astro +189 -0
- package/src/components/lib/app/PageHeader.astro +157 -0
- package/src/components/lib/app/PlanUsageCard.astro +112 -0
- package/src/components/lib/app/RoomRack.astro +207 -0
- package/src/components/lib/app/SettingsSection.astro +96 -0
- package/src/components/lib/app/SwitchRow.astro +71 -0
- package/src/components/lib/app/TeamMembers.astro +190 -0
- package/src/components/lib/app/app-icons.ts +52 -0
- package/src/components/lib/app/index.ts +19 -0
- package/src/components/lib/charts/AreaChart.astro +4 -4
- package/src/components/lib/charts/BarChart.astro +3 -3
- package/src/components/lib/charts/ChartFrame.astro +10 -10
- package/src/components/lib/charts/DonutChart.astro +2 -2
- package/src/components/lib/charts/DumbbellChart.astro +1 -1
- package/src/components/lib/charts/ForecastLineChart.astro +1 -1
- package/src/components/lib/charts/GaugeChart.astro +1 -1
- package/src/components/lib/charts/HeatmapChart.astro +1 -1
- package/src/components/lib/charts/HorizontalBarChart.astro +2 -2
- package/src/components/lib/charts/KpiStatTile.astro +4 -4
- package/src/components/lib/charts/LinearProgressGauge.astro +4 -4
- package/src/components/lib/charts/MetricDeltaTable.astro +3 -3
- package/src/components/lib/charts/RadarMetricChart.astro +4 -4
- package/src/components/lib/charts/RadialBarChart.astro +1 -1
- package/src/components/lib/charts/RetentionCohortTable.astro +2 -2
- package/src/components/lib/charts/TreemapChart.astro +1 -1
- package/src/components/lib/ecommerce/CartDrawer.astro +483 -0
- package/src/components/lib/ecommerce/CartPageList.astro +290 -0
- package/src/components/lib/ecommerce/CartToast.astro +276 -0
- package/src/components/lib/ecommerce/CategoryTiles.astro +143 -0
- package/src/components/lib/ecommerce/CheckoutForm.astro +423 -0
- package/src/components/lib/ecommerce/CountdownBanner.astro +230 -0
- package/src/components/lib/ecommerce/FilterBar.astro +278 -0
- package/src/components/lib/ecommerce/FilterSidebar.astro +405 -0
- package/src/components/lib/ecommerce/LiveActivityToast.astro +213 -0
- package/src/components/lib/ecommerce/OrderSummary.astro +295 -0
- package/src/components/lib/ecommerce/ProductBuyBox.astro +247 -0
- package/src/components/lib/ecommerce/ProductCardMinimal.astro +229 -0
- package/src/components/lib/ecommerce/ProductGallery.astro +145 -0
- package/src/components/lib/ecommerce/ProductGrid.astro +118 -0
- package/src/components/lib/ecommerce/ProductMedia.astro +113 -0
- package/src/components/lib/ecommerce/ProductRating.astro +78 -0
- package/src/components/lib/ecommerce/ProductToolbar.astro +93 -0
- package/src/components/lib/ecommerce/PromoBar.astro +145 -0
- package/src/components/lib/ecommerce/StockIndicator.astro +127 -0
- package/src/components/lib/ecommerce/StoreHeader.astro +446 -0
- package/src/components/lib/ecommerce/StoreHero.astro +260 -0
- package/src/components/lib/ecommerce/StoreProductCard.astro +307 -0
- package/src/components/lib/ecommerce/TrustBadges.astro +101 -0
- package/src/components/lib/ecommerce/VariantPicker.astro +145 -0
- package/src/components/lib/ecommerce/cart-store.ts +151 -0
- package/src/components/lib/ecommerce/catalog-filter.ts +62 -0
- package/src/components/lib/ecommerce/index.ts +34 -0
- package/src/components/lib/ecommerce/product-icons.ts +28 -0
- package/src/components/lib/ecommerce/types.ts +70 -0
- package/src/components/lib/forms/AnimatedInput.astro +4 -2
- package/src/components/lib/forms/CustomRadioGroup.astro +3 -1
- package/src/components/lib/index.ts +2 -0
- package/src/components/lib/layout/BentoGrid3.astro +6 -4
- package/src/components/lib/layout/CenterFixedBox.astro +2 -2
- package/src/components/lib/layout/CenteredContainer.astro +4 -2
- package/src/components/lib/layout/ClusterHorizontal.astro +2 -2
- package/src/components/lib/layout/FeatureHero.astro +4 -2
- package/src/components/lib/layout/FooterCenteredMinimal.astro +4 -2
- package/src/components/lib/layout/FullBleedSection.astro +2 -2
- package/src/components/lib/layout/GalleryGrid4.astro +2 -2
- package/src/components/lib/layout/HolyGrailGrid.astro +11 -9
- package/src/components/lib/layout/LandingSectionSplit.astro +5 -3
- package/src/components/lib/layout/MasonryGrid.astro +2 -2
- package/src/components/lib/layout/MinimalFooterGrid.astro +1 -1
- package/src/components/lib/layout/ScrollSnapSection.astro +1 -1
- package/src/components/lib/layout/SidebarLayoutWrapper.astro +4 -2
- package/src/components/lib/layout/SplitScreenLayout.astro +3 -3
- package/src/components/lib/layout/StepLayoutVertical.astro +1 -1
- package/src/components/lib/layout/StickySidebarWrapper.astro +4 -2
- package/src/components/lib/sections/AgencyContactBrief.astro +194 -0
- package/src/components/lib/sections/AgencyFooterCta.astro +94 -0
- package/src/components/lib/sections/AgencyHeader.astro +161 -0
- package/src/components/lib/sections/AgencyHeroKinetic.astro +172 -0
- package/src/components/lib/sections/AgencyServicesList.astro +113 -0
- package/src/components/lib/sections/AgencyTeamGrid.astro +111 -0
- package/src/components/lib/sections/AgencyWorkGrid.astro +147 -0
- package/src/components/lib/sections/BlogGridSection.astro +9 -7
- package/src/components/lib/sections/ButtonsShowcase.astro +20 -18
- package/src/components/lib/sections/CardsShowcase.astro +28 -26
- package/src/components/lib/sections/CareersOpenings.astro +10 -8
- package/src/components/lib/sections/ChangelogSection.astro +20 -7
- package/src/components/lib/sections/ContactGlassForm.astro +10 -8
- package/src/components/lib/sections/ContactSplitMap.astro +11 -9
- package/src/components/lib/sections/CtaAppDownload.astro +13 -11
- package/src/components/lib/sections/CtaGlowBanner.astro +12 -10
- package/src/components/lib/sections/CtaNewsletterSection.astro +13 -11
- package/src/components/lib/sections/CtaSplitImage.astro +13 -11
- package/src/components/lib/sections/DataShowcase.astro +23 -21
- package/src/components/lib/sections/FaqAccordionSection.astro +8 -8
- package/src/components/lib/sections/FaqTwoColumn.astro +9 -7
- package/src/components/lib/sections/FeatureAlternatingRows.astro +10 -8
- package/src/components/lib/sections/FeatureBentoGrid.astro +13 -11
- package/src/components/lib/sections/FeatureIconGrid.astro +6 -6
- package/src/components/lib/sections/FeatureTabsShowcase.astro +13 -11
- package/src/components/lib/sections/FeatureTimelineFlow.astro +8 -6
- package/src/components/lib/sections/FeedbackShowcase.astro +15 -13
- package/src/components/lib/sections/FooterMegaSection.astro +13 -11
- package/src/components/lib/sections/FormsShowcase.astro +22 -20
- package/src/components/lib/sections/HeroDashboardPreview.astro +11 -9
- package/src/components/lib/sections/HeroGlass.astro +22 -20
- package/src/components/lib/sections/HeroGradient.astro +15 -13
- package/src/components/lib/sections/HeroMinimalCentered.astro +10 -10
- package/src/components/lib/sections/HeroShowcaseSplit.astro +18 -16
- package/src/components/lib/sections/HeroSplit.astro +13 -11
- package/src/components/lib/sections/HeroTerminal.astro +14 -12
- package/src/components/lib/sections/HeroWaitlist.astro +10 -8
- package/src/components/lib/sections/HowItWorksSteps.astro +12 -10
- package/src/components/lib/sections/IntegrationsGrid.astro +7 -7
- package/src/components/lib/sections/LayoutShowcase.astro +21 -19
- package/src/components/lib/sections/LogoCloudSection.astro +4 -4
- package/src/components/lib/sections/LogoWallGrid.astro +6 -4
- package/src/components/lib/sections/NavigationShowcase.astro +15 -13
- package/src/components/lib/sections/OverlaysShowcase.astro +21 -19
- package/src/components/lib/sections/PricingComparisonMatrix.astro +15 -13
- package/src/components/lib/sections/PricingSinglePlan.astro +13 -11
- package/src/components/lib/sections/PricingTierCards.astro +11 -9
- package/src/components/lib/sections/PricingToggleCards.astro +13 -13
- package/src/components/lib/sections/ShopCategoryHero.astro +103 -0
- package/src/components/lib/sections/ShopCollectionMosaic.astro +131 -0
- package/src/components/lib/sections/ShopFooterWordmark.astro +100 -0
- package/src/components/lib/sections/ShopHeaderEditorial.astro +396 -0
- package/src/components/lib/sections/ShopHeroEditorial.astro +151 -0
- package/src/components/lib/sections/ShopLookbook.astro +250 -0
- package/src/components/lib/sections/ShopNewsletterEditorial.astro +128 -0
- package/src/components/lib/sections/ShopProductRail.astro +150 -0
- package/src/components/lib/sections/ShopReviewsEditorial.astro +133 -0
- package/src/components/lib/sections/ShopValuesMarquee.astro +91 -0
- package/src/components/lib/sections/StatsCounterBand.astro +9 -7
- package/src/components/lib/sections/StatsDashboardSection.astro +4 -2
- package/src/components/lib/sections/StatsMetricShowcase.astro +9 -7
- package/src/components/lib/sections/TeamGridSection.astro +12 -10
- package/src/components/lib/sections/TestimonialCarousel.astro +10 -8
- package/src/components/lib/sections/TestimonialFeatured.astro +7 -5
- package/src/components/lib/sections/TestimonialGridSection.astro +7 -7
- package/src/components/lib/sections/TestimonialWallGlass.astro +11 -9
- package/src/components/lib/sections/TypographyShowcase.astro +10 -8
- package/src/components/lib/sections/index.ts +10 -0
- package/src/components/lib/templates/ecommerce/StoreCategoryPage.astro +160 -0
- package/src/components/lib/templates/ecommerce/StoreCheckoutPage.astro +98 -0
- package/src/components/lib/templates/ecommerce/StoreHomePage.astro +191 -0
- package/src/components/lib/templates/ecommerce/StoreLayout.astro +169 -0
- package/src/components/lib/templates/ecommerce/StoreProductPage.astro +165 -0
- package/src/components/lib/templates/ecommerce/data.ts +187 -0
- package/src/components/lib/templates/ecommerce/index.ts +14 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialBagPage.astro +52 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialCheckoutPage.astro +123 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialHomePage.astro +102 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialLayout.astro +216 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialProductPage.astro +205 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialShopPage.astro +112 -0
- package/src/components/lib/templates/ecommerce-editorial/data.ts +125 -0
- package/src/components/lib/templates/ecommerce-editorial/index.ts +16 -0
- package/src/components/lib/templates/saas-hotel/AppLayout.astro +83 -0
- package/src/components/lib/templates/saas-hotel/DashboardPage.astro +66 -0
- package/src/components/lib/templates/saas-hotel/GuestsPage.astro +65 -0
- package/src/components/lib/templates/saas-hotel/LandingPage.astro +213 -0
- package/src/components/lib/templates/saas-hotel/ReportsPage.astro +63 -0
- package/src/components/lib/templates/saas-hotel/ReservationsPage.astro +49 -0
- package/src/components/lib/templates/saas-hotel/RoomsPage.astro +48 -0
- package/src/components/lib/templates/saas-hotel/SettingsPage.astro +115 -0
- package/src/components/lib/templates/saas-hotel/SignInPage.astro +50 -0
- package/src/components/lib/templates/saas-hotel/data.ts +229 -0
- package/src/components/lib/templates/saas-hotel/index.ts +19 -0
- package/src/components/lib/templates/saas-hotel/lobby-theme.css +90 -0
- package/src/data/registry/app.ts +93 -0
- package/src/data/registry/buttons.ts +3279 -0
- package/src/data/registry/cards.ts +1753 -0
- package/src/data/registry/charts-svg.ts +557 -0
- package/src/data/registry/charts.ts +500 -0
- package/src/data/registry/data.ts +986 -0
- package/src/data/registry/ecommerce.ts +269 -0
- package/src/data/registry/feedback.ts +1824 -0
- package/src/data/registry/forms.ts +2513 -0
- package/src/data/registry/index.ts +64 -0
- package/src/data/registry/layout.ts +206 -0
- package/src/data/registry/navigation.ts +936 -0
- package/src/data/registry/overlays.ts +1133 -0
- package/src/data/registry/sections-extra.ts +397 -0
- package/src/data/registry/sections.ts +361 -0
- package/src/data/registry/sources.ts +41 -0
- package/src/data/registry/templates.ts +414 -0
- package/src/data/registry/types.ts +30 -0
- package/src/data/registry/typography.ts +777 -0
- package/src/mcp/http-server.ts +324 -0
- package/src/mcp/index.ts +67 -0
- package/src/mcp/installer.ts +178 -0
- package/src/mcp/registry-adapter.ts +278 -0
- package/src/mcp/stdio-server.ts +11 -0
- package/src/mcp/tools.ts +247 -0
- package/src/mcp/types.ts +53 -0
- package/src/styles/global.css +95 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
// src/mcp/http-server.ts
|
|
2
|
+
// Production-ready SSE HTTP server for Astro Components Kit MCP on Coolify.
|
|
3
|
+
import express, { type Request, type Response, type NextFunction } from 'express';
|
|
4
|
+
import cors from 'cors';
|
|
5
|
+
import rateLimit from 'express-rate-limit';
|
|
6
|
+
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
7
|
+
import { createMcpServer } from './tools.js';
|
|
8
|
+
import { getLibraryStats } from './registry-adapter.js';
|
|
9
|
+
|
|
10
|
+
export interface HttpServerOptions {
|
|
11
|
+
port?: number;
|
|
12
|
+
host?: string;
|
|
13
|
+
rateLimitMax?: number;
|
|
14
|
+
rateLimitWindowMs?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function startHttpServer(options: HttpServerOptions = {}) {
|
|
18
|
+
const port = options.port || Number(process.env.PORT) || 3000;
|
|
19
|
+
const host = options.host || process.env.HOST || '0.0.0.0';
|
|
20
|
+
const rateLimitMax = options.rateLimitMax || Number(process.env.RATE_LIMIT_MAX) || 120;
|
|
21
|
+
const rateLimitWindowMs = options.rateLimitWindowMs || Number(process.env.RATE_LIMIT_WINDOW_MS) || 60 * 1000;
|
|
22
|
+
|
|
23
|
+
const app = express();
|
|
24
|
+
|
|
25
|
+
// Trust reverse proxies (Coolify / Traefik / Caddy / Nginx) for proper IP rate limiting
|
|
26
|
+
app.set('trust proxy', 1);
|
|
27
|
+
|
|
28
|
+
// Disable identifying header
|
|
29
|
+
app.disable('x-powered-by');
|
|
30
|
+
|
|
31
|
+
// Security headers middleware
|
|
32
|
+
app.use((_req: Request, res: Response, next: NextFunction) => {
|
|
33
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
34
|
+
res.setHeader('X-Frame-Options', 'DENY');
|
|
35
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
36
|
+
next();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// CORS for public MCP client access
|
|
40
|
+
app.use(
|
|
41
|
+
cors({
|
|
42
|
+
origin: '*',
|
|
43
|
+
methods: ['GET', 'POST', 'OPTIONS'],
|
|
44
|
+
allowedHeaders: ['Content-Type', 'Authorization', 'Accept'],
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Rate Limiting ā protects Coolify container from abuse
|
|
49
|
+
const limiter = rateLimit({
|
|
50
|
+
windowMs: rateLimitWindowMs,
|
|
51
|
+
max: rateLimitMax,
|
|
52
|
+
standardHeaders: true,
|
|
53
|
+
legacyHeaders: false,
|
|
54
|
+
message: {
|
|
55
|
+
error: 'Too Many Requests',
|
|
56
|
+
message: `Rate limit of ${rateLimitMax} requests per minute exceeded. Please try again later.`,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
app.use(limiter);
|
|
61
|
+
|
|
62
|
+
// Track active SSE transports by sessionId
|
|
63
|
+
const transports = new Map<string, SSEServerTransport>();
|
|
64
|
+
|
|
65
|
+
// 1. Healthcheck Endpoint (for Coolify / Docker health checks)
|
|
66
|
+
app.get('/health', (_req: Request, res: Response) => {
|
|
67
|
+
const stats = getLibraryStats();
|
|
68
|
+
res.json({
|
|
69
|
+
status: 'ok',
|
|
70
|
+
service: 'astro-components-kit-mcp',
|
|
71
|
+
version: stats.version,
|
|
72
|
+
componentsCount: stats.totalComponents,
|
|
73
|
+
templatesCount: stats.totalTemplates,
|
|
74
|
+
uptimeSeconds: Math.floor(process.uptime()),
|
|
75
|
+
timestamp: new Date().toISOString(),
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// 2. Human-friendly landing page
|
|
80
|
+
app.get('/', (_req: Request, res: Response) => {
|
|
81
|
+
const stats = getLibraryStats();
|
|
82
|
+
const serverUrl = `https://${_req.get('host') || 'mcp.astrocomponents.dev'}`;
|
|
83
|
+
|
|
84
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
85
|
+
res.send(`<!DOCTYPE html>
|
|
86
|
+
<html lang="en">
|
|
87
|
+
<head>
|
|
88
|
+
<meta charset="utf-8">
|
|
89
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
90
|
+
<title>Astro Components Kit ā MCP Server</title>
|
|
91
|
+
<style>
|
|
92
|
+
:root {
|
|
93
|
+
--bg: #090d16;
|
|
94
|
+
--card-bg: rgba(255, 255, 255, 0.04);
|
|
95
|
+
--border: rgba(255, 255, 255, 0.1);
|
|
96
|
+
--primary: #f59e0b;
|
|
97
|
+
--primary-glow: rgba(245, 158, 11, 0.25);
|
|
98
|
+
--text: #f1f5f9;
|
|
99
|
+
--text-muted: #94a3b8;
|
|
100
|
+
--code-bg: #030712;
|
|
101
|
+
}
|
|
102
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
103
|
+
body {
|
|
104
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
105
|
+
background: var(--bg);
|
|
106
|
+
color: var(--text);
|
|
107
|
+
line-height: 1.6;
|
|
108
|
+
padding: 2.5rem 1.25rem;
|
|
109
|
+
min-height: 100vh;
|
|
110
|
+
display: flex;
|
|
111
|
+
justify-content: center;
|
|
112
|
+
align-items: center;
|
|
113
|
+
}
|
|
114
|
+
.container {
|
|
115
|
+
max-width: 760px;
|
|
116
|
+
width: 100%;
|
|
117
|
+
background: var(--card-bg);
|
|
118
|
+
border: 1px solid var(--border);
|
|
119
|
+
border-radius: 20px;
|
|
120
|
+
padding: 2.5rem;
|
|
121
|
+
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
|
|
122
|
+
backdrop-filter: blur(16px);
|
|
123
|
+
}
|
|
124
|
+
.badge {
|
|
125
|
+
display: inline-flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
gap: 0.4rem;
|
|
128
|
+
font-size: 0.8rem;
|
|
129
|
+
font-weight: 700;
|
|
130
|
+
color: var(--primary);
|
|
131
|
+
background: var(--primary-glow);
|
|
132
|
+
border: 1px solid rgba(245, 158, 11, 0.4);
|
|
133
|
+
padding: 0.25rem 0.75rem;
|
|
134
|
+
border-radius: 999px;
|
|
135
|
+
margin-bottom: 1rem;
|
|
136
|
+
}
|
|
137
|
+
.dot { width: 8px; height: 8px; border-radius: 50%; background: #10b981; }
|
|
138
|
+
h1 { font-size: 2rem; font-weight: 800; margin-bottom: 0.5rem; letter-spacing: -0.02em; }
|
|
139
|
+
p.lead { color: var(--text-muted); font-size: 1.05rem; margin-bottom: 2rem; }
|
|
140
|
+
.stats {
|
|
141
|
+
display: grid;
|
|
142
|
+
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
|
143
|
+
gap: 1rem;
|
|
144
|
+
margin-bottom: 2rem;
|
|
145
|
+
}
|
|
146
|
+
.stat-box {
|
|
147
|
+
background: rgba(0, 0, 0, 0.3);
|
|
148
|
+
border: 1px solid var(--border);
|
|
149
|
+
padding: 1rem;
|
|
150
|
+
border-radius: 12px;
|
|
151
|
+
text-align: center;
|
|
152
|
+
}
|
|
153
|
+
.stat-val { font-size: 1.6rem; font-weight: 800; color: var(--primary); }
|
|
154
|
+
.stat-label { font-size: 0.8rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
|
|
155
|
+
h2 { font-size: 1.25rem; margin-bottom: 0.8rem; }
|
|
156
|
+
pre {
|
|
157
|
+
background: var(--code-bg);
|
|
158
|
+
border: 1px solid var(--border);
|
|
159
|
+
border-radius: 12px;
|
|
160
|
+
padding: 1.25rem;
|
|
161
|
+
overflow-x: auto;
|
|
162
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
163
|
+
font-size: 0.9rem;
|
|
164
|
+
color: #e2e8f0;
|
|
165
|
+
margin-bottom: 1.5rem;
|
|
166
|
+
}
|
|
167
|
+
.endpoint {
|
|
168
|
+
display: flex;
|
|
169
|
+
align-items: center;
|
|
170
|
+
gap: 0.5rem;
|
|
171
|
+
padding: 0.75rem 1rem;
|
|
172
|
+
background: rgba(16, 185, 129, 0.1);
|
|
173
|
+
border: 1px solid rgba(16, 185, 129, 0.3);
|
|
174
|
+
border-radius: 10px;
|
|
175
|
+
color: #34d399;
|
|
176
|
+
font-family: monospace;
|
|
177
|
+
font-size: 0.95rem;
|
|
178
|
+
margin-bottom: 2rem;
|
|
179
|
+
}
|
|
180
|
+
footer {
|
|
181
|
+
display: flex;
|
|
182
|
+
justify-content: space-between;
|
|
183
|
+
align-items: center;
|
|
184
|
+
padding-top: 1.5rem;
|
|
185
|
+
border-top: 1px solid var(--border);
|
|
186
|
+
font-size: 0.85rem;
|
|
187
|
+
color: var(--text-muted);
|
|
188
|
+
}
|
|
189
|
+
footer a { color: var(--primary); text-decoration: none; }
|
|
190
|
+
footer a:hover { text-decoration: underline; }
|
|
191
|
+
</style>
|
|
192
|
+
</head>
|
|
193
|
+
<body>
|
|
194
|
+
<div class="container">
|
|
195
|
+
<div class="badge"><span class="dot"></span> Online & Ready Ā· v${stats.version}</div>
|
|
196
|
+
<h1>Astro Components Kit MCP</h1>
|
|
197
|
+
<p class="lead">Model Context Protocol server for Astro 5.x. Connect this endpoint to Cursor, Claude Desktop, Windsurf, or Antigravity to let your AI build directly with the library.</p>
|
|
198
|
+
|
|
199
|
+
<div class="stats">
|
|
200
|
+
<div class="stat-box">
|
|
201
|
+
<div class="stat-val">${stats.totalComponents}+</div>
|
|
202
|
+
<div class="stat-label">Components</div>
|
|
203
|
+
</div>
|
|
204
|
+
<div class="stat-box">
|
|
205
|
+
<div class="stat-val">${stats.totalCategories}</div>
|
|
206
|
+
<div class="stat-label">Categories</div>
|
|
207
|
+
</div>
|
|
208
|
+
<div class="stat-box">
|
|
209
|
+
<div class="stat-val">${stats.totalTemplates}</div>
|
|
210
|
+
<div class="stat-label">Templates</div>
|
|
211
|
+
</div>
|
|
212
|
+
<div class="stat-box">
|
|
213
|
+
<div class="stat-val">WCAG AA</div>
|
|
214
|
+
<div class="stat-label">Accessible</div>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<h2>Connect via SSE URL</h2>
|
|
219
|
+
<div class="endpoint">
|
|
220
|
+
<strong>SSE Endpoint:</strong> ${serverUrl}/sse
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<h2>Configuration (Cursor / Claude / Windsurf)</h2>
|
|
224
|
+
<pre>{
|
|
225
|
+
"mcpServers": {
|
|
226
|
+
"astro-components": {
|
|
227
|
+
"url": "${serverUrl}/sse"
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}</pre>
|
|
231
|
+
|
|
232
|
+
<footer>
|
|
233
|
+
<span>Astro Components Kit v${stats.version}</span>
|
|
234
|
+
<div>
|
|
235
|
+
<a href="https://astrocomponents.dev" target="_blank">Docs</a> Ā·
|
|
236
|
+
<a href="https://github.com/konstantinwdk/astro-components" target="_blank">GitHub</a> Ā·
|
|
237
|
+
<a href="https://www.npmjs.com/package/astro-component-kit" target="_blank">npm</a>
|
|
238
|
+
</div>
|
|
239
|
+
</footer>
|
|
240
|
+
</div>
|
|
241
|
+
</body>
|
|
242
|
+
</html>`);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// 3. SSE Transport Endpoint (Client establishes SSE connection)
|
|
246
|
+
app.get('/sse', async (req: Request, res: Response) => {
|
|
247
|
+
try {
|
|
248
|
+
const server = createMcpServer();
|
|
249
|
+
const transport = new SSEServerTransport('/message', res);
|
|
250
|
+
const sessionId = transport.sessionId;
|
|
251
|
+
|
|
252
|
+
transports.set(sessionId, transport);
|
|
253
|
+
|
|
254
|
+
req.on('close', () => {
|
|
255
|
+
transports.delete(sessionId);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
await server.connect(transport);
|
|
259
|
+
} catch (err: any) {
|
|
260
|
+
console.error('[mcp] Error establishing SSE session:', err?.message || err);
|
|
261
|
+
if (!res.headersSent) {
|
|
262
|
+
res.status(500).json({ error: 'Failed to establish SSE session' });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// 4. Message Endpoint (Client posts JSON-RPC calls)
|
|
268
|
+
app.post('/message', express.json({ limit: '256kb' }), async (req: Request, res: Response) => {
|
|
269
|
+
const sessionId = (req.query.sessionId as string) || '';
|
|
270
|
+
if (!sessionId) {
|
|
271
|
+
res.status(400).json({ error: 'Missing sessionId query parameter' });
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const transport = transports.get(sessionId);
|
|
276
|
+
if (!transport) {
|
|
277
|
+
res.status(404).json({ error: 'Session not found or expired' });
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
await transport.handlePostMessage(req, res);
|
|
283
|
+
} catch (err: any) {
|
|
284
|
+
console.error(`[mcp] Error handling message for session ${sessionId}:`, err?.message || err);
|
|
285
|
+
if (!res.headersSent) {
|
|
286
|
+
res.status(500).json({ error: 'Internal server error processing message' });
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// Start HTTP listener
|
|
292
|
+
const serverInstance = app.listen(port, host, () => {
|
|
293
|
+
const stats = getLibraryStats();
|
|
294
|
+
console.log(`\nš [Astro Components Kit MCP Server]`);
|
|
295
|
+
console.log(` Version: v${stats.version}`);
|
|
296
|
+
console.log(` Components: ${stats.totalComponents}`);
|
|
297
|
+
console.log(` Templates: ${stats.totalTemplates}`);
|
|
298
|
+
console.log(` HTTP/SSE: http://${host}:${port}/sse`);
|
|
299
|
+
console.log(` Health: http://${host}:${port}/health`);
|
|
300
|
+
console.log(` Rate limit: ${rateLimitMax} req/${rateLimitWindowMs / 1000}s\n`);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Graceful shutdown
|
|
304
|
+
const shutdown = () => {
|
|
305
|
+
console.log('\n[mcp] Shutting down gracefully...');
|
|
306
|
+
for (const [, t] of transports) {
|
|
307
|
+
try {
|
|
308
|
+
t.close();
|
|
309
|
+
} catch {
|
|
310
|
+
// ignore
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
transports.clear();
|
|
314
|
+
serverInstance.close(() => {
|
|
315
|
+
console.log('[mcp] Server closed.');
|
|
316
|
+
process.exit(0);
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
process.on('SIGINT', shutdown);
|
|
321
|
+
process.on('SIGTERM', shutdown);
|
|
322
|
+
|
|
323
|
+
return serverInstance;
|
|
324
|
+
}
|
package/src/mcp/index.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// src/mcp/index.ts
|
|
3
|
+
// CLI and entry point for Astro Components Kit MCP Server.
|
|
4
|
+
import { startHttpServer } from './http-server.js';
|
|
5
|
+
import { startStdioServer } from './stdio-server.js';
|
|
6
|
+
import { installMcpForClient } from './installer.js';
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const firstArg = args[0]?.toLowerCase();
|
|
10
|
+
|
|
11
|
+
async function main() {
|
|
12
|
+
// 1. Install command: npx astro-component-kit mcp install <client>
|
|
13
|
+
if (firstArg === 'install' || (firstArg === 'mcp' && args[1]?.toLowerCase() === 'install')) {
|
|
14
|
+
const client = firstArg === 'install' ? args[1] : args[2];
|
|
15
|
+
if (!client) {
|
|
16
|
+
console.log(`\nUsage: npx astro-component-kit mcp install <cursor|claude|codex|lovable|mcp>`);
|
|
17
|
+
console.log(`Example: npx astro-component-kit mcp install cursor\n`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const success = await installMcpForClient(client);
|
|
21
|
+
process.exit(success ? 0 : 1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 2. HTTP Server command: npx astro-component-kit mcp serve
|
|
25
|
+
if (firstArg === 'serve' || (firstArg === 'mcp' && args[1]?.toLowerCase() === 'serve')) {
|
|
26
|
+
startHttpServer();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 3. Stdio mode: if invoked with --stdio or piped
|
|
31
|
+
if (args.includes('--stdio') || firstArg === 'stdio' || (firstArg === 'mcp' && args[1]?.toLowerCase() === 'stdio')) {
|
|
32
|
+
startStdioServer().catch((err) => {
|
|
33
|
+
console.error('[mcp-stdio] Fatal error:', err);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 4. Default in production / Docker (PORT set): start HTTP server
|
|
40
|
+
if (process.env.PORT || process.env.COOLIFY_APP_ID || process.env.NODE_ENV === 'production') {
|
|
41
|
+
startHttpServer();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 5. Help output when invoked in terminal
|
|
46
|
+
console.log(`
|
|
47
|
+
š Astro Components Kit ā MCP Server (Model Context Protocol)
|
|
48
|
+
|
|
49
|
+
Usage:
|
|
50
|
+
npx astro-component-kit mcp install <cursor|claude|codex|lovable|mcp>
|
|
51
|
+
ā Automatically configure your AI editor/agent to use Astro Components MCP
|
|
52
|
+
|
|
53
|
+
npx astro-component-kit mcp serve
|
|
54
|
+
ā Start the remote SSE HTTP server locally (default port 3000)
|
|
55
|
+
|
|
56
|
+
npx astro-component-kit mcp --stdio
|
|
57
|
+
ā Run in stdio mode for direct local MCP integration
|
|
58
|
+
|
|
59
|
+
Online Endpoint:
|
|
60
|
+
https://mcp.astrocomponents.dev/sse
|
|
61
|
+
`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
main().catch((err) => {
|
|
65
|
+
console.error('[mcp] Error:', err);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
});
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// src/mcp/installer.ts
|
|
2
|
+
// Automated 1-click CLI installer for Cursor, Claude, Codex, Lovable, Windsurf, Cline, and Universal MCP.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
|
|
7
|
+
export type SupportedClient = 'cursor' | 'claude' | 'codex' | 'lovable' | 'mcp' | 'windsurf' | 'cline';
|
|
8
|
+
|
|
9
|
+
const MCP_SERVER_URL = 'https://mcp.astrocomponents.dev/sse';
|
|
10
|
+
|
|
11
|
+
const SERVER_CONFIG = {
|
|
12
|
+
url: MCP_SERVER_URL,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function getHomeDir(): string {
|
|
16
|
+
return os.homedir();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function normalizeClient(input: string): SupportedClient | null {
|
|
20
|
+
const c = input.toLowerCase().trim();
|
|
21
|
+
if (c === 'cursor' || c === 'cursos') return 'cursor';
|
|
22
|
+
if (c === 'claude' || c === 'claude-desktop' || c === 'claude-code') return 'claude';
|
|
23
|
+
if (c === 'codex' || c === 'openai-codex' || c === 'copilot') return 'codex';
|
|
24
|
+
if (c === 'lovable' || c === 'lovable-dev') return 'lovable';
|
|
25
|
+
if (c === 'mcp' || c === 'universal' || c === 'generic') return 'mcp';
|
|
26
|
+
if (c === 'windsurf') return 'windsurf';
|
|
27
|
+
if (c === 'cline') return 'cline';
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns the candidate configuration paths for each supported client.
|
|
33
|
+
*/
|
|
34
|
+
function getClientConfigPaths(client: SupportedClient): { primary: string; fallback?: string } {
|
|
35
|
+
const home = getHomeDir();
|
|
36
|
+
const platform = os.platform();
|
|
37
|
+
|
|
38
|
+
switch (client) {
|
|
39
|
+
case 'cursor': {
|
|
40
|
+
const localCursor = path.resolve(process.cwd(), '.cursor/mcp.json');
|
|
41
|
+
const globalCursor = path.resolve(home, '.cursor/mcp.json');
|
|
42
|
+
return { primary: localCursor, fallback: globalCursor };
|
|
43
|
+
}
|
|
44
|
+
case 'claude': {
|
|
45
|
+
if (platform === 'darwin') {
|
|
46
|
+
return { primary: path.resolve(home, 'Library/Application Support/Claude/claude_desktop_config.json') };
|
|
47
|
+
}
|
|
48
|
+
if (platform === 'win32') {
|
|
49
|
+
const appData = process.env.APPDATA || path.resolve(home, 'AppData/Roaming');
|
|
50
|
+
return { primary: path.resolve(appData, 'Claude/claude_desktop_config.json') };
|
|
51
|
+
}
|
|
52
|
+
return { primary: path.resolve(home, '.config/Claude/claude_desktop_config.json') };
|
|
53
|
+
}
|
|
54
|
+
case 'codex': {
|
|
55
|
+
const localCodex = path.resolve(process.cwd(), '.codex/mcp.json');
|
|
56
|
+
const globalCodex = path.resolve(home, '.codex/config.json');
|
|
57
|
+
return { primary: localCodex, fallback: globalCodex };
|
|
58
|
+
}
|
|
59
|
+
case 'lovable': {
|
|
60
|
+
const localLovable = path.resolve(process.cwd(), '.lovable/mcp.json');
|
|
61
|
+
const globalLovable = path.resolve(home, '.lovable/config.json');
|
|
62
|
+
return { primary: localLovable, fallback: globalLovable };
|
|
63
|
+
}
|
|
64
|
+
case 'mcp': {
|
|
65
|
+
const localMcp = path.resolve(process.cwd(), 'mcp.json');
|
|
66
|
+
const globalMcp = path.resolve(home, '.mcp/config.json');
|
|
67
|
+
return { primary: localMcp, fallback: globalMcp };
|
|
68
|
+
}
|
|
69
|
+
case 'windsurf': {
|
|
70
|
+
return { primary: path.resolve(home, '.codeium/windsurf/mcp_config.json') };
|
|
71
|
+
}
|
|
72
|
+
case 'cline': {
|
|
73
|
+
if (platform === 'darwin') {
|
|
74
|
+
return {
|
|
75
|
+
primary: path.resolve(
|
|
76
|
+
home,
|
|
77
|
+
'Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json'
|
|
78
|
+
),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (platform === 'win32') {
|
|
82
|
+
const appData = process.env.APPDATA || path.resolve(home, 'AppData/Roaming');
|
|
83
|
+
return {
|
|
84
|
+
primary: path.resolve(
|
|
85
|
+
appData,
|
|
86
|
+
'Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json'
|
|
87
|
+
),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
primary: path.resolve(
|
|
92
|
+
home,
|
|
93
|
+
'.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json'
|
|
94
|
+
),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Installs or updates the astro-components MCP server in the target client's configuration.
|
|
102
|
+
*/
|
|
103
|
+
export async function installMcpForClient(targetClient: string): Promise<boolean> {
|
|
104
|
+
const client = normalizeClient(targetClient);
|
|
105
|
+
const validClients: SupportedClient[] = ['cursor', 'claude', 'codex', 'lovable', 'mcp', 'windsurf', 'cline'];
|
|
106
|
+
|
|
107
|
+
if (!client) {
|
|
108
|
+
console.error(`\nā Unknown client "${targetClient}".`);
|
|
109
|
+
console.log(` Supported clients: ${validClients.join(', ')}`);
|
|
110
|
+
console.log(`\nExamples:`);
|
|
111
|
+
console.log(` npx astro-component-kit mcp install cursor`);
|
|
112
|
+
console.log(` npx astro-component-kit mcp install claude`);
|
|
113
|
+
console.log(` npx astro-component-kit mcp install codex`);
|
|
114
|
+
console.log(` npx astro-component-kit mcp install lovable`);
|
|
115
|
+
console.log(` npx astro-component-kit mcp install mcp\n`);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const { primary } = getClientConfigPaths(client);
|
|
120
|
+
const targetDir = path.dirname(primary);
|
|
121
|
+
|
|
122
|
+
console.log(`\nš¦ Configuring Astro Components Kit MCP for [${client}]...`);
|
|
123
|
+
console.log(` Target config: ${primary}`);
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
if (!fs.existsSync(targetDir)) {
|
|
127
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let config: any = {};
|
|
131
|
+
if (fs.existsSync(primary)) {
|
|
132
|
+
try {
|
|
133
|
+
const raw = fs.readFileSync(primary, 'utf8');
|
|
134
|
+
config = JSON.parse(raw);
|
|
135
|
+
} catch {
|
|
136
|
+
config = {};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!config || typeof config !== 'object') {
|
|
141
|
+
config = {};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!config.mcpServers || typeof config.mcpServers !== 'object') {
|
|
145
|
+
config.mcpServers = {};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Add or update astro-components server
|
|
149
|
+
config.mcpServers['astro-components'] = SERVER_CONFIG;
|
|
150
|
+
|
|
151
|
+
fs.writeFileSync(primary, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
152
|
+
|
|
153
|
+
console.log(`\nā
Successfully installed!`);
|
|
154
|
+
console.log(` Server name: "astro-components"`);
|
|
155
|
+
console.log(` Endpoint: ${MCP_SERVER_URL}`);
|
|
156
|
+
console.log(`\nš” What to do next:`);
|
|
157
|
+
console.log(` Restart ${client.toUpperCase()} (or reload MCP servers), then prompt your AI:`);
|
|
158
|
+
console.log(` > "Search astro-components for ecommerce cards and buy box"`);
|
|
159
|
+
console.log(` > "Insert a KPI stat tile chart from astro-components"\n`);
|
|
160
|
+
return true;
|
|
161
|
+
} catch (err: any) {
|
|
162
|
+
console.error(`\nā Failed to write configuration: ${err?.message || err}`);
|
|
163
|
+
console.log(`\nYou can configure it manually by adding this JSON:`);
|
|
164
|
+
console.log(
|
|
165
|
+
JSON.stringify(
|
|
166
|
+
{
|
|
167
|
+
mcpServers: {
|
|
168
|
+
'astro-components': SERVER_CONFIG,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
null,
|
|
172
|
+
2
|
|
173
|
+
)
|
|
174
|
+
);
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|