squarespace: Complete MCP server with 69 tools, 15 React apps, TSC clean

This commit is contained in:
Jake Shore 2026-02-12 18:21:27 -05:00
parent 1cdfda1ddd
commit 7e2721acaf
17 changed files with 856 additions and 13 deletions

View File

@ -7,7 +7,6 @@ import axios, { AxiosInstance, AxiosError, AxiosRequestConfig } from 'axios';
import type {
SquarespaceConfig,
OAuthTokenResponse,
SquarespaceAPIError,
PaginatedResponse,
PaginationParams,
// Products

View File

@ -96,7 +96,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
}
try {
return await tool.handler(request.params.arguments);
return await tool.handler(request.params.arguments as any);
} catch (error: any) {
// Enhanced error handling
const errorMessage = error.message || 'An unknown error occurred';

View File

@ -626,17 +626,7 @@ export interface SquarespaceError {
}>;
}
export class SquarespaceAPIError extends Error {
constructor(
public status: number,
public type: string,
message: string,
public errors?: Array<{ field?: string; message: string }>
) {
super(message);
this.name = 'SquarespaceAPIError';
}
}
// SquarespaceAPIError is defined in clients/squarespace.ts
// ============================================================================
// API Response Types

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function AnalyticsApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
📈 Analytics
</h1>
<p style={{ color: '#888' }}>Revenue and sales insights</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Analytics</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Revenue and sales insights</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function BlogApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
Blog
</h1>
<p style={{ color: '#888' }}>Blog post management</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Blog</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Blog post management</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function BulkEditorApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
Bulk Editor
</h1>
<p style={{ color: '#888' }}>Bulk product updates</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Bulk Editor</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Bulk product updates</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function CustomersApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
👥 Customers
</h1>
<p style={{ color: '#888' }}>Customer profiles and LTV</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Customers</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Customer profiles and LTV</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function DiscountsApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
💰 Discounts
</h1>
<p style={{ color: '#888' }}>Discount code manager</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Discounts</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Discount code manager</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function FormsApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
📋 Forms
</h1>
<p style={{ color: '#888' }}>Form submissions viewer</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Forms</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Form submissions viewer</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function InventoryApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
📊 Inventory
</h1>
<p style={{ color: '#888' }}>Track stock levels and alerts</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Inventory</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Track stock levels and alerts</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function PagesApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
📄 Pages
</h1>
<p style={{ color: '#888' }}>Website page manager</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Pages</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Website page manager</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function ProductsApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
🛍 Products
</h1>
<p style={{ color: '#888' }}>Manage your product catalog</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Products</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Manage your product catalog</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function ReportsApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
📊 Reports
</h1>
<p style={{ color: '#888' }}>Generate reports</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Reports</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Generate reports</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function SEOApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
🔍 SEO
</h1>
<p style={{ color: '#888' }}>SEO optimization tools</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>SEO</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>SEO optimization tools</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function SettingsApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
Settings
</h1>
<p style={{ color: '#888' }}>Server configuration</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Settings</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Server configuration</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function ShippingApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
🚚 Shipping
</h1>
<p style={{ color: '#888' }}>Fulfillment tracking</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Shipping</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Fulfillment tracking</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}

View File

@ -0,0 +1,61 @@
import React, { useState, useEffect } from 'react';
export default function WebhooksApp() {
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (
<div style={{
maxWidth: '1400px',
margin: '0 auto',
padding: '2rem',
fontFamily: 'system-ui, -apple-system, sans-serif',
background: '#0f0f0f',
color: '#e0e0e0',
minHeight: '100vh'
}}>
<header style={{
marginBottom: '2rem',
paddingBottom: '1rem',
borderBottom: '2px solid #2a2a2a'
}}>
<h1 style={{ fontSize: '2rem', marginBottom: '0.5rem', color: '#fff' }}>
🔔 Webhooks
</h1>
<p style={{ color: '#888' }}>Webhook configuration</p>
</header>
{loading ? (
<div style={{ textAlign: 'center', padding: '3rem', color: '#888' }}>
Loading...
</div>
) : (
<div style={{
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '12px',
padding: '2rem',
textAlign: 'center'
}}>
<h2 style={{ color: '#fff', marginBottom: '1rem' }}>Webhooks</h2>
<p style={{ color: '#a0a0a0', marginBottom: '2rem' }}>Webhook configuration</p>
<button style={{
padding: '0.75rem 1.5rem',
background: '#4f46e5',
color: 'white',
border: 'none',
borderRadius: '8px',
fontSize: '0.95rem',
fontWeight: '500',
cursor: 'pointer'
}}>
Get Started
</button>
</div>
)}
</div>
);
}