Skip to content

feat(mcp): serve n8n-skills markdown via MCP Resources#793

Merged
czlonkowski merged 2 commits into
mainfrom
feat/mcp-skills-resources
May 18, 2026
Merged

feat(mcp): serve n8n-skills markdown via MCP Resources#793
czlonkowski merged 2 commits into
mainfrom
feat/mcp-skills-resources

Conversation

@czlonkowski

Copy link
Copy Markdown
Owner

Summary

Adds a SkillResourceRegistry that mirrors UIAppRegistry to expose the seven n8n-mcp skill bundles (~36 markdown files from the n8n-skills repo) through MCP Resources under a new skill://n8n-mcp/{name}/{file} URI scheme. The server already wired ListResources/ReadResource for UI apps at ui://n8n-mcp/{id} — both schemes now coexist in the same handlers, with a new ListResourceTemplates handler advertising the two URI templates.

The skill markdown is brought in via npm run sync:skills, which copies from a sibling n8n-skills/skills/ checkout (overridable via N8N_SKILLS_SOURCE) into data/skills/. The copy is committed so the npm artifact and Docker image ship the skills without requiring the sibling repo on the build host.

Why

The n8n-skills repo ships only as a Claude Code plugin. That reaches Claude Code users with the plugin installed; every other MCP client — Cursor, Claude Desktop without plugins, the OpenAI Agents SDK, custom agents — had no path to discover or read the same content even though they all consume n8n-mcp. MCP Resources is the standard surface for on-demand markdown context, so a parallel skill:// namespace lets every MCP client reach the same skill bundle the plugin provides.

This is complementary, not a replacement: Claude Code users still get the better UX via the plugin (auto-loaded SKILL frontmatter, description-based triggering via the Skill tool). Other clients now get the content via resources/list + resources/read.

Test plan

  • npm run typecheck — clean
  • npm test -- tests/unit/mcp/skills/registry.test.ts — 15/15 passing
  • npm run test:unit — 4854 passing, no regressions
  • npm run build — clean, dist/mcp/skills/ emitted
  • Live MCP smoke test against the running server:
    • resources/list returns 38 entries (2 UI apps + 36 skill files) with text/markdown mime type
    • resources/read skill://n8n-mcp/n8n-code-javascript resolves to SKILL.md (bare URI alias)
    • resources/read skill://n8n-mcp/n8n-validation-expert/FALSE_POSITIVES.md returns the file body
    • resources/read ui://n8n-mcp/operation-result still returns the operation-result HTML unchanged (regression)
  • Copilot CI review

Notes for reviewers

  • data/skills/ is committed (37 markdown files, ~28k lines). Pulled from czlonkowski/n8n-skills via the new npm run sync:skills script. The script tries two candidate sibling locations and accepts an N8N_SKILLS_SOURCE override.
  • .secretlintignore exempts data/skills/ — the upstream markdown contains placeholder Slack/API tokens (xoxb-your-token etc.) in code examples, same as the existing n8n-docs/ exemption.
  • Version bumped to 2.54.0 (minor — additive feature, no breaking changes).

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

🤖 Generated with Claude Code

Add a SkillResourceRegistry that mirrors UIAppRegistry to expose the
seven n8n-mcp skill bundles (~36 markdown files from the n8n-skills
repo) under a new skill://n8n-mcp/{name}/{file} URI scheme. The MCP
host already wired ListResources/ReadResource for ui://n8n-mcp/{id}
UI apps; both schemes now coexist in the same handlers.

The skill markdown is brought in via npm run sync:skills, which
copies from a sibling n8n-skills/skills/ checkout (overridable via
N8N_SKILLS_SOURCE) into data/skills/. The copy is committed so npm
and Docker artifacts ship the skills without requiring the sibling
repo on the build host. Dockerfile copies data/skills/ alongside
data/nodes.db; package.json files field ships data/skills/**/*.md.
data/skills/ is added to .secretlintignore because the upstream
markdown contains placeholder credentials in code examples — same
treatment as the n8n-docs clone.

A bare skill://n8n-mcp/{name} URI resolves to that skill's SKILL.md
as a convenience. A new resources/templates/list handler advertises
both URI templates so capable clients can construct URIs directly.
text/markdown is used as the mime type throughout. Description for
SKILL.md is parsed from frontmatter; supporting files fall back to
the first heading.

Claude Code users still get the better UX through the existing
n8n-mcp-skills plugin (auto-loaded SKILL frontmatter, description-
based triggering via the Skill tool). MCP Resources reach the
clients that lack a skill system: Cursor, Claude Desktop without
plugins, the OpenAI Agents SDK, and other custom agents — so
the same skill content now reaches every n8n-mcp consumer.

- 15 unit tests cover registry init, frontmatter parsing, URI
  resolution (bare and explicit), template listing, and reset
- Live smoke test against the running MCP server: resources/list
  returns 38 entries (2 UI apps + 36 skill files); resources/read
  resolves bare skill URI to SKILL.md and a specific file URI to
  its body; ui://n8n-mcp/operation-result still returns the
  operation-result HTML unchanged

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 18, 2026 13:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

Address code-reviewer feedback on PR #793:

- parseFrontmatter now normalizes \r\n → \n before checking the leading
  fence, so a Windows checkout of n8n-skills does not silently lose all
  SKILL.md metadata (previously content.startsWith('---\\n') returned
  false against '---\\r\\n', dropping name + description).
- Inline the getByUri simplification — a single Map.get + truthy
  check replaces the has/get! pattern, no behavior change.
- New test for CRLF frontmatter exercises the normalization above.
- New traversal test locks the security guarantee on the bare-URI
  fallback: skill://n8n-mcp/../../../etc/passwd and
  skill://n8n-mcp/a/../b/SKILL.md both resolve to null, because
  the bare-name path refuses any remainder containing '/' and the
  explicit-file path requires an exact Map key match.

17/17 registry tests pass.

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Test Results Summary

📊 Artifacts


Generated at Mon, 18 May 2026 13:26:37 GMT
Commit: 9eef05c
Run: #1092

@codecov

codecov Bot commented May 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@czlonkowski czlonkowski merged commit f1edbc9 into main May 18, 2026
14 checks passed
@czlonkowski czlonkowski deleted the feat/mcp-skills-resources branch May 18, 2026 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants