Skip to main content
Glama
richcorabbithole

RichCorabbithole MCP Server

README.md
# RichCorabbithole MCP Server

Project-aware MCP server for richcorabbithole-api development. Reduces token usage by caching file contents and providing high-level operations.

## Installation

```bash
npm install
```

## Configuration

1. **Get Asana Personal Access Token**:
   - Go to Asana → Settings → Apps → Personal Access Tokens
   - Create new token
   - Copy it

2. **Add to Claude Desktop config** (`~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "richcorabbithole": {
      "command": "node",
      "args": ["/Users/richardcompton/projects/richcorabbithole/richcorabbithole-mcp/index.js"],
      "env": {
        "ASANA_TOKEN": "your_asana_token_here"
      }
    }
  }
}
```

3. **Restart Claude Desktop**

## Available Tools

### API Tools

#### `get_worker_prompts`
Get all worker system prompts (write, edit, seo) in one call.

#### `run_tests`
Run npm test and return summary. Set `verbose: true` for full output.

#### `get_project_status`
Get current git status and modified files.

#### `get_pipeline_info`
Get pipeline architecture and status flow info.

#### `compare_prompts`
Compare prompts across workers to find inconsistencies.

#### `get_file`
Get cached file content. Uses cache to reduce file reads. Set `refresh: true` to force reload.

**Parameters:**
- `path` (required): Relative path from API root
- `refresh` (optional): Force refresh cache

#### `get_asana_tasks`
Get tasks from Asana project by GID. Cached 5 minutes. Set `refresh: true` to force reload.

**Parameters:**
- `project_gid` (required): Asana project GID
- `refresh` (optional): Force refresh cache

**Find your project GID**: Open project in Asana, check URL: `asana.com/0/{project_gid}/...`

### Site Tools

#### `list_blog_posts`
List all blog posts with metadata (title, date, category, depth, draft status).

**Parameters:**
- `drafts` (optional): Include draft posts (default: true)

#### `get_blog_post`
Get full content of a blog post by slug.

**Parameters:**
- `slug` (required): Blog post slug (filename without .md)

#### `run_site_tests`
Run site tests (unit and/or e2e).

**Parameters:**
- `type` (optional): Type of tests to run: 'unit', 'e2e', or 'all' (default: unit)
- `verbose` (optional): Show full output (default: false)

#### `get_site_build_status`
Check if site builds successfully.

#### `get_site_config`
Get Astro site configuration.

#### `validate_blog_frontmatter`
Validate frontmatter of blog posts against schema.

**Parameters:**
- `slug` (optional): Blog post slug to validate (validates all if not provided)

#### `get_category_schema`
Get current hyperfixation categories with colors, Zod enum values, and CSS variables. Use before any category-related work.

## Pipeline Overview

Topics flow through five Lambda workers: Research → Write → Edit → SEO → Publish. Each stage is decoupled by SQS. Task state is tracked in DynamoDB.

Every post has two classification axes resolved at research time:
- **Hyperfixation category** — scored against known categories, can propose new ones
- **Article type** — `knowledge`, `best-of`, `how-to`, or `masterclass`. Inferred from the topic if not provided. Shapes both research focus and post structure.

## Benefits

- **Reduced token usage**: Caches files, provides summaries instead of full output
- **Project context**: Understands pipeline stages, worker relationships
- **High-level operations**: "run tests" instead of bash → parse → summarize
- **Faster iteration**: Pre-indexed project knowledge

## Technical Notes

### Dependencies

- **Zod v4.3.6**: Used for input schema validation. All tool schemas are defined using Zod's type-safe API.
- **MCP SDK v1.26.0**: Requires Zod schemas (v3 or v4) for input validation, not plain JSON schemas.
- **Axios**: For Asana API calls.

### Schema Validation

This server uses Zod schemas for all tool input validation. The MCP SDK automatically validates inputs against these schemas before calling tool handlers. Example:

```javascript
this.server.registerTool('get_file', {
  description: 'Get cached file content',
  inputSchema: z.object({
    path: z.string().describe('Relative path from API root'),
    refresh: z.boolean().optional().describe('Force refresh cache'),
  }),
}, async (args) => await this.getFile(args.path, args?.refresh));
```