@appsyogi/adsense-mcp-server 0.1.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/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1927 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +342 -0
- package/dist/index.js +1645 -0
- package/dist/index.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/index.ts","../src/adsense/client.ts","../src/auth/tokenStore.ts","../src/auth/oauth.ts","../src/types.ts","../src/auth/serviceAccount.ts","../src/adsense/rateLimiter.ts","../src/adsense/cache.ts","../src/server/tools/accounts.ts","../src/server/tools/reports.ts","../src/server/tools/sites.ts","../src/server/tools/alerts.ts","../src/server/tools/payments.ts","../src/server/tools/adUnits.ts","../src/server/tools/export.ts","../src/server/tools/index.ts","../src/server/resources/index.ts"],"sourcesContent":["/**\n * MCP Server - Main setup\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ListResourcesRequestSchema,\n ReadResourceRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { registerTools, handleToolCall } from './tools/index.js';\nimport { handleListResources, handleReadResource } from './resources/index.js';\n\n/**\n * Create and configure the MCP server\n */\nexport function createServer() {\n const server = new Server(\n {\n name: 'adsense-mcp-server',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n resources: {},\n },\n }\n );\n\n // Register tool handlers\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: registerTools(),\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n return handleToolCall(request.params.name, request.params.arguments || {});\n });\n\n // Register resource handlers\n server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return handleListResources();\n });\n\n server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n return handleReadResource(request.params.uri);\n });\n\n return server;\n}\n\n/**\n * Start the MCP server with stdio transport\n */\nexport async function startServer(accountId?: string) {\n // Store account ID in environment for tools to access\n if (accountId) {\n process.env.ADSENSE_ACCOUNT_ID = accountId;\n }\n\n const server = createServer();\n const transport = new StdioServerTransport();\n\n await server.connect(transport);\n\n // Handle graceful shutdown\n process.on('SIGINT', async () => {\n await server.close();\n process.exit(0);\n });\n\n process.on('SIGTERM', async () => {\n await server.close();\n process.exit(0);\n });\n}\n","/**\n * AdSense API Client\n * \n * Wraps the googleapis client with:\n * - Automatic authentication (OAuth or service account)\n * - Rate limiting with exponential backoff\n * - Response caching for performance\n * - Pagination handling\n */\n\nimport { google, adsense_v2 } from 'googleapis';\nimport { loadConfig } from '../auth/tokenStore.js';\nimport { createOAuthClient } from '../auth/oauth.js';\nimport { createServiceAccountClient } from '../auth/serviceAccount.js';\nimport { rateLimiter, withRetry } from './rateLimiter.js';\nimport { getCache, CacheTTL } from './cache.js';\nimport type {\n AdSenseAccount,\n AdSenseSite,\n AdSenseAlert,\n AdSensePolicyIssue,\n AdSensePayment,\n AdSenseAdClient,\n AdSenseAdUnit,\n ReportQuery,\n ReportResponse,\n EarningsSummary,\n EarningsPeriod,\n} from '../types.js';\n\n/**\n * AdSense API Client\n */\nexport class AdSenseClient {\n private adsense: adsense_v2.Adsense;\n private defaultAccountId?: string;\n\n private constructor(adsense: adsense_v2.Adsense, defaultAccountId?: string) {\n this.adsense = adsense;\n this.defaultAccountId = defaultAccountId;\n }\n\n /**\n * Create an authenticated AdSense client\n */\n static async create(accountIdOverride?: string): Promise<AdSenseClient> {\n const config = await loadConfig();\n\n let auth;\n if (config.authType === 'service-account') {\n auth = await createServiceAccountClient();\n } else {\n auth = await createOAuthClient();\n }\n\n const adsense = google.adsense({\n version: 'v2',\n auth,\n });\n\n const accountId = accountIdOverride || config.defaultAccountId;\n return new AdSenseClient(adsense, accountId);\n }\n\n /**\n * Get the account ID to use (explicit > default > first available)\n */\n private async resolveAccountId(explicitId?: string): Promise<string> {\n if (explicitId) {\n return explicitId.startsWith('accounts/') ? explicitId : `accounts/${explicitId}`;\n }\n\n if (this.defaultAccountId) {\n return this.defaultAccountId.startsWith('accounts/')\n ? this.defaultAccountId\n : `accounts/${this.defaultAccountId}`;\n }\n\n // Fall back to first available account\n const accounts = await this.listAccounts();\n if (accounts.length === 0) {\n throw new Error('No AdSense accounts found');\n }\n return accounts[0].name;\n }\n\n /**\n * Extract publisher ID from account name\n */\n private extractPubId(accountName: string): string {\n return accountName.replace('accounts/', '');\n }\n\n // ==================== Account Operations ====================\n\n /**\n * List all AdSense accounts\n */\n async listAccounts(): Promise<AdSenseAccount[]> {\n const cache = getCache();\n const cacheKey = 'accounts';\n const cached = cache.get<AdSenseAccount[]>(cacheKey, {});\n\n if (cached) {\n return cached;\n }\n\n await rateLimiter.throttle();\n const response = await withRetry(() =>\n this.adsense.accounts.list()\n );\n\n const accounts = (response.data.accounts || []) as AdSenseAccount[];\n cache.set(cacheKey, {}, accounts, CacheTTL.ACCOUNTS, 'global');\n\n return accounts;\n }\n\n /**\n * Get a specific account\n */\n async getAccount(accountId?: string): Promise<AdSenseAccount | null> {\n const resolvedId = await this.resolveAccountId(accountId);\n\n await rateLimiter.throttle();\n try {\n const response = await withRetry(() =>\n this.adsense.accounts.get({ name: resolvedId })\n );\n return response.data as AdSenseAccount;\n } catch {\n return null;\n }\n }\n\n // ==================== Sites Operations ====================\n\n /**\n * List all sites for an account\n */\n async listSites(accountId?: string): Promise<AdSenseSite[]> {\n const resolvedId = await this.resolveAccountId(accountId);\n const cache = getCache();\n const params = { accountId: resolvedId };\n const cached = cache.get<AdSenseSite[]>('sites', params);\n\n if (cached) {\n return cached;\n }\n\n await rateLimiter.throttle();\n const response = await withRetry(() =>\n this.adsense.accounts.sites.list({ parent: resolvedId })\n );\n\n const sites = (response.data.sites || []) as AdSenseSite[];\n cache.set('sites', params, sites, CacheTTL.SITES, this.extractPubId(resolvedId));\n\n return sites;\n }\n\n // ==================== Alerts Operations ====================\n\n /**\n * List alerts for an account\n */\n async listAlerts(accountId?: string): Promise<AdSenseAlert[]> {\n const resolvedId = await this.resolveAccountId(accountId);\n const cache = getCache();\n const params = { accountId: resolvedId };\n const cached = cache.get<AdSenseAlert[]>('alerts', params);\n\n if (cached) {\n return cached;\n }\n\n await rateLimiter.throttle();\n const response = await withRetry(() =>\n this.adsense.accounts.alerts.list({ parent: resolvedId })\n );\n\n const alerts = (response.data.alerts || []) as AdSenseAlert[];\n cache.set('alerts', params, alerts, CacheTTL.ALERTS, this.extractPubId(resolvedId));\n\n return alerts;\n }\n\n // ==================== Policy Issues Operations ====================\n\n /**\n * List policy issues for an account\n */\n async listPolicyIssues(accountId?: string): Promise<AdSensePolicyIssue[]> {\n const resolvedId = await this.resolveAccountId(accountId);\n const cache = getCache();\n const params = { accountId: resolvedId };\n const cached = cache.get<AdSensePolicyIssue[]>('policyIssues', params);\n\n if (cached) {\n return cached;\n }\n\n await rateLimiter.throttle();\n const response = await withRetry(() =>\n this.adsense.accounts.policyIssues.list({ parent: resolvedId })\n );\n\n const issues = (response.data.policyIssues || []) as AdSensePolicyIssue[];\n cache.set('policyIssues', params, issues, CacheTTL.POLICY_ISSUES, this.extractPubId(resolvedId));\n\n return issues;\n }\n\n // ==================== Payments Operations ====================\n\n /**\n * List payments for an account\n */\n async listPayments(accountId?: string): Promise<AdSensePayment[]> {\n const resolvedId = await this.resolveAccountId(accountId);\n const cache = getCache();\n const params = { accountId: resolvedId };\n const cached = cache.get<AdSensePayment[]>('payments', params);\n\n if (cached) {\n return cached;\n }\n\n await rateLimiter.throttle();\n const response = await withRetry(() =>\n this.adsense.accounts.payments.list({ parent: resolvedId })\n );\n\n const payments = (response.data.payments || []) as AdSensePayment[];\n cache.set('payments', params, payments, CacheTTL.PAYMENTS, this.extractPubId(resolvedId));\n\n return payments;\n }\n\n // ==================== Ad Client Operations ====================\n\n /**\n * List ad clients for an account\n */\n async listAdClients(accountId?: string): Promise<AdSenseAdClient[]> {\n const resolvedId = await this.resolveAccountId(accountId);\n\n await rateLimiter.throttle();\n const response = await withRetry(() =>\n this.adsense.accounts.adclients.list({ parent: resolvedId })\n );\n\n return (response.data.adClients || []) as AdSenseAdClient[];\n }\n\n // ==================== Ad Unit Operations ====================\n\n /**\n * List ad units for an account (across all ad clients)\n */\n async listAdUnits(accountId?: string): Promise<AdSenseAdUnit[]> {\n const resolvedId = await this.resolveAccountId(accountId);\n const cache = getCache();\n const params = { accountId: resolvedId };\n const cached = cache.get<AdSenseAdUnit[]>('adUnits', params);\n\n if (cached) {\n return cached;\n }\n\n // First get all ad clients\n const adClients = await this.listAdClients(accountId);\n const allAdUnits: AdSenseAdUnit[] = [];\n\n // Then get ad units for each client\n for (const client of adClients) {\n await rateLimiter.throttle();\n const response = await withRetry(() =>\n this.adsense.accounts.adclients.adunits.list({ parent: client.name })\n );\n allAdUnits.push(...((response.data.adUnits || []) as AdSenseAdUnit[]));\n }\n\n cache.set('adUnits', params, allAdUnits, CacheTTL.AD_UNITS, this.extractPubId(resolvedId));\n\n return allAdUnits;\n }\n\n /**\n * Get ad code for an ad unit\n */\n async getAdCode(adClientId: string, adUnitId: string, accountId?: string): Promise<string> {\n const resolvedId = await this.resolveAccountId(accountId);\n const adUnitName = `${resolvedId}/adclients/${adClientId}/adunits/${adUnitId}`;\n\n await rateLimiter.throttle();\n const response = await withRetry(() =>\n this.adsense.accounts.adclients.adunits.getAdcode({ name: adUnitName })\n );\n\n return response.data.adCode || '';\n }\n\n // ==================== Report Operations ====================\n\n /**\n * Generate a report\n */\n async generateReport(query: ReportQuery): Promise<ReportResponse> {\n const resolvedId = await this.resolveAccountId(query.accountId);\n const cache = getCache();\n\n // Determine appropriate TTL based on date range\n const ttl = this.getReportTTL(query.startDate, query.endDate);\n const cached = cache.get<ReportResponse>('report', { ...query, accountId: resolvedId });\n\n if (cached) {\n return cached;\n }\n\n await rateLimiter.throttle();\n\n // Build request parameters\n const params: any = {\n account: resolvedId,\n 'dateRange': query.dateRange || 'CUSTOM',\n 'startDate.year': parseInt(query.startDate.split('-')[0]),\n 'startDate.month': parseInt(query.startDate.split('-')[1]),\n 'startDate.day': parseInt(query.startDate.split('-')[2]),\n 'endDate.year': parseInt(query.endDate.split('-')[0]),\n 'endDate.month': parseInt(query.endDate.split('-')[1]),\n 'endDate.day': parseInt(query.endDate.split('-')[2]),\n };\n\n // Add dimensions\n if (query.dimensions && query.dimensions.length > 0) {\n params.dimensions = query.dimensions;\n }\n\n // Add metrics (default to basic earnings metrics)\n params.metrics = query.metrics || [\n 'ESTIMATED_EARNINGS',\n 'IMPRESSIONS',\n 'CLICKS',\n 'PAGE_VIEWS',\n 'PAGE_VIEWS_CTR',\n 'PAGE_VIEWS_RPM',\n ];\n\n // Add ordering\n if (query.orderBy) {\n params.orderBy = query.orderBy.startsWith('-')\n ? `${query.orderBy.slice(1)} DESC`\n : `${query.orderBy} ASC`;\n }\n\n // Add limit\n if (query.limit) {\n params.limit = Math.min(query.limit, 100000);\n }\n\n const response = await withRetry(() =>\n this.adsense.accounts.reports.generate(params)\n );\n\n const report = response.data as ReportResponse;\n cache.set('report', { ...query, accountId: resolvedId }, report, ttl, this.extractPubId(resolvedId));\n\n return report;\n }\n\n /**\n * Generate a CSV report\n */\n async generateCsvReport(query: ReportQuery): Promise<string> {\n const resolvedId = await this.resolveAccountId(query.accountId);\n\n await rateLimiter.throttle();\n\n const params: any = {\n account: resolvedId,\n 'dateRange': query.dateRange || 'CUSTOM',\n 'startDate.year': parseInt(query.startDate.split('-')[0]),\n 'startDate.month': parseInt(query.startDate.split('-')[1]),\n 'startDate.day': parseInt(query.startDate.split('-')[2]),\n 'endDate.year': parseInt(query.endDate.split('-')[0]),\n 'endDate.month': parseInt(query.endDate.split('-')[1]),\n 'endDate.day': parseInt(query.endDate.split('-')[2]),\n };\n\n if (query.dimensions) {\n params.dimensions = query.dimensions;\n }\n\n params.metrics = query.metrics || [\n 'ESTIMATED_EARNINGS',\n 'IMPRESSIONS',\n 'CLICKS',\n 'PAGE_VIEWS',\n ];\n\n const response = await withRetry(() =>\n this.adsense.accounts.reports.generateCsv(params)\n );\n\n // Response is a stream, convert to string\n return response.data as unknown as string;\n }\n\n /**\n * Get earnings summary (today, yesterday, last 7 days, this month, last month)\n */\n async getEarningsSummary(accountId?: string): Promise<EarningsSummary> {\n const resolvedId = await this.resolveAccountId(accountId);\n const today = new Date();\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n\n const formatDate = (d: Date) => d.toISOString().split('T')[0];\n\n // Calculate date ranges\n const todayStr = formatDate(today);\n const yesterdayStr = formatDate(yesterday);\n\n const last7DaysStart = new Date(today);\n last7DaysStart.setDate(last7DaysStart.getDate() - 6);\n\n const thisMonthStart = new Date(today.getFullYear(), today.getMonth(), 1);\n const lastMonthStart = new Date(today.getFullYear(), today.getMonth() - 1, 1);\n const lastMonthEnd = new Date(today.getFullYear(), today.getMonth(), 0);\n\n // Fetch reports for each period\n const [todayReport, yesterdayReport, last7DaysReport, thisMonthReport, lastMonthReport] =\n await Promise.all([\n this.generateReport({\n accountId: resolvedId,\n startDate: todayStr,\n endDate: todayStr,\n }),\n this.generateReport({\n accountId: resolvedId,\n startDate: yesterdayStr,\n endDate: yesterdayStr,\n }),\n this.generateReport({\n accountId: resolvedId,\n startDate: formatDate(last7DaysStart),\n endDate: todayStr,\n }),\n this.generateReport({\n accountId: resolvedId,\n startDate: formatDate(thisMonthStart),\n endDate: todayStr,\n }),\n this.generateReport({\n accountId: resolvedId,\n startDate: formatDate(lastMonthStart),\n endDate: formatDate(lastMonthEnd),\n }),\n ]);\n\n return {\n today: this.extractEarningsPeriod(todayReport),\n yesterday: this.extractEarningsPeriod(yesterdayReport),\n last7Days: this.extractEarningsPeriod(last7DaysReport),\n thisMonth: this.extractEarningsPeriod(thisMonthReport),\n lastMonth: this.extractEarningsPeriod(lastMonthReport),\n };\n }\n\n /**\n * Extract earnings data from a report response\n */\n private extractEarningsPeriod(report: ReportResponse): EarningsPeriod {\n const totals = report.totals?.cells || report.rows?.[0]?.cells || [];\n const headers = report.headers || [];\n\n const getValue = (metricName: string): number => {\n const index = headers.findIndex(h => h.name === metricName);\n if (index >= 0 && totals[index]) {\n return parseFloat(totals[index].value) || 0;\n }\n return 0;\n };\n\n return {\n earnings: getValue('ESTIMATED_EARNINGS'),\n impressions: getValue('IMPRESSIONS'),\n clicks: getValue('CLICKS'),\n ctr: getValue('PAGE_VIEWS_CTR') || getValue('IMPRESSIONS_CTR'),\n rpm: getValue('PAGE_VIEWS_RPM') || getValue('IMPRESSIONS_RPM'),\n pageViews: getValue('PAGE_VIEWS'),\n };\n }\n\n /**\n * Determine appropriate cache TTL based on date range\n */\n private getReportTTL(startDate: string, endDate: string): number {\n const today = new Date().toISOString().split('T')[0];\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n const yesterdayStr = yesterday.toISOString().split('T')[0];\n\n if (endDate === today || startDate === today) {\n return CacheTTL.TODAY_EARNINGS;\n }\n\n if (endDate === yesterdayStr) {\n return CacheTTL.YESTERDAY_EARNINGS;\n }\n\n return CacheTTL.HISTORICAL_REPORT;\n }\n}\n","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport envPaths from 'env-paths';\nimport type { Config, StoredTokens } from '../types.js';\n\nconst paths = envPaths('adsense-mcp');\n\n// Service name for keytar\nconst KEYTAR_SERVICE = 'adsense-mcp';\nconst KEYTAR_ACCOUNT = 'tokens';\n\n/**\n * Get the configuration directory path\n */\nexport function getConfigDir(): string {\n return paths.config;\n}\n\n/**\n * Ensure the config directory exists\n */\nasync function ensureConfigDir(): Promise<void> {\n await fs.mkdir(paths.config, { recursive: true });\n}\n\n/**\n * Load configuration from disk\n */\nexport async function loadConfig(): Promise<Config> {\n await ensureConfigDir();\n const configPath = path.join(paths.config, 'config.json');\n\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n return JSON.parse(content) as Config;\n } catch {\n // Return default config if file doesn't exist\n return {\n authType: 'oauth',\n scope: 'readonly',\n };\n }\n}\n\n/**\n * Save configuration to disk\n */\nexport async function saveConfig(config: Config): Promise<void> {\n await ensureConfigDir();\n const configPath = path.join(paths.config, 'config.json');\n await fs.writeFile(configPath, JSON.stringify(config, null, 2));\n}\n\n/**\n * Load tokens from secure storage (keytar) or fallback to file\n */\nexport async function loadTokens(): Promise<StoredTokens | null> {\n // Try keytar first (secure OS keychain)\n try {\n const keytar = await import('keytar');\n const stored = await keytar.getPassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);\n if (stored) {\n return JSON.parse(stored) as StoredTokens;\n }\n } catch {\n // Keytar not available, fall back to file\n }\n\n // Fallback to file storage\n await ensureConfigDir();\n const tokensPath = path.join(paths.config, 'tokens.json');\n\n try {\n const content = await fs.readFile(tokensPath, 'utf-8');\n return JSON.parse(content) as StoredTokens;\n } catch {\n return null;\n }\n}\n\n/**\n * Save tokens to secure storage (keytar) or fallback to file\n */\nexport async function saveTokens(tokens: StoredTokens): Promise<void> {\n const tokenString = JSON.stringify(tokens);\n\n // Try keytar first (secure OS keychain)\n try {\n const keytar = await import('keytar');\n await keytar.setPassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT, tokenString);\n return;\n } catch {\n // Keytar not available, fall back to file\n }\n\n // Fallback to file storage\n await ensureConfigDir();\n const tokensPath = path.join(paths.config, 'tokens.json');\n await fs.writeFile(tokensPath, tokenString, { mode: 0o600 });\n}\n\n/**\n * Delete stored tokens\n */\nexport async function deleteTokens(): Promise<void> {\n // Try keytar first\n try {\n const keytar = await import('keytar');\n await keytar.deletePassword(KEYTAR_SERVICE, KEYTAR_ACCOUNT);\n } catch {\n // Ignore errors\n }\n\n // Also delete file if exists\n const tokensPath = path.join(paths.config, 'tokens.json');\n try {\n await fs.unlink(tokensPath);\n } catch {\n // Ignore errors\n }\n}\n\n/**\n * Get the cache database path\n */\nexport function getCachePath(): string {\n return path.join(paths.config, 'cache.sqlite');\n}\n\n/**\n * Get the logs directory\n */\nexport function getLogsDir(): string {\n return path.join(paths.config, 'logs');\n}\n","import { OAuth2Client } from 'google-auth-library';\nimport { loadConfig, loadTokens, saveTokens } from './tokenStore.js';\nimport { ADSENSE_SCOPES, type ScopeType } from '../types.js';\n\n/**\n * Create an authenticated OAuth2 client\n */\nexport async function createOAuthClient(): Promise<OAuth2Client> {\n const config = await loadConfig();\n\n if (config.authType !== 'oauth') {\n throw new Error('OAuth not configured. Run `adsense-mcp init` to set up OAuth.');\n }\n\n const oauth2Client = new OAuth2Client({\n clientId: config.clientId,\n clientSecret: config.clientSecret,\n });\n\n const tokens = await loadTokens();\n if (!tokens) {\n throw new Error('No tokens found. Run `adsense-mcp init` to authenticate.');\n }\n\n oauth2Client.setCredentials({\n access_token: tokens.accessToken,\n refresh_token: tokens.refreshToken,\n expiry_date: tokens.expiryDate,\n });\n\n // Set up automatic token refresh\n oauth2Client.on('tokens', async (newTokens) => {\n await saveTokens({\n accessToken: newTokens.access_token || tokens.accessToken,\n refreshToken: newTokens.refresh_token || tokens.refreshToken,\n expiryDate: newTokens.expiry_date || Date.now() + 3600000,\n });\n });\n\n return oauth2Client;\n}\n\n/**\n * Get the required scopes for the current configuration\n */\nexport async function getScopes(): Promise<string[]> {\n const config = await loadConfig();\n return ADSENSE_SCOPES[config.scope];\n}\n\n/**\n * Get scopes by type\n */\nexport function getScopesByType(scopeType: ScopeType): string[] {\n return ADSENSE_SCOPES[scopeType];\n}\n\n/**\n * Check if the current scope supports a given feature\n */\nexport async function hasScope(requiredScope: ScopeType): Promise<boolean> {\n const config = await loadConfig();\n\n if (requiredScope === 'readonly') {\n return true; // readonly is always available\n }\n\n return config.scope === requiredScope;\n}\n\n/**\n * Get a helpful error message for scope upgrade\n */\nexport function getScopeUpgradeMessage(feature: string): string {\n return `The \"${feature}\" feature requires full scope access.\\n` +\n 'Note: This MCP server uses read-only scope by design for safety.';\n}\n","/**\n * AdSense MCP Server - Type Definitions\n */\n\n// OAuth Scopes\nexport const ADSENSE_SCOPES: Record<string, string[]> = {\n readonly: ['https://www.googleapis.com/auth/adsense.readonly'],\n // Full scope available but NOT recommended for MCP use:\n // full: ['https://www.googleapis.com/auth/adsense'],\n};\n\nexport type ScopeType = 'readonly';\n\n// Configuration\nexport interface Config {\n authType: 'oauth' | 'service-account';\n clientId?: string;\n clientSecret?: string;\n serviceAccountPath?: string;\n defaultAccountId?: string;\n scope: ScopeType;\n}\n\n// Token storage\nexport interface StoredTokens {\n accessToken: string;\n refreshToken?: string;\n expiryDate?: number;\n}\n\n// AdSense Account\nexport interface AdSenseAccount {\n name: string; // Format: accounts/pub-XXXXXXXXXXXXXXXX\n displayName?: string;\n timeZone?: {\n id: string;\n };\n createTime?: string;\n premium?: boolean;\n pendingTasks?: string[];\n}\n\n// AdSense Site\nexport interface AdSenseSite {\n name: string;\n reportingDimensionId?: string;\n domain: string;\n state: 'REQUIRES_REVIEW' | 'GETTING_READY' | 'READY' | 'NEEDS_ATTENTION' | 'STATE_UNSPECIFIED';\n autoAdsEnabled?: boolean;\n}\n\n// AdSense Alert\nexport interface AdSenseAlert {\n name: string;\n severity: 'SEVERITY_UNSPECIFIED' | 'INFO' | 'WARNING' | 'SEVERE';\n message: string;\n type: string;\n}\n\n// AdSense Policy Issue\nexport interface AdSensePolicyIssue {\n name: string;\n site?: string;\n siteSection?: string;\n uri?: string;\n adRequestCount?: string;\n entityType?: 'ENTITY_TYPE_UNSPECIFIED' | 'SITE' | 'SITE_SECTION' | 'PAGE';\n action?: 'ENFORCEMENT_ACTION_UNSPECIFIED' | 'WARNED' | 'AD_SERVING_RESTRICTED' | 'AD_SERVING_DISABLED' | 'AD_SERVED_WITH_CLICK_CONFIRMATION' | 'AD_PERSONALIZATION_RESTRICTED';\n warningEscalationDate?: { year: number; month: number; day: number };\n}\n\n// AdSense Payment\nexport interface AdSensePayment {\n name: string;\n amount?: string;\n date?: { year: number; month: number; day: number };\n}\n\n// AdSense Ad Client\nexport interface AdSenseAdClient {\n name: string;\n reportingDimensionId?: string;\n productCode?: 'AFC' | 'AFG' | 'AFMC' | 'AFS' | 'AFV' | 'AFVH';\n state?: 'READY' | 'GETTING_READY' | 'REQUIRES_REVIEW' | 'STATE_UNSPECIFIED';\n}\n\n// AdSense Ad Unit\nexport interface AdSenseAdUnit {\n name: string;\n reportingDimensionId?: string;\n displayName: string;\n state: 'ACTIVE' | 'ARCHIVED' | 'STATE_UNSPECIFIED';\n contentAdsSettings?: {\n type?: 'DISPLAY' | 'FEED' | 'ARTICLE' | 'MATCHED_CONTENT' | 'LINK';\n size?: string;\n };\n}\n\n// Report Types\nexport type ReportDimension =\n | 'DATE'\n | 'WEEK'\n | 'MONTH'\n | 'DOMAIN_CODE'\n | 'DOMAIN_NAME'\n | 'PAGE_URL'\n | 'AD_UNIT_ID'\n | 'AD_UNIT_NAME'\n | 'AD_UNIT_SIZE_CODE'\n | 'AD_UNIT_SIZE_NAME'\n | 'AD_FORMAT_CODE'\n | 'AD_FORMAT_NAME'\n | 'AD_PLACEMENT_CODE'\n | 'AD_PLACEMENT_NAME'\n | 'COUNTRY_CODE'\n | 'COUNTRY_NAME'\n | 'PLATFORM_TYPE_CODE'\n | 'PLATFORM_TYPE_NAME'\n | 'CONTENT_PLATFORM_CODE'\n | 'CONTENT_PLATFORM_NAME'\n | 'TRAFFIC_SOURCE_CODE'\n | 'TRAFFIC_SOURCE_NAME'\n | 'BUYER_NETWORK_ID'\n | 'BUYER_NETWORK_NAME'\n | 'BID_TYPE_CODE'\n | 'BID_TYPE_NAME'\n | 'TARGETING_TYPE_CODE'\n | 'TARGETING_TYPE_NAME'\n | 'CUSTOM_CHANNEL_ID'\n | 'CUSTOM_CHANNEL_NAME'\n | 'URL_CHANNEL_ID'\n | 'URL_CHANNEL_NAME'\n | 'OWNED_SITE_ID'\n | 'OWNED_SITE_DOMAIN_NAME';\n\nexport type ReportMetric =\n | 'ESTIMATED_EARNINGS'\n | 'TOTAL_EARNINGS'\n | 'COST_PER_CLICK'\n | 'PAGE_VIEWS'\n | 'AD_REQUESTS'\n | 'MATCHED_AD_REQUESTS'\n | 'IMPRESSIONS'\n | 'INDIVIDUAL_AD_IMPRESSIONS'\n | 'CLICKS'\n | 'AD_REQUESTS_COVERAGE'\n | 'PAGE_VIEWS_CTR'\n | 'AD_REQUESTS_CTR'\n | 'IMPRESSIONS_CTR'\n | 'PAGE_VIEWS_RPM'\n | 'AD_REQUESTS_RPM'\n | 'IMPRESSIONS_RPM'\n | 'ACTIVE_VIEW_MEASURABILITY'\n | 'ACTIVE_VIEW_VIEWABILITY'\n | 'ACTIVE_VIEW_TIME'\n | 'PAGE_VIEWS_SPAM_RATIO'\n | 'AD_REQUESTS_SPAM_RATIO'\n | 'CLICKS_SPAM_RATIO'\n | 'IMPRESSIONS_SPAM_RATIO';\n\nexport interface ReportQuery {\n accountId: string;\n startDate: string; // YYYY-MM-DD\n endDate: string; // YYYY-MM-DD\n dimensions?: ReportDimension[];\n metrics?: ReportMetric[];\n orderBy?: string;\n limit?: number;\n filters?: string[];\n currencyCode?: string;\n dateRange?: 'CUSTOM' | 'TODAY' | 'YESTERDAY' | 'MONTH_TO_DATE' | 'YEAR_TO_DATE' | 'LAST_7_DAYS' | 'LAST_30_DAYS';\n}\n\nexport interface ReportRow {\n cells: Array<{\n value: string;\n }>;\n}\n\nexport interface ReportResponse {\n headers: Array<{\n name: string;\n type: 'DIMENSION' | 'METRIC_TALLY' | 'METRIC_RATIO' | 'METRIC_CURRENCY' | 'METRIC_MILLISECONDS' | 'METRIC_DECIMAL';\n currencyCode?: string;\n }>;\n rows: ReportRow[];\n totals?: ReportRow;\n averages?: ReportRow;\n startDate?: { year: number; month: number; day: number };\n endDate?: { year: number; month: number; day: number };\n totalMatchedRows?: string;\n}\n\n// Earnings Summary (computed)\nexport interface EarningsSummary {\n today: EarningsPeriod;\n yesterday: EarningsPeriod;\n last7Days: EarningsPeriod;\n thisMonth: EarningsPeriod;\n lastMonth: EarningsPeriod;\n}\n\nexport interface EarningsPeriod {\n earnings: number;\n impressions: number;\n clicks: number;\n ctr: number;\n rpm: number;\n pageViews: number;\n}\n\n// Cache types\nexport interface CacheEntry {\n id?: number;\n cacheKey: string;\n accountId: string;\n queryHash: string;\n responseData: string;\n createdAt: number;\n expiresAt: number;\n}\n\n// Tool input types\nexport interface ListAccountsInput {\n // No parameters\n}\n\nexport interface EarningsSummaryInput {\n accountId?: string;\n}\n\nexport interface GenerateReportInput {\n accountId?: string;\n startDate?: string;\n endDate?: string;\n dimensions?: string[];\n metrics?: string[];\n orderBy?: string;\n limit?: number;\n}\n\nexport interface ComparePeriodsInput {\n accountId?: string;\n period1Start: string;\n period1End: string;\n period2Start: string;\n period2End: string;\n dimensions?: string[];\n}\n\nexport interface ListSitesInput {\n accountId?: string;\n}\n\nexport interface ListAlertsInput {\n accountId?: string;\n}\n\nexport interface ListPolicyIssuesInput {\n accountId?: string;\n}\n\nexport interface ListPaymentsInput {\n accountId?: string;\n}\n\nexport interface ListAdUnitsInput {\n accountId?: string;\n}\n\nexport interface GetAdCodeInput {\n accountId?: string;\n adClientId: string;\n adUnitId: string;\n}\n\nexport interface ExportCsvInput {\n accountId?: string;\n startDate: string;\n endDate: string;\n dimensions?: string[];\n metrics?: string[];\n}\n","import { google } from 'googleapis';\nimport { loadConfig } from './tokenStore.js';\nimport { ADSENSE_SCOPES } from '../types.js';\nimport * as fs from 'fs/promises';\n\n/**\n * Create an authenticated client using service account credentials\n */\nexport async function createServiceAccountClient() {\n const config = await loadConfig();\n\n if (config.authType !== 'service-account') {\n throw new Error('Service account not configured. Run `adsense-mcp init --service-account <path>` to set up.');\n }\n\n if (!config.serviceAccountPath) {\n throw new Error('Service account path not configured.');\n }\n\n // Read the service account key file\n const keyFileContent = await fs.readFile(config.serviceAccountPath, 'utf-8');\n const keyFile = JSON.parse(keyFileContent);\n\n // Create JWT client\n const auth = new google.auth.JWT({\n email: keyFile.client_email,\n key: keyFile.private_key,\n scopes: ADSENSE_SCOPES[config.scope],\n });\n\n return auth;\n}\n","/**\n * Rate limiter for AdSense API\n * \n * AdSense API limits:\n * - 100 requests per minute per user\n * - 500 requests per minute per project\n * - 10,000 requests per day\n */\n\nconst MAX_REQUESTS_PER_MINUTE = 100;\nconst MAX_RETRIES = 5;\nconst BASE_DELAY_MS = 1000;\nconst MAX_DELAY_MS = 32000;\n\nexport class RateLimiter {\n private requestTimestamps: number[] = [];\n\n /**\n * Wait if necessary to stay under rate limit\n */\n async throttle(): Promise<void> {\n const now = Date.now();\n const oneMinuteAgo = now - 60000;\n\n // Remove old timestamps\n this.requestTimestamps = this.requestTimestamps.filter(\n ts => ts > oneMinuteAgo\n );\n\n // If we're at the limit, wait until the oldest request expires\n if (this.requestTimestamps.length >= MAX_REQUESTS_PER_MINUTE) {\n const oldestInWindow = this.requestTimestamps[0];\n const waitTime = oldestInWindow + 60000 - now + 100; // Add 100ms buffer\n if (waitTime > 0) {\n await sleep(waitTime);\n }\n }\n\n // Record this request\n this.requestTimestamps.push(Date.now());\n }\n\n /**\n * Get current request count in the last minute\n */\n getRequestCount(): number {\n const oneMinuteAgo = Date.now() - 60000;\n return this.requestTimestamps.filter(ts => ts > oneMinuteAgo).length;\n }\n\n /**\n * Check if we're close to the rate limit\n */\n isNearLimit(): boolean {\n return this.getRequestCount() >= MAX_REQUESTS_PER_MINUTE * 0.8;\n }\n}\n\n/**\n * Execute an operation with exponential backoff retry\n */\nexport async function withRetry<T>(\n operation: () => Promise<T>,\n retries = MAX_RETRIES\n): Promise<T> {\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n return await operation();\n } catch (error: any) {\n lastError = error;\n\n const isRateLimited =\n error.code === 429 ||\n error.status === 429 ||\n error.message?.includes('quota') ||\n error.message?.includes('rate limit') ||\n error.message?.includes('RATE_LIMIT_EXCEEDED');\n\n const isRetryable =\n isRateLimited ||\n error.code === 503 ||\n error.code === 500 ||\n error.status === 503 ||\n error.status === 500 ||\n error.code === 'ECONNRESET' ||\n error.code === 'ETIMEDOUT';\n\n if (!isRetryable || attempt === retries - 1) {\n throw error;\n }\n\n // Calculate delay with exponential backoff + jitter\n const delay = Math.min(\n BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 1000,\n MAX_DELAY_MS\n );\n\n console.error(\n `Request failed (attempt ${attempt + 1}/${retries}), retrying in ${Math.round(delay)}ms...`\n );\n\n await sleep(delay);\n }\n }\n\n throw lastError || new Error('Max retries exceeded');\n}\n\n/**\n * Sleep helper\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n// Global rate limiter instance\nexport const rateLimiter = new RateLimiter();\n","/**\n * SQLite cache for AdSense API responses\n * \n * TTL Strategy:\n * - Today's earnings: 5 minutes (changes frequently)\n * - Yesterday's earnings: 1 hour (may update for spam filtering)\n * - Historical reports (>2 days): 24 hours (stable data)\n * - Account list: 24 hours (rarely changes)\n * - Sites list: 1 hour (status can change)\n * - Alerts: 15 minutes (important to catch quickly)\n * - Policy issues: 30 minutes (critical monitoring)\n * - Payments: 6 hours (rarely changes)\n */\n\nimport Database from 'better-sqlite3';\nimport { getCachePath } from '../auth/tokenStore.js';\nimport * as crypto from 'crypto';\n\n// TTL values in milliseconds\nexport const CacheTTL = {\n TODAY_EARNINGS: 5 * 60 * 1000, // 5 minutes\n YESTERDAY_EARNINGS: 60 * 60 * 1000, // 1 hour\n HISTORICAL_REPORT: 24 * 60 * 60 * 1000, // 24 hours\n ACCOUNTS: 24 * 60 * 60 * 1000, // 24 hours\n SITES: 60 * 60 * 1000, // 1 hour\n ALERTS: 15 * 60 * 1000, // 15 minutes\n POLICY_ISSUES: 30 * 60 * 1000, // 30 minutes\n PAYMENTS: 6 * 60 * 60 * 1000, // 6 hours\n AD_UNITS: 60 * 60 * 1000, // 1 hour\n} as const;\n\nexport class CacheManager {\n private db: Database.Database;\n\n constructor(dbPath?: string) {\n this.db = new Database(dbPath || getCachePath());\n this.initSchema();\n }\n\n /**\n * Initialize database schema\n */\n private initSchema(): void {\n this.db.exec(`\n -- Report cache with TTL\n CREATE TABLE IF NOT EXISTS report_cache (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n cache_key TEXT UNIQUE NOT NULL,\n account_id TEXT NOT NULL,\n query_hash TEXT NOT NULL,\n response_data TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_report_cache_key ON report_cache(cache_key);\n CREATE INDEX IF NOT EXISTS idx_report_cache_expires ON report_cache(expires_at);\n\n -- Account info cache\n CREATE TABLE IF NOT EXISTS accounts_cache (\n account_id TEXT PRIMARY KEY,\n account_data TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n );\n\n -- Query history for analytics\n CREATE TABLE IF NOT EXISTS query_history (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n account_id TEXT NOT NULL,\n tool_name TEXT NOT NULL,\n query_params TEXT,\n executed_at INTEGER NOT NULL,\n response_time_ms INTEGER\n );\n `);\n }\n\n /**\n * Generate a cache key from query parameters\n */\n private generateCacheKey(prefix: string, params: Record<string, any>): string {\n const hash = crypto\n .createHash('md5')\n .update(JSON.stringify(params))\n .digest('hex');\n return `${prefix}:${hash}`;\n }\n\n /**\n * Get cached data if not expired\n */\n get<T>(prefix: string, params: Record<string, any>): T | null {\n const cacheKey = this.generateCacheKey(prefix, params);\n const now = Date.now();\n\n const row = this.db\n .prepare('SELECT response_data, expires_at FROM report_cache WHERE cache_key = ?')\n .get(cacheKey) as { response_data: string; expires_at: number } | undefined;\n\n if (row && row.expires_at > now) {\n return JSON.parse(row.response_data) as T;\n }\n\n return null;\n }\n\n /**\n * Store data in cache\n */\n set(prefix: string, params: Record<string, any>, data: any, ttl: number, accountId: string): void {\n const cacheKey = this.generateCacheKey(prefix, params);\n const queryHash = crypto.createHash('md5').update(JSON.stringify(params)).digest('hex');\n const now = Date.now();\n\n this.db\n .prepare(`\n INSERT OR REPLACE INTO report_cache \n (cache_key, account_id, query_hash, response_data, created_at, expires_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `)\n .run(cacheKey, accountId, queryHash, JSON.stringify(data), now, now + ttl);\n }\n\n /**\n * Clear expired cache entries\n */\n clearExpired(): number {\n const result = this.db\n .prepare('DELETE FROM report_cache WHERE expires_at < ?')\n .run(Date.now());\n return result.changes;\n }\n\n /**\n * Clear all cache for an account\n */\n clearAccount(accountId: string): number {\n const result = this.db\n .prepare('DELETE FROM report_cache WHERE account_id = ?')\n .run(accountId);\n return result.changes;\n }\n\n /**\n * Clear all cache\n */\n clearAll(): void {\n this.db.exec('DELETE FROM report_cache');\n this.db.exec('DELETE FROM accounts_cache');\n }\n\n /**\n * Record a query for analytics\n */\n recordQuery(accountId: string, toolName: string, params: any, responseTimeMs: number): void {\n this.db\n .prepare(`\n INSERT INTO query_history (account_id, tool_name, query_params, executed_at, response_time_ms)\n VALUES (?, ?, ?, ?, ?)\n `)\n .run(accountId, toolName, JSON.stringify(params), Date.now(), responseTimeMs);\n }\n\n /**\n * Get cache statistics\n */\n getStats(): { totalEntries: number; totalSize: number; expiredCount: number } {\n const now = Date.now();\n\n const totalEntries = (this.db\n .prepare('SELECT COUNT(*) as count FROM report_cache')\n .get() as { count: number }).count;\n\n const expiredCount = (this.db\n .prepare('SELECT COUNT(*) as count FROM report_cache WHERE expires_at < ?')\n .get(now) as { count: number }).count;\n\n // Estimate size (rough, based on response_data length)\n const sizeResult = this.db\n .prepare('SELECT SUM(LENGTH(response_data)) as size FROM report_cache')\n .get() as { size: number | null };\n\n return {\n totalEntries,\n totalSize: sizeResult.size || 0,\n expiredCount,\n };\n }\n\n /**\n * Close database connection\n */\n close(): void {\n this.db.close();\n }\n}\n\n// Singleton instance\nlet cacheInstance: CacheManager | null = null;\n\nexport function getCache(): CacheManager {\n if (!cacheInstance) {\n cacheInstance = new CacheManager();\n }\n return cacheInstance;\n}\n\nexport function closeCache(): void {\n if (cacheInstance) {\n cacheInstance.close();\n cacheInstance = null;\n }\n}\n","/**\n * Account tools\n */\n\nimport { AdSenseClient } from '../../adsense/client.js';\n\n/**\n * List all AdSense accounts\n */\nexport async function handleListAccounts() {\n const client = await AdSenseClient.create();\n const accounts = await client.listAccounts();\n\n return {\n accounts: accounts.map(account => ({\n id: account.name.replace('accounts/', ''),\n name: account.name,\n displayName: account.displayName || 'Unnamed Account',\n timeZone: account.timeZone?.id || 'Unknown',\n createTime: account.createTime,\n premium: account.premium || false,\n })),\n total: accounts.length,\n };\n}\n","/**\n * Report tools\n */\n\nimport { AdSenseClient } from '../../adsense/client.js';\nimport type { ReportDimension, ReportMetric } from '../../types.js';\n\n/**\n * Get earnings summary\n */\nexport async function handleEarningsSummary(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const client = await AdSenseClient.create(accountId);\n const summary = await client.getEarningsSummary(accountId);\n\n // Format currency\n const formatCurrency = (value: number) => `$${value.toFixed(2)}`;\n const formatNumber = (value: number) => value.toLocaleString();\n const formatPercent = (value: number) => `${(value * 100).toFixed(2)}%`;\n\n return {\n summary: {\n today: {\n earnings: formatCurrency(summary.today.earnings),\n impressions: formatNumber(summary.today.impressions),\n clicks: formatNumber(summary.today.clicks),\n ctr: formatPercent(summary.today.ctr),\n rpm: formatCurrency(summary.today.rpm),\n pageViews: formatNumber(summary.today.pageViews),\n },\n yesterday: {\n earnings: formatCurrency(summary.yesterday.earnings),\n impressions: formatNumber(summary.yesterday.impressions),\n clicks: formatNumber(summary.yesterday.clicks),\n ctr: formatPercent(summary.yesterday.ctr),\n rpm: formatCurrency(summary.yesterday.rpm),\n pageViews: formatNumber(summary.yesterday.pageViews),\n },\n last7Days: {\n earnings: formatCurrency(summary.last7Days.earnings),\n impressions: formatNumber(summary.last7Days.impressions),\n clicks: formatNumber(summary.last7Days.clicks),\n ctr: formatPercent(summary.last7Days.ctr),\n rpm: formatCurrency(summary.last7Days.rpm),\n pageViews: formatNumber(summary.last7Days.pageViews),\n },\n thisMonth: {\n earnings: formatCurrency(summary.thisMonth.earnings),\n impressions: formatNumber(summary.thisMonth.impressions),\n clicks: formatNumber(summary.thisMonth.clicks),\n ctr: formatPercent(summary.thisMonth.ctr),\n rpm: formatCurrency(summary.thisMonth.rpm),\n pageViews: formatNumber(summary.thisMonth.pageViews),\n },\n lastMonth: {\n earnings: formatCurrency(summary.lastMonth.earnings),\n impressions: formatNumber(summary.lastMonth.impressions),\n clicks: formatNumber(summary.lastMonth.clicks),\n ctr: formatPercent(summary.lastMonth.ctr),\n rpm: formatCurrency(summary.lastMonth.rpm),\n pageViews: formatNumber(summary.lastMonth.pageViews),\n },\n },\n raw: summary,\n comparison: {\n vsYesterday: summary.yesterday.earnings > 0\n ? ((summary.today.earnings - summary.yesterday.earnings) / summary.yesterday.earnings * 100).toFixed(1) + '%'\n : 'N/A',\n vsLastMonth: summary.lastMonth.earnings > 0\n ? ((summary.thisMonth.earnings - summary.lastMonth.earnings) / summary.lastMonth.earnings * 100).toFixed(1) + '%'\n : 'N/A',\n },\n };\n}\n\n/**\n * Generate a detailed report\n */\nexport async function handleGenerateReport(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const client = await AdSenseClient.create(accountId);\n\n // Default date range: last 7 days\n const endDate = args.endDate as string || getYesterday();\n const startDate = args.startDate as string || get7DaysAgo();\n\n const report = await client.generateReport({\n accountId: accountId || '',\n startDate,\n endDate,\n dimensions: (args.dimensions as ReportDimension[]) || undefined,\n metrics: (args.metrics as ReportMetric[]) || undefined,\n orderBy: (args.orderBy as string) || undefined,\n limit: (args.limit as number) || 100,\n });\n\n // Transform to more readable format\n const headers = report.headers?.map(h => h.name) || [];\n const rows = report.rows?.map(row =>\n row.cells.reduce((acc, cell, i) => {\n acc[headers[i]] = cell.value;\n return acc;\n }, {} as Record<string, string>)\n ) || [];\n\n return {\n dateRange: {\n start: startDate,\n end: endDate,\n },\n headers,\n rows,\n totals: report.totals?.cells.reduce((acc, cell, i) => {\n acc[headers[i]] = cell.value;\n return acc;\n }, {} as Record<string, string>),\n totalRows: report.totalMatchedRows || rows.length.toString(),\n };\n}\n\n/**\n * Compare two time periods\n */\nexport async function handleComparePeriods(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const client = await AdSenseClient.create(accountId);\n\n const period1Start = args.period1Start as string;\n const period1End = args.period1End as string;\n const period2Start = args.period2Start as string;\n const period2End = args.period2End as string;\n\n if (!period1Start || !period1End || !period2Start || !period2End) {\n throw new Error('All period dates are required');\n }\n\n const dimensions = (args.dimensions as ReportDimension[]) || undefined;\n\n // Fetch both periods\n const [report1, report2] = await Promise.all([\n client.generateReport({\n accountId: accountId || '',\n startDate: period1Start,\n endDate: period1End,\n dimensions,\n }),\n client.generateReport({\n accountId: accountId || '',\n startDate: period2Start,\n endDate: period2End,\n dimensions,\n }),\n ]);\n\n // Extract totals\n const extractTotals = (report: any) => {\n const headers = report.headers?.map((h: any) => h.name) || [];\n const totals = report.totals?.cells || report.rows?.[0]?.cells || [];\n return headers.reduce((acc: any, header: string, i: number) => {\n acc[header] = parseFloat(totals[i]?.value) || 0;\n return acc;\n }, {});\n };\n\n const period1Totals = extractTotals(report1);\n const period2Totals = extractTotals(report2);\n\n // Calculate changes\n const changes: Record<string, { period1: number; period2: number; change: string; changePercent: string }> = {};\n\n for (const key of Object.keys(period1Totals)) {\n const val1 = period1Totals[key];\n const val2 = period2Totals[key] || 0;\n const diff = val1 - val2;\n const percent = val2 !== 0 ? (diff / val2) * 100 : 0;\n\n changes[key] = {\n period1: val1,\n period2: val2,\n change: diff >= 0 ? `+${diff.toFixed(2)}` : diff.toFixed(2),\n changePercent: percent >= 0 ? `+${percent.toFixed(1)}%` : `${percent.toFixed(1)}%`,\n };\n }\n\n return {\n period1: {\n start: period1Start,\n end: period1End,\n totals: period1Totals,\n },\n period2: {\n start: period2Start,\n end: period2End,\n totals: period2Totals,\n },\n changes,\n };\n}\n\n// Helper functions\nfunction getYesterday(): string {\n const d = new Date();\n d.setDate(d.getDate() - 1);\n return d.toISOString().split('T')[0];\n}\n\nfunction get7DaysAgo(): string {\n const d = new Date();\n d.setDate(d.getDate() - 7);\n return d.toISOString().split('T')[0];\n}\n","/**\n * Sites tools\n */\n\nimport { AdSenseClient } from '../../adsense/client.js';\n\n/**\n * List all sites with their approval status\n */\nexport async function handleListSites(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const client = await AdSenseClient.create(accountId);\n const sites = await client.listSites(accountId);\n\n // Group by status\n const byStatus = {\n ready: sites.filter(s => s.state === 'READY'),\n gettingReady: sites.filter(s => s.state === 'GETTING_READY'),\n needsAttention: sites.filter(s => s.state === 'NEEDS_ATTENTION'),\n requiresReview: sites.filter(s => s.state === 'REQUIRES_REVIEW'),\n };\n\n // Format sites with status emoji\n const formatSite = (site: any) => {\n const statusEmojiMap: Record<string, string> = {\n 'READY': '✅',\n 'GETTING_READY': '⏳',\n 'NEEDS_ATTENTION': '⚠️',\n 'REQUIRES_REVIEW': '📝',\n 'STATE_UNSPECIFIED': '❓',\n };\n const statusEmoji = statusEmojiMap[site.state] || '❓';\n\n return {\n domain: site.domain,\n status: site.state,\n statusEmoji,\n autoAdsEnabled: site.autoAdsEnabled || false,\n name: site.name,\n };\n };\n\n return {\n sites: sites.map(formatSite),\n summary: {\n total: sites.length,\n ready: byStatus.ready.length,\n gettingReady: byStatus.gettingReady.length,\n needsAttention: byStatus.needsAttention.length,\n requiresReview: byStatus.requiresReview.length,\n },\n statusDescriptions: {\n READY: 'Approved and serving ads',\n GETTING_READY: 'Under review by Google (may take 1-2 weeks)',\n NEEDS_ATTENTION: 'Issues to fix before approval',\n REQUIRES_REVIEW: 'Site needs review or is inactive',\n },\n };\n}\n","/**\n * Alerts and Policy Issues tools\n */\n\nimport { AdSenseClient } from '../../adsense/client.js';\n\n/**\n * List alerts\n */\nexport async function handleListAlerts(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const client = await AdSenseClient.create(accountId);\n const alerts = await client.listAlerts(accountId);\n\n // Group by severity\n const bySeverity = {\n severe: alerts.filter(a => a.severity === 'SEVERE'),\n warning: alerts.filter(a => a.severity === 'WARNING'),\n info: alerts.filter(a => a.severity === 'INFO'),\n };\n\n // Format alerts with severity emoji\n const formatAlert = (alert: any) => {\n const severityEmojiMap: Record<string, string> = {\n 'SEVERE': '🔴',\n 'WARNING': '🟡',\n 'INFO': '🔵',\n 'SEVERITY_UNSPECIFIED': '⚪',\n };\n const severityEmoji = severityEmojiMap[alert.severity] || '⚪';\n\n return {\n message: alert.message,\n severity: alert.severity,\n severityEmoji,\n type: alert.type,\n name: alert.name,\n };\n };\n\n return {\n alerts: alerts.map(formatAlert),\n summary: {\n total: alerts.length,\n severe: bySeverity.severe.length,\n warning: bySeverity.warning.length,\n info: bySeverity.info.length,\n },\n hasIssues: bySeverity.severe.length > 0 || bySeverity.warning.length > 0,\n severityDescriptions: {\n SEVERE: 'Immediate action required (payment holds, violations)',\n WARNING: 'Action recommended',\n INFO: 'General notifications',\n },\n };\n}\n\n/**\n * List policy issues\n */\nexport async function handleListPolicyIssues(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const client = await AdSenseClient.create(accountId);\n const issues = await client.listPolicyIssues(accountId);\n\n // Format policy issues with action emoji\n const formatIssue = (issue: any) => {\n const actionEmojiMap: Record<string, string> = {\n 'WARNED': '⚠️',\n 'AD_SERVING_RESTRICTED': '🔶',\n 'AD_SERVING_DISABLED': '🔴',\n 'AD_SERVED_WITH_CLICK_CONFIRMATION': '🟡',\n 'AD_PERSONALIZATION_RESTRICTED': '🟠',\n 'ENFORCEMENT_ACTION_UNSPECIFIED': '⚪',\n };\n const actionEmoji = actionEmojiMap[issue.action] || '⚪';\n\n return {\n site: issue.site,\n siteSection: issue.siteSection,\n uri: issue.uri,\n entityType: issue.entityType,\n action: issue.action,\n actionEmoji,\n adRequestCount: issue.adRequestCount,\n warningEscalationDate: issue.warningEscalationDate\n ? `${issue.warningEscalationDate.year}-${String(issue.warningEscalationDate.month).padStart(2, '0')}-${String(issue.warningEscalationDate.day).padStart(2, '0')}`\n : null,\n name: issue.name,\n };\n };\n\n // Group by action\n const byAction = {\n warned: issues.filter(i => i.action === 'WARNED'),\n restricted: issues.filter(i => i.action === 'AD_SERVING_RESTRICTED'),\n disabled: issues.filter(i => i.action === 'AD_SERVING_DISABLED'),\n clickConfirmation: issues.filter(i => i.action === 'AD_SERVED_WITH_CLICK_CONFIRMATION'),\n personalizationRestricted: issues.filter(i => i.action === 'AD_PERSONALIZATION_RESTRICTED'),\n };\n\n return {\n issues: issues.map(formatIssue),\n summary: {\n total: issues.length,\n warned: byAction.warned.length,\n restricted: byAction.restricted.length,\n disabled: byAction.disabled.length,\n clickConfirmation: byAction.clickConfirmation.length,\n personalizationRestricted: byAction.personalizationRestricted.length,\n },\n hasIssues: issues.length > 0,\n actionDescriptions: {\n WARNED: 'Pending enforcement with deadline - fix before escalation',\n AD_SERVING_RESTRICTED: 'Reduced ad demand on affected pages',\n AD_SERVING_DISABLED: 'Ads completely stopped on affected pages',\n AD_SERVED_WITH_CLICK_CONFIRMATION: 'Extra click verification required',\n AD_PERSONALIZATION_RESTRICTED: 'Limited to basic (non-personalized) ads',\n },\n };\n}\n","/**\n * Payments tools\n */\n\nimport { AdSenseClient } from '../../adsense/client.js';\n\n/**\n * List payments\n */\nexport async function handleListPayments(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const client = await AdSenseClient.create(accountId);\n const payments = await client.listPayments(accountId);\n\n // Format payments\n const formatPayment = (payment: any) => {\n const date = payment.date\n ? `${payment.date.year}-${String(payment.date.month).padStart(2, '0')}-${String(payment.date.day).padStart(2, '0')}`\n : null;\n\n // Determine payment type from name\n const name = payment.name || '';\n let type = 'payment';\n if (name.includes('unpaid')) {\n type = 'unpaid';\n } else if (name.includes('youtube')) {\n type = 'youtube';\n }\n\n return {\n amount: payment.amount || 'N/A',\n date,\n type,\n name: payment.name,\n };\n };\n\n // Separate unpaid from paid\n const unpaid = payments.filter(p => p.name?.includes('unpaid'));\n const paid = payments.filter(p => !p.name?.includes('unpaid'));\n\n // Calculate total paid\n const totalPaid = paid.reduce((sum, p) => {\n const match = p.amount?.match(/[\\d.]+/);\n return sum + (match ? parseFloat(match[0]) : 0);\n }, 0);\n\n return {\n payments: payments.map(formatPayment),\n summary: {\n totalPayments: paid.length,\n unpaidBalance: unpaid.length > 0 ? unpaid[0].amount : 'N/A',\n totalPaidAllTime: `$${totalPaid.toFixed(2)}`,\n },\n unpaid: unpaid.map(formatPayment),\n paid: paid.map(formatPayment),\n };\n}\n","/**\n * Ad Units tools\n */\n\nimport { AdSenseClient } from '../../adsense/client.js';\n\n/**\n * List all ad units\n */\nexport async function handleListAdUnits(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const client = await AdSenseClient.create(accountId);\n const adUnits = await client.listAdUnits(accountId);\n\n // Format ad units\n const formatAdUnit = (unit: any) => {\n const stateEmojiMap: Record<string, string> = {\n 'ACTIVE': '✅',\n 'ARCHIVED': '📦',\n 'STATE_UNSPECIFIED': '❓',\n };\n const stateEmoji = stateEmojiMap[unit.state] || '❓';\n\n // Extract ad client ID and ad unit ID from name\n // Format: accounts/{pub-id}/adclients/{ad-client-id}/adunits/{ad-unit-id}\n const nameParts = unit.name.split('/');\n const adClientId = nameParts[3] || '';\n const adUnitId = nameParts[5] || '';\n\n return {\n displayName: unit.displayName,\n state: unit.state,\n stateEmoji,\n type: unit.contentAdsSettings?.type || 'UNKNOWN',\n size: unit.contentAdsSettings?.size || 'Auto',\n adClientId,\n adUnitId,\n name: unit.name,\n reportingDimensionId: unit.reportingDimensionId,\n };\n };\n\n // Group by state\n const byState = {\n active: adUnits.filter(u => u.state === 'ACTIVE'),\n archived: adUnits.filter(u => u.state === 'ARCHIVED'),\n };\n\n // Group by type\n const byType: Record<string, any[]> = {};\n for (const unit of adUnits) {\n const type = unit.contentAdsSettings?.type || 'UNKNOWN';\n if (!byType[type]) {\n byType[type] = [];\n }\n byType[type].push(unit);\n }\n\n return {\n adUnits: adUnits.map(formatAdUnit),\n summary: {\n total: adUnits.length,\n active: byState.active.length,\n archived: byState.archived.length,\n byType: Object.fromEntries(\n Object.entries(byType).map(([type, units]) => [type, units.length])\n ),\n },\n typeDescriptions: {\n DISPLAY: 'Standard display ads (image, text, rich media)',\n FEED: 'In-feed ads that match your content style',\n ARTICLE: 'In-article ads for between paragraphs',\n MATCHED_CONTENT: 'Content recommendations with ads',\n LINK: 'Contextual link unit ads',\n },\n };\n}\n\n/**\n * Get ad code for an ad unit\n */\nexport async function handleGetAdCode(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const adClientId = args.adClientId as string;\n const adUnitId = args.adUnitId as string;\n\n if (!adClientId || !adUnitId) {\n throw new Error('adClientId and adUnitId are required');\n }\n\n const client = await AdSenseClient.create(accountId);\n const adCode = await client.getAdCode(adClientId, adUnitId, accountId);\n\n return {\n adCode,\n adClientId,\n adUnitId,\n instructions: [\n 'Copy the ad code above',\n 'Paste it into your website HTML where you want the ad to appear',\n 'The ad code should be placed within the <body> tags',\n 'Make sure to test the ad placement before publishing',\n ],\n };\n}\n","/**\n * Export tools\n */\n\nimport { AdSenseClient } from '../../adsense/client.js';\nimport type { ReportDimension, ReportMetric } from '../../types.js';\n\n/**\n * Export report as CSV\n */\nexport async function handleExportCsv(args: Record<string, unknown>) {\n const accountId = (args.accountId as string) || process.env.ADSENSE_ACCOUNT_ID;\n const startDate = args.startDate as string;\n const endDate = args.endDate as string;\n\n if (!startDate || !endDate) {\n throw new Error('startDate and endDate are required');\n }\n\n const client = await AdSenseClient.create(accountId);\n\n // Try to get CSV directly from API\n try {\n const csvData = await client.generateCsvReport({\n accountId: accountId || '',\n startDate,\n endDate,\n dimensions: (args.dimensions as ReportDimension[]) || undefined,\n metrics: (args.metrics as ReportMetric[]) || undefined,\n });\n\n return {\n format: 'csv',\n dateRange: { start: startDate, end: endDate },\n data: csvData,\n };\n } catch {\n // Fall back to generating CSV from JSON report\n const report = await client.generateReport({\n accountId: accountId || '',\n startDate,\n endDate,\n dimensions: (args.dimensions as ReportDimension[]) || undefined,\n metrics: (args.metrics as ReportMetric[]) || undefined,\n limit: 10000,\n });\n\n // Convert to CSV\n const headers = report.headers?.map(h => h.name) || [];\n const rows = report.rows || [];\n\n const csvLines = [\n headers.join(','),\n ...rows.map(row =>\n row.cells.map(cell => {\n // Escape values that contain commas or quotes\n const value = cell.value;\n if (value.includes(',') || value.includes('\"')) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n }).join(',')\n ),\n ];\n\n return {\n format: 'csv',\n dateRange: { start: startDate, end: endDate },\n data: csvLines.join('\\n'),\n rowCount: rows.length,\n };\n }\n}\n","/**\n * MCP Tools - Registration and dispatch\n */\n\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { handleListAccounts } from './accounts.js';\nimport {\n handleEarningsSummary,\n handleGenerateReport,\n handleComparePeriods,\n} from './reports.js';\nimport { handleListSites } from './sites.js';\nimport { handleListAlerts, handleListPolicyIssues } from './alerts.js';\nimport { handleListPayments } from './payments.js';\nimport { handleListAdUnits, handleGetAdCode } from './adUnits.js';\nimport { handleExportCsv } from './export.js';\n\n/**\n * Register all available tools\n */\nexport function registerTools(): Tool[] {\n return [\n // Account tools\n {\n name: 'adsense_list_accounts',\n description: 'List all AdSense accounts you have access to',\n inputSchema: {\n type: 'object',\n properties: {},\n required: [],\n },\n },\n\n // Report tools\n {\n name: 'adsense_earnings_summary',\n description: 'Get a quick earnings summary (today, yesterday, last 7 days, this month, last month)',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID (e.g., pub-1234567890123456). Uses default if not specified.',\n },\n },\n required: [],\n },\n },\n {\n name: 'adsense_generate_report',\n description: 'Generate a detailed AdSense performance report with custom dimensions and metrics',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n startDate: {\n type: 'string',\n description: 'Start date (YYYY-MM-DD). Defaults to 7 days ago.',\n },\n endDate: {\n type: 'string',\n description: 'End date (YYYY-MM-DD). Defaults to yesterday.',\n },\n dimensions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Dimensions to group by: DATE, WEEK, MONTH, DOMAIN_NAME, PAGE_URL, AD_UNIT_NAME, COUNTRY_NAME, PLATFORM_TYPE_CODE, TRAFFIC_SOURCE_CODE',\n },\n metrics: {\n type: 'array',\n items: { type: 'string' },\n description: 'Metrics to include: ESTIMATED_EARNINGS, IMPRESSIONS, CLICKS, PAGE_VIEWS, PAGE_VIEWS_CTR, PAGE_VIEWS_RPM, AD_REQUESTS, AD_REQUESTS_COVERAGE',\n },\n orderBy: {\n type: 'string',\n description: 'Metric to sort by (prefix with - for descending, e.g., -ESTIMATED_EARNINGS)',\n },\n limit: {\n type: 'number',\n description: 'Max rows to return (default: 100, max: 10000)',\n },\n },\n required: [],\n },\n },\n {\n name: 'adsense_compare_periods',\n description: 'Compare AdSense performance between two time periods',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n period1Start: {\n type: 'string',\n description: 'First period start date (YYYY-MM-DD)',\n },\n period1End: {\n type: 'string',\n description: 'First period end date (YYYY-MM-DD)',\n },\n period2Start: {\n type: 'string',\n description: 'Second period start date (YYYY-MM-DD)',\n },\n period2End: {\n type: 'string',\n description: 'Second period end date (YYYY-MM-DD)',\n },\n dimensions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Dimensions to group by for comparison',\n },\n },\n required: ['period1Start', 'period1End', 'period2Start', 'period2End'],\n },\n },\n\n // Sites tools\n {\n name: 'adsense_list_sites',\n description: 'List all sites and their AdSense approval status (READY, GETTING_READY, NEEDS_ATTENTION, REQUIRES_REVIEW)',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n },\n required: [],\n },\n },\n\n // Alerts tools\n {\n name: 'adsense_list_alerts',\n description: 'List AdSense account alerts and warnings (INFO, WARNING, SEVERE)',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n },\n required: [],\n },\n },\n {\n name: 'adsense_list_policy_issues',\n description: 'List policy issues and violations affecting your account (WARNED, AD_SERVING_RESTRICTED, AD_SERVING_DISABLED)',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n },\n required: [],\n },\n },\n\n // Payments tools\n {\n name: 'adsense_list_payments',\n description: 'List payment history and pending earnings',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n },\n required: [],\n },\n },\n\n // Ad units tools\n {\n name: 'adsense_list_ad_units',\n description: 'List all ad units across your ad clients',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n },\n required: [],\n },\n },\n {\n name: 'adsense_get_ad_code',\n description: 'Get the HTML embed code for an ad unit',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n adClientId: {\n type: 'string',\n description: 'Ad client ID (e.g., ca-pub-1234567890123456)',\n },\n adUnitId: {\n type: 'string',\n description: 'Ad unit ID',\n },\n },\n required: ['adClientId', 'adUnitId'],\n },\n },\n\n // Export tools\n {\n name: 'adsense_export_csv',\n description: 'Export AdSense report data as CSV format',\n inputSchema: {\n type: 'object',\n properties: {\n accountId: {\n type: 'string',\n description: 'AdSense account ID. Uses default if not specified.',\n },\n startDate: {\n type: 'string',\n description: 'Start date (YYYY-MM-DD)',\n },\n endDate: {\n type: 'string',\n description: 'End date (YYYY-MM-DD)',\n },\n dimensions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Dimensions to include',\n },\n metrics: {\n type: 'array',\n items: { type: 'string' },\n description: 'Metrics to include',\n },\n },\n required: ['startDate', 'endDate'],\n },\n },\n ];\n}\n\n/**\n * Handle tool calls\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n try {\n let result: any;\n\n switch (name) {\n case 'adsense_list_accounts':\n result = await handleListAccounts();\n break;\n case 'adsense_earnings_summary':\n result = await handleEarningsSummary(args);\n break;\n case 'adsense_generate_report':\n result = await handleGenerateReport(args);\n break;\n case 'adsense_compare_periods':\n result = await handleComparePeriods(args);\n break;\n case 'adsense_list_sites':\n result = await handleListSites(args);\n break;\n case 'adsense_list_alerts':\n result = await handleListAlerts(args);\n break;\n case 'adsense_list_policy_issues':\n result = await handleListPolicyIssues(args);\n break;\n case 'adsense_list_payments':\n result = await handleListPayments(args);\n break;\n case 'adsense_list_ad_units':\n result = await handleListAdUnits(args);\n break;\n case 'adsense_get_ad_code':\n result = await handleGetAdCode(args);\n break;\n case 'adsense_export_csv':\n result = await handleExportCsv(args);\n break;\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n\n return {\n content: [\n {\n type: 'text',\n text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (error: any) {\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${error.message}`,\n },\n ],\n };\n }\n}\n","/**\n * MCP Resources\n */\n\nimport { AdSenseClient } from '../../adsense/client.js';\n\n/**\n * List available resources\n */\nexport async function handleListResources() {\n return {\n resources: [\n {\n uri: 'adsense://accounts',\n name: 'AdSense Accounts',\n description: 'List of all AdSense accounts you have access to',\n mimeType: 'application/json',\n },\n ],\n };\n}\n\n/**\n * Read a resource\n */\nexport async function handleReadResource(uri: string) {\n const url = new URL(uri);\n\n if (url.protocol !== 'adsense:') {\n throw new Error(`Unsupported protocol: ${url.protocol}`);\n }\n\n const path = url.pathname.replace(/^\\/\\//, '');\n\n // Handle different resource paths\n if (path === 'accounts') {\n const client = await AdSenseClient.create();\n const accounts = await client.listAccounts();\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(accounts, null, 2),\n },\n ],\n };\n }\n\n // Handle accounts/{accountId}/sites\n const sitesMatch = path.match(/^accounts\\/([^/]+)\\/sites$/);\n if (sitesMatch) {\n const accountId = sitesMatch[1];\n const client = await AdSenseClient.create(accountId);\n const sites = await client.listSites(accountId);\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(sites, null, 2),\n },\n ],\n };\n }\n\n // Handle accounts/{accountId}/adunits\n const adUnitsMatch = path.match(/^accounts\\/([^/]+)\\/adunits$/);\n if (adUnitsMatch) {\n const accountId = adUnitsMatch[1];\n const client = await AdSenseClient.create(accountId);\n const adUnits = await client.listAdUnits(accountId);\n\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(adUnits, null, 2),\n },\n ],\n };\n }\n\n throw new Error(`Unknown resource: ${uri}`);\n}\n"],"mappings":"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","names":["google","fs","google","path"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@appsyogi/adsense-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Google AdSense MCP Server - Monitor earnings, reports, and account health via Claude/AI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"adsense-mcp": "./dist/cli/index.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"start": "node dist/cli/index.js",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"lint": "eslint src/",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"mcp",
|
|
29
|
+
"google-adsense",
|
|
30
|
+
"adsense",
|
|
31
|
+
"earnings",
|
|
32
|
+
"publisher",
|
|
33
|
+
"model-context-protocol",
|
|
34
|
+
"claude",
|
|
35
|
+
"cursor",
|
|
36
|
+
"ai",
|
|
37
|
+
"monetization"
|
|
38
|
+
],
|
|
39
|
+
"author": "SuperZero11",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/AppsYogi-com/adsense-mcp-server.git"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/AppsYogi-com/adsense-mcp-server/issues"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/AppsYogi-com/adsense-mcp-server#readme",
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18.0.0"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
54
|
+
"better-sqlite3": "^11.0.0",
|
|
55
|
+
"chalk": "^5.3.0",
|
|
56
|
+
"commander": "^12.0.0",
|
|
57
|
+
"env-paths": "^3.0.0",
|
|
58
|
+
"googleapis": "^140.0.0",
|
|
59
|
+
"keytar": "^7.9.0",
|
|
60
|
+
"open": "^10.0.0",
|
|
61
|
+
"ora": "^8.0.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
65
|
+
"@types/node": "^20.0.0",
|
|
66
|
+
"tsup": "^8.0.0",
|
|
67
|
+
"typescript": "^5.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|