#
tokens: 6796/50000 5/5 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── LICENSE
├── package.json
├── README.md
├── src
│   └── server.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Dependencies
node_modules/
yarn.lock
package-lock.json

# Build output
dist/
build/
*.tsbuildinfo

# Environment variables and secrets
.env
.env.*
.cursor/mcp.json

# IDE and editor files
.idea/
.vscode/
*.swp
*.swo
.DS_Store
Thumbs.db

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Testing
coverage/
.nyc_output/

# Temporary files
tmp/
temp/

# Workato specific
.workato-token
workato.config.json 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
🤖 Workato MCP Server
Welcome to your Workato API integration toolkit, designed as a Model Context Protocol (MCP) server for Cursor or Claude! This project provides seamless interaction with Workato's API through custom AI tools.

✨ Features
🔄 Recipe Management
- List, create, start, and stop recipes
- Monitor recipe execution jobs
- Manage recipe folders and projects

🔌 Connection Management
- List and create connections
- View connection details and status
- Manage connection configurations

🔍 Connector Discovery
- List available connectors and their capabilities
- View connector metadata and supported operations
- Browse all platform connectors

📂 Folder & Project Organization
- Create and manage folders
- Organize recipes and connections
- Handle project-level configurations

📊 Activity Logs
- Track all activities within your workspace
- Filter logs by time range, users, and event types
- Monitor resource changes and user actions
- Support for multiple environments (dev, sandbox, prod, etc.)
- Advanced filtering by resource and event types


🔖 Tag Management
- Create, update, and delete tags in your workspace
- List and retrieve available tags with advanced filtering options
- Apply or remove tags from assets (recipes and connections)
- Supports batch operations for multiple assets and tags
- Filter tags by title, description, author, and usage
- Sort tags by various criteria (title, usage count, etc.)
- Customize tag appearance with color options


🚀 Getting Started
2. Installation
```bash
npm install
# or
yarn install
```

3. Build the Server
```bash
npm run build
```

4. Adding to Cursor
This project is designed to be used as an MCP server in Cursor. Here's how to set it up:

1. Open Cursor
2. Go to Cursor Settings > Features > MCP
3. Click + Add New MCP Server
4. Fill out the form:
   - Name: Workato MCP Server
   - Type: stdio
   - Command: node /path/to/your/project/dist/server.js
   - Environment Variables:
     - Click "Add Environment Variable"
     - Name: WORKATO_API_TOKEN
     - Value: your_token_here

📘 Pro Tip: Use the full path to your project's built server.js file.

Alternative Configuration:
You can also configure the MCP server using a `.cursor/mcp.json` file in your project:

```json
{
  "mcpServers": {
    "workato-tools": {
      "command": "node",
      "args": ["/path/to/your/project/dist/server.js"],
      "env": {
        "WORKATO_API_TOKEN": "your_token_here"
      }
    }
  }
}
```

Using with Claude Desktop:
If you're using Claude Desktop instead of Cursor, you can configure the MCP server by editing the Claude desktop configuration:

1. Open or create the configuration file:
   ```bash
   # On macOS
   ~/Library/Application Support/Claude/claude_desktop_config.json
   # On Windows
   %APPDATA%\Claude\claude_desktop_config.json
   # On Linux
   ~/.config/Claude/claude_desktop_config.json
   ```

2. Add your MCP server configuration:
   ```json
   {
     "mcp_servers": {
       "workato-tools": {
         "command": "node",
         "args": ["/path/to/your/project/dist/server.js"],
         "env": {
           "WORKATO_API_TOKEN": "your_token_here"
         }
       }
     }
   }
   ```

3. Save the file and restart Claude Desktop for the changes to take effect

This method allows you to:
- Version control your MCP configuration
- Include environment variables directly in the config
- Share the same configuration across team members (excluding sensitive values)
- Automatically load the server when opening the project in Cursor

🛠️ Available Tools

Recipe Management:
- list-recipes: List all recipes with filtering options
- create-recipe: Create a new recipe
- start-recipe: Start a specific recipe
- stop-recipe: Stop a running recipe

Connection Management:
- list-connections: List all connections
- create-connection: Create a new connection

Connector Tools:
- list-connectors: Get metadata for specific connectors
- list-all-connectors: List all available connectors

Organization Tools:
- list-folders: List all folders
- create-folder: Create a new folder
- update-folder: Modify folder properties
- list-projects: List all projects
- update-project: Update project details

API Management:
- list-api-endpoints: List all API endpoints with optional filtering by collection

Activity Monitoring:
- list-activity-logs: Retrieve detailed activity logs with advanced filtering options
  - Filter by time range, users, and event types
  - Include or exclude specific resource types
  - Track changes across different environments
  - Monitor user actions and system events

Tag Management:
- list-tags: List and filter available tags in your workspace with advanced query options
- create-tag: Create a new tag with custom title, description, and color
- update-tag: Modify an existing tag's properties
- delete-tag: Remove a tag from your workspace
- manage-tags: Apply or remove tags from recipes and connections

Job Management:
- list-recipe-jobs: View jobs for a specific recipe
- get-job: Get detailed job information
- resume-job: Resume a paused job

🤝 Contributing Contributions welcome! Please feel free to submit a Pull Request.

📝 License This project is licensed under the MIT License - see the LICENSE file for details.

🐛 Issues & Support Found a bug or need help? Open an issue with:

What you were trying to do
What happened instead
Steps to reproduce
Your environment details

Made with ❤️ by Jacob Goren, for Workato automation
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "es2022",
    "module": "es2022",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
} 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "workato-mpc-server",
  "version": "1.0.0",
  "type": "module",
  "main": "dist/server.js",
  "scripts": {
    "build": "yarn tsc",
    "start": "node dist/server.js",
    "dev": "yarn build && yarn start"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/jacobgoren-sb/workato-mpc-server.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/jacobgoren-sb/workato-mpc-server/issues"
  },
  "homepage": "https://github.com/jacobgoren-sb/workato-mpc-server#readme",
  "description": "",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.7.0",
    "@types/node": "^20.11.24",
    "typescript": "^5.3.3",
    "zod": "^3.22.4"
  }
}

```

--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// Create an MCP server
const server = new McpServer({
  name: "workato-mcp-server",
  version: "1.0.0"
});

// Add list-recipes tool
server.tool(
  "list-recipes",
  {
    adapter_names_all: z.string().optional(),
    adapter_names_any: z.string().optional(),
    folder_id: z.string().optional(),
    order: z.enum(["activity", "default"]).optional(),
    page: z.number().int().min(1).optional().default(1),
    per_page: z.number().int().min(1).max(100).optional().default(100),
    running: z.boolean().optional(),
    since_id: z.number().int().optional(),
    stopped_after: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/).optional(),
    stop_cause: z.enum(["trigger_errors_limit", "action_quota_limit", "trial_expired", "txn_quota_limit"]).optional(),
    updated_after: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/).optional(),
    includes: z.array(z.string()).optional()
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined) {
        if (Array.isArray(value)) {
          value.forEach(v => queryParams.append(`${key}[]`, v));
        } else {
          queryParams.append(key, String(value));
        }
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/recipes?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add create-recipe tool
server.tool(
  "create-recipe",
  {
    recipe: z.object({
      name: z.string().optional(),
      code: z.string(),
      config: z.string().optional(),
      folder_id: z.string().optional(),
      description: z.string().optional()
    })
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch('https://www.workato.com/api/recipes', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(params)
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add start-recipe tool
server.tool(
  "start-recipe",
  {
    id: z.number().int()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/recipes/${params.id}/start`, {
      method: 'PUT',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add stop-recipe tool
server.tool(
  "stop-recipe",
  {
    id: z.number().int()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/recipes/${params.id}/stop`, {
      method: 'PUT',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add list-connections tool
server.tool(
  "list-connections",
  {
    folder_id: z.string().optional(),
    parent_id: z.string().optional(),
    external_id: z.string().optional(),
    include_runtime_connections: z.string().optional(),
    includes: z.array(z.string()).optional()
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined) {
        if (Array.isArray(value)) {
          value.forEach(v => queryParams.append(`${key}[]`, v));
        } else {
          queryParams.append(key, String(value));
        }
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/connections?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add create-connection tool
server.tool(
  "create-connection",
  {
    name: z.string().optional(),
    provider: z.string().optional(),
    parent_id: z.string().optional(),
    folder_id: z.string().optional(),
    external_id: z.string().optional(),
    shell_connection: z.boolean().optional(),
    input: z.record(z.any()).optional()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch('https://www.workato.com/api/connections', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(params)
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add list-connectors tool
server.tool(
  "list-connectors",
  {
    applications: z.string()
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    queryParams.append('applications', params.applications);

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/integrations?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add list-all-connectors tool
server.tool(
  "list-all-connectors",
  {
    page: z.number().int().min(1).optional().default(1),
    per_page: z.number().int().min(1).max(100).optional().default(100)
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined) {
        queryParams.append(key, String(value));
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/integrations/all?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add list-folders tool
server.tool(
  "list-folders",
  {
    parent_id: z.string().optional(),
    page: z.number().int().min(1).optional().default(1),
    per_page: z.number().int().min(1).max(100).optional().default(100)
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined) {
        queryParams.append(key, String(value));
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/folders?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add list-projects tool
server.tool(
  "list-projects",
  {
    page: z.number().int().min(1).optional().default(1),
    per_page: z.number().int().min(1).max(100).optional().default(100)
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined) {
        queryParams.append(key, String(value));
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/projects?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add create-folder tool
server.tool(
  "create-folder",
  {
    name: z.string(),
    parent_id: z.string().optional()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch('https://www.workato.com/api/folders', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(params)
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add update-folder tool
server.tool(
  "update-folder",
  {
    folder_id: z.string(),
    name: z.string().optional(),
    parent_id: z.string().optional()
  },
  async (params) => {
    const { folder_id, ...updateParams } = params;
    
    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/folders/${folder_id}`, {
      method: 'PUT',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updateParams)
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add update-project tool
server.tool(
  "update-project",
  {
    project_id: z.string(),
    name: z.string(),
    description: z.string().optional()
  },
  async (params) => {
    const { project_id, ...updateParams } = params;
    
    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/projects/${project_id}`, {
      method: 'PUT',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updateParams)
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add list-recipe-jobs tool
server.tool(
  "list-recipe-jobs",
  {
    recipe_id: z.number().int(),
    offset_job_id: z.string().optional(),
    prev: z.boolean().optional().default(false),
    status: z.enum(["succeeded", "failed", "pending"]).optional(),
    rerun_only: z.boolean().optional()
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined && key !== 'recipe_id') {
        queryParams.append(key, String(value));
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/recipes/${params.recipe_id}/jobs?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add get-job tool
server.tool(
  "get-job",
  {
    recipe_id: z.number().int(),
    job_handle: z.string()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/recipes/${params.recipe_id}/jobs/${params.job_handle}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add resume-job tool
server.tool(
  "resume-job",
  {
    token: z.string(),
    data: z.record(z.any()).optional()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch('https://www.workato.com/api/job/resume', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(params)
    });

    // Since this endpoint returns 204 with no content, we'll return a success message
    return {
      content: [{ type: "text", text: "Job resumed successfully" }]
    };
  }
);

// Add list-api-endpoints tool
server.tool(
  "list-api-endpoints",
  {
    api_collection_id: z.string().optional(),
    per_page: z.number().int().min(1).max(100).optional().default(100),
    page: z.number().int().min(1).optional().default(1)
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined) {
        queryParams.append(key, String(value));
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/api_endpoints?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add manage-tags tool
server.tool(
  "manage-tags",
  {
    add_tags: z.array(z.string()).optional(),
    remove_tags: z.array(z.string()).optional(),
    recipe_ids: z.array(z.number()).optional(),
    connection_ids: z.array(z.number()).optional()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch('https://www.workato.com/api/tags_assignments', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(params)
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Update list-tags tool with full parameters
server.tool(
  "list-tags",
  {
    page: z.number().int().min(1).optional().default(1),
    per_page: z.number().int().min(1).max(100).optional().default(100),
    'q[title_or_description_cont]': z.string().optional(),
    'q[handle_in]': z.array(z.string()).optional(),
    'q[author_id_eq]': z.number().optional(),
    'q[recipe_id_eq]': z.number().optional(),
    'q[connection_id_eq]': z.number().optional(),
    'q[only_assigned]': z.boolean().optional(),
    'sort_by[]': z.array(z.enum(['title', 'assignment_count', 'updated_at', 'last_assigned_at'])).optional(),
    'sort_direction[]': z.array(z.enum(['asc', 'desc'])).optional(),
    'includes[]': z.array(z.enum(['assignment_count', 'author'])).optional()
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined) {
        if (Array.isArray(value)) {
          value.forEach(v => queryParams.append(key, String(v)));
        } else {
          queryParams.append(key, String(value));
        }
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/tags?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add create-tag tool
server.tool(
  "create-tag",
  {
    title: z.string().max(30),
    description: z.string().max(150).optional(),
    color: z.enum(['blue', 'violet', 'green', 'red', 'orange', 'gold', 'indigo', 'brown', 'teal', 'plum', 'slate', 'neutral']).optional()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch('https://www.workato.com/api/tags', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(params)
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add update-tag tool
server.tool(
  "update-tag",
  {
    handle: z.string(),
    title: z.string().max(30),
    description: z.string().max(150).optional(),
    color: z.enum(['blue', 'violet', 'green', 'red', 'orange', 'gold', 'indigo', 'brown', 'teal', 'plum', 'slate', 'neutral']).optional()
  },
  async (params) => {
    const { handle, ...updateParams } = params;
    
    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/tags/${handle}`, {
      method: 'PUT',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(updateParams)
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Add delete-tag tool
server.tool(
  "delete-tag",
  {
    handle: z.string()
  },
  async (params) => {
    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/tags/${params.handle}`, {
      method: 'DELETE',
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    return {
      content: [{ type: "text", text: "Tag deleted successfully" }]
    };
  }
);

// Add list-activity-logs tool
server.tool(
  "list-activity-logs",
  {
    'page[after]': z.number().int().optional(),
    'page[size]': z.number().int().min(1).max(100).optional().default(100),
    from: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/).optional(),
    to: z.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/).optional(),
    'users_ids[]': z.array(z.number()).optional(),
    'include_resource_types[]': z.array(z.string()).optional(),
    'exclude_resource_types[]': z.array(z.string()).optional(),
    'include_event_types[]': z.array(z.string()).optional(),
    'exclude_event_types[]': z.array(z.string()).optional()
  },
  async (params) => {
    // Construct query parameters
    const queryParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined) {
        if (Array.isArray(value)) {
          value.forEach(v => queryParams.append(key, String(v)));
        } else {
          queryParams.append(key, String(value));
        }
      }
    });

    // Make API call to Workato
    const response = await fetch(`https://www.workato.com/api/activity_logs?${queryParams.toString()}`, {
      headers: {
        'Authorization': 'Bearer ' + process.env.WORKATO_API_TOKEN
      }
    });

    const data = await response.json();
    return {
      content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
    };
  }
);

// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport); 
```