Skip to main content
Glama

Productive.io MCP Server

A Model Context Protocol (MCP) server for interacting with Productive.io task management platform.

Features

  • šŸ”§ Extensible Architecture - Plugin-based tool system for easy extension

  • šŸ“¦ Modular Design - Clean separation of concerns with TypeScript

  • šŸ”’ Type-Safe - Full TypeScript support with strict type checking

  • āš™ļø Configuration Management - Environment-based configuration

  • šŸŽÆ Easy to Extend - Add new tools by creating a single class

Related MCP server: productive-mcp-rb2

Installation

# Install dependencies
pnpm install

# Build the project
npm run build

Configuration

For Claude Desktop

Add the MCP server to your Claude Desktop config file with environment variables:

Location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Configuration:

{
  "mcpServers": {
    "productive.io": {
      "command": "node",
      "args": ["/Users/joelkrause/dev/productive-mcp/build/index.js"],
      "env": {
        "PRODUCTIVE_API_TOKEN": "your-api-token-here",
        "PRODUCTIVE_ORGANIZATION_ID": "your-organization-id",
        "PRODUCTIVE_USER_ID": "your-user-id"
      }
    }
  }
}

For Development/Testing

You can also use a .env file (use .env.example as a template):

cp .env.example .env

Required environment variables:

  • PRODUCTIVE_API_TOKEN - Your Productive.io API token

  • PRODUCTIVE_ORGANIZATION_ID - Your organization ID

  • PRODUCTIVE_USER_ID - Your user ID

Available Tools

get_task

Get a single task from Productive.io by URL.

Parameters:

  • url (string) - Productive.io task URL

get_tasks

Get multiple tasks with optional filters.

Parameters:

  • assignee_id (string, optional) - Filter by assignee ID

  • status (number, optional) - Filter by status (1=Open, 2=Closed)

  • project_id (string, optional) - Filter by project ID

Project Structure

src/
ā”œā”€ā”€ config/           # Configuration management
│   └── index.ts      # Environment-based config loader
ā”œā”€ā”€ services/         # API clients and services
│   └── ProductiveApiClient.ts  # Typed Productive.io API client
ā”œā”€ā”€ tools/           # MCP tools (plugins)
│   ā”œā”€ā”€ base/        # Base tool class
│   │   └── BaseTool.ts
│   ā”œā”€ā”€ get-task/    # Individual tool modules
│   │   ā”œā”€ā”€ index.ts    # Tool implementation
│   │   ā”œā”€ā”€ handler.ts  # Business logic (includes URL extraction)
│   │   └── schema.ts   # Zod validation schema
│   ā”œā”€ā”€ get-tasks/
│   │   ā”œā”€ā”€ index.ts
│   │   ā”œā”€ā”€ handler.ts
│   │   └── schema.ts
│   └── index.ts     # Tool registry and auto-registration
ā”œā”€ā”€ types/           # TypeScript type definitions
│   ā”œā”€ā”€ config.types.ts
│   ā”œā”€ā”€ productive.types.ts
│   └── tool.types.ts
└── index.ts         # Main entry point

Adding a New Tool

Adding a new tool is simple with the extensible architecture:

1. Create a new tool directory

mkdir -p src/tools/your-tool

2. Create the schema (src/tools/your-tool/schema.ts)

import { z } from "zod";

export const YourToolSchema = z.object({
  param1: z.string().describe("Description of param1"),
  param2: z.number().optional().describe("Optional param2"),
});

export type YourToolInput = z.infer<typeof YourToolSchema>;

3. Create the handler (src/tools/your-tool/handler.ts)

import { ProductiveApiClient } from "../../services/ProductiveApiClient.js";
import { ToolResponse } from "../../types/tool.types.js";

export async function handleYourTool(
  input: YourToolInput,
  apiClient: ProductiveApiClient
): Promise<ToolResponse> {
  try {
    // Your logic here
    const result = await apiClient.someMethod();

    return {
      content: [{ type: "text", text: "Success!" }],
    };
  } catch (error) {
    return {
      content: [
        {
          type: "text",
          text: `Error: ${error instanceof Error ? error.message : "Unknown"}`,
        },
      ],
      isError: true,
    };
  }
}

4. Create the tool class (src/tools/your-tool/index.ts)

import { BaseTool } from "../base/BaseTool.js";
import { ProductiveApiClient } from "../../services/ProductiveApiClient.js";
import { ToolResponse } from "../../types/tool.types.js";
import { YourToolSchema, YourToolInput } from "./schema.js";
import { handleYourTool } from "./handler.js";

export class YourTool extends BaseTool<YourToolInput> {
  readonly name = "your_tool";
  readonly description = "Description of what your tool does";
  readonly schema = YourToolSchema;

  private apiClient: ProductiveApiClient;

  constructor(apiClient?: ProductiveApiClient) {
    super();
    this.apiClient = apiClient || new ProductiveApiClient();
  }

  async execute(input: YourToolInput): Promise<ToolResponse> {
    return handleYourTool(input, this.apiClient);
  }
}

5. Register the tool (src/tools/index.ts)

import { YourTool } from "./your-tool/index.js";

export function getAllTools(): Tool[] {
  return [
    new GetTaskTool(),
    new GetTasksTool(),
    new YourTool(), // Add your tool here
  ];
}

That's it! Your new tool will be automatically registered and available.

Development

# Build the project
npm run build

# Watch mode for development
npm run dev

# Type checking only
npm run typecheck

# Clean build directory
npm run clean

# Clean and rebuild
npm run rebuild

Architecture Benefits

Extensibility

  • Plugin-based: New tools are self-contained modules

  • Auto-registration: Tools are automatically registered from the registry

  • No core changes: Adding tools doesn't require modifying the main server code

Type Safety

  • Full TypeScript: Strict type checking enabled

  • Type inference: Zod schemas provide runtime validation and compile-time types

  • API types: Fully typed Productive.io API responses

Maintainability

  • Separation of concerns: Each tool has its own directory with schema, handler, and implementation

  • Reusable components: BaseTool provides common functionality

  • Clear structure: Easy to navigate and understand

Best Practices

  • Error handling: Consistent error responses across all tools

  • Configuration: Environment-based configuration management

  • Documentation: JSDoc comments throughout the codebase

License

MIT

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers