toolfunnel 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +228 -231
  2. package/SECURITY.md +84 -0
  3. package/bin/toolfunnel.js +451 -372
  4. package/docs/KNOWN_BUGS.md +80 -99
  5. package/docs/MANUAL.pdf +0 -0
  6. package/docs/design.md +84 -70
  7. package/docs/packaging.md +115 -115
  8. package/hooks/hooks.manifest.json +27 -27
  9. package/hooks/scripts/example-audit.js +21 -21
  10. package/hooks/scripts/example-deny-dangerous.js +39 -31
  11. package/mcp/expose.example.json +30 -30
  12. package/mcp/servers/mock-modern/server.js +147 -147
  13. package/mcp/servers/mock-upstream/server.js +380 -350
  14. package/package.json +3 -1
  15. package/src/auth/config.js +174 -174
  16. package/src/auth/install.js +181 -181
  17. package/src/auth/resource-server.js +353 -344
  18. package/src/core/child-reaper.js +61 -0
  19. package/src/core/config-home.js +134 -134
  20. package/src/core/events.js +105 -105
  21. package/src/core/hook-engine.js +329 -275
  22. package/src/core/hook-loader.js +824 -791
  23. package/src/core/hook-runner.js +566 -346
  24. package/src/core/logger.js +297 -171
  25. package/src/core/matcher.js +100 -51
  26. package/src/core/metrics.js +75 -75
  27. package/src/core/rename-migration.js +163 -0
  28. package/src/core/requires.js +138 -138
  29. package/src/core/server-config.js +98 -98
  30. package/src/extend/add-hook.md +152 -152
  31. package/src/extend/add-mcp.md +119 -122
  32. package/src/extend/configure.md +88 -87
  33. package/src/extend/create-tool.md +168 -168
  34. package/src/extend/howto.js +102 -102
  35. package/src/extend/package.md +190 -187
  36. package/src/extend/wrap.md +99 -99
  37. package/src/mcp/aggregator.js +1719 -1246
  38. package/src/mcp/expose-store.js +577 -460
  39. package/src/mcp/gated-run.js +210 -201
  40. package/src/mcp/http-transport.js +1563 -1311
  41. package/src/mcp/mcp-client.js +1070 -907
  42. package/src/mcp/modern.js +406 -372
  43. package/src/mcp/protocol.js +468 -468
  44. package/src/mcp/server.js +3112 -2688
  45. package/src/tools/registry.js +661 -513
  46. package/src/tools/tool-state.js +170 -170
  47. package/src/ui/public/app.js +1187 -1174
  48. package/src/ui/public/index.html +286 -286
  49. package/src/ui/public/styles.css +535 -535
  50. package/src/ui/server.js +1616 -1348
  51. package/tools/scripts/base64.js +139 -139
  52. package/tools/scripts/danger.js +61 -61
  53. package/tools/scripts/echo.js +39 -39
  54. package/tools/scripts/hash.js +101 -101
  55. package/tools/scripts/json.js +109 -109
  56. package/tools/scripts/text-stats.js +131 -131
  57. package/tools/scripts/tf-env.js +43 -43
  58. package/tools/scripts/tf-hook-add.js +151 -151
  59. package/tools/scripts/tf-hook-set.js +120 -112
  60. package/tools/scripts/tf-list.js +192 -192
  61. package/tools/scripts/tf-log.js +86 -86
  62. package/tools/scripts/tf-mcp-add.js +117 -117
  63. package/tools/scripts/tf-mcp-set.js +121 -121
  64. package/tools/scripts/tf-pack.js +237 -237
  65. package/tools/scripts/tf-tool-add.js +134 -134
  66. package/tools/scripts/tf-tool-set.js +142 -142
  67. package/tools/scripts/tf-wrap.js +103 -103
  68. package/tools/scripts/uuid.js +102 -102
  69. package/tools/tools.register.json +227 -227
  70. package/src/core/tool-registry.js +0 -180
  71. package/src/packages/packager.js +0 -715
  72. package/src/tools/drift.js +0 -138
package/SECURITY.md ADDED
@@ -0,0 +1,84 @@
1
+ # Security Policy
2
+
3
+ ToolFunnel sits between MCP clients and MCP servers - it gates, filters, and forwards
4
+ tool calls. That makes its security surface worth taking seriously, and reports are
5
+ genuinely welcome.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ **Please use GitHub's private vulnerability reporting:** go to the
10
+ [Security tab](https://github.com/Rendeverance/toolfunnel/security) → **Report a
11
+ vulnerability**. That opens a private thread with the maintainer - nothing is public
12
+ until a fix is out.
13
+
14
+ Please **do not** open a public issue for a security-sensitive report. If you're unsure
15
+ whether something is security-relevant, please err on the side of the private route.
16
+
17
+ ## What counts
18
+
19
+ Anything that lets a client or upstream server do what the configuration says it
20
+ shouldn't. For example:
21
+
22
+ - Bypassing the tool gate / hidden-tool filtering (`tf_tool_set`, expose config)
23
+ - Auth bypass in the HTTP transport or OAuth resource-server validation
24
+ - Token or credential leakage (in logs, error messages, or forwarded traffic)
25
+ - Escaping the PreToolUse deny-hook
26
+ - Injection via tool names, schemas, or forwarded arguments
27
+
28
+ Bugs that crash ToolFunnel but don't cross a trust boundary are ordinary bugs -
29
+ public issues are fine for those.
30
+
31
+ ## What to expect
32
+
33
+ This is a single-maintainer project. Reports get a response on a best-effort basis -
34
+ normally within a few days. Confirmed vulnerabilities are fixed as a priority, and
35
+ you'll be credited in the release notes unless you'd rather not be.
36
+
37
+ ## Supported versions
38
+
39
+ Only the latest published release (`npm install toolfunnel`) is supported with
40
+ security fixes.
41
+
42
+ ## Trust model
43
+
44
+ **The config home is the trust boundary.** Anyone who can write the config home
45
+ (`tools/`, `mcp/`, `hooks/`, `auth/`, `toolfunnel.json`) can define register tools, hooks,
46
+ and upstream commands that execute with the gateway process's privileges. Protect it with
47
+ filesystem permissions like you would a crontab or a shell profile.
48
+
49
+ Everything else follows from that line:
50
+
51
+ - **Upstream MCP servers are operator-chosen code.** Attaching or wrapping a server means
52
+ trusting it with whatever its command can reach. In funnel mode the gateway *refuses*
53
+ upstream arguments, working directories, and code-loading environment variables that
54
+ reference paths outside the config home. The per-upstream opt-outs are explicit, and each
55
+ is wider than a single check: `allowOutsidePaths` lifts the outside-path refusal for
56
+ everything path-shaped that upstream carries - its arguments (including the value after
57
+ `=` in a `--flag=value` form), the working directory its bare arguments resolve against,
58
+ and its path-list environment variables; `allowCodeLoadingEnv` permits the code-loading
59
+ environment class (`NODE_OPTIONS`, `NODE_PATH`, and their equivalents for other runtimes)
60
+ on its own. Wrap mode permits outside paths with a security notice, because serving your
61
+ real files is usually the point of a wrapped server. The guard is a tripwire for configs that quietly reach
62
+ outside an auditable config home - not a sandbox against an untrusted pack author:
63
+ installing a pack is installing software.
64
+ - **The network surface binds loopback by default** (HTTP, SSE, and the web UI), validates
65
+ the `Origin` header against loopback origins, and enforces the protocol-version
66
+ and parameter-mirroring header rules of the 2026-07-28 revision. Exposing the port beyond
67
+ localhost is an operator decision; put OAuth 2.1 (opt-in) or your own reverse proxy in
68
+ front of it if you do.
69
+ - **Zero runtime dependencies** - the supply-chain audit surface is this repository's own
70
+ code (OAuth, if enabled, adds exactly one audited library: `jose`).
71
+ - **An unreadable gate decision is a deny.** A hook that floods its output past the cap, whose
72
+ decision JSON cannot be parsed, or whose decision slot carries a value outside the exact
73
+ protocol vocabulary (a miscased `"DENY"`, a synonym like `"denied"`, the right word in the
74
+ wrong slot, a wrong type) blocks the call it was gating rather than waving it through. A hook
75
+ matcher that does not compile is the same class: it is refused at authoring, and one already
76
+ in the manifest denies every tool-bearing call of its event until fixed. A `null` in a
77
+ protocol slot is NOT an attempt - it reads as "no value", exactly like an absent key, and
78
+ falls through. The deliberate exception: a hook script that CRASHES, is MISSING, or HANGS
79
+ past its timeout is a non-blocking error and the call proceeds - Claude Code hook parity, so
80
+ a script-execution failure cannot take every tool offline. An authored-config defect (the
81
+ matcher, the decision vocabulary) gets no such grace: the author wrote a gate the runner
82
+ cannot read, and it denies until corrected. Denies are `exit 2`; a gate that cannot reach a
83
+ decision should exit 2 explicitly rather than error out. Pinned by
84
+ `test/gate-semantics.test.js` and `test/matcher-compile.test.js`.