#
tokens: 49778/50000 79/86 files (page 1/2)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 2. Use http://codebase.md/leonardsellem/n8n-mcp-server?page={x} to view the full context.

# Directory Structure

```
├── .babelrc
├── .env.example
├── .eslintrc.json
├── .github
│   └── workflows
│       ├── claude-code-review.yml
│       ├── claude.yml
│       ├── docker-publish.yml
│       └── release-package.yml
├── .gitignore
├── AGENTS.md
├── babel.config.cjs
├── CLAUDE.md
├── Dockerfile
├── docs
│   ├── .gitkeep
│   ├── api
│   │   ├── dynamic-resources.md
│   │   ├── execution-tools.md
│   │   ├── index.md
│   │   ├── static-resources.md
│   │   └── workflow-tools.md
│   ├── development
│   │   ├── architecture.md
│   │   ├── extending.md
│   │   ├── index.md
│   │   └── testing.md
│   ├── examples
│   │   ├── advanced-scenarios.md
│   │   ├── basic-examples.md
│   │   ├── index.md
│   │   └── integration-examples.md
│   ├── images
│   │   ├── architecture.png.placeholder
│   │   └── n8n-api-key.png.placeholder
│   ├── index.md
│   └── setup
│       ├── configuration.md
│       ├── index.md
│       ├── installation.md
│       └── troubleshooting.md
├── jest.config.cjs
├── LICENSE
├── manual_verify_update.mjs
├── n8n-openapi.yml
├── package-lock.json
├── package.json
├── README.md
├── requirements.txt
├── run-tests.js
├── smithery.yaml
├── src
│   ├── .gitkeep
│   ├── api
│   │   ├── client.ts
│   │   └── n8n-client.ts
│   ├── config
│   │   ├── environment.ts
│   │   └── server.ts
│   ├── errors
│   │   ├── error-codes.ts
│   │   └── index.ts
│   ├── index.ts
│   ├── resources
│   │   ├── dynamic
│   │   │   ├── execution.ts
│   │   │   └── workflow.ts
│   │   ├── index.ts
│   │   └── static
│   │       ├── execution-stats.ts
│   │       └── workflows.ts
│   ├── tools
│   │   ├── execution
│   │   │   ├── base-handler.ts
│   │   │   ├── delete.ts
│   │   │   ├── get.ts
│   │   │   ├── handler.ts
│   │   │   ├── index.ts
│   │   │   ├── list.ts
│   │   │   └── run.ts
│   │   └── workflow
│   │       ├── activate.ts
│   │       ├── base-handler.ts
│   │       ├── create.ts
│   │       ├── deactivate.ts
│   │       ├── delete.ts
│   │       ├── get.ts
│   │       ├── handler.ts
│   │       ├── index.ts
│   │       ├── list.ts
│   │       └── update.ts
│   ├── types
│   │   └── index.ts
│   └── utils
│       ├── execution-formatter.ts
│       └── resource-formatter.ts
├── tests
│   ├── jest-globals.d.ts
│   ├── mocks
│   │   ├── axios-mock.ts
│   │   └── n8n-fixtures.ts
│   ├── README.md
│   ├── test-setup.ts
│   ├── tsconfig.json
│   └── unit
│       ├── api
│       │   ├── client.test.ts.bak
│       │   └── simple-client.test.ts
│       ├── config
│       │   ├── environment.test.ts
│       │   ├── environment.test.ts.bak
│       │   └── simple-environment.test.ts
│       ├── resources
│       │   └── dynamic
│       │       └── workflow.test.ts
│       ├── tools
│       │   └── workflow
│       │       ├── list.test.ts.bak
│       │       └── simple-tool.test.ts
│       └── utils
│           ├── execution-formatter.test.ts
│           └── resource-formatter.test.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/docs/.gitkeep:
--------------------------------------------------------------------------------

```

```

--------------------------------------------------------------------------------
/src/.gitkeep:
--------------------------------------------------------------------------------

```

```

--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------

```
{
  "presets": [
    ["@babel/preset-env", { "targets": { "node": "current" } }],
    "@babel/preset-typescript"
  ]
}

```

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
# n8n MCP Server Environment Variables

# Required: URL of the n8n API (e.g., http://localhost:5678/api/v1)
N8N_API_URL=http://localhost:5678/api/v1

# Required: API key for authenticating with n8n
# Generate this in the n8n UI under Settings > API > API Keys
N8N_API_KEY=your_n8n_api_key_here

# Optional: Set to 'true' to enable debug logging
DEBUG=false

```

--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------

```json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "@typescript-eslint"
  ],
  "root": true,
  "rules": {
    "@typescript-eslint/no-explicit-any": "off",
    "@typescript-eslint/no-unused-vars": [
      "error",
      {
        "argsIgnorePattern": "^_",
        "varsIgnorePattern": "^_"
      }
    ]
  }
}

```

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

```
# Dependency directories
node_modules/
coverage/

# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Build outputs
dist/
build/

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

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# macOS
.DS_Store

# Misc
.npm
.eslintcache
.yarn-integrity

# CRCT System
cline_docs/
strategy_tasks/
Previous_versions/
--output
test-output-summary.md

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
ENV/
env/
.env/
.venv/
*.egg-info/
dist/
build/

# Embeddings
*.embedding
embeddings/
mcp-config.json
```

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

```markdown
# Testing System for n8n MCP Server

This directory contains the testing framework and tests for the n8n MCP Server project. The tests are organized in a hierarchical structure to match the project's architecture.

## Test Structure

- **unit/**: Unit tests for individual components
  - **api/**: Tests for API clients and services
  - **config/**: Tests for configuration handling
  - **errors/**: Tests for error handling
  - **resources/**: Tests for MCP resource handlers
    - **dynamic/**: Tests for dynamic resource handlers
    - **static/**: Tests for static resource handlers
  - **tools/**: Tests for MCP tool handlers
    - **workflow/**: Tests for workflow-related tools
    - **execution/**: Tests for execution-related tools
  - **utils/**: Tests for utility functions

- **integration/**: Integration tests for component interactions
  - Tests that verify multiple components work together correctly

- **e2e/**: End-to-end tests for full server functionality
  - Tests that simulate real-world usage scenarios

- **mocks/**: Mock data and utilities for testing
  - Reusable mock data and functions shared across tests

## Running Tests

The project uses Jest as the test runner with ESM support. The following npm scripts are available:

```bash
# Run all tests
npm test

# Run tests in watch mode (useful during development)
npm run test:watch

# Run tests with coverage report
npm run test:coverage

# Run specific test file(s)
npm test -- tests/unit/api/client.test.ts

# Run tests matching a specific pattern
npm test -- -t "should format and return workflows"
```

## Writing Tests

### Test File Naming Convention

- All test files should end with `.test.ts`
- Test files should be placed in the same directory structure as the source files they test

### Test Organization

Each test file should follow this structure:

```typescript
/**
 * Description of what's being tested
 */

import '@jest/globals';
import { ComponentToTest } from '../../../src/path/to/component.js';
// Import other dependencies and mocks

// Mock dependencies
jest.mock('../../../src/path/to/dependency.js');

describe('ComponentName', () => {
  // Setup and teardown
  beforeEach(() => {
    // Common setup
  });
  
  afterEach(() => {
    // Common cleanup
  });
  
  describe('methodName', () => {
    it('should do something specific', () => {
      // Arrange
      // ...
      
      // Act
      // ...
      
      // Assert
      expect(result).toBe(expectedValue);
    });
    
    // More test cases...
  });
  
  // More method tests...
});
```

### Testing Utilities

The project provides several testing utilities:

- **test-setup.ts**: Common setup for all tests
- **mocks/axios-mock.ts**: Utilities for mocking Axios HTTP requests
- **mocks/n8n-fixtures.ts**: Mock data for n8n API responses

## Best Practices

1. **Isolation**: Each test should be independent and not rely on other tests
2. **Mock Dependencies**: External dependencies should be mocked
3. **Descriptive Names**: Use descriptive test and describe names
4. **Arrange-Act-Assert**: Structure your tests with clear sections
5. **Coverage**: Aim for high test coverage, especially for critical paths
6. **Readability**: Write clear, readable tests that serve as documentation

## Extending the Test Suite

When adding new functionality to the project:

1. Create corresponding test files in the appropriate directory
2. Use existing mocks and utilities when possible
3. Create new mock data in `mocks/` for reusability
4. Update this README if you add new testing patterns or utilities

## Troubleshooting

If you encounter issues running the tests:

- Ensure you're using Node.js 20 or later
- Run `npm install` to ensure all dependencies are installed
- Check for ESM compatibility issues if importing CommonJS modules
- Use `console.log` or `console.error` for debugging (removed in production)

```

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

```markdown
# n8n MCP Server

[![npm version](https://badge.fury.io/js/%40leonardsellem%2Fn8n-mcp-server.svg)](https://badge.fury.io/js/%40leonardsellem%2Fn8n-mcp-server)

A Model Context Protocol (MCP) server that allows AI assistants to interact with n8n workflows through natural language.

## Overview

This project provides a Model Context Protocol (MCP) server that empowers AI assistants to seamlessly interact with n8n, a popular workflow automation tool. It acts as a bridge, enabling AI assistants to programmatically manage and control n8n workflows and executions using natural language commands.

## Installation

### Prerequisites

- Node.js 20 or later
- n8n instance with API access enabled

### Install from npm

```bash
npm install -g @leonardsellem/n8n-mcp-server
```

### Install from source

```bash
# Clone the repository
git clone https://github.com/leonardsellem/n8n-mcp-server.git
cd n8n-mcp-server

# Install dependencies
npm install

# Build the project
npm run build

# Optional: Install globally
npm install -g .
```

### Docker Installation

You can also run the server using Docker:

```bash
# Pull the image
docker pull leonardsellem/n8n-mcp-server

# Run the container with your n8n API configuration
docker run -e N8N_API_URL=http://your-n8n:5678/api/v1 \
  -e N8N_API_KEY=your_n8n_api_key \
  -e N8N_WEBHOOK_USERNAME=username \
  -e N8N_WEBHOOK_PASSWORD=password \
  leonardsellem/n8n-mcp-server
```

## Updating the Server

How you update the server depends on how you initially installed it.

### 1. Installed globally via npm

If you installed the server using `npm install -g @leonardsellem/n8n-mcp-server`:

1.  Open your terminal or command prompt.
2.  Run the following command to get the latest version:
    ```bash
    npm install -g @leonardsellem/n8n-mcp-server@latest
    ```
3.  If the server is currently running (e.g., as a background process or service), you'll need to restart it for the changes to take effect.

### 2. Installed from source

If you cloned the repository and installed from source:

1.  Open your terminal or command prompt.
2.  Navigate to the directory where you cloned the project:
    ```bash
    cd path/to/n8n-mcp-server
    ```
3.  If you've made any local changes to the code that you want to keep, consider stashing them (optional):
    ```bash
    git stash
    ```
    You can apply them later with `git stash pop`.
4.  Pull the latest changes from the repository (assuming you are on the `main` branch):
    ```bash
    git pull origin main
    ```
    If you are on a different branch, replace `main` with your branch name.
5.  Install or update any changed dependencies:
    ```bash
    npm install
    ```
6.  Rebuild the project to include the latest updates:
    ```bash
    npm run build
    ```
7.  If you previously installed it globally from this source folder using `npm install -g .`, you might want to run this command again to update the global link:
    ```bash
    npm install -g .
    ```
8.  Restart the server.
    *   If you run the server directly using a command like `node build/index.js` in your AI assistant's MCP configuration, ensure the path is still correct. Using `npm install -g .` and then `n8n-mcp-server` as the command should keep this consistent.

### 3. Using Docker

If you are running the server using Docker:

1.  Pull the latest image from Docker Hub:
    ```bash
    docker pull leonardsellem/n8n-mcp-server:latest
    ```
2.  Stop and remove your old container. You'll need your container's name or ID (you can find it using `docker ps`):
    ```bash
    docker stop <your_container_name_or_id>
    docker rm <your_container_name_or_id>
    ```
3.  Start a new container with the updated image. Use the same `docker run` command you used previously, including all your necessary environment variables (refer to the "Docker Installation" section for an example command). For instance:
    ```bash
    docker run -e N8N_API_URL=http://your-n8n:5678/api/v1 \
      -e N8N_API_KEY=your_n8n_api_key \
      -e N8N_WEBHOOK_USERNAME=username \
      -e N8N_WEBHOOK_PASSWORD=password \
      leonardsellem/n8n-mcp-server:latest
    ```
    Ensure you use `:latest` or the specific version tag you intend to run.

## Configuration

Create a `.env` file in the directory where you'll run the server, using `.env.example` as a template:

```bash
cp .env.example .env
```

Configure the following environment variables:

| Variable | Description | Example |
|----------|-------------|---------|
| `N8N_API_URL` | Full URL of the n8n API, including `/api/v1` | `http://localhost:5678/api/v1` |
| `N8N_API_KEY` | API key for authenticating with n8n | `n8n_api_...` |
| `N8N_WEBHOOK_USERNAME` | Username for webhook authentication (if using webhooks) | `username` |
| `N8N_WEBHOOK_PASSWORD` | Password for webhook authentication | `password` |
| `DEBUG` | Enable debug logging (optional) | `true` or `false` |

### Generating an n8n API Key

1. Open your n8n instance in a browser
2. Go to Settings > API > API Keys
3. Create a new API key with appropriate permissions
4. Copy the key to your `.env` file

## Usage

### Running the Server

From the installation directory:

```bash
n8n-mcp-server
```

Or if installed globally:

```bash
n8n-mcp-server
```

### Integrating with AI Assistants

After building the server (`npm run build`), you need to configure your AI assistant (like VS Code with the Claude extension or the Claude Desktop app) to run it. This typically involves editing a JSON configuration file.

**Example Configuration (e.g., in VS Code `settings.json` or Claude Desktop `claude_desktop_config.json`):**

```json
{
  "mcpServers": {
    // Give your server a unique name
    "n8n-local": {
      // Use 'node' to execute the built JavaScript file
      "command": "node",
      // Provide the *absolute path* to the built index.js file
      "args": [
        "/path/to/your/cloned/n8n-mcp-server/build/index.js"
        // On Windows, use double backslashes:
        // "C:\\path\\to\\your\\cloned\\n8n-mcp-server\\build\\index.js"
      ],
      // Environment variables needed by the server
      "env": {
        "N8N_API_URL": "http://your-n8n-instance:5678/api/v1", // Replace with your n8n URL
        "N8N_API_KEY": "YOUR_N8N_API_KEY", // Replace with your key
        // Add webhook credentials only if you plan to use webhook tools
        // "N8N_WEBHOOK_USERNAME": "your_webhook_user",
        // "N8N_WEBHOOK_PASSWORD": "your_webhook_password"
      },
      // Ensure the server is enabled
      "disabled": false,
      // Default autoApprove settings
      "autoApprove": []
    }
    // ... other servers might be configured here
  }
}
```

**Key Points:**

*   Replace `/path/to/your/cloned/n8n-mcp-server/` with the actual absolute path where you cloned and built the repository.
*   Use the correct path separator for your operating system (forward slashes `/` for macOS/Linux, double backslashes `\\` for Windows).
*   Ensure you provide the correct `N8N_API_URL` (including `/api/v1`) and `N8N_API_KEY`.
*   The server needs to be built (`npm run build`) before the assistant can run the `build/index.js` file.

## Available Tools

The server provides the following tools:

### Using Webhooks

This MCP server supports executing workflows through n8n webhooks. To use this functionality:

1. Create a webhook-triggered workflow in n8n.
2. Set up Basic Authentication on your webhook node.
3. Use the `run_webhook` tool to trigger the workflow, passing just the workflow name.

Example:
```javascript
const result = await useRunWebhook({
  workflowName: "hello-world", // Will call <n8n-url>/webhook/hello-world
  data: {
    prompt: "Hello from AI assistant!"
  }
});
```

The webhook authentication is handled automatically using the `N8N_WEBHOOK_USERNAME` and `N8N_WEBHOOK_PASSWORD` environment variables.

### Workflow Management

- `workflow_list`: List all workflows
- `workflow_get`: Get details of a specific workflow
- `workflow_create`: Create a new workflow
- `workflow_update`: Update an existing workflow
- `workflow_delete`: Delete a workflow
- `workflow_activate`: Activate a workflow
- `workflow_deactivate`: Deactivate a workflow

### Execution Management

- `execution_run`: Execute a workflow via the API
- `run_webhook`: Execute a workflow via a webhook
- `execution_get`: Get details of a specific execution
- `execution_list`: List executions for a workflow
- `execution_stop`: Stop a running execution

## Resources

The server provides the following resources:

- `n8n://workflows/list`: List of all workflows
- `n8n://workflow/{id}`: Details of a specific workflow
- `n8n://executions/{workflowId}`: List of executions for a workflow
- `n8n://execution/{id}`: Details of a specific execution

## Roadmap

The n8n MCP Server is a community-driven project, and its future direction will be shaped by your feedback and contributions!

Currently, our roadmap is flexible and under continuous development. We believe in evolving the server based on the needs and ideas of our users.

We encourage you to get involved in shaping the future of this tool:

-   **Suggest Features:** Have an idea for a new tool, resource, or improvement?
-   **Discuss Priorities:** Want to weigh in on what we should focus on next?

Please share your thoughts, feature requests, and ideas by opening an issue on our [GitHub Issues page](https://github.com/leonardsellem/n8n-mcp-server/issues). Let's build a powerful tool for AI assistants together!

## Development

### Building

```bash
npm run build
```

### Running in Development Mode

```bash
npm run dev
```

### Testing

```bash
npm test
```

### Linting

```bash
npm run lint
```

## Contributing

We welcome contributions from the community and are excited to see how you can help improve the n8n MCP Server! Whether you're fixing a bug, proposing a new feature, or improving documentation, your help is valued.

### Reporting Bugs

If you encounter a bug, please report it by opening an issue on our [GitHub Issues page](https://github.com/leonardsellem/n8n-mcp-server/issues).

When submitting a bug report, please include the following:

-   A clear and descriptive title.
-   A detailed description of the problem, including steps to reproduce the bug.
-   Information about your environment (e.g., Node.js version, n8n MCP Server version, operating system).
-   Any relevant error messages or screenshots.

### Suggesting Enhancements

We're always looking for ways to make the server better. If you have an idea for an enhancement or a new feature, please open an issue on our [GitHub Issues page](https://github.com/leonardsellem/n8n-mcp-server/issues).

Please provide:

-   A clear and descriptive title for your suggestion.
-   A detailed explanation of the proposed enhancement and why it would be beneficial.
-   Any potential use cases or examples.

### Submitting Pull Requests

If you'd like to contribute code, please follow these steps:

1.  **Fork the repository:** Create your own fork of the [n8n-mcp-server repository](https://github.com/leonardsellem/n8n-mcp-server).
2.  **Create a branch:** Create a new branch in your fork for your changes (e.g., `git checkout -b feature/your-feature-name` or `bugfix/issue-number`).
3.  **Make your changes:** Implement your feature or bug fix.
    *   Ensure your code adheres to the existing coding style. (We use Prettier for formatting, which can be run with `npm run lint`).
    *   Include tests for your changes if applicable. You can run tests using `npm test`.
4.  **Commit your changes:** Write clear and concise commit messages.
5.  **Push to your fork:** Push your changes to your forked repository.
6.  **Open a Pull Request (PR):** Submit a PR to the `main` branch of the official `n8n-mcp-server` repository.
    *   Provide a clear title and description for your PR, explaining the changes you've made and referencing any related issues.

We'll review your PR as soon as possible and provide feedback. Thank you for your contribution!

## License

[MIT](LICENSE)

## 🚀 Join Our Team: Call for Co-Maintainers!

This project is a vibrant, community-driven tool actively used by AI enthusiasts and developers. Currently, it's maintained on a part-time basis by a passionate individual who isn't a seasoned engineer but is dedicated to bridging AI with workflow automation. To help this project flourish, ensure its long-term health, and keep up with its growing user base, we're looking for enthusiastic **co-maintainers** to join the team!

### Why Contribute?

-   **Learn and Grow:** Sharpen your skills in areas like TypeScript, Node.js, API integration, and AI tool development.
-   **Collaborate:** Work alongside other motivated developers and AI users.
-   **Make an Impact:** Directly shape the future of this project and help build a valuable tool for the AI community.
-   **Open Source:** Gain experience contributing to an open-source project.

### How You Can Help

We welcome contributions in many forms! Here are some areas where you could make a big difference:

-   **Bug Fixing:** Help us identify and squash bugs to improve stability.
-   **Feature Development:** Implement new tools and functionalities based on user needs and your ideas.
-   **Documentation:** Improve our guides, examples, and API references to make the project more accessible.
-   **Testing:** Enhance our test suite (unit, integration) to ensure code quality and reliability.
-   **CI/CD:** Help streamline our development and deployment pipelines.
-   **Code Reviews:** Provide feedback on pull requests and help maintain code standards.
-   **Community Support:** Assist users with questions and help manage discussions.

### Get Involved!

If you're excited about the intersection of AI and workflow automation, and you're looking for a rewarding open-source opportunity, we'd love to hear from you!

**Ready to contribute?**

1.  Check out our [GitHub Issues page](https://github.com/leonardsellem/n8n-mcp-server/issues) to find existing tasks, suggest new ideas, or express your interest in becoming a co-maintainer.
2.  You can open an issue titled "Co-maintainer Application" to formally apply, or simply start contributing to existing issues.
3.  Alternatively, feel free to reach out to the existing maintainers if you have questions.

Let’s build the future of AI-powered workflow automation together! 🙌

**Thanks to the community for the support!**
[![Star History Chart](https://api.star-history.com/svg?repos=leonardsellem/n8n-mcp-server&type=Date)](https://www.star-history.com/#leonardsellem/n8n-mcp-server&Date)

```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Status

This appears to be a new/empty repository for an n8n MCP (Model Context Protocol) server project.

## Getting Started

When this project is initialized, common commands to look for:
- `npm install` - Install dependencies
- `npm run build` - Build the project
- `npm run dev` - Run in development mode
- `npm run test` - Run tests
- `npm run lint` - Run linting

## Architecture Notes

This will be populated once the project structure is established. Key areas to document:
- MCP server implementation details
- n8n integration patterns
- Configuration management
- API endpoints and protocols
```

--------------------------------------------------------------------------------
/AGENTS.md:
--------------------------------------------------------------------------------

```markdown
# Guidelines for Coding Agents

These rules apply to all automated contributors working on this project.

## Development
- Use **TypeScript** and ES modules. Source files live under `src/`.
- Place tests in the `tests/` directory mirroring the source structure. Test files must end with `.test.ts`.
- Install dependencies with `npm install` and build with `npm run build` when required.
- Format code using `npm run lint` and ensure all tests pass via `npm test` before committing.
- Do **not** commit files ignored by `.gitignore` (e.g. `node_modules/`, `build/`, `.env`).
- Follow existing patterns when adding new tools or resources as described in `docs/development`.

## Commit Messages
- Use short messages in the form `type: description` (e.g. `feat: add webhook tool`, `fix: handle null id`).

## Pull Requests
- Provide a concise summary of changes and reference related issues when opening a PR.
- CI must pass before requesting review.

## Environment
- Node.js 20 or later is required.

## Continuous Improvement
- After completing a task, review this guide and update it with any lessons
  learned about the codebase, coding principles, or user preferences.

```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
version: 1
start:
  command: ["node", "build/index.js"]
  port: 8000 
```

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

```json
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "types": ["jest", "node"],
    "esModuleInterop": true,
    "rootDir": ".."
  },
  "include": [
    "**/*.ts",
    "**/*.tsx"
  ]
}

```

--------------------------------------------------------------------------------
/babel.config.cjs:
--------------------------------------------------------------------------------

```
module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' }, modules: false }],
    '@babel/preset-typescript',
  ],
  plugins: [
    // No explicit CJS transform plugin
  ]
};
```

--------------------------------------------------------------------------------
/src/errors/error-codes.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Error Codes Module
 * 
 * This module defines error codes used throughout the application.
 * These codes are compatible with the MCP SDK error handling system.
 */

// Numeric error codes for McpError
export enum ErrorCode {
  InitializationError = 1000,
  AuthenticationError = 1001,
  NotFoundError = 1002,
  InvalidRequest = 1003,
  InternalError = 1004,
  NotImplemented = 1005,
}

```

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

```json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "strict": true,
    "outDir": "build",
    "declaration": true,
    "sourceMap": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "rootDir": "src",
    "lib": [
      "ES2020",
      "DOM"
    ],
    "types": [
      "node"
    ]
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "build",
    "**/*.test.ts"
  ]
}

```

--------------------------------------------------------------------------------
/tests/test-setup.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Global test setup for n8n MCP Server tests
 */
import { beforeEach, afterEach, jest } from '@jest/globals';

// Reset environment variables before each test
beforeEach(() => {
  process.env = { 
    ...process.env,
    NODE_ENV: 'test' 
  };
});

// Clean up after each test
afterEach(() => {
  jest.resetAllMocks();
  jest.clearAllMocks();
});

export const mockEnv = (envVars: Record<string, string>) => {
  const originalEnv = process.env;
  
  beforeEach(() => {
    process.env = { 
      ...originalEnv,
      ...envVars 
    };
  });
  
  afterEach(() => {
    process.env = originalEnv;
  });
};

```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
astroid==3.3.8
certifi==2025.1.31
charset-normalizer==3.4.1
colorama==0.4.6
dill==0.3.9
filelock==3.17.0
fsspec==2025.2.0
huggingface-hub==0.29.2
idna==3.10
isort==6.0.1
Jinja2==3.1.6
joblib==1.4.2
MarkupSafe==3.0.2
mccabe==0.7.0
mpmath==1.3.0
networkx==3.4.2
numpy==2.2.3
packaging==24.2
pillow==11.1.0
platformdirs==4.3.6
pylint==3.3.4
PyYAML==6.0.2
regex==2024.11.6
requests==2.32.3
safetensors==0.5.3
scikit-learn==1.6.1
scipy==1.15.2
sentence-transformers==3.4.1
setuptools==75.8.2
sympy==1.13.1
threadpoolctl==3.5.0
tokenizers==0.21.0
tomlkit==0.13.2
torch==2.6.0
tqdm==4.67.1
transformers==4.49.0
typing_extensions==4.12.2
urllib3==2.3.0

```

--------------------------------------------------------------------------------
/docs/setup/index.md:
--------------------------------------------------------------------------------

```markdown
# Setup and Configuration

This section covers everything you need to know to set up and configure the n8n MCP Server.

## Topics

- [Installation](./installation.md): Instructions for installing the n8n MCP Server from npm or from source.
- [Configuration](./configuration.md): Information on configuring the server, including environment variables and n8n API setup.
- [Troubleshooting](./troubleshooting.md): Solutions to common issues you might encounter.

## Quick Start

For a quick start, follow these steps:

1. Install the server: `npm install -g @leonardsellem/n8n-mcp-server`
2. Create a `.env` file with your n8n API URL and API key
3. Run the server: `n8n-mcp-server`
4. Register the server with your AI assistant platform

```

--------------------------------------------------------------------------------
/tests/unit/utils/resource-formatter.test.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Resource formatter utility tests
 */

import { describe, it, expect } from '@jest/globals';
import { formatResourceUri } from '../../../src/utils/resource-formatter.js';

describe('formatResourceUri', () => {
  it('appends "s" for singular resource types', () => {
    expect(formatResourceUri('workflow', '1')).toBe('n8n://workflows/1');
    expect(formatResourceUri('execution', '2')).toBe('n8n://executions/2');
  });

  it('does not append "s" for already plural resource types', () => {
    expect(formatResourceUri('workflows', '3')).toBe('n8n://workflows/3');
    expect(formatResourceUri('execution-stats', '4')).toBe('n8n://execution-stats/4');
  });

  it('returns URI without id when none is provided', () => {
    expect(formatResourceUri('workflow')).toBe('n8n://workflow');
    expect(formatResourceUri('workflows')).toBe('n8n://workflows');
  });
});

```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
# Stage 1: Build the application
FROM node:20 AS builder

WORKDIR /app

# 1️⃣  Copy only dependency manifests first (keeps layer cache efficient)
COPY package*.json ./

# 2️⃣  Install deps *without* running any scripts ➜ skips the automatic `prepare`
RUN npm ci --ignore-scripts            # dev + prod deps, no build yet

# 3️⃣  Now bring in the full source tree (tsconfig.json, src/, …)
COPY . .

# 4️⃣  Build explicitly – everything is present now
RUN npm run build

# 5️⃣  Strip dev-dependencies; keeps runtime small
RUN npm prune --omit=dev

# Stage 2: Create the production image
FROM node:20-slim

WORKDIR /app

# 6️⃣  Copy ready-to-run artefacts from builder
COPY --from=builder /app/build ./build
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./

# Set executable permissions for the binary
RUN chmod +x build/index.js

# Expose the port the app runs on
EXPOSE 8000

# Set the entrypoint to run the MCP server
CMD ["node", "build/index.js"]

```

--------------------------------------------------------------------------------
/src/tools/execution/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Execution Tools Module
 * 
 * This module provides MCP tools for interacting with n8n workflow executions.
 */

import { ToolDefinition } from '../../types/index.js';
import { getListExecutionsToolDefinition } from './list.js';
import { getGetExecutionToolDefinition } from './get.js';
import { getDeleteExecutionToolDefinition } from './delete.js';
import { getRunWebhookToolDefinition } from './run.js';

/**
 * Set up execution management tools
 * 
 * @returns Array of execution tool definitions
 */
export async function setupExecutionTools(): Promise<ToolDefinition[]> {
  return [
    getListExecutionsToolDefinition(),
    getGetExecutionToolDefinition(),
    getDeleteExecutionToolDefinition(),
    getRunWebhookToolDefinition()
  ];
}

// Export execution tool handlers for use in the handler
export { ListExecutionsHandler } from './list.js';
export { GetExecutionHandler } from './get.js';
export { DeleteExecutionHandler } from './delete.js';
export { RunWebhookHandler } from './run.js';

```

--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Core Types Module
 * 
 * This module provides type definitions used throughout the application
 * and bridges compatibility with the MCP SDK.
 */

// Tool definition for MCP tools
export interface ToolDefinition {
  name: string;
  description: string;
  inputSchema: {
    type: string;
    properties: Record<string, any>;
    required?: string[];
  };
}

// Tool call result for MCP tool responses
export interface ToolCallResult {
  content: Array<{
    type: string;
    text: string;
  }>;
  isError?: boolean;
}

// Type for n8n workflow object
export interface Workflow {
  id: string;
  name: string;
  active: boolean;
  nodes: any[];
  connections: any;
  createdAt: string;
  updatedAt: string;
  [key: string]: any;
}

// Type for n8n execution object
export interface Execution {
  id: string;
  workflowId: string;
  finished: boolean;
  mode: string;
  startedAt: string;
  stoppedAt: string;
  status: string;
  data: {
    resultData: {
      runData: any;
    };
  };
  [key: string]: any;
}

```

--------------------------------------------------------------------------------
/docs/examples/index.md:
--------------------------------------------------------------------------------

```markdown
# Usage Examples

This section provides practical examples of using the n8n MCP Server with AI assistants.

## Overview

The examples in this section demonstrate how AI assistants can interact with n8n workflows through the MCP server. They range from basic operations to complex integration scenarios.

## Examples Categories

- [Basic Examples](./basic-examples.md): Simple examples covering fundamental operations like listing workflows, retrieving workflow details, and executing workflows.
- [Advanced Scenarios](./advanced-scenarios.md): More complex examples showing how to chain operations, handle errors, and implement common workflow patterns.
- [Integration Examples](./integration-examples.md): Examples of integrating the n8n MCP Server with different AI assistant platforms and other tools.

## How to Use These Examples

The examples in this section show both:

1. **User Prompts**: What a user might ask an AI assistant to do
2. **Assistant Actions**: How the assistant would use the MCP tools and resources to accomplish the task

You can use these examples as inspiration for your own interactions with the n8n MCP Server or as templates for building more complex workflows.

```

--------------------------------------------------------------------------------
/run-tests.js:
--------------------------------------------------------------------------------

```javascript
/**
 * Test Runner Script
 * 
 * This script provides a more reliable way to run Jest tests with proper
 * ESM support and error handling.
 */

import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import { dirname, resolve } from 'path';

// Get the directory of the current module
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Set NODE_OPTIONS to ensure proper ESM support
process.env.NODE_OPTIONS = '--experimental-vm-modules';

console.log('🧪 Running tests for n8n MCP Server...');

// Get command line arguments to pass to Jest
const args = process.argv.slice(2);
const jestArgs = ['--config', './jest.config.cjs', ...args];

// Spawn Jest process
const jestProcess = spawn('node_modules/.bin/jest', jestArgs, {
  stdio: 'inherit',
  cwd: __dirname,
  env: { ...process.env, NODE_ENV: 'test' }
});

// Handle process events
jestProcess.on('error', (error) => {
  console.error('Error running tests:', error);
  process.exit(1);
});

jestProcess.on('close', (code) => {
  if (code !== 0) {
    console.error(`Test process exited with code ${code}`);
    process.exit(code);
  }
  console.log('✅ Tests completed successfully');
});

```

--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------

```markdown
# n8n MCP Server Documentation

Welcome to the n8n MCP Server documentation. This documentation provides comprehensive information about setting up, configuring, and using the n8n MCP Server.

## Table of Contents

- [Setup and Configuration](./setup/index.md)
  - [Installation](./setup/installation.md)
  - [Configuration](./setup/configuration.md)
  - [Troubleshooting](./setup/troubleshooting.md)

- [API Reference](./api/index.md)
  - [Tools](./api/tools.md)
    - [Workflow Tools](./api/workflow-tools.md)
    - [Execution Tools](./api/execution-tools.md)
  - [Resources](./api/resources.md)
    - [Static Resources](./api/static-resources.md)
    - [Dynamic Resources](./api/dynamic-resources.md)

- [Usage Examples](./examples/index.md)
  - [Basic Examples](./examples/basic-examples.md)
  - [Advanced Scenarios](./examples/advanced-scenarios.md)
  - [Integration Examples](./examples/integration-examples.md)

- [Development](./development/index.md)
  - [Architecture](./development/architecture.md)
  - [Extending the Server](./development/extending.md)
  - [Testing](./development/testing.md)

## Quick Links

- [GitHub Repository](https://github.com/yourusername/n8n-mcp-server)
- [n8n Documentation](https://docs.n8n.io/)
- [Model Context Protocol Documentation](https://modelcontextprotocol.github.io/)

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node
/**
 * n8n MCP Server - Main Entry Point
 * 
 * This file serves as the entry point for the n8n MCP Server,
 * which allows AI assistants to interact with n8n workflows through the MCP protocol.
 */

import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { loadEnvironmentVariables } from './config/environment.js';
import { configureServer } from './config/server.js';

// Load environment variables
loadEnvironmentVariables();

/**
 * Main function to start the n8n MCP Server
 */
async function main() {
  try {
    console.error('Starting n8n MCP Server...');

    // Create and configure the MCP server
    const server = await configureServer();

    // Set up error handling
    server.onerror = (error: unknown) => console.error('[MCP Error]', error);

    // Set up clean shutdown
    process.on('SIGINT', async () => {
      console.error('Shutting down n8n MCP Server...');
      await server.close();
      process.exit(0);
    });

    // Connect to the server transport (stdio)
    const transport = new StdioServerTransport();
    await server.connect(transport);

    console.error('n8n MCP Server running on stdio');
  } catch (error) {
    console.error('Failed to start n8n MCP Server:', error);
    process.exit(1);
  }
}

// Start the server
main().catch(console.error);

```

--------------------------------------------------------------------------------
/tests/unit/resources/dynamic/workflow.test.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Simple test for URI Template functionality
 */

import { describe, it, expect } from '@jest/globals';

// Simple functions to test without complex imports
function getWorkflowResourceTemplateUri() {
  return 'n8n://workflows/{id}';
}

function extractWorkflowIdFromUri(uri: string): string | null {
  const regex = /^n8n:\/\/workflows\/([^/]+)$/;
  const match = uri.match(regex);
  return match ? match[1] : null;
}

describe('Workflow Resource URI Functions', () => {
  describe('getWorkflowResourceTemplateUri', () => {
    it('should return the correct URI template', () => {
      expect(getWorkflowResourceTemplateUri()).toBe('n8n://workflows/{id}');
    });
  });
  
  describe('extractWorkflowIdFromUri', () => {
    it('should extract workflow ID from valid URI', () => {
      expect(extractWorkflowIdFromUri('n8n://workflows/123abc')).toBe('123abc');
      expect(extractWorkflowIdFromUri('n8n://workflows/workflow-name-with-dashes')).toBe('workflow-name-with-dashes');
    });
    
    it('should return null for invalid URI formats', () => {
      expect(extractWorkflowIdFromUri('n8n://workflows/')).toBeNull();
      expect(extractWorkflowIdFromUri('n8n://workflows')).toBeNull();
      expect(extractWorkflowIdFromUri('n8n://workflow/123')).toBeNull();
      expect(extractWorkflowIdFromUri('invalid://workflows/123')).toBeNull();
    });
  });
});

```

--------------------------------------------------------------------------------
/.github/workflows/release-package.yml:
--------------------------------------------------------------------------------

```yaml
name: Node.js Package

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build-and-publish:
    runs-on: ubuntu-latest
    permissions:
      contents: write # Allow workflow to push to the repository
    steps:
      - uses: actions/checkout@v4
        with:
          token: ${{ github.token }} # Uses the default GITHUB_TOKEN
      - uses: actions/setup-node@v4
        with:
          node-version: '20' # Specify your desired Node.js version
          registry-url: 'https://registry.npmjs.org' # Point to npmjs.com
      - run: npm ci
      - run: npm run build # Add your build script here if you have one, otherwise remove this line
      - name: Bump version, commit, and push
        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
        run: |
          git config --global user.name 'github-actions[bot]'
          git config --global user.email 'github-actions[bot]@users.noreply.github.com'
          npm version patch -m "chore: release %s"
          git push
          git push --tags
        env:
          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} # NPM_TOKEN might be needed for npm version if it interacts with registry
      - name: Publish to npmjs.com
        if: github.event_name == 'push' && github.ref == 'refs/heads/main'
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} # Use the NPM_TOKEN secret

```

--------------------------------------------------------------------------------
/src/tools/workflow/get.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Get Workflow Tool
 * 
 * This tool retrieves a specific workflow from n8n by ID.
 */

import { BaseWorkflowToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';

/**
 * Handler for the get_workflow tool
 */
export class GetWorkflowHandler extends BaseWorkflowToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments containing workflowId
   * @returns Workflow details
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async (args) => {
      const { workflowId } = args;
      
      if (!workflowId) {
        throw new N8nApiError('Missing required parameter: workflowId');
      }
      
      const workflow = await this.apiService.getWorkflow(workflowId);
      
      return this.formatSuccess(workflow, `Retrieved workflow: ${workflow.name}`);
    }, args);
  }
}

/**
 * Get tool definition for the get_workflow tool
 * 
 * @returns Tool definition
 */
export function getGetWorkflowToolDefinition(): ToolDefinition {
  return {
    name: 'get_workflow',
    description: 'Retrieve a specific workflow by ID',
    inputSchema: {
      type: 'object',
      properties: {
        workflowId: {
          type: 'string',
          description: 'ID of the workflow to retrieve',
        },
      },
      required: ['workflowId'],
    },
  };
}

```

--------------------------------------------------------------------------------
/src/tools/workflow/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Workflow Tools Module
 * 
 * This module provides MCP tools for interacting with n8n workflows.
 */

import { ToolDefinition } from '../../types/index.js';

// Import tool definitions
import { getListWorkflowsToolDefinition, ListWorkflowsHandler } from './list.js';
import { getGetWorkflowToolDefinition, GetWorkflowHandler } from './get.js';
import { getCreateWorkflowToolDefinition, CreateWorkflowHandler } from './create.js';
import { getUpdateWorkflowToolDefinition, UpdateWorkflowHandler } from './update.js';
import { getDeleteWorkflowToolDefinition, DeleteWorkflowHandler } from './delete.js';
import { getActivateWorkflowToolDefinition, ActivateWorkflowHandler } from './activate.js';
import { getDeactivateWorkflowToolDefinition, DeactivateWorkflowHandler } from './deactivate.js';

// Export handlers
export {
  ListWorkflowsHandler,
  GetWorkflowHandler,
  CreateWorkflowHandler,
  UpdateWorkflowHandler,
  DeleteWorkflowHandler,
  ActivateWorkflowHandler,
  DeactivateWorkflowHandler,
};

/**
 * Set up workflow management tools
 * 
 * @returns Array of workflow tool definitions
 */
export async function setupWorkflowTools(): Promise<ToolDefinition[]> {
  return [
    getListWorkflowsToolDefinition(),
    getGetWorkflowToolDefinition(),
    getCreateWorkflowToolDefinition(),
    getUpdateWorkflowToolDefinition(),
    getDeleteWorkflowToolDefinition(),
    getActivateWorkflowToolDefinition(),
    getDeactivateWorkflowToolDefinition(),
  ];
}

```

--------------------------------------------------------------------------------
/tests/unit/api/simple-client.test.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Simple HTTP client tests without complex dependencies
 */

import { describe, it, expect } from '@jest/globals';

// Create a simple HTTP client class to test
class SimpleHttpClient {
  constructor(private baseUrl: string, private apiKey: string) {}
  
  getBaseUrl(): string {
    return this.baseUrl;
  }
  
  getApiKey(): string {
    return this.apiKey;
  }
  
  buildAuthHeader(): Record<string, string> {
    return {
      'X-N8N-API-KEY': this.apiKey
    };
  }
  
  formatUrl(path: string): string {
    return `${this.baseUrl}${path.startsWith('/') ? path : '/' + path}`;
  }
}

describe('SimpleHttpClient', () => {
  it('should store baseUrl and apiKey properly', () => {
    const baseUrl = 'https://n8n.example.com/api/v1';
    const apiKey = 'test-api-key';
    const client = new SimpleHttpClient(baseUrl, apiKey);
    
    expect(client.getBaseUrl()).toBe(baseUrl);
    expect(client.getApiKey()).toBe(apiKey);
  });
  
  it('should create proper auth headers', () => {
    const client = new SimpleHttpClient('https://n8n.example.com/api/v1', 'test-api-key');
    const headers = client.buildAuthHeader();
    
    expect(headers).toEqual({ 'X-N8N-API-KEY': 'test-api-key' });
  });
  
  it('should format URLs correctly', () => {
    const baseUrl = 'https://n8n.example.com/api/v1';
    const client = new SimpleHttpClient(baseUrl, 'test-api-key');
    
    expect(client.formatUrl('workflows')).toBe(`${baseUrl}/workflows`);
    expect(client.formatUrl('/workflows')).toBe(`${baseUrl}/workflows`);
  });
});

```

--------------------------------------------------------------------------------
/src/tools/workflow/list.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * List Workflows Tool
 * 
 * This tool retrieves a list of workflows from n8n.
 */

import { BaseWorkflowToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition, Workflow } from '../../types/index.js';

/**
 * Handler for the list_workflows tool
 */
export class ListWorkflowsHandler extends BaseWorkflowToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments
   * @returns List of workflows
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async () => {
      const workflows = await this.apiService.getWorkflows();
      
      // Format the workflows for display
      const formattedWorkflows = workflows.map((workflow: Workflow) => ({
        id: workflow.id,
        name: workflow.name,
        active: workflow.active,
        updatedAt: workflow.updatedAt,
      }));
      
      return this.formatSuccess(
        formattedWorkflows,
        `Found ${formattedWorkflows.length} workflow(s)`
      );
    }, args);
  }
}

/**
 * Get tool definition for the list_workflows tool
 * 
 * @returns Tool definition
 */
export function getListWorkflowsToolDefinition(): ToolDefinition {
  return {
    name: 'list_workflows',
    description: 'Retrieve a list of all workflows available in n8n',
    inputSchema: {
      type: 'object',
      properties: {
        active: {
          type: 'boolean',
          description: 'Optional filter to show only active or inactive workflows',
        },
      },
      required: [],
    },
  };
}

```

--------------------------------------------------------------------------------
/jest.config.cjs:
--------------------------------------------------------------------------------

```
module.exports = {
  // Use commonjs style export
  preset: 'ts-jest/presets/default-esm', // Using ESM preset for ts-jest
  testEnvironment: 'node',
  // transform: { // Removed to let ts-jest handle transformation via preset
  //   '^.+\\.tsx?$': 'babel-jest',
  // },
  // globals: { // Deprecated way to configure ts-jest
  //   'ts-jest': {
  //     useESM: true,
  //   }
  // },
  transform: {
    '^.+\\.tsx?$': ['ts-jest', {
      useESM: true,
      tsconfig: 'tests/tsconfig.json', // Point to the tsconfig in the tests directory
      // babelConfig: true, // If babel.config.cjs is still needed for some features not in ts-jest
    }],
  },
  // Allow src and test folders to resolve imports properly
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
    // For ESM, Jest might need help resolving module paths if they are not fully specified
    // or if there are conditions in package.json exports.
    // Example: '(@modelcontextprotocol/sdk)(.*)': '<rootDir>/node_modules/$1/dist$2.js'
    // This line below is a guess, might need adjustment or might not be needed.
    // '^(@modelcontextprotocol/sdk/.*)\\.js$': '<rootDir>/node_modules/$1.js',
  },
  // Handle the modelcontextprotocol SDK
  // Default is /node_modules/, so we want to NOT transform anything in node_modules
  transformIgnorePatterns: [
    "node_modules/"
  ],
  collectCoverage: true,
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov'],
  testMatch: ['**/tests/**/*.test.ts'],
  verbose: true,
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  setupFilesAfterEnv: ['<rootDir>/tests/test-setup.ts']
};

```

--------------------------------------------------------------------------------
/src/tools/workflow/activate.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Activate Workflow Tool
 * 
 * This tool activates an existing workflow in n8n.
 */

import { BaseWorkflowToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';

/**
 * Handler for the activate_workflow tool
 */
export class ActivateWorkflowHandler extends BaseWorkflowToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments containing workflowId
   * @returns Activation confirmation
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async (args) => {
      const { workflowId } = args;
      
      if (!workflowId) {
        throw new N8nApiError('Missing required parameter: workflowId');
      }
      
      // Activate the workflow
      const workflow = await this.apiService.activateWorkflow(workflowId);
      
      return this.formatSuccess(
        {
          id: workflow.id,
          name: workflow.name,
          active: workflow.active
        },
        `Workflow "${workflow.name}" (ID: ${workflowId}) has been successfully activated`
      );
    }, args);
  }
}

/**
 * Get tool definition for the activate_workflow tool
 * 
 * @returns Tool definition
 */
export function getActivateWorkflowToolDefinition(): ToolDefinition {
  return {
    name: 'activate_workflow',
    description: 'Activate a workflow in n8n',
    inputSchema: {
      type: 'object',
      properties: {
        workflowId: {
          type: 'string',
          description: 'ID of the workflow to activate',
        },
      },
      required: ['workflowId'],
    },
  };
}

```

--------------------------------------------------------------------------------
/src/tools/execution/handler.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Execution Tools Handler
 * 
 * This module handles calls to execution-related tools.
 */

import { ToolCallResult } from '../../types/index.js';
import { McpError } from '@modelcontextprotocol/sdk/types.js';
import { ErrorCode } from '../../errors/error-codes.js';
import { getErrorMessage } from '../../errors/index.js';
import { 
  ListExecutionsHandler, 
  GetExecutionHandler,
  DeleteExecutionHandler,
  RunWebhookHandler
} from './index.js';

/**
 * Handle execution tool calls
 * 
 * @param toolName Name of the tool being called
 * @param args Arguments passed to the tool
 * @returns Tool call result
 */
export default async function executionHandler(
  toolName: string,
  args: Record<string, any>
): Promise<ToolCallResult> {
  try {
    // Route to the appropriate handler based on tool name
    switch (toolName) {
      case 'list_executions':
        return await new ListExecutionsHandler().execute(args);
        
      case 'get_execution':
        return await new GetExecutionHandler().execute(args);
        
      case 'delete_execution':
        return await new DeleteExecutionHandler().execute(args);
        
      case 'run_webhook':
        return await new RunWebhookHandler().execute(args);
        
      default:
        throw new McpError(
          ErrorCode.NotImplemented,
          `Unknown execution tool: '${toolName}'`
        );
    }
  } catch (error) {
    // Get appropriate error message
    const errorMessage = getErrorMessage(error);
    
    return {
      content: [
        {
          type: 'text',
          text: `Error executing execution tool: ${errorMessage}`,
        },
      ],
      isError: true,
    };
  }
}

```

--------------------------------------------------------------------------------
/src/tools/workflow/deactivate.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Deactivate Workflow Tool
 * 
 * This tool deactivates an existing workflow in n8n.
 */

import { BaseWorkflowToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';

/**
 * Handler for the deactivate_workflow tool
 */
export class DeactivateWorkflowHandler extends BaseWorkflowToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments containing workflowId
   * @returns Deactivation confirmation
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async (args) => {
      const { workflowId } = args;
      
      if (!workflowId) {
        throw new N8nApiError('Missing required parameter: workflowId');
      }
      
      // Deactivate the workflow
      const workflow = await this.apiService.deactivateWorkflow(workflowId);
      
      return this.formatSuccess(
        {
          id: workflow.id,
          name: workflow.name,
          active: workflow.active
        },
        `Workflow "${workflow.name}" (ID: ${workflowId}) has been successfully deactivated`
      );
    }, args);
  }
}

/**
 * Get tool definition for the deactivate_workflow tool
 * 
 * @returns Tool definition
 */
export function getDeactivateWorkflowToolDefinition(): ToolDefinition {
  return {
    name: 'deactivate_workflow',
    description: 'Deactivate a workflow in n8n',
    inputSchema: {
      type: 'object',
      properties: {
        workflowId: {
          type: 'string',
          description: 'ID of the workflow to deactivate',
        },
      },
      required: ['workflowId'],
    },
  };
}

```

--------------------------------------------------------------------------------
/src/tools/workflow/delete.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Delete Workflow Tool
 * 
 * This tool deletes an existing workflow from n8n.
 */

import { BaseWorkflowToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';

/**
 * Handler for the delete_workflow tool
 */
export class DeleteWorkflowHandler extends BaseWorkflowToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments containing workflowId
   * @returns Deletion confirmation
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async (args) => {
      const { workflowId } = args;
      
      if (!workflowId) {
        throw new N8nApiError('Missing required parameter: workflowId');
      }
      
      // Get the workflow info first for the confirmation message
      const workflow = await this.apiService.getWorkflow(workflowId);
      const workflowName = workflow.name;
      
      // Delete the workflow
      await this.apiService.deleteWorkflow(workflowId);
      
      return this.formatSuccess(
        { id: workflowId },
        `Workflow "${workflowName}" (ID: ${workflowId}) has been successfully deleted`
      );
    }, args);
  }
}

/**
 * Get tool definition for the delete_workflow tool
 * 
 * @returns Tool definition
 */
export function getDeleteWorkflowToolDefinition(): ToolDefinition {
  return {
    name: 'delete_workflow',
    description: 'Delete a workflow from n8n',
    inputSchema: {
      type: 'object',
      properties: {
        workflowId: {
          type: 'string',
          description: 'ID of the workflow to delete',
        },
      },
      required: ['workflowId'],
    },
  };
}

```

--------------------------------------------------------------------------------
/docs/setup/installation.md:
--------------------------------------------------------------------------------

```markdown
# Installation Guide

This guide covers the installation process for the n8n MCP Server.

## Prerequisites

- Before installing the n8n MCP Server, ensure you have:

- Node.js 20 or later installed
- An n8n instance running and accessible via HTTP/HTTPS
- API access enabled on your n8n instance
- An API key with appropriate permissions (see [Configuration](./configuration.md))

## Option 1: Install from npm (Recommended)

The easiest way to install the n8n MCP Server is from npm:

```bash
npm install -g n8n-mcp-server
```

This will install the server globally, making the `n8n-mcp-server` command available in your terminal.

## Option 2: Install from Source

For development purposes or to use the latest features, you can install from source:

```bash
# Clone the repository
git clone https://github.com/yourusername/n8n-mcp-server.git
cd n8n-mcp-server

# Install dependencies
npm install

# Build the project
npm run build

# Optional: Install globally
npm install -g .
```

## Verifying Installation

Once installed, you can verify the installation by running:

```bash
n8n-mcp-server --version
```

This should display the version number of the installed n8n MCP Server.

## Next Steps

After installation, you'll need to:

1. [Configure the server](./configuration.md) by setting up environment variables
2. Run the server
3. Register the server with your AI assistant platform

## Upgrading

To upgrade a global installation from npm:

```bash
npm update -g n8n-mcp-server
```

To upgrade a source installation:

```bash
# Navigate to the repository directory
cd n8n-mcp-server

# Pull the latest changes
git pull

# Install dependencies and rebuild
npm install
npm run build

# If installed globally, reinstall
npm install -g .

```

--------------------------------------------------------------------------------
/.github/workflows/docker-publish.yml:
--------------------------------------------------------------------------------

```yaml
name: Build & Publish Docker image

# ➊ Triggers – push to main OR new GitHub Release
on:
  push:
    branches: [main]
  release:
    types: [published]

jobs:
  build-and-push:
    runs-on: ubuntu-latest

    # ➋ The job needs these repo secrets (add in Settings ▸ Secrets ▸ Actions):
    #    DOCKERHUB_USERNAME  – e.g. 'leonardsellem'
    #    DOCKERHUB_TOKEN     – a Docker Hub access token / password
    env:
      IMAGE_NAME: ${{ secrets.DOCKERHUB_USERNAME }}/n8n-mcp-server

    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      # ➌ Enable multi-arch builds (amd64 + arm64)
      - uses: docker/setup-qemu-action@v3
      - uses: docker/setup-buildx-action@v3

      # ➍ Log in to Docker Hub
      - uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      # ➎ Generate convenient tags & labels (latest, sha-short, release tag …)
      - id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.IMAGE_NAME }}
          tags: |
            type=sha,format=short
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=raw,value=latest,enable={{is_default_branch}}

      # ➏ Build & push
      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          platforms: linux/amd64,linux/arm64
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          # optional build-cache (makes repeated builds faster)
          cache-from: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache
          cache-to: type=registry,ref=${{ env.IMAGE_NAME }}:buildcache,mode=max
```

--------------------------------------------------------------------------------
/src/tools/execution/delete.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Delete Execution Tool
 * 
 * This tool deletes a specific workflow execution from n8n.
 */

import { BaseExecutionToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { McpError } from '@modelcontextprotocol/sdk/types.js';
import { ErrorCode } from '../../errors/error-codes.js';

/**
 * Handler for the delete_execution tool
 */
export class DeleteExecutionHandler extends BaseExecutionToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments (executionId)
   * @returns Result of the deletion operation
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async () => {
      // Validate required parameters
      if (!args.executionId) {
        throw new McpError(
          ErrorCode.InvalidRequest,
          'Missing required parameter: executionId'
        );
      }
      
      // Store execution ID for response message
      const executionId = args.executionId;
      
      // Delete the execution
      await this.apiService.deleteExecution(executionId);
      
      return this.formatSuccess(
        { id: executionId, deleted: true },
        `Successfully deleted execution with ID: ${executionId}`
      );
    }, args);
  }
}

/**
 * Get tool definition for the delete_execution tool
 * 
 * @returns Tool definition
 */
export function getDeleteExecutionToolDefinition(): ToolDefinition {
  return {
    name: 'delete_execution',
    description: 'Delete a specific workflow execution from n8n',
    inputSchema: {
      type: 'object',
      properties: {
        executionId: {
          type: 'string',
          description: 'ID of the execution to delete',
        },
      },
      required: ['executionId'],
    },
  };
}

```

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

```json
{
  "name": "@leonardsellem/n8n-mcp-server",
  "version": "0.1.8",
  "description": "Model Context Protocol (MCP) server for n8n workflow automation",
  "main": "build/index.js",
  "type": "module",
  "scripts": {
    "build": "tsc && chmod +x build/index.js",
    "start": "node build/index.js",
    "dev": "tsc -w",
    "lint": "eslint --ext .ts src/",
    "test": "node --experimental-vm-modules run-tests.js",
    "test:watch": "node --experimental-vm-modules run-tests.js --watch",
    "test:coverage": "node --experimental-vm-modules run-tests.js --coverage",
    "prepare": "npm run build"
  },
  "bin": {
    "n8n-mcp-server": "build/index.js"
  },
  "keywords": [
    "mcp",
    "n8n",
    "workflow",
    "automation",
    "ai"
  ],
  "author": "Leonard Sellem (https://sellem.me)",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/leonardsellem/n8n-mcp-server.git"
  },
  "bugs": {
    "url": "https://github.com/leonardsellem/n8n-mcp-server/issues"
  },
  "homepage": "https://github.com/leonardsellem/n8n-mcp-server#readme",
  "files": [
    "build",
    "README.md",
    "LICENSE",
    "package.json"
  ],
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.7.0",
    "axios": "^1.6.2",
    "dotenv": "^16.3.1",
    "find-config": "^1.0.0"
  },
  "devDependencies": {
    "@babel/core": "^7.26.10",
    "@babel/plugin-transform-modules-commonjs": "^7.26.3",
    "@babel/preset-env": "^7.26.9",
    "@babel/preset-typescript": "^7.26.0",
    "@types/find-config": "^1.0.4",
    "@types/jest": "^29.5.14",
    "@types/node": "^20.10.0",
    "@typescript-eslint/eslint-plugin": "^6.13.1",
    "@typescript-eslint/parser": "^6.13.1",
    "babel-jest": "^29.7.0",
    "eslint": "^8.54.0",
    "jest": "^29.7.0",
    "ts-jest": "^29.1.1",
    "typescript": "^5.3.2"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}

```

--------------------------------------------------------------------------------
/src/tools/execution/get.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Get Execution Tool
 * 
 * This tool retrieves detailed information about a specific workflow execution.
 */

import { BaseExecutionToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { McpError } from '@modelcontextprotocol/sdk/types.js';
import { ErrorCode } from '../../errors/error-codes.js';
import { formatExecutionDetails } from '../../utils/execution-formatter.js';

/**
 * Handler for the get_execution tool
 */
export class GetExecutionHandler extends BaseExecutionToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments (executionId)
   * @returns Execution details
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async () => {
      // Validate required parameters
      if (!args.executionId) {
        throw new McpError(
          ErrorCode.InvalidRequest,
          'Missing required parameter: executionId'
        );
      }
      
      // Get execution details
      const execution = await this.apiService.getExecution(args.executionId);
      
      // Format the execution for display
      const formattedExecution = formatExecutionDetails(execution);
      
      return this.formatSuccess(
        formattedExecution,
        `Execution Details for ID: ${args.executionId}`
      );
    }, args);
  }
  
}

/**
 * Get tool definition for the get_execution tool
 * 
 * @returns Tool definition
 */
export function getGetExecutionToolDefinition(): ToolDefinition {
  return {
    name: 'get_execution',
    description: 'Retrieve detailed information about a specific workflow execution',
    inputSchema: {
      type: 'object',
      properties: {
        executionId: {
          type: 'string',
          description: 'ID of the execution to retrieve',
        },
      },
      required: ['executionId'],
    },
  };
}

```

--------------------------------------------------------------------------------
/src/resources/static/execution-stats.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Static Execution Statistics Resource Handler
 * 
 * This module provides the MCP resource implementation for execution statistics.
 */

import { N8nApiService } from '../../api/n8n-client.js';
import { formatExecutionStats, formatResourceUri } from '../../utils/resource-formatter.js';
import { McpError, ErrorCode } from '../../errors/index.js';

/**
 * Get execution statistics resource data
 * 
 * @param apiService n8n API service
 * @returns Formatted execution statistics resource data
 */
export async function getExecutionStatsResource(apiService: N8nApiService): Promise<string> {
  try {
    // Get executions from the API
    const executions = await apiService.getExecutions();
    
    // Format the execution statistics
    const stats = formatExecutionStats(executions);
    
    // Add metadata about the resource
    const result = {
      resourceType: 'execution-stats',
      ...stats,
      _links: {
        self: formatResourceUri('execution-stats'),
      }
    };
    
    return JSON.stringify(result, null, 2);
  } catch (error) {
    console.error('Error fetching execution statistics resource:', error);
    throw new McpError(
      ErrorCode.InternalError, 
      `Failed to retrieve execution statistics: ${error instanceof Error ? error.message : 'Unknown error'}`
    );
  }
}

/**
 * Get execution statistics resource URI
 * 
 * @returns Formatted resource URI
 */
export function getExecutionStatsResourceUri(): string {
  return formatResourceUri('execution-stats');
}

/**
 * Get execution statistics resource metadata
 * 
 * @returns Resource metadata object
 */
export function getExecutionStatsResourceMetadata(): Record<string, any> {
  return {
    uri: getExecutionStatsResourceUri(),
    name: 'n8n Execution Statistics',
    mimeType: 'application/json',
    description: 'Summary statistics of workflow executions including success rates, average duration, and trends',
  };
}

```

--------------------------------------------------------------------------------
/src/resources/static/workflows.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Static Workflows Resource Handler
 * 
 * This module provides the MCP resource implementation for listing all workflows.
 */

import { N8nApiService } from '../../api/n8n-client.js';
import { formatWorkflowSummary, formatResourceUri } from '../../utils/resource-formatter.js';
import { McpError, ErrorCode } from '../../errors/index.js';

/**
 * Get workflows resource data
 * 
 * @param apiService n8n API service
 * @returns Formatted workflows resource data
 */
export async function getWorkflowsResource(apiService: N8nApiService): Promise<string> {
  try {
    // Get all workflows from the API
    const workflows = await apiService.getWorkflows();
    
    // Format the workflows for resource consumption
    const formattedWorkflows = workflows.map(workflow => formatWorkflowSummary(workflow));
    
    // Add metadata about the resource
    const result = {
      resourceType: 'workflows',
      count: formattedWorkflows.length,
      workflows: formattedWorkflows,
      _links: {
        self: formatResourceUri('workflows'),
      },
      lastUpdated: new Date().toISOString(),
    };
    
    return JSON.stringify(result, null, 2);
  } catch (error) {
    console.error('Error fetching workflows resource:', error);
    throw new McpError(
      ErrorCode.InternalError, 
      `Failed to retrieve workflows: ${error instanceof Error ? error.message : 'Unknown error'}`
    );
  }
}

/**
 * Get workflows resource URI
 * 
 * @returns Formatted resource URI
 */
export function getWorkflowsResourceUri(): string {
  return formatResourceUri('workflows');
}

/**
 * Get workflows resource metadata
 * 
 * @returns Resource metadata object
 */
export function getWorkflowsResourceMetadata(): Record<string, any> {
  return {
    uri: getWorkflowsResourceUri(),
    name: 'n8n Workflows',
    mimeType: 'application/json',
    description: 'List of all workflows in the n8n instance with their basic information',
  };
}

```

--------------------------------------------------------------------------------
/tests/jest-globals.d.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Jest global type declarations
 * This file adds typings for Jest globals to reduce TypeScript errors in test files
 */

import '@jest/globals';

// Declare global Jest types explicitly to help TypeScript
declare global {
  // Jest testing functions
  const describe: typeof import('@jest/globals').describe;
  const it: typeof import('@jest/globals').it;
  const test: typeof import('@jest/globals').test;
  const expect: typeof import('@jest/globals').expect;
  const beforeAll: typeof import('@jest/globals').beforeAll;
  const beforeEach: typeof import('@jest/globals').beforeEach;
  const afterAll: typeof import('@jest/globals').afterAll;
  const afterEach: typeof import('@jest/globals').afterEach;
  
  // Jest mock functionality
  const jest: typeof import('@jest/globals').jest;
  
  // Additional common helpers
  namespace jest {
    interface Mock<T = any, Y extends any[] = any[]> extends Function {
      new (...args: Y): T;
      (...args: Y): T;
      mockImplementation(fn: (...args: Y) => T): this;
      mockImplementationOnce(fn: (...args: Y) => T): this;
      mockReturnValue(value: T): this;
      mockReturnValueOnce(value: T): this;
      mockResolvedValue(value: T): this;
      mockResolvedValueOnce(value: T): this;
      mockRejectedValue(value: any): this;
      mockRejectedValueOnce(value: any): this;
      mockClear(): this;
      mockReset(): this;
      mockRestore(): this;
      mockName(name: string): this;
      getMockName(): string;
      mock: {
        calls: Y[];
        instances: T[];
        contexts: any[];
        lastCall: Y;
        results: Array<{ type: string; value: T }>;
      };
    }
    
    function fn<T = any, Y extends any[] = any[]>(): Mock<T, Y>;
    function fn<T = any, Y extends any[] = any[]>(implementation: (...args: Y) => T): Mock<T, Y>;
    
    function spyOn<T extends object, M extends keyof T>(
      object: T,
      method: M & string
    ): Mock<Required<T>[M]>;
    
    function mocked<T>(item: T, deep?: boolean): jest.Mocked<T>;
  }
}

export {};

```

--------------------------------------------------------------------------------
/.github/workflows/claude.yml:
--------------------------------------------------------------------------------

```yaml
name: Claude Code

on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
  issues:
    types: [opened, assigned]
  pull_request_review:
    types: [submitted]

jobs:
  claude:
    if: |
      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
      (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Run Claude Code
        id: claude
        uses: anthropics/claude-code-action@beta
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          
          # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
          # model: "claude-opus-4-20250514"
          
          # Optional: Customize the trigger phrase (default: @claude)
          # trigger_phrase: "/claude"
          
          # Optional: Trigger when specific user is assigned to an issue
          # assignee_trigger: "claude-bot"
          
          # Optional: Allow Claude to run specific commands
          # allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
          
          # Optional: Add custom instructions for Claude to customize its behavior for your project
          # custom_instructions: |
          #   Follow our coding standards
          #   Ensure all new code has tests
          #   Use TypeScript for new files
          
          # Optional: Custom environment variables for Claude
          # claude_env: |
          #   NODE_ENV: test


```

--------------------------------------------------------------------------------
/src/tools/workflow/handler.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Workflow Tools Handler
 * 
 * This module handles calls to workflow-related tools.
 */

import { ToolCallResult } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';
import {
  ListWorkflowsHandler,
  GetWorkflowHandler,
  CreateWorkflowHandler,
  UpdateWorkflowHandler,
  DeleteWorkflowHandler,
  ActivateWorkflowHandler,
  DeactivateWorkflowHandler,
} from './index.js';

/**
 * Handle workflow tool calls
 * 
 * @param toolName Name of the tool being called
 * @param args Arguments passed to the tool
 * @returns Tool call result
 */
export default async function workflowHandler(
  toolName: string,
  args: Record<string, any>
): Promise<ToolCallResult> {
  try {
    // Route to the appropriate handler based on the tool name
    switch (toolName) {
      case 'list_workflows':
        return await new ListWorkflowsHandler().execute(args);
        
      case 'get_workflow':
        return await new GetWorkflowHandler().execute(args);
        
      case 'create_workflow':
        return await new CreateWorkflowHandler().execute(args);
        
      case 'update_workflow':
        return await new UpdateWorkflowHandler().execute(args);
        
      case 'delete_workflow':
        return await new DeleteWorkflowHandler().execute(args);
        
      case 'activate_workflow':
        return await new ActivateWorkflowHandler().execute(args);
        
      case 'deactivate_workflow':
        return await new DeactivateWorkflowHandler().execute(args);
        
      default:
        throw new N8nApiError(`Unknown workflow tool: ${toolName}`);
    }
  } catch (error) {
    if (error instanceof N8nApiError) {
      return {
        content: [
          {
            type: 'text',
            text: error.message,
          },
        ],
        isError: true,
      };
    }
    
    // Handle unexpected errors
    const errorMessage = error instanceof Error 
      ? error.message 
      : 'Unknown error occurred';
      
    return {
      content: [
        {
          type: 'text',
          text: `Error executing workflow tool: ${errorMessage}`,
        },
      ],
      isError: true,
    };
  }
}

```

--------------------------------------------------------------------------------
/src/tools/workflow/base-handler.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Base Workflow Tool Handler
 * 
 * This module provides a base handler for workflow-related tools.
 */

import { ToolCallResult } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';
import { createApiService } from '../../api/n8n-client.js';
import { getEnvConfig } from '../../config/environment.js';

/**
 * Base class for workflow tool handlers
 */
export abstract class BaseWorkflowToolHandler {
  protected apiService = createApiService(getEnvConfig());
  
  /**
   * Validate and execute the tool
   * 
   * @param args Arguments passed to the tool
   * @returns Tool call result
   */
  abstract execute(args: Record<string, any>): Promise<ToolCallResult>;
  
  /**
   * Format a successful response
   * 
   * @param data Response data
   * @param message Optional success message
   * @returns Formatted success response
   */
  protected formatSuccess(data: any, message?: string): ToolCallResult {
    const formattedData = typeof data === 'object' 
      ? JSON.stringify(data, null, 2)
      : String(data);
      
    return {
      content: [
        {
          type: 'text',
          text: message ? `${message}\n\n${formattedData}` : formattedData,
        },
      ],
    };
  }
  
  /**
   * Format an error response
   * 
   * @param error Error object or message
   * @returns Formatted error response
   */
  protected formatError(error: Error | string): ToolCallResult {
    const errorMessage = error instanceof Error ? error.message : error;
    
    return {
      content: [
        {
          type: 'text',
          text: errorMessage,
        },
      ],
      isError: true,
    };
  }
  
  /**
   * Handle tool execution errors
   * 
   * @param handler Function to execute
   * @param args Arguments to pass to the handler
   * @returns Tool call result
   */
  protected async handleExecution(
    handler: (args: Record<string, any>) => Promise<ToolCallResult>,
    args: Record<string, any>
  ): Promise<ToolCallResult> {
    try {
      return await handler(args);
    } catch (error) {
      if (error instanceof N8nApiError) {
        return this.formatError(error.message);
      }
      
      const errorMessage = error instanceof Error 
        ? error.message 
        : 'Unknown error occurred';
        
      return this.formatError(`Error executing workflow tool: ${errorMessage}`);
    }
  }
}

```

--------------------------------------------------------------------------------
/src/tools/execution/base-handler.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Base Execution Tool Handler
 * 
 * This module provides a base handler for execution-related tools.
 */

import { ToolCallResult } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';
import { createApiService } from '../../api/n8n-client.js';
import { getEnvConfig } from '../../config/environment.js';

/**
 * Base class for execution tool handlers
 */
export abstract class BaseExecutionToolHandler {
  protected apiService = createApiService(getEnvConfig());
  
  /**
   * Validate and execute the tool
   * 
   * @param args Arguments passed to the tool
   * @returns Tool call result
   */
  abstract execute(args: Record<string, any>): Promise<ToolCallResult>;
  
  /**
   * Format a successful response
   * 
   * @param data Response data
   * @param message Optional success message
   * @returns Formatted success response
   */
  protected formatSuccess(data: any, message?: string): ToolCallResult {
    const formattedData = typeof data === 'object' 
      ? JSON.stringify(data, null, 2)
      : String(data);
      
    return {
      content: [
        {
          type: 'text',
          text: message ? `${message}\n\n${formattedData}` : formattedData,
        },
      ],
    };
  }
  
  /**
   * Format an error response
   * 
   * @param error Error object or message
   * @returns Formatted error response
   */
  protected formatError(error: Error | string): ToolCallResult {
    const errorMessage = error instanceof Error ? error.message : error;
    
    return {
      content: [
        {
          type: 'text',
          text: errorMessage,
        },
      ],
      isError: true,
    };
  }
  
  /**
   * Handle tool execution errors
   * 
   * @param handler Function to execute
   * @param args Arguments to pass to the handler
   * @returns Tool call result
   */
  protected async handleExecution(
    handler: (args: Record<string, any>) => Promise<ToolCallResult>,
    args: Record<string, any>
  ): Promise<ToolCallResult> {
    try {
      return await handler(args);
    } catch (error) {
      if (error instanceof N8nApiError) {
        return this.formatError(error.message);
      }
      
      const errorMessage = error instanceof Error 
        ? error.message 
        : 'Unknown error occurred';
        
      return this.formatError(`Error executing execution tool: ${errorMessage}`);
    }
  }
}

```

--------------------------------------------------------------------------------
/tests/unit/config/simple-environment.test.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Simple environment configuration tests
 */

import { describe, it, expect } from '@jest/globals';

// Simple environment validation function to test
function validateEnvironment(env: Record<string, string | undefined>): { 
  n8nApiUrl: string;
  n8nApiKey: string;
  debug: boolean;
} {
  // Check required variables
  if (!env.N8N_API_URL) {
    throw new Error('Missing required environment variable: N8N_API_URL');
  }
  
  if (!env.N8N_API_KEY) {
    throw new Error('Missing required environment variable: N8N_API_KEY');
  }
  
  // Validate URL format
  try {
    new URL(env.N8N_API_URL);
  } catch (error) {
    throw new Error(`Invalid URL format for N8N_API_URL: ${env.N8N_API_URL}`);
  }
  
  // Return parsed config
  return {
    n8nApiUrl: env.N8N_API_URL,
    n8nApiKey: env.N8N_API_KEY,
    debug: env.DEBUG?.toLowerCase() === 'true'
  };
}

describe('Environment Configuration', () => {
  describe('validateEnvironment', () => {
    it('should return a valid config when all required variables are present', () => {
      const env = {
        N8N_API_URL: 'https://n8n.example.com/api/v1',
        N8N_API_KEY: 'test-api-key'
      };
      
      const config = validateEnvironment(env);
      
      expect(config).toEqual({
        n8nApiUrl: 'https://n8n.example.com/api/v1',
        n8nApiKey: 'test-api-key',
        debug: false
      });
    });
    
    it('should set debug to true when DEBUG=true', () => {
      const env = {
        N8N_API_URL: 'https://n8n.example.com/api/v1',
        N8N_API_KEY: 'test-api-key',
        DEBUG: 'true'
      };
      
      const config = validateEnvironment(env);
      
      expect(config.debug).toBe(true);
    });
    
    it('should throw an error when N8N_API_URL is missing', () => {
      const env = {
        N8N_API_KEY: 'test-api-key'
      };
      
      expect(() => validateEnvironment(env)).toThrow(
        'Missing required environment variable: N8N_API_URL'
      );
    });
    
    it('should throw an error when N8N_API_KEY is missing', () => {
      const env = {
        N8N_API_URL: 'https://n8n.example.com/api/v1'
      };
      
      expect(() => validateEnvironment(env)).toThrow(
        'Missing required environment variable: N8N_API_KEY'
      );
    });
    
    it('should throw an error when N8N_API_URL is not a valid URL', () => {
      const env = {
        N8N_API_URL: 'invalid-url',
        N8N_API_KEY: 'test-api-key'
      };
      
      expect(() => validateEnvironment(env)).toThrow(
        'Invalid URL format for N8N_API_URL: invalid-url'
      );
    });
  });
});

```

--------------------------------------------------------------------------------
/docs/development/index.md:
--------------------------------------------------------------------------------

```markdown
# Development Guide

This section provides information for developers who want to understand, maintain, or extend the n8n MCP Server.

## Overview

The n8n MCP Server is built with TypeScript and implements the Model Context Protocol (MCP) to provide AI assistants with access to n8n workflows and executions. This development guide covers the architecture, extension points, and testing procedures.

## Topics

- [Architecture](./architecture.md): Overview of the codebase organization and design patterns
- [Extending the Server](./extending.md): Guide to adding new tools and resources
- [Testing](./testing.md): Information on testing procedures and writing tests

## Development Setup

To set up a development environment:

1. Clone the repository:
   ```bash
   git clone https://github.com/yourusername/n8n-mcp-server.git
   cd n8n-mcp-server
   ```

2. Install dependencies:
   ```bash
   npm install
   ```

3. Create a `.env` file for local development:
   ```bash
   cp .env.example .env
   # Edit the .env file with your n8n API credentials
   ```

4. Start the development server:
   ```bash
   npm run dev
   ```

This will compile the TypeScript code in watch mode, allowing you to make changes and see them take effect immediately.

## Project Structure

The project follows a modular structure:

```
n8n-mcp-server/
├── src/                  # Source code
│   ├── api/              # API client for n8n
│   ├── config/           # Configuration and environment settings
│   ├── errors/           # Error handling
│   ├── resources/        # MCP resources implementation
│   │   ├── static/       # Static resources
│   │   └── dynamic/      # Dynamic (parameterized) resources
│   ├── tools/            # MCP tools implementation
│   │   ├── workflow/     # Workflow management tools
│   │   └── execution/    # Execution management tools
│   ├── types/            # TypeScript type definitions
│   └── utils/            # Utility functions
├── tests/                # Test files
│   ├── unit/             # Unit tests
│   ├── integration/      # Integration tests
│   └── e2e/              # End-to-end tests
└── build/                # Compiled output
```

## Build and Distribution

To build the project for distribution:

```bash
npm run build
```

This will compile the TypeScript code to JavaScript in the `build` directory and make the executable script file.

## Development Workflow

1. Create a feature branch for your changes
2. Make your changes and ensure tests pass
3. Update documentation as needed
4. Submit a pull request

For more detailed instructions on specific development tasks, see the linked guides.

```

--------------------------------------------------------------------------------
/src/resources/dynamic/workflow.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Dynamic Workflow Resource Handler
 * 
 * This module provides the MCP resource implementation for retrieving
 * detailed workflow information by ID.
 */

import { N8nApiService } from '../../api/n8n-client.js';
import { formatWorkflowDetails, formatResourceUri } from '../../utils/resource-formatter.js';
import { McpError, ErrorCode } from '../../errors/index.js';

/**
 * Get workflow resource data by ID
 * 
 * @param apiService n8n API service
 * @param workflowId Workflow ID
 * @returns Formatted workflow resource data
 */
export async function getWorkflowResource(apiService: N8nApiService, workflowId: string): Promise<string> {
  try {
    // Get the specific workflow from the API
    const workflow = await apiService.getWorkflow(workflowId);
    
    // Format the workflow for resource consumption
    const formattedWorkflow = formatWorkflowDetails(workflow);
    
    // Add metadata about the resource
    const result = {
      resourceType: 'workflow',
      id: workflowId,
      ...formattedWorkflow,
      _links: {
        self: formatResourceUri('workflow', workflowId),
        // Include links to related resources
        executions: `n8n://executions?workflowId=${workflowId}`,
      },
      lastUpdated: new Date().toISOString(),
    };
    
    return JSON.stringify(result, null, 2);
  } catch (error) {
    console.error(`Error fetching workflow resource (ID: ${workflowId}):`, error);
    
    // Handle not found errors specifically
    if (error instanceof McpError && error.code === ErrorCode.NotFoundError) {
      throw error;
    }
    
    throw new McpError(
      ErrorCode.InternalError, 
      `Failed to retrieve workflow (ID: ${workflowId}): ${error instanceof Error ? error.message : 'Unknown error'}`
    );
  }
}

/**
 * Get workflow resource template URI
 * 
 * @returns Formatted resource template URI
 */
export function getWorkflowResourceTemplateUri(): string {
  return 'n8n://workflows/{id}';
}

/**
 * Get workflow resource template metadata
 * 
 * @returns Resource template metadata object
 */
export function getWorkflowResourceTemplateMetadata(): Record<string, any> {
  return {
    uriTemplate: getWorkflowResourceTemplateUri(),
    name: 'n8n Workflow Details',
    mimeType: 'application/json',
    description: 'Detailed information about a specific n8n workflow including all nodes, connections, and settings',
  };
}

/**
 * Extract workflow ID from resource URI
 * 
 * @param uri Resource URI
 * @returns Workflow ID or null if URI format is invalid
 */
export function extractWorkflowIdFromUri(uri: string): string | null {
  const match = uri.match(/^n8n:\/\/workflows\/([^/]+)$/);
  return match ? match[1] : null;
}

```

--------------------------------------------------------------------------------
/docs/api/index.md:
--------------------------------------------------------------------------------

```markdown
# API Reference

This section provides a comprehensive reference for the n8n MCP Server API, including all available tools and resources.

## Overview

The n8n MCP Server implements the Model Context Protocol (MCP) to provide AI assistants with access to n8n workflows and executions. The API is divided into two main categories:

1. **Tools**: Executable functions that can perform operations on n8n, such as creating workflows or starting executions.
2. **Resources**: Data sources that provide information about workflows and executions.

## API Architecture

The n8n MCP Server follows a clean separation of concerns:

- **Client Layer**: Handles communication with the n8n API
- **Transport Layer**: Implements the MCP protocol for communication with AI assistants
- **Tools Layer**: Exposes executable operations to AI assistants
- **Resources Layer**: Provides data access through URI-based resources

All API interactions are authenticated using the n8n API key configured in your environment.

## Available Tools

The server provides tools for managing workflows and executions:

- [Workflow Tools](./workflow-tools.md): Create, list, update, and delete workflows
- [Execution Tools](./execution-tools.md): Execute workflows and manage workflow executions

## Available Resources

The server provides resources for accessing workflow and execution data:

- [Static Resources](./static-resources.md): Fixed resources like workflow listings or execution statistics
- [Dynamic Resources](./dynamic-resources.md): Parameterized resources for specific workflows or executions

## Understanding Input Schemas

Each tool has an input schema that defines the expected parameters. These schemas follow the JSON Schema format and are automatically provided to AI assistants to enable proper parameter validation and suggestion.

Example input schema for the `workflow_get` tool:

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The ID of the workflow to retrieve"
    }
  },
  "required": ["id"]
}
```

## Error Handling

All API operations can return errors in a standardized format. Common error scenarios include:

- Authentication failures (invalid or missing API key)
- Resource not found (workflow or execution doesn't exist)
- Permission issues (API key doesn't have required permissions)
- Input validation errors (missing or invalid parameters)

Error responses include detailed messages to help troubleshoot issues.

## Next Steps

Explore the detailed documentation for each category:

- [Workflow Tools](./workflow-tools.md)
- [Execution Tools](./execution-tools.md)
- [Static Resources](./static-resources.md)
- [Dynamic Resources](./dynamic-resources.md)

```

--------------------------------------------------------------------------------
/src/resources/dynamic/execution.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Dynamic Execution Resource Handler
 * 
 * This module provides the MCP resource implementation for retrieving
 * detailed execution information by ID.
 */

import { N8nApiService } from '../../api/n8n-client.js';
import { formatExecutionDetails } from '../../utils/execution-formatter.js';
import { formatResourceUri } from '../../utils/resource-formatter.js';
import { McpError, ErrorCode } from '../../errors/index.js';

/**
 * Get execution resource data by ID
 * 
 * @param apiService n8n API service
 * @param executionId Execution ID
 * @returns Formatted execution resource data
 */
export async function getExecutionResource(apiService: N8nApiService, executionId: string): Promise<string> {
  try {
    // Get the specific execution from the API
    const execution = await apiService.getExecution(executionId);
    
    // Format the execution for resource consumption
    const formattedExecution = formatExecutionDetails(execution);
    
    // Add metadata about the resource
    const result = {
      resourceType: 'execution',
      id: executionId,
      ...formattedExecution,
      _links: {
        self: formatResourceUri('execution', executionId),
        // Include link to related workflow
        workflow: `n8n://workflows/${execution.workflowId}`,
      },
      lastUpdated: new Date().toISOString(),
    };
    
    return JSON.stringify(result, null, 2);
  } catch (error) {
    console.error(`Error fetching execution resource (ID: ${executionId}):`, error);
    
    // Handle not found errors specifically
    if (error instanceof McpError && error.code === ErrorCode.NotFoundError) {
      throw error;
    }
    
    throw new McpError(
      ErrorCode.InternalError, 
      `Failed to retrieve execution (ID: ${executionId}): ${error instanceof Error ? error.message : 'Unknown error'}`
    );
  }
}

/**
 * Get execution resource template URI
 * 
 * @returns Formatted resource template URI
 */
export function getExecutionResourceTemplateUri(): string {
  return 'n8n://executions/{id}';
}

/**
 * Get execution resource template metadata
 * 
 * @returns Resource template metadata object
 */
export function getExecutionResourceTemplateMetadata(): Record<string, any> {
  return {
    uriTemplate: getExecutionResourceTemplateUri(),
    name: 'n8n Execution Details',
    mimeType: 'application/json',
    description: 'Detailed information about a specific n8n workflow execution including node results and error information',
  };
}

/**
 * Extract execution ID from resource URI
 * 
 * @param uri Resource URI
 * @returns Execution ID or null if URI format is invalid
 */
export function extractExecutionIdFromUri(uri: string): string | null {
  const match = uri.match(/^n8n:\/\/executions\/([^/]+)$/);
  return match ? match[1] : null;
}

```

--------------------------------------------------------------------------------
/tests/unit/tools/workflow/simple-tool.test.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Simple workflow tool tests without complex dependencies
 */

import { describe, it, expect } from '@jest/globals';

interface MockWorkflow {
  id: string;
  name: string;
  active: boolean;
  createdAt: string;
  updatedAt: string;
  nodes: any[];
}

interface WorkflowFilter {
  active?: boolean;
}

// Mock workflow data
const mockWorkflows: MockWorkflow[] = [
  {
    id: '1234abc',
    name: 'Test Workflow 1',
    active: true,
    createdAt: '2025-03-01T12:00:00.000Z',
    updatedAt: '2025-03-02T14:30:00.000Z',
    nodes: []
  },
  {
    id: '5678def',
    name: 'Test Workflow 2',
    active: false,
    createdAt: '2025-03-01T12:00:00.000Z',
    updatedAt: '2025-03-12T10:15:00.000Z',
    nodes: []
  }
];

// Simple function to test tool definition
function getListWorkflowsToolDefinition() {
  return {
    name: 'list_workflows',
    description: 'List all workflows with optional filtering by status',
    inputSchema: {
      type: 'object',
      properties: {
        active: {
          type: 'boolean',
          description: 'Filter workflows by active status'
        }
      },
      required: []
    }
  };
}

// Simple function to test workflow filtering
function filterWorkflows(workflows: MockWorkflow[], filter: WorkflowFilter): MockWorkflow[] {
  if (filter && typeof filter.active === 'boolean') {
    return workflows.filter(workflow => workflow.active === filter.active);
  }
  return workflows;
}

describe('Workflow Tools', () => {
  describe('getListWorkflowsToolDefinition', () => {
    it('should return the correct tool definition', () => {
      const definition = getListWorkflowsToolDefinition();
      
      expect(definition.name).toBe('list_workflows');
      expect(definition.description).toBeTruthy();
      expect(definition.inputSchema).toBeDefined();
      expect(definition.inputSchema.properties).toHaveProperty('active');
      expect(definition.inputSchema.required).toEqual([]);
    });
  });
  
  describe('filterWorkflows', () => {
    it('should return all workflows when no filter is provided', () => {
      const result = filterWorkflows(mockWorkflows, {});
      
      expect(result).toHaveLength(2);
      expect(result).toEqual(mockWorkflows);
    });
    
    it('should filter workflows by active status when active is true', () => {
      const result = filterWorkflows(mockWorkflows, { active: true });
      
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe('1234abc');
      expect(result[0].active).toBe(true);
    });
    
    it('should filter workflows by active status when active is false', () => {
      const result = filterWorkflows(mockWorkflows, { active: false });
      
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe('5678def');
      expect(result[0].active).toBe(false);
    });
  });
});

```

--------------------------------------------------------------------------------
/.github/workflows/claude-code-review.yml:
--------------------------------------------------------------------------------

```yaml
name: Claude Code Review

on:
  pull_request:
    types: [opened, synchronize]
    # Optional: Only run on specific file changes
    # paths:
    #   - "src/**/*.ts"
    #   - "src/**/*.tsx"
    #   - "src/**/*.js"
    #   - "src/**/*.jsx"

jobs:
  claude-review:
    # Optional: Filter by PR author
    # if: |
    #   github.event.pull_request.user.login == 'external-contributor' ||
    #   github.event.pull_request.user.login == 'new-developer' ||
    #   github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
    
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
    
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1

      - name: Run Claude Code Review
        id: claude-review
        uses: anthropics/claude-code-action@beta
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          
          # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
          # model: "claude-opus-4-20250514"
          
          # Direct prompt for automated review (no @claude mention needed)
          direct_prompt: |
            Please review this pull request and provide feedback on:
            - Code quality and best practices
            - Potential bugs or issues
            - Performance considerations
            - Security concerns
            - Test coverage
            
            Be constructive and helpful in your feedback.
          
          # Optional: Customize review based on file types
          # direct_prompt: |
          #   Review this PR focusing on:
          #   - For TypeScript files: Type safety and proper interface usage
          #   - For API endpoints: Security, input validation, and error handling
          #   - For React components: Performance, accessibility, and best practices
          #   - For tests: Coverage, edge cases, and test quality
          
          # Optional: Different prompts for different authors
          # direct_prompt: |
          #   ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' && 
          #   'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' ||
          #   'Please provide a thorough code review focusing on our coding standards and best practices.' }}
          
          # Optional: Add specific tools for running tests or linting
          # allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)"
          
          # Optional: Skip review for certain conditions
          # if: |
          #   !contains(github.event.pull_request.title, '[skip-review]') &&
          #   !contains(github.event.pull_request.title, '[WIP]')


```

--------------------------------------------------------------------------------
/src/config/environment.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Environment Configuration
 * 
 * This module handles loading and validating environment variables
 * required for connecting to the n8n API.
 */

import dotenv from 'dotenv';
import findConfig from 'find-config';
import path from 'path';
import { McpError } from '@modelcontextprotocol/sdk/types.js';
import { ErrorCode } from '../errors/error-codes.js';

// Environment variable names
export const ENV_VARS = {
  N8N_API_URL: 'N8N_API_URL',
  N8N_API_KEY: 'N8N_API_KEY',
  N8N_WEBHOOK_USERNAME: 'N8N_WEBHOOK_USERNAME',
  N8N_WEBHOOK_PASSWORD: 'N8N_WEBHOOK_PASSWORD',
  DEBUG: 'DEBUG',
};

// Interface for validated environment variables
export interface EnvConfig {
  n8nApiUrl: string;
  n8nApiKey: string;
  n8nWebhookUsername?: string; // Made optional
  n8nWebhookPassword?: string; // Made optional
  debug: boolean;
}

/**
 * Load environment variables from .env file if present
 */
export function loadEnvironmentVariables(): void {
  const {
    N8N_API_URL,
    N8N_API_KEY,
    N8N_WEBHOOK_USERNAME,
    N8N_WEBHOOK_PASSWORD
  } = process.env;

  if (
    !N8N_API_URL &&
    !N8N_API_KEY &&
    !N8N_WEBHOOK_USERNAME &&
    !N8N_WEBHOOK_PASSWORD
  ) {
    const projectRoot = findConfig('package.json');
    if (projectRoot) {
      const envPath = path.resolve(path.dirname(projectRoot), '.env');
      dotenv.config({ path: envPath });
    }
  }
}

/**
 * Validate and retrieve required environment variables
 * 
 * @returns Validated environment configuration
 * @throws {McpError} If required environment variables are missing
 */
export function getEnvConfig(): EnvConfig {
  const n8nApiUrl = process.env[ENV_VARS.N8N_API_URL];
  const n8nApiKey = process.env[ENV_VARS.N8N_API_KEY];
  const n8nWebhookUsername = process.env[ENV_VARS.N8N_WEBHOOK_USERNAME];
  const n8nWebhookPassword = process.env[ENV_VARS.N8N_WEBHOOK_PASSWORD];
  const debug = process.env[ENV_VARS.DEBUG]?.toLowerCase() === 'true';

  // Validate required core environment variables
  if (!n8nApiUrl) {
    throw new McpError(
      ErrorCode.InitializationError,
      `Missing required environment variable: ${ENV_VARS.N8N_API_URL}`
    );
  }

  if (!n8nApiKey) {
    throw new McpError(
      ErrorCode.InitializationError,
      `Missing required environment variable: ${ENV_VARS.N8N_API_KEY}`
    );
  }

  // N8N_WEBHOOK_USERNAME and N8N_WEBHOOK_PASSWORD are now optional at startup.
  // Tools requiring them should perform checks at the point of use.

  // Validate URL format
  try {
    new URL(n8nApiUrl);
  } catch (error) {
    throw new McpError(
      ErrorCode.InitializationError,
      `Invalid URL format for ${ENV_VARS.N8N_API_URL}: ${n8nApiUrl}`
    );
  }

  return {
    n8nApiUrl,
    n8nApiKey,
    n8nWebhookUsername: n8nWebhookUsername || undefined, // Ensure undefined if empty
    n8nWebhookPassword: n8nWebhookPassword || undefined, // Ensure undefined if empty
    debug,
  };
}

```

--------------------------------------------------------------------------------
/tests/mocks/axios-mock.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Axios mock utilities for n8n MCP Server tests
 */

import { AxiosRequestConfig, AxiosResponse } from 'axios';

export interface MockResponse {
  data: any;
  status: number;
  statusText: string;
  headers?: Record<string, string>;
  config?: AxiosRequestConfig;
}

export const createMockAxiosResponse = (options: Partial<MockResponse> = {}): AxiosResponse => {
  return {
    data: options.data ?? {},
    status: options.status ?? 200,
    statusText: options.statusText ?? 'OK',
    headers: options.headers ?? {},
    config: options.config ?? {},
  } as AxiosResponse;
};

/**
 * Create a mock axios instance for testing
 */
export const createMockAxiosInstance = () => {
  const mockRequests: Record<string, any[]> = {};
  const mockResponses: Record<string, MockResponse[]> = {};
  
  const mockInstance = {
    get: jest.fn(),
    post: jest.fn(),
    put: jest.fn(),
    delete: jest.fn(),
    interceptors: {
      request: {
        use: jest.fn(),
      },
      response: {
        use: jest.fn(),
      },
    },
    defaults: {},
    
    // Helper method to add mock response
    addMockResponse(method: string, url: string, response: MockResponse | Error) {
      if (!mockResponses[`${method}:${url}`]) {
        mockResponses[`${method}:${url}`] = [];
      }
      
      if (response instanceof Error) {
        mockResponses[`${method}:${url}`].push(response as any);
      } else {
        mockResponses[`${method}:${url}`].push(response);
      }
    },
    
    // Helper method to get request history
    getRequestHistory(method: string, url: string) {
      return mockRequests[`${method}:${url}`] || [];
    },
    
    // Reset all mocks
    reset() {
      Object.keys(mockRequests).forEach(key => {
        delete mockRequests[key];
      });
      
      Object.keys(mockResponses).forEach(key => {
        delete mockResponses[key];
      });
      
      mockInstance.get.mockReset();
      mockInstance.post.mockReset();
      mockInstance.put.mockReset();
      mockInstance.delete.mockReset();
    }
  };
  
  // Setup method implementations
  ['get', 'post', 'put', 'delete'].forEach(method => {
    mockInstance[method].mockImplementation(async (url: string, data?: any) => {
      const requestKey = `${method}:${url}`;
      
      if (!mockRequests[requestKey]) {
        mockRequests[requestKey] = [];
      }
      
      mockRequests[requestKey].push(data);
      
      if (mockResponses[requestKey] && mockResponses[requestKey].length > 0) {
        const response = mockResponses[requestKey].shift();
        
        if (response instanceof Error) {
          throw response;
        }
        
        return createMockAxiosResponse(response);
      }
      
      throw new Error(`No mock response defined for ${method.toUpperCase()} ${url}`);
    });
  });
  
  return mockInstance;
};

export default {
  createMockAxiosResponse,
  createMockAxiosInstance,
};

```

--------------------------------------------------------------------------------
/src/tools/workflow/create.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Create Workflow Tool
 * 
 * This tool creates a new workflow in n8n.
 */

import { BaseWorkflowToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';

/**
 * Handler for the create_workflow tool
 */
export class CreateWorkflowHandler extends BaseWorkflowToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments containing workflow details
   * @returns Created workflow information
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async (args) => {
      const { name, nodes, connections, active, tags } = args;
      
      if (!name) {
        throw new N8nApiError('Missing required parameter: name');
      }
      
      // Validate nodes if provided
      if (nodes && !Array.isArray(nodes)) {
        throw new N8nApiError('Parameter "nodes" must be an array');
      }
      
      // Validate connections if provided
      if (connections && typeof connections !== 'object') {
        throw new N8nApiError('Parameter "connections" must be an object');
      }
      
      // Prepare workflow object
      const workflowData: Record<string, any> = {
        name,
        active: active === true,  // Default to false if not specified
      };
      
      // Add optional fields if provided
      if (nodes) workflowData.nodes = nodes;
      if (connections) workflowData.connections = connections;
      if (tags) workflowData.tags = tags;
      
      // Create the workflow
      const workflow = await this.apiService.createWorkflow(workflowData);
      
      return this.formatSuccess(
        {
          id: workflow.id,
          name: workflow.name,
          active: workflow.active
        },
        `Workflow created successfully`
      );
    }, args);
  }
}

/**
 * Get tool definition for the create_workflow tool
 * 
 * @returns Tool definition
 */
export function getCreateWorkflowToolDefinition(): ToolDefinition {
  return {
    name: 'create_workflow',
    description: 'Create a new workflow in n8n',
    inputSchema: {
      type: 'object',
      properties: {
        name: {
          type: 'string',
          description: 'Name of the workflow',
        },
        nodes: {
          type: 'array',
          description: 'Array of node objects that define the workflow',
          items: {
            type: 'object',
          },
        },
        connections: {
          type: 'object',
          description: 'Connection mappings between nodes',
        },
        active: {
          type: 'boolean',
          description: 'Whether the workflow should be active upon creation',
        },
        tags: {
          type: 'array',
          description: 'Tags to associate with the workflow',
          items: {
            type: 'string',
          },
        },
      },
      required: ['name'],
    },
  };
}

```

--------------------------------------------------------------------------------
/src/tools/execution/list.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * List Executions Tool
 * 
 * This tool retrieves a list of workflow executions from n8n.
 */

import { BaseExecutionToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition, Execution } from '../../types/index.js';
import { formatExecutionSummary, summarizeExecutions } from '../../utils/execution-formatter.js';

/**
 * Handler for the list_executions tool
 */
export class ListExecutionsHandler extends BaseExecutionToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments (workflowId, status, limit, lastId)
   * @returns List of executions
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async () => {
      const executions = await this.apiService.getExecutions();
      
      // Apply filters if provided
      let filteredExecutions = executions;
      
      // Filter by workflow ID if provided
      if (args.workflowId) {
        filteredExecutions = filteredExecutions.filter(
          (execution: Execution) => execution.workflowId === args.workflowId
        );
      }
      
      // Filter by status if provided
      if (args.status) {
        filteredExecutions = filteredExecutions.filter(
          (execution: Execution) => execution.status === args.status
        );
      }
      
      // Apply limit if provided
      const limit = args.limit && args.limit > 0 ? args.limit : filteredExecutions.length;
      filteredExecutions = filteredExecutions.slice(0, limit);
      
      // Format the executions for display
      const formattedExecutions = filteredExecutions.map((execution: Execution) => 
        formatExecutionSummary(execution)
      );
      
      // Generate summary if requested
      let summary = undefined;
      if (args.includeSummary) {
        summary = summarizeExecutions(executions);
      }
      
      // Prepare response data
      const responseData = {
        executions: formattedExecutions,
        summary: summary,
        total: formattedExecutions.length,
        filtered: args.workflowId || args.status ? true : false
      };
      
      return this.formatSuccess(
        responseData,
        `Found ${formattedExecutions.length} execution(s)`
      );
    }, args);
  }
}

/**
 * Get tool definition for the list_executions tool
 * 
 * @returns Tool definition
 */
export function getListExecutionsToolDefinition(): ToolDefinition {
  return {
    name: 'list_executions',
    description: 'Retrieve a list of workflow executions from n8n',
    inputSchema: {
      type: 'object',
      properties: {
        workflowId: {
          type: 'string',
          description: 'Optional ID of workflow to filter executions by',
        },
        status: {
          type: 'string',
          description: 'Optional status to filter by (success, error, waiting, or canceled)',
        },
        limit: {
          type: 'number',
          description: 'Maximum number of executions to return',
        },
        lastId: {
          type: 'string',
          description: 'ID of the last execution for pagination',
        },
        includeSummary: {
          type: 'boolean',
          description: 'Include summary statistics about executions',
        },
      },
      required: [],
    },
  };
}

```

--------------------------------------------------------------------------------
/src/errors/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Error Handling Module
 * 
 * This module provides custom error classes and error handling utilities
 * for the n8n MCP Server.
 */

import { McpError as SdkMcpError } from '@modelcontextprotocol/sdk/types.js';
import { ErrorCode } from './error-codes.js';

// Re-export McpError from SDK
export { McpError } from '@modelcontextprotocol/sdk/types.js';
// Re-export ErrorCode enum
export { ErrorCode } from './error-codes.js';

/**
 * n8n API Error class for handling errors from the n8n API
 */
export class N8nApiError extends SdkMcpError {
  constructor(message: string, statusCode?: number, details?: unknown) {
    // Map HTTP status codes to appropriate MCP error codes
    let errorCode = ErrorCode.InternalError;
    
    if (statusCode) {
      if (statusCode === 401 || statusCode === 403) {
        errorCode = ErrorCode.AuthenticationError;
      } else if (statusCode === 404) {
        errorCode = ErrorCode.NotFoundError;
      } else if (statusCode >= 400 && statusCode < 500) {
        errorCode = ErrorCode.InvalidRequest;
      }
    }
    
    super(errorCode, formatErrorMessage(message, statusCode, details));
  }
}

/**
 * Format an error message with status code and details
 */
function formatErrorMessage(message: string, statusCode?: number, details?: unknown): string {
  let formattedMessage = message;
  
  if (statusCode) {
    formattedMessage += ` (Status: ${statusCode})`;
  }
  
  if (details) {
    try {
      const detailsStr = typeof details === 'string' 
        ? details 
        : JSON.stringify(details, null, 2);
      formattedMessage += `\nDetails: ${detailsStr}`;
    } catch (error) {
      // Ignore JSON stringification errors
    }
  }
  
  return formattedMessage;
}

/**
 * Safely parse JSON response from n8n API
 * 
 * @param text Text to parse as JSON
 * @returns Parsed JSON object or null if parsing fails
 */
export function safeJsonParse(text: string): any {
  try {
    return JSON.parse(text);
  } catch (error) {
    return null;
  }
}

/**
 * Handle axios errors and convert them to N8nApiError
 * 
 * @param error Error object from axios
 * @param defaultMessage Default error message
 * @returns N8nApiError with appropriate details
 */
export function handleAxiosError(error: any, defaultMessage = 'n8n API request failed'): N8nApiError {
  // Handle axios error responses
  if (error.response) {
    const statusCode = error.response.status;
    const responseData = error.response.data;
    
    let errorMessage = defaultMessage;
    if (responseData && responseData.message) {
      errorMessage = responseData.message;
    }
    
    return new N8nApiError(errorMessage, statusCode, responseData);
  }
  
  // Handle request errors (e.g., network issues)
  if (error.request) {
    return new N8nApiError(
      'Network error connecting to n8n API', 
      undefined, 
      error.message
    );
  }
  
  // Handle other errors
  return new N8nApiError(error.message || defaultMessage);
}

/**
 * Extract a readable error message from an error object
 * 
 * @param error Error object
 * @returns Readable error message
 */
export function getErrorMessage(error: unknown): string {
  if (error instanceof Error) {
    return error.message;
  }
  
  if (typeof error === 'string') {
    return error;
  }
  
  try {
    return JSON.stringify(error);
  } catch {
    return 'Unknown error';
  }
}

```

--------------------------------------------------------------------------------
/docs/setup/configuration.md:
--------------------------------------------------------------------------------

```markdown
# Configuration Guide

This guide provides detailed information on configuring the n8n MCP Server.

## Environment Variables

The n8n MCP Server is configured using environment variables, which can be set in a `.env` file or directly in your environment.

### Required Variables

| Variable | Description | Example |
|----------|-------------|---------|
| `N8N_API_URL` | URL of the n8n API | `http://localhost:5678/api/v1` |
| `N8N_API_KEY` | API key for authenticating with n8n | `n8n_api_...` |

### Optional Variables

| Variable | Description | Default | Example |
|----------|-------------|---------|---------|
| `DEBUG` | Enable debug logging | `false` | `true` or `false` |

## Creating a .env File

The simplest way to configure the server is to create a `.env` file in the directory where you'll run the server:

```bash
# Copy the example .env file
cp .env.example .env

# Edit the .env file with your settings
nano .env  # or use any text editor
```

Example `.env` file:

```env
# n8n MCP Server Environment Variables

# Required: URL of the n8n API
N8N_API_URL=http://localhost:5678/api/v1

# Required: API key for authenticating with n8n
N8N_API_KEY=your_n8n_api_key_here

# Optional: Set to 'true' to enable debug logging
DEBUG=false
```

## Generating an n8n API Key

To use the n8n MCP Server, you need an API key from your n8n instance:

1. Open your n8n instance in a browser
2. Go to **Settings** > **API** > **API Keys**
3. Click **Create** to create a new API key
4. Set appropriate **Scope** (recommended: `workflow:read workflow:write workflow:execute`)
5. Copy the key to your `.env` file

![Creating an n8n API Key](../images/n8n-api-key.png)

## Server Connection Options

By default, the n8n MCP Server listens on `stdin` and `stdout` for Model Context Protocol communications. This is the format expected by AI assistants using the MCP protocol.

## Configuring AI Assistants

To use the n8n MCP Server with AI assistants, you need to register it with your AI assistant platform. The exact method depends on the platform you're using.

### Using the MCP Installer

If you're using Claude or another assistant that supports the MCP Installer, you can register the server with:

```bash
# Install the MCP Installer
npx @anaisbetts/mcp-installer

# Register the server (if installed globally)
install_repo_mcp_server n8n-mcp-server

# Or register from a local installation
install_local_mcp_server path/to/n8n-mcp-server
```

### Manual Configuration

For platforms without an installer, you'll need to configure the connection according to the platform's documentation. Typically, this involves:

1. Specifying the path to the executable
2. Setting environment variables for the server
3. Configuring response formatting

## Verifying Configuration

To verify your configuration:

1. Start the server
2. Open your AI assistant
3. Try a simple command like "List all workflows in n8n"

If configured correctly, the assistant should be able to retrieve and display your workflows.

## Troubleshooting

If you encounter issues with your configuration, check:

- The `.env` file is in the correct location
- The n8n API URL is accessible from where the server is running
- The API key has the correct permissions
- Any firewalls or network restrictions that might block connections

For more specific issues, see the [Troubleshooting](./troubleshooting.md) guide.

```

--------------------------------------------------------------------------------
/tests/mocks/n8n-fixtures.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Mock fixtures for n8n API responses
 */

import { Workflow, Execution } from '../../src/types/index.js';

/**
 * Create a mock workflow for testing
 */
export const createMockWorkflow = (overrides: Partial<Workflow> = {}): Workflow => {
  const id = overrides.id ?? 'mock-workflow-1';
  
  return {
    id,
    name: overrides.name ?? `Mock Workflow ${id}`,
    active: overrides.active ?? false,
    createdAt: overrides.createdAt ?? new Date().toISOString(),
    updatedAt: overrides.updatedAt ?? new Date().toISOString(),
    nodes: overrides.nodes ?? [
      {
        id: 'start',
        name: 'Start',
        type: 'n8n-nodes-base.start',
        parameters: {},
        position: [100, 300],
      },
    ],
    connections: overrides.connections ?? {},
    settings: overrides.settings ?? {},
    staticData: overrides.staticData ?? null,
    pinData: overrides.pinData ?? {},
    ...overrides,
  };
};

/**
 * Create multiple mock workflows
 */
export const createMockWorkflows = (count: number = 3): Workflow[] => {
  return Array.from({ length: count }, (_, i) => 
    createMockWorkflow({
      id: `mock-workflow-${i + 1}`,
      name: `Mock Workflow ${i + 1}`,
      active: i % 2 === 0, // Alternate active status
    })
  );
};

/**
 * Create a mock execution for testing
 */
export const createMockExecution = (overrides: Partial<Execution> = {}): Execution => {
  const id = overrides.id ?? 'mock-execution-1';
  const workflowId = overrides.workflowId ?? 'mock-workflow-1';
  
  return {
    id,
    workflowId,
    finished: overrides.finished ?? true,
    mode: overrides.mode ?? 'manual',
    waitTill: overrides.waitTill ?? null,
    startedAt: overrides.startedAt ?? new Date().toISOString(),
    stoppedAt: overrides.stoppedAt ?? new Date().toISOString(),
    status: overrides.status ?? 'success',
    data: overrides.data ?? {
      resultData: {
        runData: {},
      },
    },
    workflowData: overrides.workflowData ?? createMockWorkflow({ id: workflowId }),
    ...overrides,
  };
};

/**
 * Create multiple mock executions
 */
export const createMockExecutions = (count: number = 3): Execution[] => {
  return Array.from({ length: count }, (_, i) => 
    createMockExecution({
      id: `mock-execution-${i + 1}`,
      workflowId: `mock-workflow-${(i % 2) + 1}`, // Alternate between two workflows
      status: i % 3 === 0 ? 'success' : i % 3 === 1 ? 'error' : 'waiting',
    })
  );
};

/**
 * Create mock n8n API responses
 */
export const mockApiResponses = {
  workflows: {
    list: {
      data: createMockWorkflows(),
    },
    single: (id: string = 'mock-workflow-1') => createMockWorkflow({ id }),
    create: (workflow: Partial<Workflow> = {}) => createMockWorkflow(workflow),
    update: (id: string = 'mock-workflow-1', workflow: Partial<Workflow> = {}) => 
      createMockWorkflow({ ...workflow, id }),
    delete: { success: true },
    activate: (id: string = 'mock-workflow-1') => createMockWorkflow({ id, active: true }),
    deactivate: (id: string = 'mock-workflow-1') => createMockWorkflow({ id, active: false }),
  },
  
  executions: {
    list: {
      data: createMockExecutions(),
    },
    single: (id: string = 'mock-execution-1') => createMockExecution({ id }),
    delete: { success: true },
  },
};

export default {
  createMockWorkflow,
  createMockWorkflows,
  createMockExecution,
  createMockExecutions,
  mockApiResponses,
};

```

--------------------------------------------------------------------------------
/src/api/n8n-client.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * n8n API Client Interface
 * 
 * This module defines interfaces and types for the n8n API client.
 */

import { N8nApiClient } from './client.js';
import { EnvConfig } from '../config/environment.js';
import { Workflow, Execution } from '../types/index.js';

/**
 * n8n API service - provides functions for interacting with n8n API
 */
export class N8nApiService {
  private client: N8nApiClient;

  /**
   * Create a new n8n API service
   * 
   * @param config Environment configuration
   */
  constructor(config: EnvConfig) {
    this.client = new N8nApiClient(config);
  }

  /**
   * Check connectivity to the n8n API
   */
  async checkConnectivity(): Promise<void> {
    return this.client.checkConnectivity();
  }

  /**
   * Get all workflows from n8n
   * 
   * @returns Array of workflow objects
   */
  async getWorkflows(): Promise<Workflow[]> {
    return this.client.getWorkflows();
  }

  /**
   * Get a specific workflow by ID
   * 
   * @param id Workflow ID
   * @returns Workflow object
   */
  async getWorkflow(id: string): Promise<Workflow> {
    return this.client.getWorkflow(id);
  }

  /**
   * Execute a workflow by ID
   * 
   * @param id Workflow ID
   * @param data Optional data to pass to the workflow
   * @returns Execution result
   */
  async executeWorkflow(id: string, data?: Record<string, any>): Promise<any> {
    return this.client.executeWorkflow(id, data);
  }

  /**
   * Create a new workflow
   * 
   * @param workflow Workflow object to create
   * @returns Created workflow
   */
  async createWorkflow(workflow: Record<string, any>): Promise<Workflow> {
    return this.client.createWorkflow(workflow);
  }

  /**
   * Update an existing workflow
   * 
   * @param id Workflow ID
   * @param workflow Updated workflow object
   * @returns Updated workflow
   */
  async updateWorkflow(id: string, workflow: Record<string, any>): Promise<Workflow> {
    return this.client.updateWorkflow(id, workflow);
  }

  /**
   * Delete a workflow
   * 
   * @param id Workflow ID
   * @returns Deleted workflow or success message
   */
  async deleteWorkflow(id: string): Promise<any> {
    return this.client.deleteWorkflow(id);
  }

  /**
   * Activate a workflow
   * 
   * @param id Workflow ID
   * @returns Activated workflow
   */
  async activateWorkflow(id: string): Promise<Workflow> {
    return this.client.activateWorkflow(id);
  }

  /**
   * Deactivate a workflow
   * 
   * @param id Workflow ID
   * @returns Deactivated workflow
   */
  async deactivateWorkflow(id: string): Promise<Workflow> {
    return this.client.deactivateWorkflow(id);
  }

  /**
   * Get all workflow executions
   * 
   * @returns Array of execution objects
   */
  async getExecutions(): Promise<Execution[]> {
    return this.client.getExecutions();
  }

  /**
   * Get a specific execution by ID
   * 
   * @param id Execution ID
   * @returns Execution object
   */
  async getExecution(id: string): Promise<Execution> {
    return this.client.getExecution(id);
  }
  
  /**
   * Delete an execution
   * 
   * @param id Execution ID
   * @returns Deleted execution or success message
   */
  async deleteExecution(id: string): Promise<any> {
    return this.client.deleteExecution(id);
  }
}

/**
 * Create a new n8n API service
 * 
 * @param config Environment configuration
 * @returns n8n API service
 */
export function createApiService(config: EnvConfig): N8nApiService {
  return new N8nApiService(config);
}

```

--------------------------------------------------------------------------------
/tests/unit/utils/execution-formatter.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from '@jest/globals';
import {
  formatExecutionSummary,
  formatExecutionDetails,
  getStatusIndicator,
  summarizeExecutions
} from '../../../src/utils/execution-formatter.js';
import {
  createMockExecution,
  createMockExecutions
} from '../../mocks/n8n-fixtures.js';


describe('Execution Formatter Utilities', () => {
  describe('getStatusIndicator', () => {
    it('returns the correct emoji for known statuses', () => {
      expect(getStatusIndicator('success')).toBe('✅');
      expect(getStatusIndicator('error')).toBe('❌');
      expect(getStatusIndicator('waiting')).toBe('⏳');
      expect(getStatusIndicator('canceled')).toBe('🛑');
    });

    it('returns a default emoji for unknown status', () => {
      expect(getStatusIndicator('unknown')).toBe('⏱️');
    });
  });

  describe('formatExecutionSummary', () => {
    it('formats execution data into a summary', () => {
      const execution = createMockExecution({
        id: 'exec1',
        workflowId: 'wf1',
        status: 'success',
        startedAt: '2025-01-01T00:00:00.000Z',
        stoppedAt: '2025-01-01T00:00:05.000Z'
      });

      const summary = formatExecutionSummary(execution);

      expect(summary).toMatchObject({
        id: 'exec1',
        workflowId: 'wf1',
        status: '✅ success',
        startedAt: '2025-01-01T00:00:00.000Z',
        stoppedAt: '2025-01-01T00:00:05.000Z',
        finished: true
      });
      expect(summary.duration).toBe('5s');
    });

    it('marks execution as in progress when stoppedAt is missing', () => {
      const execution = createMockExecution({
        stoppedAt: undefined as any,
        status: 'waiting'
      });

      const summary = formatExecutionSummary(execution);
      expect(summary.stoppedAt).toBe('In progress');
    });
  });

  describe('formatExecutionDetails', () => {
    it('includes node results when present', () => {
      const execution = createMockExecution({
        data: {
          resultData: {
            runData: {
              MyNode: [
                {
                  status: 'success',
                  data: { main: [[{ foo: 'bar' }]] }
                }
              ]
            }
          }
        },
        status: 'success'
      });

      const details = formatExecutionDetails(execution);
      expect(details.nodeResults.MyNode).toEqual({
        status: 'success',
        items: 1,
        data: [{ foo: 'bar' }]
      });
    });

    it('adds error information when present', () => {
      const execution = createMockExecution({
        data: {
          resultData: {
            runData: {},
            error: { message: 'boom', stack: 'trace' }
          } as any
        },
        status: 'error'
      });

      const details = formatExecutionDetails(execution);
      expect(details.error).toEqual({ message: 'boom', stack: 'trace' });
    });
  });

  describe('summarizeExecutions', () => {
    it('summarizes counts and percentages', () => {
      const executions = [
        createMockExecution({ status: 'success' }),
        createMockExecution({ status: 'error' }),
        createMockExecution({ status: 'waiting' }),
        createMockExecution({ status: 'success' })
      ];

      const summary = summarizeExecutions(executions);

      expect(summary.total).toBe(4);
      const success = summary.byStatus.find((s: any) => s.status.includes('success'));
      const error = summary.byStatus.find((s: any) => s.status.includes('error'));
      expect(success.count).toBe(2);
      expect(error.count).toBe(1);
      expect(summary.successRate).toBe('50%');
    });
  });
});

```

--------------------------------------------------------------------------------
/docs/api/static-resources.md:
--------------------------------------------------------------------------------

```markdown
# Static Resources

This page documents the static resources available in the n8n MCP Server.

## Overview

Static resources provide access to fixed n8n data sources without requiring parameters in the URI. These resources are ideal for retrieving collections of data or summary information.

## Available Resources

### n8n://workflows/list

Provides a list of all workflows in the n8n instance.

**URI:** `n8n://workflows/list`

**Description:** Returns a comprehensive list of all workflows with their basic metadata.

**Example Usage:**

```javascript
const resource = await accessMcpResource('n8n-mcp-server', 'n8n://workflows/list');
```

**Response:**

```javascript
{
  "workflows": [
    {
      "id": "1234abc",
      "name": "Email Processing Workflow",
      "active": true,
      "createdAt": "2025-03-01T12:00:00.000Z",
      "updatedAt": "2025-03-02T14:30:00.000Z"
    },
    {
      "id": "5678def",
      "name": "Data Sync Workflow",
      "active": false,
      "createdAt": "2025-03-01T12:00:00.000Z",
      "updatedAt": "2025-03-12T10:15:00.000Z"
    }
  ],
  "count": 2,
  "pagination": {
    "hasMore": false
  }
}
```

### n8n://execution-stats

Provides aggregated statistics about workflow executions.

**URI:** `n8n://execution-stats`

**Description:** Returns summary statistics about workflow executions, including counts by status, average execution times, and recent trends.

**Example Usage:**

```javascript
const resource = await accessMcpResource('n8n-mcp-server', 'n8n://execution-stats');
```

**Response:**

```javascript
{
  "totalExecutions": 1250,
  "statusCounts": {
    "success": 1050,
    "error": 180,
    "cancelled": 20
  },
  "averageExecutionTime": 3.5, // seconds
  "recentActivity": {
    "last24Hours": 125,
    "last7Days": 450
  },
  "topWorkflows": [
    {
      "id": "1234abc",
      "name": "Email Processing Workflow",
      "executionCount": 256
    },
    {
      "id": "5678def",
      "name": "Data Sync Workflow",
      "executionCount": 198
    }
  ]
}
```

### n8n://health

Provides health information about the n8n instance.

**URI:** `n8n://health`

**Description:** Returns health status information about the n8n instance including connection status, version, and basic metrics.

**Example Usage:**

```javascript
const resource = await accessMcpResource('n8n-mcp-server', 'n8n://health');
```

**Response:**

```javascript
{
  "status": "healthy",
  "n8nVersion": "1.5.0",
  "uptime": 259200, // seconds (3 days)
  "databaseStatus": "connected",
  "apiStatus": "operational",
  "memoryUsage": {
    "rss": "156MB",
    "heapTotal": "85MB",
    "heapUsed": "72MB"
  }
}
```

## Content Types

All static resources return JSON content with the MIME type `application/json`.

## Authentication

Access to static resources requires the same authentication as tools, using the configured n8n API key. If authentication fails, the resource will return an error.

## Error Handling

Static resources can return the following errors:

| HTTP Status | Description |
|-------------|-------------|
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - API key does not have permission to access this resource |
| 500 | Internal Server Error - An unexpected error occurred on the n8n server |

## Pagination

Some resources that return large collections (like `n8n://workflows/list`) support pagination. The response includes a `pagination` object with information about whether more results are available.

## Best Practices

- Use static resources for getting an overview of what's available in the n8n instance
- Prefer static resources over tools when you only need to read data
- Check the health resource before performing operations to ensure the n8n instance is operational
- Use execution statistics to monitor the performance and reliability of your workflows

```

--------------------------------------------------------------------------------
/src/utils/resource-formatter.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Resource Formatter Utilities
 * 
 * This module provides utility functions for formatting resource data
 * in a consistent, user-friendly manner for MCP resources.
 */

import { Workflow, Execution } from '../types/index.js';

/**
 * Format workflow summary for static resource listing
 * 
 * @param workflow Workflow object
 * @returns Formatted workflow summary
 */
export function formatWorkflowSummary(workflow: Workflow): Record<string, any> {
  return {
    id: workflow.id,
    name: workflow.name,
    active: workflow.active,
    status: workflow.active ? '🟢 Active' : '⚪ Inactive',
    updatedAt: workflow.updatedAt,
    createdAt: workflow.createdAt,
  };
}

/**
 * Format detailed workflow information for dynamic resources
 * 
 * @param workflow Workflow object
 * @returns Formatted workflow details
 */
export function formatWorkflowDetails(workflow: Workflow): Record<string, any> {
  const summary = formatWorkflowSummary(workflow);
  
  // Add additional details
  return {
    ...summary,
    nodes: workflow.nodes.map(node => ({
      id: node.id,
      name: node.name,
      type: node.type,
      position: node.position,
      parameters: node.parameters,
    })),
    connections: workflow.connections,
    staticData: workflow.staticData,
    settings: workflow.settings,
    tags: workflow.tags,
    // Exclude potentially sensitive or unnecessary information
    // like pinData or other internal fields
  };
}

/**
 * Format execution statistics summary
 * 
 * @param executions Array of execution objects
 * @returns Formatted execution statistics
 */
export function formatExecutionStats(executions: Execution[]): Record<string, any> {
  // Group executions by status
  const statusCounts: Record<string, number> = {};
  executions.forEach(execution => {
    const status = execution.status || 'unknown';
    statusCounts[status] = (statusCounts[status] || 0) + 1;
  });
  
  // Calculate success rate
  const totalCount = executions.length;
  const successCount = statusCounts.success || 0;
  const successRate = totalCount > 0 ? Math.round((successCount / totalCount) * 100) : 0;
  
  // Calculate average execution time
  let totalDuration = 0;
  let completedCount = 0;
  
  executions.forEach(execution => {
    if (execution.startedAt && execution.stoppedAt) {
      const startedAt = new Date(execution.startedAt);
      const stoppedAt = new Date(execution.stoppedAt);
      const durationMs = stoppedAt.getTime() - startedAt.getTime();
      
      totalDuration += durationMs;
      completedCount++;
    }
  });
  
  const avgDurationMs = completedCount > 0 ? Math.round(totalDuration / completedCount) : 0;
  const avgDurationSec = Math.round(avgDurationMs / 1000);
  
  // Group executions by workflow
  const workflowExecutions: Record<string, number> = {};
  executions.forEach(execution => {
    const workflowId = execution.workflowId;
    workflowExecutions[workflowId] = (workflowExecutions[workflowId] || 0) + 1;
  });
  
  // Get top workflows by execution count
  const topWorkflows = Object.entries(workflowExecutions)
    .sort((a, b) => b[1] - a[1])
    .slice(0, 5)
    .map(([workflowId, count]) => ({
      workflowId,
      executionCount: count,
      percentage: totalCount > 0 ? Math.round((count / totalCount) * 100) : 0
    }));
  
  return {
    total: totalCount,
    byStatus: Object.entries(statusCounts).map(([status, count]) => ({
      status,
      count,
      percentage: totalCount > 0 ? Math.round((count / totalCount) * 100) : 0
    })),
    successRate: `${successRate}%`,
    averageExecutionTime: completedCount > 0 ? `${avgDurationSec}s` : 'N/A',
    recentTrend: {
      // Recent executions trend - last 24 hours vs previous 24 hours
      // This is a placeholder - would need timestamp filtering logic
      changePercent: '0%',
      description: 'Stable execution rate'
    },
    topWorkflows: topWorkflows,
    timeUpdated: new Date().toISOString()
  };
}

/**
 * Format resource URI for n8n resources
 * 
 * @param resourceType Type of resource (workflow or execution)
 * @param id Optional resource ID for specific resources
 * @returns Formatted resource URI
 */
export function formatResourceUri(
  resourceType: 'workflow' | 'execution' | 'workflows' | 'execution-stats',
  id?: string,
): string {
  if (id) {
    const base = ['workflow', 'execution'].includes(resourceType)
      ? `${resourceType}s`
      : resourceType;
    return `n8n://${base}/${id}`;
  }
  return `n8n://${resourceType}`;
}

```

--------------------------------------------------------------------------------
/src/utils/execution-formatter.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Execution Formatter Utilities
 * 
 * This module provides utility functions for formatting execution data
 * in a consistent, user-friendly manner.
 */

import { Execution } from '../types/index.js';

/**
 * Format basic execution information for display
 * 
 * @param execution Execution object
 * @returns Formatted execution summary
 */
export function formatExecutionSummary(execution: Execution): Record<string, any> {
  // Calculate duration
  const startedAt = new Date(execution.startedAt);
  const stoppedAt = execution.stoppedAt ? new Date(execution.stoppedAt) : new Date();
  const durationMs = stoppedAt.getTime() - startedAt.getTime();
  const durationSeconds = Math.round(durationMs / 1000);
  
  // Create status indicator emoji
  const statusIndicator = getStatusIndicator(execution.status);
  
  return {
    id: execution.id,
    workflowId: execution.workflowId,
    status: `${statusIndicator} ${execution.status}`,
    startedAt: execution.startedAt,
    stoppedAt: execution.stoppedAt || 'In progress',
    duration: `${durationSeconds}s`,
    finished: execution.finished
  };
}

/**
 * Format detailed execution information including node results
 * 
 * @param execution Execution object
 * @returns Formatted execution details
 */
export function formatExecutionDetails(execution: Execution): Record<string, any> {
  const summary = formatExecutionSummary(execution);
  
  // Extract node results
  const nodeResults: Record<string, any> = {};
  if (execution.data?.resultData?.runData) {
    for (const [nodeName, nodeData] of Object.entries(execution.data.resultData.runData)) {
      try {
        // Get the last output
        const lastOutput = Array.isArray(nodeData) && nodeData.length > 0
          ? nodeData[nodeData.length - 1]
          : null;
          
        if (lastOutput && lastOutput.data && Array.isArray(lastOutput.data.main)) {
          // Extract the output data
          const outputData = lastOutput.data.main.length > 0 
            ? lastOutput.data.main[0]
            : [];
            
          nodeResults[nodeName] = {
            status: lastOutput.status,
            items: outputData.length,
            data: outputData.slice(0, 3), // Limit to first 3 items to avoid overwhelming response
          };
        }
      } catch (error) {
        nodeResults[nodeName] = { error: 'Failed to parse node output' };
      }
    }
  }
  
  // Add node results and error information to the summary
  return {
    ...summary,
    mode: execution.mode,
    nodeResults: nodeResults,
    // Include error information if present
    error: execution.data?.resultData && 'error' in execution.data.resultData
      ? {
          message: (execution.data.resultData as any).error?.message,
          stack: (execution.data.resultData as any).error?.stack,
        }
      : undefined,
  };
}

/**
 * Get appropriate status indicator emoji based on execution status
 * 
 * @param status Execution status string
 * @returns Status indicator emoji
 */
export function getStatusIndicator(status: string): string {
  switch (status) {
    case 'success':
      return '✅'; // Success
    case 'error':
      return '❌'; // Error
    case 'waiting':
      return '⏳'; // Waiting
    case 'canceled':
      return '🛑'; // Canceled
    default:
      return '⏱️'; // In progress or unknown
  }
}

/**
 * Summarize execution results for more compact display
 * 
 * @param executions Array of execution objects
 * @param limit Maximum number of executions to include
 * @returns Summary of execution results
 */
export function summarizeExecutions(executions: Execution[], limit: number = 10): Record<string, any> {
  const limitedExecutions = executions.slice(0, limit);
  
  // Group executions by status
  const byStatus: Record<string, number> = {};
  limitedExecutions.forEach(execution => {
    const status = execution.status || 'unknown';
    byStatus[status] = (byStatus[status] || 0) + 1;
  });
  
  // Calculate success rate
  const totalCount = limitedExecutions.length;
  const successCount = byStatus.success || 0;
  const successRate = totalCount > 0 ? Math.round((successCount / totalCount) * 100) : 0;
  
  return {
    total: totalCount,
    byStatus: Object.entries(byStatus).map(([status, count]) => ({
      status: `${getStatusIndicator(status)} ${status}`,
      count,
      percentage: totalCount > 0 ? Math.round((count / totalCount) * 100) : 0
    })),
    successRate: `${successRate}%`,
    displayed: limitedExecutions.length,
    totalAvailable: executions.length
  };
}

```

--------------------------------------------------------------------------------
/src/tools/workflow/update.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Update Workflow Tool
 * 
 * This tool updates an existing workflow in n8n.
 */

import { BaseWorkflowToolHandler } from './base-handler.js';
import { ToolCallResult, ToolDefinition } from '../../types/index.js';
import { N8nApiError } from '../../errors/index.js';

/**
 * Handler for the update_workflow tool
 */
export class UpdateWorkflowHandler extends BaseWorkflowToolHandler {
  /**
   * Execute the tool
   * 
   * @param args Tool arguments containing workflow updates
   * @returns Updated workflow information
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async (args) => {
      const { workflowId, name, nodes, connections, active, tags } = args;
      
      if (!workflowId) {
        throw new N8nApiError('Missing required parameter: workflowId');
      }
      
      // Validate nodes if provided
      if (nodes && !Array.isArray(nodes)) {
        throw new N8nApiError('Parameter "nodes" must be an array');
      }
      
      // Validate connections if provided
      if (connections && typeof connections !== 'object') {
        throw new N8nApiError('Parameter "connections" must be an object');
      }
      
      // Get the current workflow to update
      const currentWorkflow = await this.apiService.getWorkflow(workflowId);
      
      // Prepare update object with only allowed properties (per n8n API schema)
      const workflowData: Record<string, any> = {
        name: name !== undefined ? name : currentWorkflow.name,
        nodes: nodes !== undefined ? nodes : currentWorkflow.nodes,
        connections: connections !== undefined ? connections : currentWorkflow.connections,
        settings: currentWorkflow.settings
      };
      
      // Add optional staticData if it exists
      if (currentWorkflow.staticData !== undefined) {
        workflowData.staticData = currentWorkflow.staticData;
      }
      
      // Note: active and tags are read-only properties and cannot be updated via this endpoint
      
      // Update the workflow
      const updatedWorkflow = await this.apiService.updateWorkflow(workflowId, workflowData);
      
      // Build a summary of changes
      const changesArray = [];
      if (name !== undefined && name !== currentWorkflow.name) changesArray.push(`name: "${currentWorkflow.name}" → "${name}"`);
      if (nodes !== undefined) changesArray.push('nodes updated');
      if (connections !== undefined) changesArray.push('connections updated');
      
      // Add warnings for read-only properties
      const warnings = [];
      if (active !== undefined) warnings.push('active (read-only, use activate/deactivate workflow tools)');
      if (tags !== undefined) warnings.push('tags (read-only property)');
      
      const changesSummary = changesArray.length > 0
        ? `Changes: ${changesArray.join(', ')}`
        : 'No changes were made';
      
      const warningsSummary = warnings.length > 0
        ? ` Note: Ignored ${warnings.join(', ')}.`
        : '';
      
      return this.formatSuccess(
        {
          id: updatedWorkflow.id,
          name: updatedWorkflow.name,
          active: updatedWorkflow.active
        },
        `Workflow updated successfully. ${changesSummary}${warningsSummary}`
      );
    }, args);
  }
}

/**
 * Get tool definition for the update_workflow tool
 * 
 * @returns Tool definition
 */
export function getUpdateWorkflowToolDefinition(): ToolDefinition {
  return {
    name: 'update_workflow',
    description: 'Update an existing workflow in n8n',
    inputSchema: {
      type: 'object',
      properties: {
        workflowId: {
          type: 'string',
          description: 'ID of the workflow to update',
        },
        name: {
          type: 'string',
          description: 'New name for the workflow',
        },
        nodes: {
          type: 'array',
          description: 'Updated array of node objects that define the workflow',
          items: {
            type: 'object',
          },
        },
        connections: {
          type: 'object',
          description: 'Updated connection mappings between nodes',
        },
        active: {
          type: 'boolean',
          description: 'Whether the workflow should be active (read-only: use activate/deactivate workflow tools instead)',
        },
        tags: {
          type: 'array',
          description: 'Tags to associate with the workflow (read-only: cannot be updated via this endpoint)',
          items: {
            type: 'string',
          },
        },
      },
      required: ['workflowId'],
    },
  };
}

```

--------------------------------------------------------------------------------
/src/resources/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Resources Module
 * 
 * This module provides MCP resource handlers for n8n workflows and executions.
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import {
  ListResourcesRequestSchema,
  ListResourceTemplatesRequestSchema,
  ReadResourceRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { EnvConfig } from '../config/environment.js';
import { createApiService } from '../api/n8n-client.js';
import { McpError, ErrorCode } from '../errors/index.js';

// Import static resource handlers
import { 
  getWorkflowsResource,
  getWorkflowsResourceMetadata,
  getWorkflowsResourceUri,
} from './static/workflows.js';
import {
  getExecutionStatsResource,
  getExecutionStatsResourceMetadata,
  getExecutionStatsResourceUri,
} from './static/execution-stats.js';

// Import dynamic resource handlers
import {
  getWorkflowResource,
  getWorkflowResourceTemplateMetadata,
  extractWorkflowIdFromUri,
} from './dynamic/workflow.js';
import {
  getExecutionResource,
  getExecutionResourceTemplateMetadata,
  extractExecutionIdFromUri,
} from './dynamic/execution.js';

/**
 * Set up resource handlers for the MCP server
 * 
 * @param server MCP server instance
 * @param envConfig Environment configuration
 */
export function setupResourceHandlers(server: Server, envConfig: EnvConfig): void {
  // Set up static resources
  setupStaticResources(server, envConfig);

  // Set up dynamic resources
  setupDynamicResources(server, envConfig);
}

/**
 * Set up static resource handlers
 * 
 * @param server MCP server instance
 * @param envConfig Environment configuration
 */
function setupStaticResources(server: Server, _envConfig: EnvConfig): void {
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
    // Return all available static resources
    return {
      resources: [
        getWorkflowsResourceMetadata(),
        getExecutionStatsResourceMetadata(),
      ],
    };
  });
}

/**
 * Set up dynamic resource handlers
 * 
 * @param server MCP server instance
 * @param envConfig Environment configuration
 */
function setupDynamicResources(server: Server, envConfig: EnvConfig): void {
  const apiService = createApiService(envConfig);
  
  server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
    // Return all available dynamic resource templates
    return {
      resourceTemplates: [
        getWorkflowResourceTemplateMetadata(),
        getExecutionResourceTemplateMetadata(),
      ],
    };
  });

  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
    const uri = request.params.uri;
    console.log(`Resource requested: ${uri}`);
    
    try {
      // Handle static resources
      if (uri === getWorkflowsResourceUri()) {
        const content = await getWorkflowsResource(apiService);
        return {
          contents: [
            {
              uri,
              mimeType: 'application/json',
              text: content,
            },
          ],
        };
      }
      
      if (uri === getExecutionStatsResourceUri()) {
        const content = await getExecutionStatsResource(apiService);
        return {
          contents: [
            {
              uri,
              mimeType: 'application/json',
              text: content,
            },
          ],
        };
      }
      
      // Handle dynamic resources
      const workflowId = extractWorkflowIdFromUri(uri);
      if (workflowId) {
        const content = await getWorkflowResource(apiService, workflowId);
        return {
          contents: [
            {
              uri,
              mimeType: 'application/json',
              text: content,
            },
          ],
        };
      }
      
      const executionId = extractExecutionIdFromUri(uri);
      if (executionId) {
        const content = await getExecutionResource(apiService, executionId);
        return {
          contents: [
            {
              uri,
              mimeType: 'application/json',
              text: content,
            },
          ],
        };
      }
      
      // If we get here, the URI isn't recognized
      throw new McpError(
        ErrorCode.NotFoundError,
        `Resource not found: ${uri}`
      );
    } catch (error) {
      console.error(`Error retrieving resource (${uri}):`, error);
      
      // Pass through McpErrors
      if (error instanceof McpError) {
        throw error;
      }
      
      // Convert other errors to McpError
      throw new McpError(
        ErrorCode.InternalError,
        `Error retrieving resource: ${error instanceof Error ? error.message : 'Unknown error'}`
      );
    }
  });
}

```

--------------------------------------------------------------------------------
/docs/setup/troubleshooting.md:
--------------------------------------------------------------------------------

```markdown
# Troubleshooting Guide

This guide addresses common issues you might encounter when setting up and using the n8n MCP Server.

## Connection Issues

### Cannot Connect to n8n API

**Symptoms:** 
- Error messages mentioning "Connection refused" or "Cannot connect to n8n API"
- Timeout errors when trying to use MCP tools

**Possible Solutions:**
1. **Verify n8n is running:**
   - Ensure your n8n instance is running and accessible
   - Try accessing the n8n URL in a browser

2. **Check n8n API URL:**
   - Verify the `N8N_API_URL` in your `.env` file
   - Make sure it includes the full path (e.g., `http://localhost:5678/api/v1`)
   - Check for typos or incorrect protocol (http vs https)

3. **Network Configuration:**
   - If running on a different machine, ensure there are no firewall rules blocking access
   - Check if n8n is configured to allow remote connections

4. **HTTPS/SSL Issues:**
   - If using HTTPS, ensure certificates are valid
   - For self-signed certificates, you may need to set up additional configuration

### Authentication Failures

**Symptoms:**
- "Authentication failed" or "Invalid API key" messages
- 401 or 403 HTTP status codes

**Possible Solutions:**
1. **Verify API Key:**
   - Check that the `N8N_API_KEY` in your `.env` file matches the one in n8n
   - Create a new API key if necessary

2. **Check API Key Permissions:**
   - Ensure the API key has appropriate scopes/permissions
   - Required scopes: `workflow:read workflow:write workflow:execute`

3. **n8n API Settings:**
   - Verify that API access is enabled in n8n settings
   - Check if there are IP restrictions on API access

## MCP Server Issues

### Server Crashes or Exits Unexpectedly

**Symptoms:**
- The MCP server stops running unexpectedly
- Error messages in logs or console output

**Possible Solutions:**
1. **Check Node.js Version:**
   - Ensure you're using Node.js 20 or later
   - Check with `node --version`

2. **Check Environment Variables:**
   - Ensure all required environment variables are set
   - Verify the format of the environment variables

3. **View Debug Logs:**
   - Set `DEBUG=true` in your `.env` file
   - Check the console output for detailed error messages

4. **Memory Issues:**
   - If running on a system with limited memory, increase available memory
   - Check for memory leaks or high consumption patterns

### AI Assistant Cannot Communicate with MCP Server

**Symptoms:**
- AI assistant reports it cannot connect to the MCP server
- Tools are not available in the assistant interface

**Possible Solutions:**
1. **Verify Server Registration:**
   - Ensure the server is properly registered with your AI assistant platform
   - Check the configuration settings for the MCP server in your assistant

2. **Server Running Check:**
   - Verify the MCP server is running
   - Check that it was started with the correct environment

3. **Restart Components:**
   - Restart the MCP server
   - Refresh the AI assistant interface
   - If using a managed AI assistant, check platform status

## Tool-Specific Issues

### Workflow Operations Fail

**Symptoms:**
- Cannot list, create, or update workflows
- Error messages about missing permissions

**Possible Solutions:**
1. **API Key Scope:**
   - Ensure your API key has `workflow:read` and `workflow:write` permissions
   - Create a new key with appropriate permissions if needed

2. **n8n Version:**
   - Check if your n8n version supports all the API endpoints being used
   - Update n8n to the latest version if possible

3. **Workflow Complexity:**
   - Complex workflows with custom nodes may not work correctly
   - Try with simpler workflows to isolate the issue

### Execution Operations Fail

**Symptoms:**
- Cannot execute workflows or retrieve execution data
- Execution starts but fails to complete

**Possible Solutions:**
1. **API Key Scope:**
   - Ensure your API key has the `workflow:execute` permission
   - Create a new key with appropriate permissions if needed

2. **Workflow Status:**
   - Check if the target workflow is active
   - Verify the workflow executes correctly in the n8n interface

3. **Workflow Inputs:**
   - Ensure all required inputs for workflow execution are provided
   - Check the format of input data

## Getting More Help

If you're still experiencing issues after trying these troubleshooting steps:

1. **Check GitHub Issues:**
   - Look for similar issues in the [GitHub repository](https://github.com/yourusername/n8n-mcp-server/issues)
   - Create a new issue with detailed information about your problem

2. **Submit Logs:**
   - Enable debug logging with `DEBUG=true`
   - Include relevant logs when seeking help

3. **Community Support:**
   - Ask in the n8n community forums
   - Check MCP-related discussion groups

```

--------------------------------------------------------------------------------
/src/tools/execution/run.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Run Execution via Webhook Tool Handler
 * 
 * This module provides a tool for running n8n workflows via webhooks.
 */

import axios from 'axios';
import { z } from 'zod';
import { ToolCallResult } from '../../types/index.js';
import { BaseExecutionToolHandler } from './base-handler.js';
import { N8nApiError } from '../../errors/index.js';
import { getEnvConfig } from '../../config/environment.js';
import { URL } from 'url';

/**
 * Webhook execution input schema
 */
const runWebhookSchema = z.object({
  workflowName: z.string().describe('Name of the workflow to execute (e.g., "hello-world")'),
  data: z.record(z.any()).optional().describe('Input data to pass to the webhook'),
  headers: z.record(z.string()).optional().describe('Additional headers to send with the request')
});

/**
 * Handler for the run_webhook tool
 */
export class RunWebhookHandler extends BaseExecutionToolHandler {
  /**
   * Tool definition for execution via webhook
   */
  public static readonly inputSchema = runWebhookSchema;

  /**
   * Extract N8N base URL from N8N API URL by removing /api/v1
   * @returns N8N base URL
   */
  private getN8nBaseUrl(): string {
    const config = getEnvConfig();
    const apiUrl = new URL(config.n8nApiUrl);
    
    // Remove /api/v1 if it exists in the path
    let path = apiUrl.pathname;
    if (path.endsWith('/api/v1') || path.endsWith('/api/v1/')) {
      path = path.replace(/\/api\/v1\/?$/, '');
    }
    
    // Create a new URL with the base path
    apiUrl.pathname = path;
    return apiUrl.toString();
  }

  /**
   * Validate and execute webhook call
   * 
   * @param args Tool arguments
   * @returns Tool call result
   */
  async execute(args: Record<string, any>): Promise<ToolCallResult> {
    return this.handleExecution(async (args) => {
      // Parse and validate arguments
      const params = runWebhookSchema.parse(args);
      
      // Get environment config for auth credentials
      const config = getEnvConfig();

      // Check if webhook credentials are provided, as they are required for this tool
      if (!config.n8nWebhookUsername || !config.n8nWebhookPassword) {
        throw new N8nApiError(
          'Webhook username and password are required for run_webhook tool. ' +
          'Please set N8N_WEBHOOK_USERNAME and N8N_WEBHOOK_PASSWORD environment variables.',
          400 // Bad Request, as it's a client-side configuration issue for this specific tool
        );
      }
      
      try {
        // Get the webhook URL with the proper prefix
        const baseUrl = this.getN8nBaseUrl();
        const webhookPath = `webhook/${params.workflowName}`;
        const webhookUrl = new URL(webhookPath, baseUrl).toString();
        
        // Prepare request config with basic auth from environment
        const requestConfig: any = {
          headers: {
            'Content-Type': 'application/json',
            ...(params.headers || {})
          },
          auth: {
            username: config.n8nWebhookUsername,
            password: config.n8nWebhookPassword
          }
        };

        // Make the request to the webhook
        const response = await axios.post(
          webhookUrl,
          params.data || {},
          requestConfig
        );

        // Return the webhook response
        return this.formatSuccess({
          status: response.status,
          statusText: response.statusText,
          data: response.data
        }, 'Webhook executed successfully');
      } catch (error) {
        // Handle error from the webhook request
        if (axios.isAxiosError(error)) {
          let errorMessage = `Webhook execution failed: ${error.message}`;
          
          if (error.response) {
            errorMessage = `Webhook execution failed with status ${error.response.status}: ${error.response.statusText}`;
            if (error.response.data) {
              return this.formatError(new N8nApiError(
                `${errorMessage}\n\n${JSON.stringify(error.response.data, null, 2)}`,
                error.response.status
              ));
            }
          }
          
          return this.formatError(new N8nApiError(errorMessage, error.response?.status || 500));
        }
        
        throw error; // Re-throw non-axios errors for the handler to catch
      }
    }, args);
  }
}

/**
 * Get the tool definition for run_webhook
 * 
 * @returns Tool definition object
 */
export function getRunWebhookToolDefinition() {
  return {
    name: 'run_webhook',
    description: 'Execute a workflow via webhook with optional input data',
    inputSchema: {
      type: 'object',
      properties: {
        workflowName: {
          type: 'string',
          description: 'Name of the workflow to execute (e.g., "hello-world")'
        },
        data: {
          type: 'object',
          description: 'Input data to pass to the webhook'
        },
        headers: {
          type: 'object',
          description: 'Additional headers to send with the request'
        }
      },
      required: ['workflowName']
    }
  };
}
```

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

```typescript
/**
 * Server Configuration
 * 
 * This module configures the MCP server with tools and resources
 * for n8n workflow management.
 */

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema
} from '@modelcontextprotocol/sdk/types.js';
import { getEnvConfig } from './environment.js';
import { setupWorkflowTools } from '../tools/workflow/index.js';
import { setupExecutionTools } from '../tools/execution/index.js';
import { setupResourceHandlers } from '../resources/index.js';
import { createApiService } from '../api/n8n-client.js';

// Import types
import { ToolCallResult } from '../types/index.js';

/**
 * Configure and return an MCP server instance with all tools and resources
 * 
 * @returns Configured MCP server instance
 */
export async function configureServer(): Promise<Server> {
  // Get validated environment configuration
  const envConfig = getEnvConfig();
  
  // Create n8n API service
  const apiService = createApiService(envConfig);
  
  // Verify n8n API connectivity
  try {
    console.error('Verifying n8n API connectivity...');
    await apiService.checkConnectivity();
    console.error(`Successfully connected to n8n API at ${envConfig.n8nApiUrl}`);
  } catch (error) {
    console.error('ERROR: Failed to connect to n8n API:', error instanceof Error ? error.message : error);
    throw error;
  }

  // Create server instance
  const server = new Server(
    {
      name: 'n8n-mcp-server',
      version: '0.1.0',
    },
    {
      capabilities: {
        resources: {},
        tools: {},
      },
    }
  );

  // Set up all request handlers
  setupToolListRequestHandler(server);
  setupToolCallRequestHandler(server);
  setupResourceHandlers(server, envConfig);

  return server;
}

/**
 * Set up the tool list request handler for the server
 * 
 * @param server MCP server instance
 */
function setupToolListRequestHandler(server: Server): void {
  server.setRequestHandler(ListToolsRequestSchema, async () => {
    // Combine tools from workflow and execution modules
    const workflowTools = await setupWorkflowTools();
    const executionTools = await setupExecutionTools();

    return {
      tools: [...workflowTools, ...executionTools],
    };
  });
}

/**
 * Set up the tool call request handler for the server
 * 
 * @param server MCP server instance
 */
function setupToolCallRequestHandler(server: Server): void {
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
    const toolName = request.params.name;
    const args = request.params.arguments || {};

    let result: ToolCallResult;

    try {
      // Handle "prompts/list" as a special case, returning an empty success response
      // This is to address client calls for a method not central to n8n-mcp-server's direct n8n integration.
      if (toolName === 'prompts/list') {
        return {
          content: [{ type: 'text', text: 'Prompts list acknowledged.' }], // Or an empty array: content: []
          isError: false,
        };
      }

      // Import handlers
      const { 
        ListWorkflowsHandler, 
        GetWorkflowHandler,
        CreateWorkflowHandler,
        UpdateWorkflowHandler,
        DeleteWorkflowHandler,
        ActivateWorkflowHandler,
        DeactivateWorkflowHandler
      } = await import('../tools/workflow/index.js');
      
      const {
        ListExecutionsHandler,
        GetExecutionHandler,
        DeleteExecutionHandler,
        RunWebhookHandler
      } = await import('../tools/execution/index.js');
      
      // Route the tool call to the appropriate handler
      if (toolName === 'list_workflows') {
        const handler = new ListWorkflowsHandler();
        result = await handler.execute(args);
      } else if (toolName === 'get_workflow') {
        const handler = new GetWorkflowHandler();
        result = await handler.execute(args);
      } else if (toolName === 'create_workflow') {
        const handler = new CreateWorkflowHandler();
        result = await handler.execute(args);
      } else if (toolName === 'update_workflow') {
        const handler = new UpdateWorkflowHandler();
        result = await handler.execute(args);
      } else if (toolName === 'delete_workflow') {
        const handler = new DeleteWorkflowHandler();
        result = await handler.execute(args);
      } else if (toolName === 'activate_workflow') {
        const handler = new ActivateWorkflowHandler();
        result = await handler.execute(args);
      } else if (toolName === 'deactivate_workflow') {
        const handler = new DeactivateWorkflowHandler();
        result = await handler.execute(args);
      } else if (toolName === 'list_executions') {
        const handler = new ListExecutionsHandler();
        result = await handler.execute(args);
      } else if (toolName === 'get_execution') {
        const handler = new GetExecutionHandler();
        result = await handler.execute(args);
      } else if (toolName === 'delete_execution') {
        const handler = new DeleteExecutionHandler();
        result = await handler.execute(args);
      } else if (toolName === 'run_webhook') {
        const handler = new RunWebhookHandler();
        result = await handler.execute(args);
      } else {
        throw new Error(`Unknown tool: ${toolName}`);
      }

      // Converting to MCP SDK expected format
      return {
        content: result.content,
        isError: result.isError,
      };
    } catch (error) {
      console.error(`Error handling tool call to ${toolName}:`, error);
      return {
        content: [
          {
            type: 'text',
            text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
          },
        ],
        isError: true,
      };
    }
  });
}

```

--------------------------------------------------------------------------------
/manual_verify_update.mjs:
--------------------------------------------------------------------------------

```
import { N8nApiClient } from './build/api/client.js';
import { getEnvConfig, loadEnvironmentVariables } from './build/config/environment.js';
import { N8nApiError } from './build/errors/index.js';

async function main() {
  console.log('Attempting to load environment configuration...');
  loadEnvironmentVariables(); // Load .env file if present and needed
  const config = getEnvConfig(); // Get validated config object

  if (!config.n8nApiUrl || !config.n8nApiKey) {
    console.error('Error: N8N_API_URL and/or N8N_API_KEY are not set.');
    console.error('Please set these environment variables to run this verification.');
    process.exit(1);
  }

  console.log(`N8N API URL: ${config.n8nApiUrl}`);
  console.log('N8N API Key: EXISTS (not printing value)');
  config.debug = true; // Enable debug logging for the client

  const client = new N8nApiClient(config);

  try {
    console.log('Checking connectivity...');
    await client.checkConnectivity();
    console.log('Connectivity check successful.');

    console.log('Fetching workflows to find one to update...');
    let workflows = await client.getWorkflows();

    if (!workflows || workflows.length === 0) {
      console.log('No workflows found. Cannot test update.');
      // If no workflows, try to create one, then update it.
      console.log('Attempting to create a dummy workflow for testing update...');
      const newWorkflowData = {
        name: 'Test Workflow for Update Verification',
        nodes: [
          {
            parameters: {},
            id: '0743771a-291a-4763-ab03-570546a05f70',
            name: 'When Webhook Called',
            type: 'n8n-nodes-base.webhook',
            typeVersion: 1,
            position: [480, 300],
            webhookId: 'test-webhook-id'
          }
        ],
        connections: {},
        active: false,
        settings: { executionOrder: 'v1' },
        tags: [] // Intentionally include tags to see if they are filtered
      };
      let createdWorkflow;
      try {
        createdWorkflow = await client.createWorkflow(newWorkflowData);
        console.log(`Successfully created workflow with ID: ${createdWorkflow.id}, Name: ${createdWorkflow.name}`);
        workflows.push(createdWorkflow); // Add to list to proceed with update
      } catch (createError) {
        console.error('Failed to create a dummy workflow:', createError);
        if (createError instanceof N8nApiError) {
          console.error(`N8nApiError Details: Status ${createError.status}, Message: ${createError.message}`);
          if (createError.cause) console.error('Cause:', createError.cause);
        }
        process.exit(1);
      }
    }

    if (!workflows || workflows.length === 0) {
        console.log('Still no workflows found after attempting creation. Cannot test update.');
        process.exit(0); // Exit gracefully, can't test.
    }

    const workflowToUpdate = workflows[0];
    const originalName = workflowToUpdate.name;
    const newName = `Updated - ${originalName} - ${Date.now()}`;

    console.log(`Attempting to update workflow ID: ${workflowToUpdate.id}, Original Name: "${originalName}"`);
    console.log(`New Name will be: "${newName}"`);

    // Construct the update payload. Include fields that should be stripped.
    const updatePayload = {
      ...workflowToUpdate, // Spread the existing workflow
      name: newName,       // Change the name
      // Explicitly include fields that should be removed by updateWorkflow
      id: workflowToUpdate.id,
      createdAt: workflowToUpdate.createdAt || '2023-01-01T00:00:00Z',
      updatedAt: workflowToUpdate.updatedAt || '2023-01-01T00:00:00Z',
      tags: workflowToUpdate.tags || [{ id: 'testtag', name: 'Test Tag' }]
    };

    // Remove nodes and connections if they are very large to avoid log clutter
    // and potential issues if they are not meant to be sent in full for simple updates.
    // The PR is about filtering metadata, not changing core workflow structure via update.
    delete updatePayload.nodes;
    delete updatePayload.connections;


    console.log('Workflow object before sending to updateWorkflow (with fields that should be stripped):', JSON.stringify(updatePayload, null, 2));

    const updatedWorkflow = await client.updateWorkflow(workflowToUpdate.id, updatePayload);

    if (updatedWorkflow.name === newName) {
      console.log(`SUCCESS: Workflow updated successfully! New name: "${updatedWorkflow.name}"`);
      console.log('Received updated workflow object:', JSON.stringify(updatedWorkflow, null, 2));

      // Optional: try to revert the name
      try {
        console.log(`Attempting to revert name for workflow ID: ${workflowToUpdate.id} to "${originalName}"`);
        await client.updateWorkflow(workflowToUpdate.id, { name: originalName });
        console.log(`Successfully reverted name to "${originalName}"`);
      } catch (revertError) {
        console.error('Failed to revert workflow name, but the main update test passed:', revertError);
      }

    } else {
      console.error(`FAILURE: Workflow name was not updated as expected. Expected: "${newName}", Got: "${updatedWorkflow.name}"`);
      process.exit(1);
    }

  } catch (error) {
    console.error('Manual verification script failed:');
    if (error instanceof N8nApiError) {
      console.error(`N8nApiError Details: Status ${error.status}, Message: ${error.message}`);
      if (error.cause) console.error('Cause:', error.cause);
    } else if (error.isAxiosError) {
      console.error('Axios Error:', error.message);
      if (error.response) {
        console.error('Response Status:', error.response.status);
        console.error('Response Data:', JSON.stringify(error.response.data, null, 2));
      }
    } else {
      console.error(error);
    }
    process.exit(1);
  }
}

main();

```

--------------------------------------------------------------------------------
/docs/development/architecture.md:
--------------------------------------------------------------------------------

```markdown
# Architecture

This document describes the architectural design of the n8n MCP Server.

## Overview

The n8n MCP Server follows a layered architecture pattern that separates concerns and promotes maintainability. The main architectural layers are:

1. **Transport Layer**: Handles communication with AI assistants via the Model Context Protocol
2. **API Client Layer**: Interacts with the n8n API
3. **Tools Layer**: Implements executable operations as MCP tools
4. **Resources Layer**: Provides data access through URI-based resources
5. **Configuration Layer**: Manages environment variables and server settings
6. **Error Handling Layer**: Provides consistent error management and reporting

## System Components

![Architecture Diagram](../images/architecture.png.placeholder)

### Entry Point

The server entry point is defined in `src/index.ts`. This file:

1. Initializes the configuration from environment variables
2. Creates and configures the MCP server instance
3. Registers tool and resource handlers
4. Connects to the transport layer (typically stdio)

### Configuration

The configuration layer (`src/config/`) handles:

- Loading environment variables
- Validating required configuration
- Providing typed access to configuration values

The main configuration component is the `Environment` class, which validates and manages environment variables like `N8N_API_URL` and `N8N_API_KEY`.

### API Client

The API client layer (`src/api/`) provides a clean interface for interacting with the n8n API. It includes:

- `N8nClient`: The main client that encapsulates communication with n8n
- API-specific functionality divided by resource type (workflows, executions)
- Authentication handling using the n8n API key

The client uses Axios for HTTP requests and includes error handling specific to the n8n API responses.

### MCP Tools

The tools layer (`src/tools/`) implements the executable operations exposed to AI assistants. Each tool follows a common pattern:

1. A tool definition that specifies name, description, and input schema
2. A handler function that processes input parameters and executes the operation
3. Error handling for validation and execution errors

Tools are categorized by resource type:

- Workflow tools: Create, list, update, delete, activate, and deactivate workflows
- Execution tools: Run, list, and manage workflow executions

Each tool is designed to be independently testable and maintains a clean separation of concerns.

### MCP Resources

The resources layer (`src/resources/`) provides data access through URI-based templates. Resources are divided into two categories:

1. **Static Resources** (`src/resources/static/`): Fixed resources like workflow listings
2. **Dynamic Resources** (`src/resources/dynamic/`): Parameterized resources like specific workflow details

Each resource implements:
- URI pattern matching
- Content retrieval
- Error handling
- Response formatting

### Error Handling

The error handling layer (`src/errors/`) provides consistent error management across the server. It includes:

- Custom error types that map to MCP error codes
- Error translation functions to convert n8n API errors to MCP errors
- Common error patterns and handling strategies

## Data Flow

A typical data flow through the system:

1. AI assistant sends a request via stdin to the MCP server
2. Server routes the request to the appropriate handler based on the request type
3. Handler validates input and delegates to the appropriate tool or resource
4. Tool/resource uses the n8n API client to interact with n8n
5. Response is processed, formatted, and returned via stdout
6. AI assistant receives and processes the response

## Key Design Principles

### 1. Separation of Concerns

Each component has a single responsibility, making the codebase easier to understand, test, and extend.

### 2. Type Safety

TypeScript interfaces and types are used extensively to ensure type safety and provide better developer experience.

### 3. Error Handling

Comprehensive error handling ensures that errors are caught at the appropriate level and translated into meaningful messages for AI assistants.

### 4. Testability

The architecture supports unit testing by keeping components loosely coupled and maintaining clear boundaries between layers.

### 5. Extensibility

New tools and resources can be added without modifying existing code, following the open-closed principle.

## Implementation Patterns

### Factory Pattern

Used for creating client instances and tool handlers based on configuration.

### Adapter Pattern

The n8n API client adapts the n8n API to the internal representation used by the server.

### Strategy Pattern

Different resource handlers implement a common interface but provide different strategies for retrieving and formatting data.

### Decorator Pattern

Used to add cross-cutting concerns like logging and error handling to base functionality.

## Core Files and Their Purposes

| File | Purpose |
|------|---------|
| `src/index.ts` | Main entry point, initializes and configures the server |
| `src/config/environment.ts` | Manages environment variables and configuration |
| `src/api/n8n-client.ts` | Main client for interacting with the n8n API |
| `src/tools/workflow/handler.ts` | Handles workflow-related tool requests |
| `src/tools/execution/handler.ts` | Handles execution-related tool requests |
| `src/resources/index.ts` | Registers and manages resource handlers |
| `src/resources/dynamic/workflow.ts` | Provides access to specific workflow resources |
| `src/resources/static/workflows.ts` | Provides access to workflow listings |
| `src/errors/index.ts` | Defines and manages error types and handling |

## Extension Points

To extend the server with new capabilities:

1. **Adding a new tool**: Create a new handler in the appropriate category under `src/tools/` and register it in the main server setup
2. **Adding a new resource**: Create a new resource handler in `src/resources/` and register it in the resource manager
3. **Supporting new n8n API features**: Extend the API client in `src/api/` to support new API endpoints or features

For detailed instructions on extending the server, see [Extending the Server](./extending.md).

```

--------------------------------------------------------------------------------
/docs/api/dynamic-resources.md:
--------------------------------------------------------------------------------

```markdown
# Dynamic Resources

This page documents the dynamic resources available in the n8n MCP Server.

## Overview

Dynamic resources are parameterized URIs that allow access to specific n8n data based on identifiers such as workflow IDs or execution IDs. These resources follow the URI template format defined in RFC 6570, with parameters enclosed in curly braces.

## Available Resource Templates

### n8n://workflow/{id}

Provides detailed information about a specific workflow.

**URI Template:** `n8n://workflow/{id}`

**Parameters:**
- `id` (required): The ID of the workflow to retrieve

**Description:** Returns comprehensive information about a specific workflow, including its nodes, connections, and settings.

**Example Usage:**

```javascript
const resource = await accessMcpResource('n8n-mcp-server', 'n8n://workflow/1234abc');
```

**Response:**

```javascript
{
  "workflow": {
    "id": "1234abc",
    "name": "Email Processing Workflow",
    "active": true,
    "createdAt": "2025-03-01T12:00:00.000Z",
    "updatedAt": "2025-03-02T14:30:00.000Z",
    "nodes": [
      {
        "id": "node1",
        "name": "Start",
        "type": "n8n-nodes-base.start",
        "position": [100, 200],
        "parameters": {}
      },
      {
        "id": "node2",
        "name": "Email Trigger",
        "type": "n8n-nodes-base.emailTrigger",
        "position": [300, 200],
        "parameters": {
          "inbox": "support",
          "domain": "example.com"
        }
      }
    ],
    "connections": {
      "node1": {
        "main": [
          [
            {
              "node": "node2",
              "type": "main",
              "index": 0
            }
          ]
        ]
      }
    },
    "settings": {
      "saveExecutionProgress": true,
      "saveManualExecutions": true,
      "timezone": "America/New_York"
    }
  }
}
```

### n8n://executions/{workflowId}

Provides a list of executions for a specific workflow.

**URI Template:** `n8n://executions/{workflowId}`

**Parameters:**
- `workflowId` (required): The ID of the workflow whose executions to retrieve

**Description:** Returns a list of execution records for the specified workflow, sorted by most recent first.

**Example Usage:**

```javascript
const resource = await accessMcpResource('n8n-mcp-server', 'n8n://executions/1234abc');
```

**Response:**

```javascript
{
  "executions": [
    {
      "id": "exec789",
      "workflowId": "1234abc",
      "status": "success",
      "startedAt": "2025-03-12T16:30:00.000Z",
      "finishedAt": "2025-03-12T16:30:05.000Z",
      "mode": "manual"
    },
    {
      "id": "exec456",
      "workflowId": "1234abc",
      "status": "error",
      "startedAt": "2025-03-11T14:20:00.000Z",
      "finishedAt": "2025-03-11T14:20:10.000Z",
      "mode": "manual"
    }
  ],
  "count": 2,
  "pagination": {
    "hasMore": false
  }
}
```

### n8n://execution/{id}

Provides detailed information about a specific execution.

**URI Template:** `n8n://execution/{id}`

**Parameters:**
- `id` (required): The ID of the execution to retrieve

**Description:** Returns comprehensive information about a specific execution, including its status, inputs, outputs, and execution path.

**Example Usage:**

```javascript
const resource = await accessMcpResource('n8n-mcp-server', 'n8n://execution/exec789');
```

**Response:**

```javascript
{
  "execution": {
    "id": "exec789",
    "workflowId": "1234abc",
    "workflowName": "Email Processing Workflow",
    "status": "success",
    "startedAt": "2025-03-12T16:30:00.000Z",
    "finishedAt": "2025-03-12T16:30:05.000Z",
    "mode": "manual",
    "data": {
      "resultData": {
        "runData": {
          "node1": [
            {
              "startTime": "2025-03-12T16:30:00.000Z",
              "endTime": "2025-03-12T16:30:01.000Z",
              "executionStatus": "success",
              "data": {
                "json": {
                  "started": true
                }
              }
            }
          ],
          "node2": [
            {
              "startTime": "2025-03-12T16:30:01.000Z",
              "endTime": "2025-03-12T16:30:05.000Z",
              "executionStatus": "success",
              "data": {
                "json": {
                  "subject": "Test Email",
                  "body": "This is a test",
                  "from": "[email protected]"
                }
              }
            }
          ]
        }
      },
      "executionData": {
        "nodeExecutionOrder": ["node1", "node2"],
        "waitingNodes": [],
        "waitingExecutionData": []
      }
    }
  }
}
```

### n8n://workflow/{id}/active

Provides information about whether a specific workflow is active.

**URI Template:** `n8n://workflow/{id}/active`

**Parameters:**
- `id` (required): The ID of the workflow to check

**Description:** Returns the active status of a specific workflow.

**Example Usage:**

```javascript
const resource = await accessMcpResource('n8n-mcp-server', 'n8n://workflow/1234abc/active');
```

**Response:**

```javascript
{
  "workflowId": "1234abc",
  "active": true
}
```

## Content Types

All dynamic resources return JSON content with the MIME type `application/json`.

## Error Handling

Dynamic resources can return the following errors:

| HTTP Status | Description |
|-------------|-------------|
| 400 | Bad Request - Invalid parameter in URI |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - API key does not have permission to access this resource |
| 404 | Not Found - The requested resource does not exist |
| 500 | Internal Server Error - An unexpected error occurred on the n8n server |

## Parameter Format

When using dynamic resources, parameters must be properly formatted:

1. **Workflow IDs**: Must be valid n8n workflow IDs (typically alphanumeric)
2. **Execution IDs**: Must be valid n8n execution IDs (typically alphanumeric)

## Best Practices

- Validate resource URIs before accessing them
- Handle possible 404 errors when accessing resources by ID
- Cache resource data when appropriate to reduce API calls
- Use specific resources (like `n8n://workflow/{id}/active`) for single properties when you don't need the entire resource
- Check workflow status before performing operations that require an active workflow

```

--------------------------------------------------------------------------------
/docs/api/workflow-tools.md:
--------------------------------------------------------------------------------

```markdown
# Workflow Tools

This page documents the tools available for managing n8n workflows.

## Overview

Workflow tools allow AI assistants to manage n8n workflows, including creating, retrieving, updating, deleting, activating, and deactivating workflows. These tools provide a natural language interface to n8n's workflow management capabilities.

## Available Tools

### workflow_list

Lists all workflows with optional filtering.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "active": {
      "type": "boolean",
      "description": "Filter workflows by active status"
    }
  },
  "required": []
}
```

**Example Usage:**

```javascript
// List all workflows
const result = await useWorkflowList({});

// List only active workflows
const activeWorkflows = await useWorkflowList({ active: true });

// List only inactive workflows
const inactiveWorkflows = await useWorkflowList({ active: false });
```

**Response:**

```javascript
[
  {
    "id": "1234abc",
    "name": "Test Workflow 1",
    "active": true,
    "createdAt": "2025-03-01T12:00:00.000Z",
    "updatedAt": "2025-03-02T14:30:00.000Z"
  },
  {
    "id": "5678def",
    "name": "Test Workflow 2",
    "active": false,
    "createdAt": "2025-03-01T12:00:00.000Z",
    "updatedAt": "2025-03-12T10:15:00.000Z"
  }
]
```

### workflow_get

Retrieves a specific workflow by ID.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The ID of the workflow to retrieve"
    }
  },
  "required": ["id"]
}
```

**Example Usage:**

```javascript
const workflow = await useWorkflowGet({ id: "1234abc" });
```

**Response:**

```javascript
{
  "id": "1234abc",
  "name": "Test Workflow 1",
  "active": true,
  "createdAt": "2025-03-01T12:00:00.000Z",
  "updatedAt": "2025-03-02T14:30:00.000Z",
  "nodes": [
    // Detailed node configuration
  ],
  "connections": {
    // Connection configuration
  },
  "settings": {
    // Workflow settings
  }
}
```

### workflow_create

Creates a new workflow.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Name of the workflow"
    },
    "nodes": {
      "type": "array",
      "description": "Array of node configurations"
    },
    "connections": {
      "type": "object",
      "description": "Connection configuration"
    },
    "active": {
      "type": "boolean",
      "description": "Whether the workflow should be active"
    },
    "settings": {
      "type": "object",
      "description": "Workflow settings"
    }
  },
  "required": ["name"]
}
```

**Example Usage:**

```javascript
const newWorkflow = await useWorkflowCreate({
  name: "New Workflow",
  active: true,
  nodes: [
    {
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "position": [100, 200],
      "parameters": {}
    }
  ],
  connections: {}
});
```

**Response:**

```javascript
{
  "id": "new123",
  "name": "New Workflow",
  "active": true,
  "createdAt": "2025-03-12T15:30:00.000Z",
  "updatedAt": "2025-03-12T15:30:00.000Z",
  "nodes": [
    {
      "name": "Start",
      "type": "n8n-nodes-base.start",
      "position": [100, 200],
      "parameters": {}
    }
  ],
  "connections": {}
}
```

### workflow_update

Updates an existing workflow.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the workflow to update"
    },
    "name": {
      "type": "string",
      "description": "New name for the workflow"
    },
    "nodes": {
      "type": "array",
      "description": "Updated array of node configurations"
    },
    "connections": {
      "type": "object",
      "description": "Updated connection configuration"
    },
    "active": {
      "type": "boolean",
      "description": "Whether the workflow should be active"
    },
    "settings": {
      "type": "object",
      "description": "Updated workflow settings"
    }
  },
  "required": ["id"]
}
```

**Example Usage:**

```javascript
const updatedWorkflow = await useWorkflowUpdate({
  id: "1234abc",
  name: "Updated Workflow Name",
  active: false
});
```

**Response:**

```javascript
{
  "id": "1234abc",
  "name": "Updated Workflow Name",
  "active": false,
  "createdAt": "2025-03-01T12:00:00.000Z",
  "updatedAt": "2025-03-12T15:45:00.000Z",
  "nodes": [
    // Existing node configuration
  ],
  "connections": {
    // Existing connection configuration
  }
}
```

### workflow_delete

Deletes a workflow.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the workflow to delete"
    }
  },
  "required": ["id"]
}
```

**Example Usage:**

```javascript
await useWorkflowDelete({ id: "1234abc" });
```

**Response:**

```javascript
{
  "success": true
}
```

### workflow_activate

Activates a workflow.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the workflow to activate"
    }
  },
  "required": ["id"]
}
```

**Example Usage:**

```javascript
const activatedWorkflow = await useWorkflowActivate({ id: "1234abc" });
```

**Response:**

```javascript
{
  "id": "1234abc",
  "name": "Test Workflow 1",
  "active": true,
  "createdAt": "2025-03-01T12:00:00.000Z",
  "updatedAt": "2025-03-12T16:00:00.000Z"
}
```

### workflow_deactivate

Deactivates a workflow.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "ID of the workflow to deactivate"
    }
  },
  "required": ["id"]
}
```

**Example Usage:**

```javascript
const deactivatedWorkflow = await useWorkflowDeactivate({ id: "1234abc" });
```

**Response:**

```javascript
{
  "id": "1234abc",
  "name": "Test Workflow 1",
  "active": false,
  "createdAt": "2025-03-01T12:00:00.000Z",
  "updatedAt": "2025-03-12T16:15:00.000Z"
}
```

## Error Handling

All workflow tools can return the following errors:

| Error | Description |
|-------|-------------|
| Authentication Error | The provided API key is invalid or missing |
| Not Found Error | The requested workflow does not exist |
| Validation Error | The input parameters are invalid or incomplete |
| Permission Error | The API key does not have permission to perform the operation |
| Server Error | An unexpected error occurred on the n8n server |

## Best Practices

- Use `workflow_list` to discover available workflows before performing operations
- Validate workflow IDs before attempting to update or delete workflows
- Check workflow status (active/inactive) before attempting activation/deactivation
- Include only the necessary fields when updating workflows to avoid unintended changes

```

--------------------------------------------------------------------------------
/docs/examples/basic-examples.md:
--------------------------------------------------------------------------------

```markdown
# Basic Examples

This page provides basic examples of using the n8n MCP Server with AI assistants.

## Listing Workflows

### User Prompt

"Show me all the workflows in my n8n instance."

### Assistant Actions

```javascript
// The assistant uses the workflow_list tool
const result = await useMcpTool('n8n-mcp-server', 'workflow_list', {});

// The assistant formats and presents the results
if (result.length === 0) {
  return "You don't have any workflows in your n8n instance yet.";
} else {
  let response = "Here are your workflows:\n\n";
  result.forEach(workflow => {
    response += `- ${workflow.name} (ID: ${workflow.id}) - ${workflow.active ? 'Active' : 'Inactive'}\n`;
  });
  return response;
}
```

## Getting Workflow Details

### User Prompt

"Tell me about my 'Email Processing' workflow."

### Assistant Actions

```javascript
// First list all workflows to find the one with matching name
const workflows = await useMcpTool('n8n-mcp-server', 'workflow_list', {});

// Find the workflow with a name containing "Email Processing"
const emailWorkflow = workflows.find(workflow => 
  workflow.name.toLowerCase().includes('email processing')
);

if (!emailWorkflow) {
  return "I couldn't find a workflow named 'Email Processing'. Would you like to see a list of all your workflows?";
}

// Get detailed information about the workflow
const details = await useMcpTool('n8n-mcp-server', 'workflow_get', {
  id: emailWorkflow.id
});

// Format and present the workflow details
return `
# Email Processing Workflow

**Status:** ${details.active ? 'Active' : 'Inactive'}
**Created:** ${new Date(details.createdAt).toLocaleString()}
**Last Updated:** ${new Date(details.updatedAt).toLocaleString()}

## Nodes (${details.nodes.length})
${details.nodes.map(node => `- ${node.name} (${node.type})`).join('\n')}

## Settings
${Object.entries(details.settings || {}).map(([key, value]) => `- ${key}: ${value}`).join('\n')}
`;
```

## Executing a Workflow

### User Prompt

"Run my 'Data Sync' workflow."

### Assistant Actions

```javascript
// First list all workflows to find the one with matching name
const workflows = await useMcpTool('n8n-mcp-server', 'workflow_list', {});

// Find the workflow with a name containing "Data Sync"
const syncWorkflow = workflows.find(workflow => 
  workflow.name.toLowerCase().includes('data sync')
);

if (!syncWorkflow) {
  return "I couldn't find a workflow named 'Data Sync'. Would you like to see a list of all your workflows?";
}

// Check if the workflow is active
if (!syncWorkflow.active) {
  return "The 'Data Sync' workflow is currently inactive. Would you like me to activate it before running it?";
}

// Execute the workflow
const execution = await useMcpTool('n8n-mcp-server', 'execution_run', {
  workflowId: syncWorkflow.id
});

return `
I've started the 'Data Sync' workflow. 

**Execution ID:** ${execution.executionId}
**Status:** ${execution.status}
**Started At:** ${new Date(execution.startedAt).toLocaleString()}

You can check the execution status later by asking me about it.
`;
```

## Checking Execution Status

### User Prompt

"Check the status of my last workflow execution."

### Assistant Actions

```javascript
// Get recent executions (this example assumes we've stored the last execution ID in context)
// In a real scenario, you might need to list recent executions first
const lastExecutionId = "exec123"; // In practice, this would come from context or a previous response

// Get execution details
const execution = await useMcpTool('n8n-mcp-server', 'execution_get', {
  executionId: lastExecutionId
});

// Format and present the execution status
let response = `
# Execution Status for ${execution.workflowName}

**Status:** ${execution.status}
**Started:** ${new Date(execution.startedAt).toLocaleString()}
`;

if (execution.finishedAt) {
  response += `**Finished:** ${new Date(execution.finishedAt).toLocaleString()}\n`;
  response += `**Duration:** ${Math.round((new Date(execution.finishedAt) - new Date(execution.startedAt)) / 1000)} seconds\n`;
}

response += "\n## Execution Path\n";
execution.data.executionData.nodeExecutionOrder.forEach(nodeName => {
  response += `- ${nodeName}\n`;
});

return response;
```

## Activating/Deactivating a Workflow

### User Prompt

"Deactivate my 'Daily Report' workflow."

### Assistant Actions

```javascript
// First list all workflows to find the one with matching name
const workflows = await useMcpTool('n8n-mcp-server', 'workflow_list', {});

// Find the workflow with a name containing "Daily Report"
const reportWorkflow = workflows.find(workflow => 
  workflow.name.toLowerCase().includes('daily report')
);

if (!reportWorkflow) {
  return "I couldn't find a workflow named 'Daily Report'. Would you like to see a list of all your workflows?";
}

// Check if the workflow is already inactive
if (!reportWorkflow.active) {
  return "The 'Daily Report' workflow is already inactive.";
}

// Deactivate the workflow
const result = await useMcpTool('n8n-mcp-server', 'workflow_deactivate', {
  id: reportWorkflow.id
});

return `
I've deactivated the 'Daily Report' workflow. 

It was last updated on ${new Date(result.updatedAt).toLocaleString()}.

You can reactivate it at any time by asking me to activate it.
`;
```

## Creating a Simple Workflow

### User Prompt

"Create a new workflow that sends me a daily email reminder."

### Assistant Actions

```javascript
// Create a new workflow
const newWorkflow = await useMcpTool('n8n-mcp-server', 'workflow_create', {
  name: "Daily Email Reminder",
  active: false, // Start inactive until it's configured properly
  nodes: [
    {
      name: "Schedule Trigger",
      type: "n8n-nodes-base.scheduleTrigger",
      position: [100, 300],
      parameters: {
        rule: {
          interval: [
            {
              field: "hours",
              minuteInterval: 24
            }
          ]
        }
      }
    },
    {
      name: "Send Email",
      type: "n8n-nodes-base.emailSend",
      position: [300, 300],
      parameters: {
        to: "{{$json.email}}",
        subject: "Daily Reminder",
        text: "This is your daily reminder!"
      }
    }
  ],
  connections: {
    "Schedule Trigger": {
      main: [
        [
          {
            node: "Send Email",
            type: "main",
            index: 0
          }
        ]
      ]
    }
  }
});

return `
I've created a new workflow called "Daily Email Reminder".

This workflow is currently **inactive** and needs configuration:
1. You'll need to enter your email address in the "Send Email" node
2. You might want to customize the schedule and email content

You can view and edit this workflow in the n8n interface (ID: ${newWorkflow.id}), and then ask me to activate it when you're ready.
`;
```

These examples demonstrate the basic operations you can perform with the n8n MCP Server. For more complex scenarios, see the [Advanced Scenarios](./advanced-scenarios.md) page.

```

--------------------------------------------------------------------------------
/docs/api/execution-tools.md:
--------------------------------------------------------------------------------

```markdown
# Execution Tools

This page documents the tools available for managing n8n workflow executions.

## Overview

Execution tools allow AI assistants to execute n8n workflows and manage execution records. These tools provide a natural language interface to n8n's execution capabilities, allowing workflows to be run, monitored, and their results accessed.

## Available Tools

### run_webhook

Executes a workflow via webhook with optional input data.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "workflowName": {
      "type": "string",
      "description": "Name of the workflow to execute (e.g., \"hello-world\")"
    },
    "data": {
      "type": "object",
      "description": "Input data to pass to the webhook"
    },
    "headers": {
      "type": "object",
      "description": "Additional headers to send with the request"
    }
  },
  "required": ["workflowName"]
}
```

**Example Usage:**

```javascript
// Execute webhook with data
const webhookResult = await useRunWebhook({
  workflowName: "hello-world",
  data: {
    prompt: "Good morning!"
  }
});

// Execute webhook with additional headers
const webhookWithHeaders = await useRunWebhook({
  workflowName: "hello-world",
  data: {
    prompt: "Hello with custom header"
  },
  headers: {
    "X-Custom-Header": "CustomValue"
  }
});
```

**Response:**

```javascript
{
  "status": 200,
  "statusText": "OK",
  "data": {
    // Response data from the webhook
  }
}
```

**Note:** 
- Authentication for the webhook is automatically handled using the environment variables `N8N_WEBHOOK_USERNAME` and `N8N_WEBHOOK_PASSWORD`.
- The tool automatically prefixes the `workflowName` with `webhook/` to create the full webhook path. For example, if you provide `hello-world` as the workflow name, the tool will call `{baseUrl}/webhook/hello-world`.


### execution_run

Executes a workflow with optional input data.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "workflowId": {
      "type": "string",
      "description": "ID of the workflow to execute"
    },
    "data": {
      "type": "object",
      "description": "Input data to pass to the workflow"
    },
    "waitForCompletion": {
      "type": "boolean",
      "description": "Whether to wait for the workflow to complete before returning",
      "default": false
    }
  },
  "required": ["workflowId"]
}
```

**Example Usage:**

```javascript
// Execute without waiting
const execution = await useExecutionRun({
  workflowId: "1234abc"
});

// Execute with input data
const executionWithData = await useExecutionRun({
  workflowId: "1234abc",
  data: {
    firstName: "John",
    lastName: "Doe",
    email: "[email protected]"
  }
});

// Execute and wait for completion
const completedExecution = await useExecutionRun({
  workflowId: "1234abc",
  waitForCompletion: true
});
```

**Response (when waitForCompletion: false):**

```javascript
{
  "executionId": "exec789",
  "status": "running",
  "startedAt": "2025-03-12T16:30:00.000Z"
}
```

**Response (when waitForCompletion: true):**

```javascript
{
  "executionId": "exec789",
  "status": "success", // Or "error" if execution failed
  "startedAt": "2025-03-12T16:30:00.000Z",
  "finishedAt": "2025-03-12T16:30:05.000Z",
  "data": {
    // Output data from the workflow execution
  }
}
```

### execution_get

Retrieves details of a specific execution.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "executionId": {
      "type": "string",
      "description": "ID of the execution to retrieve"
    }
  },
  "required": ["executionId"]
}
```

**Example Usage:**

```javascript
const execution = await useExecutionGet({
  executionId: "exec789"
});
```

**Response:**

```javascript
{
  "id": "exec789",
  "workflowId": "1234abc",
  "workflowName": "Test Workflow 1",
  "status": "success", // Or "error", "running", "waiting", etc.
  "startedAt": "2025-03-12T16:30:00.000Z",
  "finishedAt": "2025-03-12T16:30:05.000Z",
  "mode": "manual",
  "data": {
    "resultData": {
      // Output data from the workflow execution
    },
    "executionData": {
      // Detailed execution data including node inputs/outputs
    },
    "metadata": {
      // Execution metadata
    }
  }
}
```

### execution_list

Lists executions for a specific workflow.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "workflowId": {
      "type": "string",
      "description": "ID of the workflow to get executions for"
    },
    "limit": {
      "type": "number",
      "description": "Maximum number of executions to return",
      "default": 20
    },
    "status": {
      "type": "string",
      "description": "Filter by execution status",
      "enum": ["success", "error", "running", "waiting"]
    }
  },
  "required": ["workflowId"]
}
```

**Example Usage:**

```javascript
// List all executions for a workflow
const executions = await useExecutionList({
  workflowId: "1234abc"
});

// List with limit
const limitedExecutions = await useExecutionList({
  workflowId: "1234abc",
  limit: 5
});

// List only successful executions
const successfulExecutions = await useExecutionList({
  workflowId: "1234abc",
  status: "success"
});
```

**Response:**

```javascript
[
  {
    "id": "exec789",
    "workflowId": "1234abc",
    "status": "success",
    "startedAt": "2025-03-12T16:30:00.000Z",
    "finishedAt": "2025-03-12T16:30:05.000Z",
    "mode": "manual"
  },
  {
    "id": "exec456",
    "workflowId": "1234abc",
    "status": "error",
    "startedAt": "2025-03-11T14:20:00.000Z",
    "finishedAt": "2025-03-11T14:20:10.000Z",
    "mode": "manual"
  }
]
```

### execution_delete

Deletes an execution record.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "executionId": {
      "type": "string",
      "description": "ID of the execution to delete"
    }
  },
  "required": ["executionId"]
}
```

**Example Usage:**

```javascript
await useExecutionDelete({
  executionId: "exec789"
});
```

**Response:**

```javascript
{
  "success": true
}
```

### execution_stop

Stops a running execution.

**Input Schema:**

```json
{
  "type": "object",
  "properties": {
    "executionId": {
      "type": "string",
      "description": "ID of the execution to stop"
    }
  },
  "required": ["executionId"]
}
```

**Example Usage:**

```javascript
await useExecutionStop({
  executionId: "exec789"
});
```

**Response:**

```javascript
{
  "success": true,
  "status": "cancelled",
  "stoppedAt": "2025-03-12T16:32:00.000Z"
}
```

## Execution Status Codes

Executions can have the following status codes:

| Status | Description |
|--------|-------------|
| `running` | The execution is currently in progress |
| `success` | The execution completed successfully |
| `error` | The execution failed with an error |
| `waiting` | The execution is waiting for a webhook or other event |
| `cancelled` | The execution was manually stopped |

## Error Handling

All execution tools can return the following errors:

| Error | Description |
|-------|-------------|
| Authentication Error | The provided API key is invalid or missing |
| Not Found Error | The requested workflow or execution does not exist |
| Validation Error | The input parameters are invalid or incomplete |
| Permission Error | The API key does not have permission to perform the operation |
| Server Error | An unexpected error occurred on the n8n server |

## Best Practices

- Check if a workflow is active before attempting to execute it
- Use `waitForCompletion: true` for short-running workflows, but be cautious with long-running workflows
- Always handle potential errors when executing workflows
- Filter executions by status to find problematic runs
- Use execution IDs from `execution_run` responses to track workflow progress

```
Page 1/2FirstPrevNextLast