Initial commit
This commit is contained in:
421
agents/cloudflare/binding-context-analyzer.md
Normal file
421
agents/cloudflare/binding-context-analyzer.md
Normal file
@@ -0,0 +1,421 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user