|
| 1 | +# AdSense-MCP Copilot Instructions |
| 2 | + |
| 3 | +## Project Overview |
| 4 | +This is a **Model Context Protocol (MCP) server** that provides Google AdSense API access to AI clients (Claude, Cursor, VS Code Copilot). It's distributed as a CLI tool via npm (`adsense-mcp`) with OAuth/service account authentication. |
| 5 | + |
| 6 | +## Architecture |
| 7 | + |
| 8 | +``` |
| 9 | +src/ |
| 10 | +├── index.ts # Public exports for programmatic use |
| 11 | +├── types.ts # TypeScript types (single source of truth) |
| 12 | +├── cli/ # Commander-based CLI (`adsense-mcp init|doctor|run`) |
| 13 | +├── server/ # MCP server implementation |
| 14 | +│ ├── index.ts # Server factory with stdio transport |
| 15 | +│ ├── tools/ # MCP tools organized by domain |
| 16 | +│ └── resources/ # MCP resources |
| 17 | +├── adsense/ |
| 18 | +│ ├── client.ts # AdSense API wrapper with all operations |
| 19 | +│ ├── rateLimiter.ts # Rate limiting with exponential backoff |
| 20 | +│ └── cache.ts # SQLite cache with TTL |
| 21 | +└── auth/ # OAuth2 + service account auth, token storage |
| 22 | +``` |
| 23 | + |
| 24 | +**Key data flows:** |
| 25 | +1. CLI commands → `createServer()` → MCP stdio transport |
| 26 | +2. Tool calls → `handleToolCall()` routes to domain handlers → `AdSenseClient` → Google API |
| 27 | +3. Tokens stored via `keytar` (OS keychain) with file fallback; config in `env-paths` directories |
| 28 | + |
| 29 | +## Development Commands |
| 30 | + |
| 31 | +```bash |
| 32 | +npm run build # tsup build (ESM, Node 18+) |
| 33 | +npm run dev # Watch mode |
| 34 | +npm run typecheck # tsc --noEmit |
| 35 | +npm run lint # eslint src/ |
| 36 | +adsense-mcp doctor # Check auth and API access |
| 37 | +``` |
| 38 | + |
| 39 | +## Code Conventions |
| 40 | + |
| 41 | +### Adding New MCP Tools |
| 42 | +1. Create tool definition in `src/server/tools/<domain>.ts` following the pattern: |
| 43 | + - Export handler function like `handle<Action>(args)` |
| 44 | +2. Register in `src/server/tools/index.ts`: |
| 45 | + - Add tool schema to `registerTools()` array |
| 46 | + - Add case to `handleToolCall()` switch |
| 47 | +3. Tool names use underscore notation: `adsense_earnings_summary`, `adsense_list_sites` |
| 48 | + |
| 49 | +### Type Definitions |
| 50 | +- Define types in `src/types.ts` |
| 51 | +- Tool input schemas use plain JSON Schema format for MCP |
| 52 | + |
| 53 | +### Error Handling Pattern |
| 54 | +```typescript |
| 55 | +try { |
| 56 | + const result = await client.someOperation(); |
| 57 | + return { data: result }; |
| 58 | +} catch (error: any) { |
| 59 | + return { error: error.message }; |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +### Rate Limiting |
| 64 | +- AdSense API: 100 requests/minute/user |
| 65 | +- Use `rateLimiter.throttle()` before API calls |
| 66 | +- Use `withRetry()` wrapper for automatic exponential backoff |
| 67 | + |
| 68 | +### Caching Strategy |
| 69 | +- Today's data: 5 minutes TTL (frequently changing) |
| 70 | +- Yesterday's data: 1 hour TTL |
| 71 | +- Historical data (>2 days): 24 hours TTL |
| 72 | +- Account/site info: 1 hour TTL |
| 73 | + |
| 74 | +## Security Notes |
| 75 | +- **Read-only scope only** (`adsense.readonly`) - no write operations |
| 76 | +- Never log or expose tokens |
| 77 | +- Credentials stored in OS keychain, never in repo |
0 commit comments