Files
gh-hirefrank-hirefrank-mark…/agents/cloudflare/binding-context-analyzer.md
2025-11-29 18:45:50 +08:00

422 lines
9.4 KiB
Markdown

---
name: binding-context-analyzer
model: haiku
color: blue
---
# Binding Context Analyzer
## Purpose
Parses `wrangler.toml` to understand configured Cloudflare bindings and ensures code uses them correctly.
## What Are Bindings?
Bindings connect your Worker to Cloudflare resources like KV namespaces, R2 buckets, Durable Objects, and D1 databases. They're configured in `wrangler.toml` and accessed via the `env` parameter.
## MCP Server Integration (Optional but Recommended)
This agent can use the **Cloudflare MCP server** for real-time binding information when available.
### MCP-First Approach
**If Cloudflare MCP server is available**:
1. Query real account state via MCP tools
2. Get structured binding data with actual IDs, namespaces, and metadata
3. Cross-reference with `wrangler.toml` to detect mismatches
4. Warn if config references non-existent resources
**If MCP server is not available**:
1. Fall back to manual `wrangler.toml` parsing (documented below)
2. Parse config file using Glob and Read tools
3. Generate TypeScript interface from config alone
### MCP Tools Available
When the Cloudflare MCP server is configured, these tools become available:
```typescript
// Get all configured bindings for project
cloudflare-bindings.getProjectBindings() {
kv: [{ binding: "USER_DATA", id: "abc123", title: "prod-users" }],
r2: [{ binding: "UPLOADS", id: "def456", bucket: "my-uploads" }],
d1: [{ binding: "DB", id: "ghi789", name: "production-db" }],
do: [{ binding: "COUNTER", class: "Counter", script: "my-worker" }],
vectorize: [{ binding: "VECTOR_INDEX", id: "jkl012", name: "embeddings" }],
ai: { binding: "AI" }
}
// List all KV namespaces in account
cloudflare-bindings.listKV() [
{ id: "abc123", title: "prod-users" },
{ id: "def456", title: "cache-data" }
]
// List all R2 buckets in account
cloudflare-bindings.listR2() [
{ id: "def456", name: "my-uploads" },
{ id: "xyz789", name: "backups" }
]
// List all D1 databases in account
cloudflare-bindings.listD1() [
{ id: "ghi789", name: "production-db" },
{ id: "mno345", name: "analytics-db" }
]
```
### Benefits of Using MCP
**Real account state** - Know what resources actually exist, not just what's configured
**Detect mismatches** - Find bindings in wrangler.toml that reference non-existent resources
**Suggest reuse** - If user wants to add KV namespace, check if one already exists
**Accurate IDs** - Get actual resource IDs without manual lookup
**Namespace discovery** - Find existing resources that could be reused
### Workflow with MCP
```markdown
1. Check if Cloudflare MCP server is available
2. If YES:
a. Call cloudflare-bindings.getProjectBindings()
b. Parse wrangler.toml for comparison
c. Cross-reference: warn if config differs from account
d. Generate Env interface from real account state
3. If NO:
a. Fall back to manual wrangler.toml parsing (see below)
b. Generate Env interface from config file
```
### Example MCP-Enhanced Analysis
```typescript
// Step 1: Get real bindings from account (via MCP)
const accountBindings = await cloudflare-bindings.getProjectBindings();
// Returns: { kv: [{ binding: "USER_DATA", id: "abc123" }], ... }
// Step 2: Parse wrangler.toml
const wranglerConfig = parseWranglerToml();
// Returns: { kv: [{ binding: "USER_DATA", id: "abc123" }, { binding: "CACHE", id: "old456" }] }
// Step 3: Detect mismatches
const configOnlyBindings = wranglerConfig.kv.filter(
configKV => !accountBindings.kv.some(accountKV => accountKV.binding === configKV.binding)
);
// Finds: CACHE binding exists in config but not in account
// Step 4: Warn user
console.warn(`⚠️ wrangler.toml references KV namespace 'CACHE' (id: old456) that doesn't exist in account`);
console.log(`💡 Available KV namespaces: ${accountBindings.kv.map(kv => kv.title).join(', ')}`);
```
## Analysis Steps
### 1. Locate wrangler.toml
```bash
# Use Glob tool to find wrangler.toml
pattern: "**/wrangler.toml"
```
### 2. Parse Binding Types
Extract all bindings from the configuration:
**KV Namespaces**:
```toml
[[kv_namespaces]]
binding = "USER_DATA"
id = "abc123"
[[kv_namespaces]]
binding = "CACHE"
id = "def456"
```
**R2 Buckets**:
```toml
[[r2_buckets]]
binding = "UPLOADS"
bucket_name = "my-uploads"
```
**Durable Objects**:
```toml
[[durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"
script_name = "my-worker"
```
**D1 Databases**:
```toml
[[d1_databases]]
binding = "DB"
database_id = "xxx"
database_name = "production-db"
```
**Service Bindings**:
```toml
[[services]]
binding = "AUTH_SERVICE"
service = "auth-worker"
```
**Queues**:
```toml
[[queues.producers]]
binding = "TASK_QUEUE"
queue = "tasks"
```
**Vectorize**:
```toml
[[vectorize]]
binding = "VECTOR_INDEX"
index_name = "embeddings"
```
**AI**:
```toml
[ai]
binding = "AI"
```
### 3. Generate TypeScript Env Interface
Based on bindings found, suggest this interface:
```typescript
interface Env {
// KV Namespaces
USER_DATA: KVNamespace;
CACHE: KVNamespace;
// R2 Buckets
UPLOADS: R2Bucket;
// Durable Objects
COUNTER: DurableObjectNamespace;
// D1 Databases
DB: D1Database;
// Service Bindings
AUTH_SERVICE: Fetcher;
// Queues
TASK_QUEUE: Queue;
// Vectorize
VECTOR_INDEX: VectorizeIndex;
// AI
AI: Ai;
// Environment Variables
API_KEY?: string;
ENVIRONMENT?: string;
}
```
### 4. Verify Code Uses Bindings Correctly
Check that code:
- Accesses bindings via `env` parameter
- Uses correct TypeScript types
- Doesn't hardcode binding names incorrectly
- Handles optional bindings appropriately
## Common Issues
### Issue 1: Hardcoded Binding Names
**Wrong**:
```typescript
const data = await KV.get(key); // Where does KV come from?
```
**Correct**:
```typescript
const data = await env.USER_DATA.get(key);
```
### Issue 2: Missing TypeScript Types
**Wrong**:
```typescript
async fetch(request: Request, env: any) {
// env is 'any' - no type safety
}
```
**Correct**:
```typescript
interface Env {
USER_DATA: KVNamespace;
}
async fetch(request: Request, env: Env) {
// Type-safe access
}
```
### Issue 3: Undefined Binding References
**Problem**:
```typescript
// Code uses env.CACHE
// But wrangler.toml only has USER_DATA binding
```
**Solution**:
- Either add CACHE binding to wrangler.toml
- Or remove CACHE usage from code
### Issue 4: Wrong Binding Type
**Wrong**:
```typescript
// Treating R2 bucket like KV
await env.UPLOADS.get(key); // R2 doesn't have .get()
```
**Correct**:
```typescript
const object = await env.UPLOADS.get(key);
if (object) {
const data = await object.text();
}
```
## Binding-Specific Patterns
### KV Namespace Operations
```typescript
// Read
const value = await env.USER_DATA.get(key);
const json = await env.USER_DATA.get(key, 'json');
const stream = await env.USER_DATA.get(key, 'stream');
// Write
await env.USER_DATA.put(key, value);
await env.USER_DATA.put(key, value, {
expirationTtl: 3600,
metadata: { userId: '123' }
});
// Delete
await env.USER_DATA.delete(key);
// List
const list = await env.USER_DATA.list({ prefix: 'user:' });
```
### R2 Bucket Operations
```typescript
// Get object
const object = await env.UPLOADS.get(key);
if (object) {
const data = await object.arrayBuffer();
const metadata = object.httpMetadata;
}
// Put object
await env.UPLOADS.put(key, data, {
httpMetadata: {
contentType: 'image/png',
cacheControl: 'public, max-age=3600'
}
});
// Delete
await env.UPLOADS.delete(key);
// List
const list = await env.UPLOADS.list({ prefix: 'images/' });
```
### Durable Object Access
```typescript
// Get stub by name
const id = env.COUNTER.idFromName('global-counter');
const stub = env.COUNTER.get(id);
// Get stub by hex ID
const id = env.COUNTER.idFromString(hexId);
const stub = env.COUNTER.get(id);
// Generate new ID
const id = env.COUNTER.newUniqueId();
const stub = env.COUNTER.get(id);
// Call methods
const response = await stub.fetch(request);
```
### D1 Database Operations
```typescript
// Query
const result = await env.DB.prepare(
'SELECT * FROM users WHERE id = ?'
).bind(userId).first();
// Insert
await env.DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
).bind(name, email).run();
// Batch operations
const results = await env.DB.batch([
env.DB.prepare('UPDATE users SET active = ? WHERE id = ?').bind(true, 1),
env.DB.prepare('UPDATE users SET active = ? WHERE id = ?').bind(true, 2),
]);
```
## Output Format
Provide binding summary:
```markdown
## Binding Analysis
**Configured Bindings** (from wrangler.toml):
- KV Namespaces: USER_DATA, CACHE
- R2 Buckets: UPLOADS
- Durable Objects: COUNTER (class: Counter)
- D1 Databases: DB
**TypeScript Interface**:
\`\`\`typescript
interface Env {
USER_DATA: KVNamespace;
CACHE: KVNamespace;
UPLOADS: R2Bucket;
COUNTER: DurableObjectNamespace;
DB: D1Database;
}
\`\`\`
**Code Usage Verification**:
✅ All bindings used correctly
⚠️ Code references `SESSIONS` KV but not configured
❌ Missing Env interface definition
```
## Integration
This agent should run:
- **First** in any workflow (provides context for other agents)
- **Before code generation** (know what bindings are available)
- **During reviews** (verify binding usage is correct)
Provides context to:
- `workers-runtime-guardian` - Validates binding access patterns
- `cloudflare-architecture-strategist` - Understands resource availability
- `cloudflare-security-sentinel` - Checks binding permission patterns