Wire an AI Agent to n8n via MCP

Connect an AI coding agent to n8n workflows using Docker's MCP Toolkit.

Introduction

30 Second Summary

Think about all the repetitive tasks you do on your computer every day. Now imagine telling an AI assistant to build and modify automations for those tasks just by describing what you want in plain English.

In this project, you will wire an AI coding agent to a local workflow automation tool so it can create and edit live automations through natural language commands. You'll also build a Python microservice that parses dates from task descriptions without any AI involvement.

What You'll Build

You can open your terminal, tell your AI agent to modify a live workflow, and watch the change appear in n8n's visual editor in real time.

By the end of this project, you'll have:

  • An MCP connection between OpenCode and n8n so you can type a natural-language command and watch the AI list, create, or modify workflows in your local automation instance.
  • A webhook workflow that deliberately delays responses and returns clean, formatted JSON. Your AI agent builds this for you through Model Context Protocol instead of you dragging nodes by hand.
  • A Python NLP microservice that turns messy text like "Call dentist tomorrow at 3pm" into structured date JSON instantly, with zero AI tokens burned.
  • Secret Mission: Add confidence scoring and recurring pattern detection to your date parser so it handles edge cases like "every Monday" and "daily standup."

Are there any prerequisites?

This project assumes you already have Node.js (v20.19+), Docker Desktop (installed and running), OpenCode, and Python 3.14 on your machine. You should also have basic familiarity with PowerShell.

Step 1 walks you through installing and configuring everything else you need.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters. This is your moment to commit to the goal before any hands-on work begins.

Set Up n8n and Docker MCP Toolkit

Before your AI agent can manage workflows, it needs something to manage. n8n is a visual workflow automation tool that runs locally and exposes an API for programmatic control.

In this step, you will install n8n, start it on your machine, and then wire up Docker's MCP Toolkit so your AI agent has a gateway to reach n8n.

In this step, get ready to:
  • Install n8n globally and start it on localhost.
  • Enable Docker MCP Toolkit and add the n8n MCP server.
  • Verify both services are running and ready for the next step.
Install n8n globally and start it

n8n runs as a Node.js process on your machine. Installing it globally makes the n8n command available from any terminal session.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type PowerShell and press Enter to open it.
  • Install n8n globally by running this command:
npm install n8n -g

This will take a minute or two as npm downloads n8n and its dependencies. When it finishes, you will return to your terminal prompt with no error messages.

Seeing permission errors?

Make sure you are running PowerShell as a regular user, not as Administrator. If you see an EACCES or permission-denied error, close the terminal, reopen PowerShell without elevated privileges, and try again.

Help me fix npm permission errors on Windows.

  • Start n8n by running this command:
n8n start

You will see n8n initialize and print a message confirming the editor is available at http://localhost:5678. Leave this terminal running for the rest of the project.

Why leave the terminal running?

n8n runs as a foreground process. Closing this terminal or pressing Ctrl+C stops the server. You will open new terminal tabs for commands later.

  • Open your browser and navigate to http://localhost:5678.

You should see the n8n owner account setup screen asking for your email, first name, last name, and password.

  • Fill in your email address.
  • Enter your first and last name.
  • Choose a password.
  • Click Next to complete the setup.

After finishing the setup prompts, you will land on the n8n dashboard. This is where your workflows live.

Browser showing connection refused?

Switch back to the PowerShell terminal where you ran n8n start. Make sure it is still running and shows the editor URL. If it exited, run n8n start again.

Help me troubleshoot n8n not loading in the browser.

Enable Docker MCP Toolkit and add the n8n MCP server

The Docker MCP Toolkit acts as a gateway that lets AI agents call MCP servers running in containers. You will add the n8n MCP server so that OpenCode can talk to your n8n instance.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Docker Desktop and press Enter to open it.
  • Click the gear icon to open Settings.
  • Select Beta features in the left sidebar.
  • Toggle Enable Docker MCP Toolkit on.
  • Click Apply & restart.

After Docker restarts, you will see a new MCP Toolkit entry in the left sidebar.

  • Click MCP Toolkit in the sidebar.
  • Click the Catalog tab.
  • Search for n8n.
  • Find the server labeled mcp/n8n by czlonkowski and click Add to add it to your default profile.

Now you need to tell the MCP server where your n8n instance lives.

  • Open the n8n MCP server's Configuration tab.
  • Set the N8N_API_URL environment variable to http://host.docker.internal:5678.
  • Leave N8N_API_KEY blank for now. You will set it in a later step.

Why host.docker.internal instead of localhost?

The MCP server runs inside a Docker container. From inside a container, localhost points to the container itself, not your machine. The special hostname host.docker.internal tells Docker to route traffic to your host machine where n8n is running.

Verify both services are running

Before you move on, confirm that both pieces of infrastructure are in place.

  • Switch to your browser and refresh http://localhost:5678. Confirm you see your n8n dashboard.
  • Switch back to Docker Desktop and click MCP Toolkit in the sidebar. Confirm the n8n MCP server appears in your profile.

The n8n server may show a configuration warning badge. This is expected because you have not set the API key yet.

Don't see the MCP server in your profile?

Go back to the Catalog tab and search for n8n again. Make sure you clicked Add on the mcp/n8n entry by czlonkowski. After adding, switch to the main profile view to see it listed.

Help me find the n8n MCP server in Docker MCP Toolkit.

Your automation engine is live and the MCP gateway is pointed at it. Next up, you will build your first webhook workflow to see how data flows through n8n.

Build Your First Webhook Workflow

Your n8n instance is live and waiting for its first automation. Before you let an AI agent control it, you need to understand what n8n actually does from the inside.

In this step, you will build a webhook workflow by hand. This teaches you how nodes connect and how data flows through them. The raw response you get back is intentionally ugly. It sets up a real problem to solve.

In this step, get ready to:
  • Create a webhook workflow in n8n.
  • Trigger the webhook from PowerShell and observe the raw response.
  • Understand why the output needs improvement.
Create the webhook workflow in n8n

A webhook is a URL that waits for incoming HTTP requests. When something hits that URL, n8n triggers a workflow. You will create one now.

  • In your browser, return to the n8n dashboard at http://localhost:5678.
  • Click Add workflow in the top-right corner.
  • A blank canvas opens. Click the workflow name at the top and rename it to My First Webhook.
  • Click the + button on the canvas to add a node.
  • Search for Webhook and select it from the results.
  • In the Webhook node settings panel, set HTTP Method to POST.
  • Set Path to hello.
  • Click Listen for Test Event to activate the test webhook.

What is Listen for Test Event?

n8n gives every Webhook node two URLs: a Test URL and a Production URL. Clicking Listen for Test Event registers the test webhook so it can receive requests. The test webhook stays active for 120 seconds.

While active, any data that hits the test URL gets displayed directly in the editor. This is how you debug workflows before publishing them.

Your canvas now shows a single Webhook trigger node. The status indicator changes to show it is listening. You have 120 seconds to send a test request before it times out.

Trigger it from PowerShell and observe the raw response

The webhook is listening. Now you will hit it with an HTTP request from PowerShell and see exactly what n8n sends back. Before you run the command, think about what you expect the response to look like. A clean JSON object with just your message? Something else?

  • Open a new PowerShell tab (your first tab is still running n8n).
  • Send a test request to your webhook by running this command:
Invoke-WebRequest -Uri "http://localhost:5678/webhook-test/hello" -Method POST -Body '{"message":"ping"}' -ContentType "application/json"

Look at what comes back. Instead of a clean response with just your message, you get raw n8n execution metadata. The response includes internal fields like executionId, nested body objects, and headers you did not ask for.

Why is the output so messy?

By default, n8n returns everything it knows about the incoming request. This includes HTTP headers, query parameters, the raw body, and internal execution details. It works, but it is not production-ready.

This is the problem: the output has no formatting and no timing control. You will fix this later without touching the n8n editor yourself.

Not getting a response?

If PowerShell returns a connection error, check that the n8n tab is still running. If it crashed, run n8n start again in that tab.

If you get a 404 error, the test webhook may have timed out (it only listens for 120 seconds). Switch back to n8n and click Listen for Test Event again, then re-run the PowerShell command within 120 seconds.

Help me troubleshoot my n8n webhook test request.

Save and understand what you built
  • Switch back to the n8n browser tab.
  • Press Ctrl+S to save the workflow.

Your workflow canvas shows one Webhook trigger node. Data flows left to right in n8n. Right now there is only one entry point and no processing. Everything that comes in goes straight back out with all of n8n's internal metadata attached.

What did you just build?

This is the simplest possible n8n workflow: a single trigger that accepts HTTP requests. It is the foundation that everything else builds on. Nodes you add later will sit to the right of this trigger, processing data before it reaches the output.

Your webhook workflow is saved and functional. Next, you will connect your AI agent to n8n so it can discover this workflow and improve its output programmatically.

Connect OpenCode to n8n via MCP

You have a webhook workflow running and you've seen what n8n produces on its own. Now imagine editing that workflow without ever touching the n8n editor.

Right now, OpenCode has no idea your n8n instance exists. In this step, you'll wire them together through Docker's MCP gateway so OpenCode can discover and operate on your workflows programmatically.

In this step, get ready to:
  • Generate an n8n API key for MCP authentication.
  • Configure the Docker MCP Toolkit with your key.
  • Test the connection by asking OpenCode to list your workflows.
Generate an n8n API key

The MCP server needs to authenticate with your n8n instance. An API key acts as the credential that proves the server is allowed to read and modify your workflows.

  • In n8n, click the gear icon (bottom-left) to open Settings.
  • Click n8n API in the settings menu.
  • Click Create an API key.
  • Set the label to MCP Access.
  • Choose no expiration for the key lifetime.
  • Copy the generated key. It starts with n8n_api_.

Save the key somewhere safe

The API key may only be fully visible at creation time. Paste it into a temporary notepad or keep the window open until you've entered it in Docker Desktop in the next substep.

What does this key do?

This key grants programmatic access to n8n's REST API. The MCP server will include it in every request (via the X-N8N-API-KEY header) so n8n knows the request is authorized.

Configure the MCP server with your API key

The n8n MCP server in Docker Desktop still has a blank N8N_API_KEY field from earlier. You need to give it the key you just generated so it can authenticate with your running n8n instance.

  • Switch back to Docker Desktop.
  • In the sidebar, click MCP Toolkit.
  • Find the n8n server in your default profile and click it.
  • Open the Configuration tab.
  • Paste your API key into the N8N_API_KEY field.
  • Click Save or Apply to confirm the change.

The server should now show a green status or no warning badge. This confirms n8n MCP server can authenticate with your instance.

Still seeing a warning badge?

  • Make sure n8n is still running in your original PowerShell tab. If you accidentally closed it, run n8n start again.
  • Confirm N8N_API_URL is set to http://host.docker.internal:5678 (not localhost). Docker containers cannot reach the host via localhost.
  • Double-check that the API key you pasted has no leading or trailing spaces.

Help me troubleshoot my Docker MCP Toolkit n8n server configuration.

Connect OpenCode and test the connection

OpenCode needs to know about Docker's MCP gateway. This connection is configured in a JSON file at ~/.config/opencode/opencode.json. Docker MCP Toolkit may have already added this entry for you.

  • Open a new PowerShell tab.
  • Check whether the config file already has the MCP entry by running:
Get-Content ~/.config/opencode/opencode.json

Look for a section called MCP_DOCKER in the output.

✔️ I see the MCP_DOCKER entry

Your config is already set up. Move on to launching OpenCode below.

ⓧ I don't see it or the file doesn't exist

You need to create or update the config file. The file lives at ~/.config/opencode/opencode.json.

  • Create the directory and file by running:
New-Item -ItemType Directory -Force -Path ~/.config/opencode | Out-Null
Set-Content -Path ~/.config/opencode/opencode.json -Value @'
{
  "mcp": {
    "MCP_DOCKER": {
      "type": "local",
      "command": ["docker", "mcp", "gateway", "run"],
      "enabled": true
    }
  }
}
'@

What does this config do?

The MCP_DOCKER entry tells OpenCode to route MCP tool calls through the docker mcp gateway run command. Docker's gateway then forwards those calls to whichever MCP servers you've enabled in your Docker MCP Toolkit profile.

  • Verify the file was written correctly by running:
Get-Content ~/.config/opencode/opencode.json

You should see the JSON with the MCP_DOCKER section.

  • Launch OpenCode by running:
opencode

OpenCode's terminal interface opens. You can type natural-language prompts and it will use the MCP tools available through Docker's gateway.

Before you test, predict what you expect to happen. If OpenCode is properly connected to n8n through MCP, what should it be able to tell you about your workflows?

  • Type the following prompt into OpenCode:
list my n8n workflows

OpenCode calls the n8n MCP tools and returns your workflow. You should see the name "My First Webhook" along with its workflow ID.

OpenCode not returning your workflow?

  • Make sure Docker Desktop is running. The MCP gateway needs Docker to route tool calls.
  • Confirm n8n is still running on port 5678 in your original PowerShell tab.
  • Check that your opencode.json has the MCP_DOCKER entry with "enabled": true.
  • If OpenCode cannot find any MCP tools, try exiting (type /quit) and relaunching it after saving the config changes.

Why can't OpenCode find my n8n workflows through MCP?

Your AI agent is now connected to your live n8n instance. Next up, you'll put it to work by having it surgically improve your webhook workflow through nothing but natural language.

Let the AI Refine Your Workflow

Your AI agent can now see your n8n instance. In the last step, you proved OpenCode can list your workflows through MCP.

Now comes the payoff. Your "My First Webhook" workflow returns raw execution metadata with internal fields you never asked for. Instead of fixing this by hand in the n8n editor, you will tell OpenCode to do it through natural language.

In this step, get ready to:
  • Add a 3-second Wait node to your workflow via an AI command.
  • Add a Code node that formats the response via an AI command.
  • Test the improved workflow and confirm clean, formatted output.
Ask OpenCode to add a Wait node

A Wait node adds a deliberate delay to a workflow. In production, teams use it for rate limiting, polling intervals, and debouncing. Here, you will use it to prove your AI agent can insert nodes into a live workflow.

  • Switch back to the PowerShell tab where OpenCode is running.
  • Type a prompt like the following:

"Add a 3-second Wait node to my 'My First Webhook' workflow, placed between the Webhook trigger and the end of the workflow."

  • Watch OpenCode use the MCP tools to read the workflow structure, then update it with the Wait node inserted.
  • Switch to your browser and open your n8n dashboard at http://localhost:5678.
  • Open the "My First Webhook" workflow.
  • Confirm that a Wait node now appears on the canvas between the Webhook trigger and the end of the workflow.

Refresh if you don't see it

If the canvas still shows only the Webhook node, refresh the page. OpenCode modifies the workflow through the API, and the n8n editor does not always live-update.

What just happened?

OpenCode read your workflow's node structure through the n8n MCP server, figured out where to insert the new node, and pushed the updated workflow back. You did not click a single button in the n8n UI.

Ask OpenCode to add a Code node

The Wait node controls timing. Now you need a Code node to control output. This node will strip away all the raw execution metadata and return only three fields.

  • Switch back to OpenCode in your PowerShell tab.
  • Type a prompt like the following:

"Add a Code node after the Wait node in 'My First Webhook' that formats the response. It should return only a JSON object with three fields: status set to 'success', received set to the message from the webhook body, and processed_at set to the current ISO timestamp."

  • Watch OpenCode update the workflow again through MCP.
  • Switch back to the n8n editor in your browser and refresh the page.
  • Confirm you now see three nodes in sequence on the canvas: Webhook > Wait > Code.

OpenCode didn't add the node?

If OpenCode reports an error or the canvas does not show the Code node, try rephrasing your prompt to be more specific. Mention the workflow name exactly as "My First Webhook" and explicitly state that the Code node goes after the Wait node.

If the MCP connection dropped, restart OpenCode and try again. The Docker MCP gateway occasionally needs a reconnection.

Why can't OpenCode modify my workflow?

Test the improved workflow

Your workflow now has timing control and output formatting. Time to prove it works end to end.

  • In the n8n editor, click on the Webhook node on the canvas.
  • Click Listen for test event to activate the test webhook.

Before you run the test command, think back to Step 2. What do you expect to be different this time? How long will the response take, and what fields do you expect in the body?

  • Open a new PowerShell tab and run the same test request from earlier:
Invoke-WebRequest -Uri "http://localhost:5678/webhook-test/hello" -Method POST -Body '{"message":"ping"}' -ContentType "application/json"

You will notice a 3-second pause before the response arrives. That is the Wait node doing its job.

The response body now contains only clean, formatted JSON with three fields:

{
  "status": "success",
  "received": "ping",
  "processed_at": "2026-07-26T10:15:30.000Z"
}

What changed from Step 2?

In Step 2, the response came back instantly with raw execution metadata, nested body objects, and headers you never asked for. Now the Wait node adds a deliberate 3-second delay and the Code node strips everything down to exactly the three fields you specified.

You made this improvement without touching the n8n editor. Your AI agent surgically edited a live workflow through MCP. That is the core value of connecting an AI agent to your automation tools.

Still seeing raw metadata?

Make sure you clicked Listen for test event on the Webhook node before running the PowerShell command. The test webhook only activates when n8n is listening.

If the Code node exists but the output still looks wrong, open the Code node in n8n and check that it returns an object with status, received, and processed_at fields. If it does not, ask OpenCode to fix it by describing the exact output shape you want.

Help me debug my n8n webhook response

You just used natural language to surgically improve a live automation workflow. Next up, you will build a Python microservice that proves when a purpose-built library beats burning AI tokens.

Build the NLP Date Parser Microservice

In the previous step, you proved that your AI agent can surgically edit a live workflow. That power is real. But not every automation problem needs an LLM.

Extracting dates from natural language like "tomorrow at 3pm" or "next Friday" is a solved problem. The dateparser library handles 200+ languages, relative dates, and time zones for $0 per request with zero latency. In this step, you will build a Python microservice that does this, then wire it into n8n to create a full task-parsing pipeline.

In this step, get ready to:
  • Build a Python HTTP microservice that parses dates from natural language.
  • Create an n8n workflow that calls your Python service via HTTP.
  • Test the full pipeline with real task descriptions.
Create the Python microservice

Your date parser will be a standalone HTTP server using Python's standard library. It receives a task string, extracts the date, and returns structured JSON.

  • Open a new PowerShell tab (keep the n8n terminal running in its own tab).
  • Create a project folder and set up a virtual environment by running these commands:
mkdir ~/n8n-date-parser
cd ~/n8n-date-parser
python -m venv .venv
./.venv/Scripts/Activate.ps1

Your prompt should now show (.venv) at the beginning, confirming the virtual environment is active.

Don't see (.venv) in your prompt?

Make sure you ran the activation script with the correct path. On PowerShell 7, you may need to run Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned first if scripts are blocked.

help me activate my Python virtual environment in PowerShell

  • Install the date parsing library by running:
pip install dateparser==1.4.1

You should see pip download and install dateparser along with its dependencies, ending with a "Successfully installed" message.

Why dateparser instead of an LLM?

The dateparser library supports 200+ language locales, relative dates ("in 2 hours", "tomorrow"), and timezone abbreviations. It returns results instantly and deterministically.

An LLM would be slower, non-deterministic, and cost tokens for every request. When a purpose-built library solves the problem perfectly, reaching for AI is overengineering.

  • Create a file called server.py inside your n8n-date-parser folder. Open it in your preferred text editor.
  • Add the imports and HTTP handler class by pasting this code at the top of server.py:
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import re
from datetime import datetime

import dateparser


class TaskHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        # Read the incoming JSON body
        content_length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(content_length)
        data = json.loads(body)

        # Extract the task text and parse it
        task_text = data.get("task", "")
        result = parse_task(task_text)

        # Send the parsed result back as JSON
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(json.dumps(result, indent=2).encode())

    def log_message(self, format, *args):
        print(f"[{datetime.now().strftime('%H:%M:%S')}] {args[0]}")

What does this code do?

  • TaskHandler extends Python's built-in HTTP server to handle POST requests.
  • do_POST reads the request body, parses it as JSON, calls parse_task() (which you will write next), and returns the result.
  • log_message overrides the default logging to show clean timestamps.
  • Add the core parsing function below the class by pasting this code next:

def parse_task(task_text):
    # Use dateparser to find a date in the text
    parsed_date = dateparser.parse(
        task_text,
        settings={"PREFER_DATES_FROM": "future"}
    )

    if parsed_date:
        date_str = parsed_date.strftime("%Y-%m-%dT%H:%M:%S")
        task_name = extract_task_name(task_text, parsed_date)
    else:
        date_str = None
        task_name = task_text.strip()

    return {
        "task": task_name,
        "due_date": date_str,
        "original": task_text
    }

What does parse_task do?

  • dateparser.parse() scans the text for any date-like expression and converts it to a Python datetime object.
  • PREFER_DATES_FROM set to "future" means "tomorrow" resolves to tomorrow's date, not yesterday's.
  • The function returns a dictionary with the cleaned task name, the parsed date as an ISO string, and the original input.
  • Save server.py and verify the module loads correctly by running:
python -c "from server import TaskHandler, parse_task; print('Module loads OK')"

You should see Module loads OK printed. This confirms your imports and class definitions have no syntax errors.

Seeing a ModuleNotFoundError?

If the error mentions dateparser, make sure your virtual environment is still active (you should see (.venv) in your prompt). If not, run ./.venv/Scripts/Activate.ps1 again.

help me fix a ModuleNotFoundError for dateparser in my Python virtual environment

  • Add the task name extraction function and the server startup code below parse_task:

def extract_task_name(text, parsed_date):
    # Common time-related phrases to strip from the task name
    time_keywords = [
        "tomorrow", "today", "tonight", "yesterday",
        "next week", "next month", "next friday", "next monday",
        "next tuesday", "next wednesday", "next thursday",
        "next saturday", "next sunday",
        "this morning", "this afternoon", "this evening",
        "in an hour", "in 2 hours", "in 30 minutes",
        "at noon", "at midnight",
    ]

    cleaned = text
    for keyword in time_keywords:
        cleaned = re.sub(re.escape(keyword), "", cleaned, flags=re.IGNORECASE)

    # Remove patterns like "at 3pm" or "at 10:30am"
    cleaned = re.sub(r"\bat\s+\d{1,2}(:\d{2})?\s*(am|pm)?\b", "", cleaned, flags=re.IGNORECASE)
    cleaned = re.sub(r"\s{2,}", " ", cleaned).strip()

    if cleaned:
        return cleaned
    return text.strip()


if __name__ == "__main__":
    server = HTTPServer(("localhost", 8000), TaskHandler)
    print("NLP Date Parser running on http://localhost:8000")
    print("Send POST requests with JSON body: {\"task\": \"your task text\"}")
    print("Press Ctrl+C to stop.")
    server.serve_forever()

What does this code do?

  • extract_task_name() strips time-related phrases from the input so you get a clean task name ("Call dentist" instead of "Call dentist tomorrow at 3pm").
  • It uses regex to catch patterns like "at 3pm" or "at 10:30am" that the keyword list does not cover.
  • The if __name__ == "__main__" block starts the server on port 8000 when you run the file directly.
  • Save server.py and start your microservice by running:
python server.py

You should see three lines of output confirming the server is running on http://localhost:8000.

Seeing an error when starting the server?

If you see NameError: name 'extract_task_name' is not defined, make sure you pasted the extract_task_name function ABOVE the if __name__ block, not below it.

If port 8000 is already in use, check for other processes with netstat -ano | findstr :8000 and stop them.

help me fix an error when starting my Python HTTP server on port 8000

  • Test your microservice directly by opening a second PowerShell tab and running:
Invoke-WebRequest -Uri "http://localhost:8000" -Method POST -Body '{"task":"Call dentist tomorrow at 3pm"}' -ContentType "application/json" | Select-Object -ExpandProperty Content

You should see a JSON response with "task": "Call dentist" and a due_date containing tomorrow's date as an ISO timestamp.

Getting a connection refused error?

Make sure the server is still running in your other PowerShell tab. You should see NLP Date Parser running on http://localhost:8000 in that tab. If you accidentally closed it, activate your venv again and rerun python server.py.

help me connect to my Python HTTP server running on localhost:8000 from PowerShell

✔️ Awesome, I've got everything!

Great. Double check you have saved server.py and that your server is running.

ⓧ I'd like to double check the full code

Your server.py should contain these three sections in order. Scroll up and confirm each is present:

  • Imports and the TaskHandler class (handles POST requests, reads JSON, calls parse_task, returns the result).
  • The parse_task function (uses dateparser.parse() with PREFER_DATES_FROM: future, returns a dict with task, due_date, and original).
  • The extract_task_name function (strips time phrases from input) and the if __name__ == "__main__" block (starts server on port 8000).
Create the n8n workflow that calls the Python service

Now you will create a second workflow in n8n that accepts task descriptions via webhook and routes them to your Python microservice for parsing.

  • Switch back to n8n in your browser at http://localhost:5678.
  • Click Add workflow in the top-right corner to create a new workflow.
  • Name the workflow Task Date Parser.
  • Click the + button on the canvas, search for Webhook, and add it.
  • In the Webhook node settings, set HTTP Method to POST and Path to parse-task.
  • Click the + button on the Webhook node's output to add a new node. Search for HTTP Request and add it.
  • In the HTTP Request node settings, set Method to POST and URL to http://localhost:8000.
  • Under Body, set the body content type to JSON. Add a parameter with name task and value set to the expression {{ $json.body.task }} (this passes the task field from the incoming webhook request to your Python service).
  • Click the + button on the HTTP Request node's output. Search for Respond to Webhook and add it.
  • In the Respond to Webhook node settings, set Respond With to All Incoming Items.
  • Save the workflow with Ctrl+S.

What does this workflow do?

Your workflow has three nodes forming a pipeline. The Webhook node receives task descriptions via HTTP. The HTTP Request node forwards them to your Python microservice on port 8000. The Respond to Webhook node returns the parsed result back to the original caller.

This pattern (webhook receives input, HTTP node calls a microservice, response node returns the result) is a common integration pattern for connecting external services to n8n.

Test the full pipeline

Before you send the test request, think about what you expect to happen. The request goes from PowerShell to n8n, then from n8n to your Python service, then back through both.

  • In n8n, click Listen for test event on the Webhook node to activate the test listener.
  • Before you run the test command, predict: will you get back raw n8n metadata (like in Step 2), or a clean parsed result? Why?
  • In your PowerShell tab (not the one running the Python server), send a test task by running:
Invoke-WebRequest -Uri "http://localhost:5678/webhook-test/parse-task" -Method POST -Body '{"task":"Call dentist tomorrow at 3pm"}' -ContentType "application/json" | Select-Object -ExpandProperty Content

You should see a clean JSON response containing the task name separated from a parsed ISO date string. The task field shows "Call dentist" and due_date contains tomorrow's date in YYYY-MM-DDTHH:MM:SS format.

Why clean output this time?

Unlike your first webhook in Step 2 (which returned raw execution metadata), this workflow has a Respond to Webhook node that controls exactly what gets sent back. The output is clean because you designed the pipeline to return only the Python service's parsed result.

  • Try a few more inputs to see the parser handle different date expressions. Run each one:
Invoke-WebRequest -Uri "http://localhost:5678/webhook-test/parse-task" -Method POST -Body '{"task":"Submit report next Friday"}' -ContentType "application/json" | Select-Object -ExpandProperty Content
Invoke-WebRequest -Uri "http://localhost:5678/webhook-test/parse-task" -Method POST -Body '{"task":"Team standup in 2 hours"}' -ContentType "application/json" | Select-Object -ExpandProperty Content
Invoke-WebRequest -Uri "http://localhost:5678/webhook-test/parse-task" -Method POST -Body '{"task":"Buy groceries this evening"}' -ContentType "application/json" | Select-Object -ExpandProperty Content

Each response returns instantly with a parsed date and cleaned task name. No tokens burned. No API costs. Deterministic results every time.

Getting an empty due_date or an error?

If due_date is null, check that your Python server is still running in its PowerShell tab. The n8n HTTP Request node silently fails if the target server is down.

If you see an n8n error about the HTTP Request node, verify the URL is set to http://localhost:8000 (not host.docker.internal). Your n8n runs on the host, not in Docker, so it can reach localhost directly.

help me debug my n8n HTTP Request node failing to reach my Python server on localhost:8000

You now have a working integration pattern: a webhook receives natural language, an HTTP node routes it to a purpose-built microservice, and the result flows back cleanly. Next up, you will take this further with a secret mission that makes your parser production-ready.

Secret mission

Add Confidence Scoring and Recurring Pattern Detection

Your date parser handles single events well, but real-world tasks are messier. "Weekly standup" and "every Monday morning" imply recurrence, not a one-time date. Can you teach your parser to tell the difference and report how confident it is?

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally, so there are no ongoing costs.

Resources you used:

  • n8n installed globally via npm (stores data in ~/.n8n/ using a local SQLite database).
  • Docker MCP Toolkit with the n8n MCP server (mcp/n8n by czlonkowski) in your default profile.
  • Python virtual environment and project files at ~/n8n-date-parser/.
  • n8n API key (local only, stored inside the ~/.n8n/ database).

Keep everything running

No action needed. Choose this if you are still actively building or plan to extend this project soon.

  • n8n stays installed globally. Start it anytime by running n8n start in PowerShell.
  • The Docker MCP Toolkit and n8n MCP server remain configured and ready for OpenCode.
  • Your Python virtual environment at ~/n8n-date-parser/.venv stays on disk. Reactivate it with .\n8n-date-parser\.venv\Scripts\Activate.ps1 when you need it.

Pause - I'll come back to this later

Stop running processes to free up memory and ports. Your files and config stay intact for next time.

  • In the PowerShell tab running n8n, press Ctrl+C to stop the n8n server.
  • In the PowerShell tab running your Python server, press Ctrl+C to stop it.
  • In Docker Desktop, go to MCP Toolkit and disable the n8n MCP server in your profile (toggle it off).
  • Deactivate your Python virtual environment by running:
deactivate

Everything stays installed. When you return, start n8n with n8n start, re-enable the MCP server in Docker Desktop, and reactivate your virtual environment.

Delete - I don't want to use this again

Remove all project resources and start fresh. This cannot be undone.

  • Stop n8n and the Python server if they are still running (Ctrl+C in each terminal).
  • Uninstall n8n globally by running:
npm uninstall n8n -g
  • Remove the n8n data folder (contains your workflows, credentials, and the API key) by running:
Remove-Item -Recurse -Force ~/.n8n
  • Remove the Python project folder (includes the virtual environment and server.py) by running:
Remove-Item -Recurse -Force ~/n8n-date-parser
  • In Docker Desktop, go to MCP Toolkit, find the n8n MCP server in your profile, and click Remove to delete it from your catalog.

That's a Wrap!

That's a Wrap!

Nice work! You just built a local AI-powered workflow automation lab where you can type a natural-language command and watch it surgically edit a live workflow running on your machine.

You've learned how to:

  • Connected OpenCode to a local n8n instance via Docker MCP Toolkit, giving your AI agent the ability to discover, create, and modify workflows through natural language.
  • Used your AI agent to add Wait and Code nodes to a live webhook workflow through MCP, turning raw execution metadata into clean, delayed, formatted output without touching the n8n editor.
  • Built a Python NLP date parser microservice using dateparser that extracts due dates from natural language at zero cost per request, demonstrating when a purpose-built library beats burning AI tokens.
  • Secret Mission: Added confidence scoring and recurring pattern detection to handle edge cases like "every Monday" and "daily standup", making your date parser production-worthy.

Ready to quiz yourself?