This project is an MCP (Model Context Protocol) connector that sits between an MCP client (like Claude Desktop) and an n8n MCP server.
It handles Microsoft OAuth, stores the Microsoft token in memory, dynamically discovers n8n workflows, and exposes those workflows as MCP tools.
- Hosts an MCP HTTP endpoint at
http://localhost:<MCP_PORT>/mcp(default8787) - Implements OAuth endpoints for MCP clients:
/.well-known/oauth-authorization-server/.well-known/oauth-protected-resource/mcp/authorize/token/oauth/callback
- Uses Microsoft OAuth to obtain an access token
- Connects to an upstream n8n MCP server (
N8N_MCP) - Registers one MCP tool per discovered n8n workflow
- Injects Microsoft
access_tokeninto supported workflow input shapes before execution
- Node.js 18+
- An Azure app registration (for Microsoft OAuth)
- A reachable n8n MCP endpoint
- (Recommended for local OAuth callback testing) a public tunnel URL such as ngrok
You need an Azure App Registration so this connector can sign users in with Microsoft and exchange auth codes for tokens.
- Go to Azure Portal → Microsoft Entra ID → App registrations → New registration.
- Give the app a name (for example:
n8n-middleman-mcp). - Choose supported account type:
- Accounts in any organizational directory and personal Microsoft accounts for most flexible local testing (matches
MS_TENANT_ID=common), or - your org-only option if you want single-tenant behavior.
- Accounts in any organizational directory and personal Microsoft accounts for most flexible local testing (matches
- Set a Redirect URI (Web):
https://<your-public-host>/oauth/callback- Example:
https://your-public-url.ngrok-free.app/oauth/callback
- Create the app registration.
Then configure the app:
- In API permissions, add delegated permissions you need.
- Minimum used by default in this repo:
User.Read - Keep
openid,profile, andoffline_accessin requested scopes.
- Minimum used by default in this repo:
- Click Grant admin consent if your tenant policies require it.
- Copy Application (client) ID and set it as
MS_CLIENT_IDin.env. - (Optional/confidential clients) Create a Client secret under Certificates & secrets and set
MS_CLIENT_SECRET.
Environment values to align with Azure:
MS_CLIENT_ID= Azure Application (client) IDMS_TENANT_ID=common(multi-tenant/personal) or your tenant GUID/domainMCP_PUBLIC_URLmust match the host used in your Azure redirect URI
Important: if
MCP_PUBLIC_URLchanges (for example a new ngrok URL), update the Azure Redirect URI to the new.../oauth/callbackURL.
npm installCreate a .env file in the repo root.
| Variable | Description |
|---|---|
MS_CLIENT_ID |
Azure app client ID used for Microsoft OAuth |
| Variable | Description |
|---|---|
MCP_PUBLIC_URL |
Public base URL used in OAuth metadata and callbacks (for example an ngrok URL) |
N8N_MCP |
Upstream n8n MCP endpoint URL |
| Variable | Default | Description |
|---|---|---|
MS_TENANT_ID |
common |
Microsoft tenant |
MS_SCOPES |
openid profile offline_access User.Read |
OAuth scopes requested from Microsoft |
MS_CLIENT_SECRET |
unset | Needed for confidential client flows |
N8N_MCP_AUTH_TOKEN |
unset | Bearer token for n8n MCP if your upstream requires auth |
N8N_DEFAULT_WEBHOOK_URL |
unset | Optional n8n webhook URL (reserved/auxiliary) |
MCP_PORT |
8787 |
Local server port |
MCP_USER |
default-user |
In-memory user key for stored Microsoft tokens |
Example:
MS_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
MS_TENANT_ID=common
MS_SCOPES="openid profile offline_access User.Read"
MCP_PUBLIC_URL=https://your-public-url.ngrok-free.app
MCP_PORT=8787
N8N_MCP=https://your-n8n-host/mcp
N8N_MCP_AUTH_TOKEN=your_n8n_mcp_tokennpm startYou should see:
External MCP connector listening at http://localhost:8787/mcp
- MCP client requests authorization.
- Connector redirects to Microsoft login.
- Microsoft returns to
/oauth/callback. - Connector exchanges code for Microsoft tokens.
- Connector issues MCP auth code/access token/refresh token back to the MCP client.
- MCP client calls
/mcpwith bearer token.
At tool execution time, the connector ensures a valid Microsoft access token and forwards workflow execution to n8n MCP.
Current storage is in-memory (
Mapobjects). Restarting the process clears sessions and tokens.
On startup, if N8N_MCP is configured, the connector:
- Calls upstream
search_workflows - Calls
get_workflow_detailsper workflow - Registers each workflow as an MCP tool named like:
n8n_workflow_<slugified_name>_<workflow_id_prefix>
Workflow description metadata can include JSON hints for expected inputs and an optional return_immediately flag.
For each discovered workflow, the connector parses workflow.description using this pattern:
- First line is treated as human-readable summary text.
- Remaining lines are treated as JSON (optional).
If the JSON parses successfully, the connector interprets it as either:
- a plain object of input hints, or
- an object with a
varsobject plus optional top-level flags.
Supported parsing behavior:
return_immediately(boolean or string) enables async fire-and-forget execution.- All other keys become MCP tool input fields (as optional args) with descriptions from their values.
- If
varsexists, keys are read fromvars(exceptreturn_immediately, which is read from the top level).
Example description format:
Create a calendar summary from user events
{
"vars": {
"startDate": "ISO start date",
"endDate": "ISO end date",
"timezone": "IANA timezone string"
},
"return_immediately": true
}
Notes:
- Invalid JSON in the metadata block is safely ignored; the connector falls back to generic
inputshandling. - When input hints are present, provided args are mapped into webhook/form/chat inputs automatically and
access_tokenis injected where applicable.
You can verify your upstream n8n MCP setup directly:
npm run test:n8n-mcpOptional test env vars:
TEST_TOOL_NAME– tool to invoke after listing toolsTEST_TOOL_ARGS– JSON string of arguments for that toolVERBOSE_TOOL_SCHEMAS=1– prints full tool schema details
-
Missing required environment variable: MS_CLIENT_ID- Add
MS_CLIENT_IDto.env
- Add
-
401 / missing bearer token at
/mcp- Complete OAuth flow through your MCP client first
-
OAuth discovery errors requiring
MCP_PUBLIC_URL- Set
MCP_PUBLIC_URLto a valid public base URL
- Set
-
Cannot connect to n8n MCP
- Check
N8N_MCPURL - If protected, set/rotate
N8N_MCP_AUTH_TOKEN
- Check
npm start– start connector servernpm run test:n8n-mcp– test upstream n8n MCP connectivity and tools