# Claude's Office MCP Server Specification

## Overview

The Claude's Office MCP Server transforms the existing file-based Claude's Office CLI into a dynamic, API-driven environment where the office structure is maintained as a living system rather than static files. This enables LLMs to directly interact with the office environment through standardized MCP tools, with a "Secretary" model providing behind-the-scenes assistance.

## Project Structure

We will create a new package called `claudes-office-mcp-server` that depends on the existing `claudes-office-cli` package:

```
claudes-office-mcp-server/
├── src/
│   ├── index.ts               # Main entry point
│   ├── secretary/             # Secretary model integration
│   │   ├── index.ts           # Main export
│   │   ├── openrouter.ts      # OpenRouter API client
│   │   └── handlers/          # Task-specific handlers
│   ├── server/                # MCP server implementation
│   │   ├── index.ts           # Server initialization
│   │   ├── tools.ts           # Tool definitions and handlers
│   │   ├── resources.ts       # Resource definitions and handlers
│   │   └── prompts.ts         # Prompt definitions and handlers
│   ├── office/                # Office data management
│   │   ├── index.ts           # Main office functionality
│   │   ├── store.ts           # Storage implementation (in-memory/DB)
│   │   ├── roles.ts           # Role management
│   │   └── documents.ts       # Document management
│   └── utils/                 # Utility functions
├── tests/                     # Test suite
├── package.json               # Dependencies and scripts
├── tsconfig.json              # TypeScript configuration
└── README.md                  # Documentation
```

## Architecture

### Component Diagram

```
┌─────────────────────────┐         ┌───────────────────────┐
│                         │         │                       │
│    Claude or other      │◄───────►│   MCP Office Server   │
│      primary LLM        │         │                       │
│                         │         └───────────┬───────────┘
└─────────────────────────┘                     │
                                                │
                                                ▼
                                  ┌─────────────────────────┐
                                  │                         │
                                  │  Office Data Manager    │
                                  │                         │
                                  └──────────┬──────────────┘
                                             │
                                             │
              ┌──────────────────────────────┴─────────────────────────────┐
              │                                                            │
              ▼                                                            ▼
┌─────────────────────────┐                                 ┌─────────────────────────┐
│                         │                                 │                         │
│   Secretary Model       │◄────────────────────────────────│     Template Files      │
│   (via OpenRouter)      │                                 │   (from claudes-office) │
│                         │                                 │                         │
└─────────────────────────┘                                 └─────────────────────────┘
```

### Core Components

1. **MCP Server**
   - Exposes the MCP protocol endpoints (tools, resources, prompts)
   - Handles client connections and message routing
   - Delegates complex operations to the Office Data Manager

2. **Office Data Manager**
   - Maintains the office structure (roles, documents, sessions)
   - Provides CRUD operations for office components
   - Abstracts storage details (in-memory or database)

3. **Secretary Model**
   - Processes complex requests through OpenRouter API
   - Handles role selection, document retrieval, content generation
   - Acts as an intelligent assistant for office operations

4. **Template Files**
   - Imported from the `claudes-office-cli` package
   - Provide baseline role definitions and structure
   - Used for initial population and as reference

## MCP Implementation

### Tools

The server will expose the following tools:

1. **Office Navigation Tools**

```typescript
// Office structure exploration tool
server.tool(
  "explore-office",
  {
    path: z.string().optional().describe("Office path to explore, defaults to root")
  },
  async ({ path }) => {
    const structure = await officeManager.exploreStructure(path || "/");
    return {
      content: [{ type: "text", text: JSON.stringify(structure, null, 2) }]
    };
  }
);

// Document finding tool
server.tool(
  "find-document",
  {
    query: z.string().describe("Search term or criteria"),
    type: z.enum(["role", "document", "any"]).optional().describe("Type of document to find")
  },
  async ({ query, type }) => {
    // Delegate complex search to Secretary model
    const results = await secretary.findDocuments(query, type);
    return {
      content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
    };
  }
);
```

2. **Role Management Tools**

```typescript
// Adopt a role based on requirements
server.tool(
  "adopt-role",
  {
    domain: z.string().optional().describe("Domain expertise needed"),
    skills: z.array(z.string()).optional().describe("Specific skills required"),
    task: z.string().optional().describe("Description of the task")
  },
  async ({ domain, skills, task }) => {
    const roleContent = await secretary.findBestRole(domain, skills, task);
    return {
      content: [{ type: "text", text: roleContent }]
    };
  }
);

// Create a new role
server.tool(
  "create-role",
  {
    name: z.string().describe("Name for the new role"),
    description: z.string().describe("Short description of the role"),
    skills: z.array(z.string()).describe("Skills this role should have"),
    domain: z.string().describe("Domain this role belongs to")
  },
  async ({ name, description, skills, domain }) => {
    const newRole = await secretary.createRole(name, description, skills, domain);
    return {
      content: [{ type: "text", text: newRole }]
    };
  }
);
```

3. **Document Management Tools**

```typescript
// Read a document by path
server.tool(
  "read-document",
  {
    path: z.string().describe("Path to the document")
  },
  async ({ path }) => {
    const content = await officeManager.readDocument(path);
    return {
      content: [{ type: "text", text: content }]
    };
  }
);

// Create or update a document
server.tool(
  "update-document",
  {
    path: z.string().describe("Path to the document"),
    content: z.string().describe("New content for the document"),
    createIfMissing: z.boolean().optional().default(true).describe("Create document if it doesn't exist")
  },
  async ({ path, content, createIfMissing }) => {
    const result = await officeManager.updateDocument(path, content, createIfMissing);
    return {
      content: [{ type: "text", text: `Document at ${path} ${result.created ? 'created' : 'updated'} successfully` }]
    };
  }
);
```

4. **Workflow Tools**

```typescript
// Create a new work session
server.tool(
  "create-session",
  {
    name: z.string().describe("Name for this work session"),
    description: z.string().describe("Description of work to be done"),
    context: z.array(z.string()).optional().describe("Relevant context resources")
  },
  async ({ name, description, context }) => {
    const session = await officeManager.createSession(name, description, context);
    return {
      content: [{ type: "text", text: `Session "${name}" created with ID: ${session.id}` }]
    };
  }
);

// Generate a project plan
server.tool(
  "plan-project",
  {
    name: z.string().describe("Project name"),
    description: z.string().describe("Project description"),
    technologies: z.array(z.string()).describe("Technologies to be used")
  },
  async ({ name, description, technologies }) => {
    // This is a complex task delegated to the Secretary model
    const plan = await secretary.generateProjectPlan(name, description, technologies);
    return {
      content: [{ type: "text", text: plan }]
    };
  }
);
```

### Resources

The server will expose these key resources:

```typescript
// Office structure as a resource
server.resource(
  "office-structure",
  "office://structure",
  async (uri) => ({
    contents: [{
      uri: uri.href,
      text: JSON.stringify(await officeManager.getFullStructure(), null, 2)
    }]
  })
);

// Current session information
server.resource(
  "current-session",
  "office://session/current",
  async (uri) => ({
    contents: [{
      uri: uri.href,
      text: JSON.stringify(await officeManager.getCurrentSession(), null, 2)
    }]
  })
);

// Available roles resource
server.resource(
  "available-roles",
  new ResourceTemplate("office://roles/{domain?}", { list: undefined }),
  async (uri, { domain }) => ({
    contents: [{
      uri: uri.href,
      text: JSON.stringify(await officeManager.listRoles(domain), null, 2)
    }]
  })
);

// Specific role content
server.resource(
  "role-content",
  new ResourceTemplate("office://role/{rolePath}", { list: undefined }),
  async (uri, { rolePath }) => ({
    contents: [{
      uri: uri.href,
      text: await officeManager.getRoleContent(rolePath)
    }]
  })
);
```

### Prompts

The server will expose helpful prompt templates:

```typescript
server.prompt(
  "adopt-expert-role",
  {
    domain: z.string().describe("Domain of expertise"),
    task: z.string().describe("Task description")
  },
  async ({ domain, task }) => {
    const roleContent = await secretary.findBestRole(domain, [], task);
    return {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: `I need your help with a task in the ${domain} domain. The task is: ${task}\n\nPlease adopt the following role and expertise:\n\n${roleContent}`
          }
        }
      ]
    };
  }
);

server.prompt(
  "plan-implementation",
  {
    feature: z.string().describe("Feature to implement"),
    technologies: z.array(z.string()).describe("Technologies to use")
  },
  async ({ feature, technologies }) => {
    const techStr = technologies.join(", ");
    return {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: `Please help me plan the implementation of this feature: "${feature}". The implementation should use these technologies: ${techStr}.\n\nProvide a step-by-step implementation plan, listing key components, their responsibilities, and how they interact.`
          }
        }
      ]
    };
  }
);
```

## Secretary Model Integration

The Secretary model will be integrated using the OpenRouter API:

```typescript
export class Secretary {
  private openRouterClient: OpenRouterClient;
  private officeManager: OfficeManager;
  
  constructor(apiKey: string, officeManager: OfficeManager) {
    this.openRouterClient = new OpenRouterClient(apiKey);
    this.officeManager = officeManager;
  }
  
  async findBestRole(domain?: string, skills?: string[], task?: string): Promise<string> {
    // 1. Get available roles matching criteria
    const roles = await this.officeManager.findRoles(domain, skills);
    
    // 2. Create a prompt for the secretary model
    const prompt = `
      I need to find the best role for this task: "${task || 'general assistance'}".
      Domain: ${domain || 'any'}
      Required skills: ${skills?.join(', ') || 'any'}
      
      Available roles:
      ${roles.map(r => `- ${r.path}: ${r.description}`).join('\n')}
      
      Please select the most appropriate role and explain why it's a good fit.
      Then return the full role content for the selected role.
    `;
    
    // 3. Call the secretary model
    const response = await this.openRouterClient.complete({
      model: "anthropic/claude-instant-1.2",
      prompt,
      max_tokens: 1500
    });
    
    // 4. Parse the response to extract role content
    // ... Implementation details ...
    
    return roleContent;
  }
  
  // Other secretary methods like createRole, findDocuments, etc.
}
```

## Office Data Manager

The Office Data Manager will provide an abstraction over the office data:

```typescript
export class OfficeManager {
  private store: OfficeStore;
  private templateProvider: TemplateProvider;
  
  constructor(store: OfficeStore, templateProvider: TemplateProvider) {
    this.store = store;
    this.templateProvider = templateProvider;
  }
  
  async initialize(): Promise<void> {
    // Load initial templates from claudes-office-cli
    const templates = await this.templateProvider.getTemplates();
    await this.store.initializeWithTemplates(templates);
  }
  
  // Structure exploration
  async exploreStructure(path: string): Promise<OfficeStructure> {
    return this.store.getStructureAt(path);
  }
  
  // Role management
  async listRoles(domain?: string): Promise<RoleSummary[]> {
    return this.store.findRoles(domain);
  }
  
  async getRoleContent(path: string): Promise<string> {
    return this.store.getDocumentContent(path);
  }
  
  async findRoles(domain?: string, skills?: string[]): Promise<RoleSummary[]> {
    return this.store.findRolesByAttributes(domain, skills);
  }
  
  // Document management
  async readDocument(path: string): Promise<string> {
    return this.store.getDocumentContent(path);
  }
  
  async updateDocument(
    path: string, 
    content: string, 
    createIfMissing: boolean
  ): Promise<{created: boolean}> {
    const exists = await this.store.documentExists(path);
    if (!exists && !createIfMissing) {
      throw new Error(`Document at ${path} does not exist`);
    }
    
    await this.store.setDocumentContent(path, content);
    return { created: !exists };
  }
  
  // Session management
  async createSession(
    name: string, 
    description: string, 
    context?: string[]
  ): Promise<Session> {
    const session = {
      id: generateId(),
      name,
      description,
      context: context || [],
      created: new Date().toISOString()
    };
    
    await this.store.saveSession(session);
    await this.store.setCurrentSession(session.id);
    return session;
  }
  
  async getCurrentSession(): Promise<Session | null> {
    const currentSessionId = await this.store.getCurrentSessionId();
    if (!currentSessionId) return null;
    return this.store.getSession(currentSessionId);
  }
}
```

## Storage Implementation

We'll provide multiple storage backends, starting with in-memory:

```typescript
export interface OfficeStore {
  // Structure operations
  getStructureAt(path: string): Promise<OfficeStructure>;
  
  // Document operations
  documentExists(path: string): Promise<boolean>;
  getDocumentContent(path: string): Promise<string>;
  setDocumentContent(path: string, content: string): Promise<void>;
  
  // Role operations
  findRoles(domain?: string): Promise<RoleSummary[]>;
  findRolesByAttributes(domain?: string, skills?: string[]): Promise<RoleSummary[]>;
  
  // Session operations
  saveSession(session: Session): Promise<void>;
  getSession(id: string): Promise<Session | null>;
  getCurrentSessionId(): Promise<string | null>;
  setCurrentSession(id: string): Promise<void>;
  
  // Initialization
  initializeWithTemplates(templates: Template[]): Promise<void>;
}

// In-memory implementation
export class InMemoryOfficeStore implements OfficeStore {
  private structure: Record<string, any> = {};
  private documents: Record<string, string> = {};
  private sessions: Record<string, Session> = {};
  private currentSessionId: string | null = null;
  
  // Implementation details...
}
```

## Template Provider

The template provider integrates with the existing CLI package:

```typescript
export interface TemplateProvider {
  getTemplates(): Promise<Template[]>;
}

export class CliTemplateProvider implements TemplateProvider {
  private templateDir: string;
  
  constructor() {
    // Find the node_modules path to claudes-office-cli
    this.templateDir = path.resolve(
      require.resolve('claudes-office-cli'),
      '../../template'
    );
  }
  
  async getTemplates(): Promise<Template[]> {
    // Read template files from the CLI package
    // Transform them into our internal format
    // ...
    return templates;
  }
}
```

## Server Initialization

Here's how we'll initialize the server:

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { InMemoryOfficeStore } from "./office/store.js";
import { CliTemplateProvider } from "./office/templates.js";
import { OfficeManager } from "./office/index.js";
import { Secretary } from "./secretary/index.js";
import { registerTools } from "./server/tools.js";
import { registerResources } from "./server/resources.js";
import { registerPrompts } from "./server/prompts.js";

export async function createServer(config: {
  openRouterApiKey: string,
  useStdio?: boolean
}) {
  // Create the MCP server
  const server = new McpServer({
    name: "claudes-office",
    version: "1.0.0"
  });
  
  // Initialize the office stack
  const store = new InMemoryOfficeStore();
  const templateProvider = new CliTemplateProvider();
  const officeManager = new OfficeManager(store, templateProvider);
  const secretary = new Secretary(config.openRouterApiKey, officeManager);
  
  // Initialize the office data
  await officeManager.initialize();
  
  // Register MCP capabilities
  registerTools(server, officeManager, secretary);
  registerResources(server, officeManager);
  registerPrompts(server, officeManager, secretary);
  
  // Connect transport
  if (config.useStdio) {
    const transport = new StdioServerTransport();
    await server.connect(transport);
  }
  
  return { server, officeManager, secretary };
}
```

## Package Configuration

```json
{
  "name": "claudes-office-mcp-server",
  "version": "1.0.0",
  "description": "MCP server implementation of Claude's Office",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "test": "jest",
    "dev": "ts-node-dev --respawn src/index.ts"
  },
  "bin": {
    "claudes-office-mcp": "./bin/claudes-office-mcp"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.2.0",
    "claudes-office-cli": "^1.0.0",
    "dotenv": "^16.0.3",
    "express": "^4.18.2",
    "nanoid": "^3.3.6",
    "openrouter": "^2.0.0",
    "zod": "^3.21.4"
  },
  "devDependencies": {
    "@types/express": "^4.17.17",
    "@types/jest": "^29.5.0",
    "@types/node": "^18.15.11",
    "jest": "^29.5.0",
    "ts-jest": "^29.1.0",
    "ts-node-dev": "^2.0.0",
    "typescript": "^5.0.4"
  },
  "engines": {
    "node": ">=16.0.0"
  }
}
```

## CLI Interface

```typescript
#!/usr/bin/env node

import { program } from 'commander';
import dotenv from 'dotenv';
import { createServer } from '../dist/index.js';

// Load environment variables
dotenv.config();

program
  .name('claudes-office-mcp')
  .description('MCP server for Claude\'s Office')
  .version('1.0.0');

program
  .command('start')
  .description('Start the MCP server')
  .option('-p, --port <port>', 'Port to run on (for HTTP mode)', '3000')
  .option('-m, --mode <mode>', 'Transport mode (stdio or http)', 'stdio')
  .option('-k, --key <key>', 'OpenRouter API key (override env var)')
  .action(async (options) => {
    const apiKey = options.key || process.env.OPENROUTER_API_KEY;
    
    if (!apiKey) {
      console.error('Error: OpenRouter API key is required. Set OPENROUTER_API_KEY env var or use --key option.');
      process.exit(1);
    }
    
    try {
      if (options.mode === 'stdio') {
        await createServer({
          openRouterApiKey: apiKey,
          useStdio: true
        });
        // Server is now running on stdio
      } else if (options.mode === 'http') {
        const express = require('express');
        const app = express();
        
        // Set up HTTP endpoints
        // ...
        
        app.listen(options.port, () => {
          console.log(`Server running on http://localhost:${options.port}`);
        });
      }
    } catch (error) {
      console.error('Error starting server:', error);
      process.exit(1);
    }
  });

program.parse();
```

## Development Roadmap

### Phase 1: Core Implementation (2 weeks)
- Set up project structure and build system
- Implement basic MCP server with tool and resource definitions
- Create in-memory office store
- Integrate template loading from CLI package
- Implement basic office manager functionality

### Phase 2: Secretary Integration (2 weeks)
- Set up OpenRouter API client
- Implement core Secretary functionality
- Create basic role matching and document finding
- Add role content generation capabilities
- Implement session management

### Phase 3: Advanced Features (2 weeks)
- Add HTTP/SSE transport support
- Implement persistent storage option
- Add role composition and specialization
- Create workflow management features
- Build project planning capabilities

### Phase 4: Polish and Deploy (1 week)
- Comprehensive testing
- Documentation
- Performance optimization
- Publish to npm registry

## Testing Strategy

1. **Unit Tests**
   - Office manager component tests
   - Secretary model service tests
   - Storage implementations tests
   - Tool and resource handler tests

2. **Integration Tests**
   - MCP server protocol compliance
   - End-to-end workflows using test clients
   - Secretary model integration tests

3. **Performance Tests**
   - Load testing with multiple simultaneous clients
   - Secretary model response time benchmarks
   - Memory usage profiling

## Conclusion

The Claude's Office MCP Server transforms the static file-based office structure into a dynamic, intelligent environment. By combining the structured organization of the CLI with the power of an MCP server and a dedicated Secretary model, we create a system that:

1. Maintains the benefits of role-based contextual AI assistance
2. Enhances the experience with dynamic role selection and generation
3. Provides a standardized interface for LLM interaction
4. Creates a more intelligent workspace that evolves with use

This implementation maintains backward compatibility with the existing CLI package while offering a significantly enhanced experience for users working with Claude and other MCP-compatible LLMs.