@wootsup/mcp 0.1.0-rc.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 (135) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/LICENSE +21 -0
  3. package/README.md +179 -0
  4. package/SECURITY.md +163 -0
  5. package/dist/auth/keychain.d.ts +47 -0
  6. package/dist/auth/keychain.js +262 -0
  7. package/dist/auth/keychain.js.map +1 -0
  8. package/dist/auth/oauth-provider.d.ts +68 -0
  9. package/dist/auth/oauth-provider.js +232 -0
  10. package/dist/auth/oauth-provider.js.map +1 -0
  11. package/dist/auth/profiles.d.ts +52 -0
  12. package/dist/auth/profiles.js +200 -0
  13. package/dist/auth/profiles.js.map +1 -0
  14. package/dist/auth/token.d.ts +27 -0
  15. package/dist/auth/token.js +88 -0
  16. package/dist/auth/token.js.map +1 -0
  17. package/dist/index.d.ts +13 -0
  18. package/dist/index.js +137 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/install-skill.d.ts +23 -0
  21. package/dist/install-skill.js +73 -0
  22. package/dist/install-skill.js.map +1 -0
  23. package/dist/modules/apimapper/cache.d.ts +2 -0
  24. package/dist/modules/apimapper/cache.js +71 -0
  25. package/dist/modules/apimapper/cache.js.map +1 -0
  26. package/dist/modules/apimapper/client.d.ts +85 -0
  27. package/dist/modules/apimapper/client.js +523 -0
  28. package/dist/modules/apimapper/client.js.map +1 -0
  29. package/dist/modules/apimapper/connections.d.ts +2 -0
  30. package/dist/modules/apimapper/connections.js +406 -0
  31. package/dist/modules/apimapper/connections.js.map +1 -0
  32. package/dist/modules/apimapper/credential-sanitizer.d.ts +7 -0
  33. package/dist/modules/apimapper/credential-sanitizer.js +70 -0
  34. package/dist/modules/apimapper/credential-sanitizer.js.map +1 -0
  35. package/dist/modules/apimapper/credentials.d.ts +2 -0
  36. package/dist/modules/apimapper/credentials.js +258 -0
  37. package/dist/modules/apimapper/credentials.js.map +1 -0
  38. package/dist/modules/apimapper/diagnose.d.ts +18 -0
  39. package/dist/modules/apimapper/diagnose.js +305 -0
  40. package/dist/modules/apimapper/diagnose.js.map +1 -0
  41. package/dist/modules/apimapper/flows.d.ts +2 -0
  42. package/dist/modules/apimapper/flows.js +372 -0
  43. package/dist/modules/apimapper/flows.js.map +1 -0
  44. package/dist/modules/apimapper/get-skill.d.ts +4 -0
  45. package/dist/modules/apimapper/get-skill.js +88 -0
  46. package/dist/modules/apimapper/get-skill.js.map +1 -0
  47. package/dist/modules/apimapper/graph-builder.d.ts +47 -0
  48. package/dist/modules/apimapper/graph-builder.js +117 -0
  49. package/dist/modules/apimapper/graph-builder.js.map +1 -0
  50. package/dist/modules/apimapper/graph.d.ts +2 -0
  51. package/dist/modules/apimapper/graph.js +117 -0
  52. package/dist/modules/apimapper/graph.js.map +1 -0
  53. package/dist/modules/apimapper/index.d.ts +2 -0
  54. package/dist/modules/apimapper/index.js +43 -0
  55. package/dist/modules/apimapper/index.js.map +1 -0
  56. package/dist/modules/apimapper/inspect.d.ts +20 -0
  57. package/dist/modules/apimapper/inspect.js +86 -0
  58. package/dist/modules/apimapper/inspect.js.map +1 -0
  59. package/dist/modules/apimapper/library.d.ts +2 -0
  60. package/dist/modules/apimapper/library.js +237 -0
  61. package/dist/modules/apimapper/library.js.map +1 -0
  62. package/dist/modules/apimapper/license.d.ts +2 -0
  63. package/dist/modules/apimapper/license.js +142 -0
  64. package/dist/modules/apimapper/license.js.map +1 -0
  65. package/dist/modules/apimapper/local-sources.d.ts +2 -0
  66. package/dist/modules/apimapper/local-sources.js +123 -0
  67. package/dist/modules/apimapper/local-sources.js.map +1 -0
  68. package/dist/modules/apimapper/misc.d.ts +2 -0
  69. package/dist/modules/apimapper/misc.js +149 -0
  70. package/dist/modules/apimapper/misc.js.map +1 -0
  71. package/dist/modules/apimapper/node-schema.d.ts +217 -0
  72. package/dist/modules/apimapper/node-schema.js +218 -0
  73. package/dist/modules/apimapper/node-schema.js.map +1 -0
  74. package/dist/modules/apimapper/normalizers.d.ts +13 -0
  75. package/dist/modules/apimapper/normalizers.js +37 -0
  76. package/dist/modules/apimapper/normalizers.js.map +1 -0
  77. package/dist/modules/apimapper/onboarding.d.ts +51 -0
  78. package/dist/modules/apimapper/onboarding.js +201 -0
  79. package/dist/modules/apimapper/onboarding.js.map +1 -0
  80. package/dist/modules/apimapper/schema.d.ts +2 -0
  81. package/dist/modules/apimapper/schema.js +84 -0
  82. package/dist/modules/apimapper/schema.js.map +1 -0
  83. package/dist/modules/apimapper/settings.d.ts +2 -0
  84. package/dist/modules/apimapper/settings.js +157 -0
  85. package/dist/modules/apimapper/settings.js.map +1 -0
  86. package/dist/modules/apimapper/skill-resources.d.ts +4 -0
  87. package/dist/modules/apimapper/skill-resources.js +85 -0
  88. package/dist/modules/apimapper/skill-resources.js.map +1 -0
  89. package/dist/modules/apimapper/types.d.ts +111 -0
  90. package/dist/modules/apimapper/types.js +14 -0
  91. package/dist/modules/apimapper/types.js.map +1 -0
  92. package/dist/modules/apimapper/use-profile.d.ts +34 -0
  93. package/dist/modules/apimapper/use-profile.js +176 -0
  94. package/dist/modules/apimapper/use-profile.js.map +1 -0
  95. package/dist/modules/apimapper/workflows.d.ts +2 -0
  96. package/dist/modules/apimapper/workflows.js +301 -0
  97. package/dist/modules/apimapper/workflows.js.map +1 -0
  98. package/dist/platform/index.d.ts +71 -0
  99. package/dist/platform/index.js +377 -0
  100. package/dist/platform/index.js.map +1 -0
  101. package/dist/server-http.d.ts +22 -0
  102. package/dist/server-http.js +159 -0
  103. package/dist/server-http.js.map +1 -0
  104. package/dist/setup/detect-clients.d.ts +39 -0
  105. package/dist/setup/detect-clients.js +152 -0
  106. package/dist/setup/detect-clients.js.map +1 -0
  107. package/dist/setup/probe-handshake.d.ts +26 -0
  108. package/dist/setup/probe-handshake.js +159 -0
  109. package/dist/setup/probe-handshake.js.map +1 -0
  110. package/dist/setup/write-config.d.ts +25 -0
  111. package/dist/setup/write-config.js +247 -0
  112. package/dist/setup/write-config.js.map +1 -0
  113. package/dist/setup-cli.d.ts +49 -0
  114. package/dist/setup-cli.js +292 -0
  115. package/dist/setup-cli.js.map +1 -0
  116. package/dist/skill-instructions.d.ts +10 -0
  117. package/dist/skill-instructions.js +68 -0
  118. package/dist/skill-instructions.js.map +1 -0
  119. package/dist/transports/http.d.ts +29 -0
  120. package/dist/transports/http.js +267 -0
  121. package/dist/transports/http.js.map +1 -0
  122. package/dist/transports/stdio.d.ts +9 -0
  123. package/dist/transports/stdio.js +19 -0
  124. package/dist/transports/stdio.js.map +1 -0
  125. package/docs/architecture.md +140 -0
  126. package/docs/customgraph-internal-migration.md +210 -0
  127. package/docs/security.md +126 -0
  128. package/docs/tools.md +230 -0
  129. package/manifest.json +76 -0
  130. package/package.json +61 -0
  131. package/skills/apimapper/SKILL.md +57 -0
  132. package/skills/apimapper/reference/joomla.md +85 -0
  133. package/skills/apimapper/reference/oauth.md +94 -0
  134. package/skills/apimapper/reference/troubleshooting.md +123 -0
  135. package/skills/apimapper/reference/yootheme.md +96 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,91 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@wootsup/mcp` will be documented here.
4
+
5
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
6
+ this project uses [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [0.1.0-rc.1] - 2026-05-18 (unreleased)
9
+
10
+ First public release candidate. Ships the full 74-tool MCP surface
11
+ plus a complete setup story (`npx setup` wizard + Claude Desktop DXT
12
+ bundle). Built across Phases 0–10 of the
13
+ `apimapper-mcp-implementation-plan` (vault).
14
+
15
+ ### Added
16
+
17
+ - **Stripe-style HMAC-SHA256 auth.** `amk_live_…` / `amk_test_…`
18
+ token format, server-side signing key, identity-probe handshake
19
+ with site-title confirmation in the setup wizard.
20
+ - **WordPress plugin foundation.** REST routes under
21
+ `/wp-json/api-mapper/v1/mcp/*`, key generation UI under
22
+ *API Mapper → Connections → MCP Access*, key list + rotate +
23
+ revoke endpoints.
24
+ - **Joomla plugin foundation.** Mirror surface via `com_ajax`
25
+ envelope; same key lifecycle as WordPress. Joomla envelope unwrap
26
+ is handled by the client layer transparently.
27
+ - **5 admin UI components** for MCP key management: KeyList,
28
+ CreateKey, KeyDetail, RotateKey, RevokeKey — shared between
29
+ WordPress and Joomla via the platform abstraction.
30
+ - **Platform abstraction.** Each MCP tool routes through a single
31
+ platform-router that detects WordPress vs. Joomla from the site
32
+ URL + `APIMAPPER_PLATFORM` env, then dispatches to the correct
33
+ REST shape.
34
+ - **Keychain + Profiles.** OS keychain integration via
35
+ `@napi-rs/keyring` (macOS Keychain, Windows Credential Manager,
36
+ Linux libsecret) with named profile support (`APIMAPPER_PROFILE`)
37
+ and a `0600` file fallback when no keychain is available.
38
+ - **Setup CLI (`apimapper-mcp` binary).** Interactive
39
+ `@clack/prompts` wizard with subcommands: `setup` (default),
40
+ `install-skill`, `help`. Auto-detects Claude Desktop, Claude Code,
41
+ Cursor, VS Code, Cline, Codex. Idempotent config writers; rollback
42
+ on probe failure.
43
+ - **Skills bundling.** `skills/apimapper/SKILL.md` plus four reference
44
+ docs (`oauth.md`, `joomla.md`, `yootheme.md`, `troubleshooting.md`)
45
+ shipped with every install. Resources surfaced via
46
+ `apimapper_get_skill` tool.
47
+ - **Composite tools.** `apimapper_flow_setup_with_sources` (create
48
+ flow + add sources + compile + publish), `apimapper_diagnose`
49
+ (pre-flight: health + license + platform parity + connection probe
50
+ + recent flow status). Reduces multi-turn back-and-forth for the
51
+ most common workflows.
52
+ - **Multi-transport.** stdio transport (default, local install) plus
53
+ HTTP transport with OAuth 2.0 (PKCE-required, S256) for remote
54
+ consumption. Bearer tokens are site-bound (rejected on origin
55
+ mismatch).
56
+ - **DXT bundle.** `apimapper-mcp.dxt` packaged via `build-dxt.js`
57
+ for one-click Claude Desktop install. User-config keys
58
+ (`APIMAPPER_TOKEN`, `APIMAPPER_SITE_URL`, `APIMAPPER_PLATFORM`)
59
+ bridged into the runtime via env shimming. Build verified with a
60
+ grep-gate that ensures every declared user-config key has a
61
+ runtime consumer.
62
+ - **74 MCP tools** spanning: connections, credentials, flows, graph
63
+ preview/validate, local sources, schema profile, library catalog,
64
+ cache, settings, license, releases, brandfetch, feedback,
65
+ workflows, plus health / onboarding / diagnose / inspect-token /
66
+ use-profile.
67
+
68
+ ### Engineering
69
+
70
+ - **Test suite.** 243 tests across 27 files
71
+ (vitest + `tsx watch` dev). Includes a stdio-transport spawn
72
+ smoke-test, HTTP+Bearer transport tests, build-dxt manifest
73
+ invariants, and unit coverage of every register file.
74
+ - **CI matrix.** ubuntu-latest, macos-latest, windows-latest × Node
75
+ 22.x, gated by path filter and concurrency-cancel per ref
76
+ (`.github/workflows/apimapper-mcp-ci.yml`).
77
+ - **Publish workflow.** Tag-triggered (`apimapper-mcp-v*`),
78
+ verifies tag-version vs. `package.json#version` before publishing,
79
+ publishes with `--provenance`, uploads DXT bundle to GitHub
80
+ Release (`.github/workflows/apimapper-mcp-publish.yml`).
81
+
82
+ ### Known issues
83
+
84
+ - `@getimo/mcp-toolkit@1.0.0` declares a `workspace:*` peer-dep on
85
+ `@pipeline-studio/screenshot-capture` that is unresolvable outside
86
+ the source monorepo. Install with `npm install --legacy-peer-deps`
87
+ (or `npm ci --legacy-peer-deps` in CI). Tracked upstream; will be
88
+ fixed in `@getimo/mcp-toolkit@1.1.0`. Does not affect runtime —
89
+ `npx @wootsup/mcp` and the DXT bundle work without intervention.
90
+
91
+ [0.1.0-rc.1]: https://github.com/wootsup/api-mapper/releases/tag/apimapper-mcp-v0.1.0-rc.1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WootsUp / getimo productions
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # @wootsup/mcp
2
+
3
+ **Build YOOtheme dynamic content via natural conversation.** The official MCP
4
+ server for [API Mapper](https://wootsup.com/products/api-mapper) — connect
5
+ your AI assistant to API Mapper running on WordPress or Joomla, then create
6
+ flows, manage OAuth credentials, and publish sources without leaving the
7
+ chat.
8
+
9
+ [![npm version](https://img.shields.io/npm/v/@wootsup/mcp.svg)](https://www.npmjs.com/package/@wootsup/mcp)
10
+ [![CI](https://github.com/wootsup/api-mapper/actions/workflows/apimapper-mcp-ci.yml/badge.svg)](https://github.com/wootsup/api-mapper/actions/workflows/apimapper-mcp-ci.yml)
11
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
12
+
13
+ ---
14
+
15
+ ## Install
16
+
17
+ Two paths, pick one.
18
+
19
+ ### Option A — `npx` (Claude Code, Cursor, VS Code, Cline, Codex, ChatGPT)
20
+
21
+ ```bash
22
+ npx -y @wootsup/mcp setup
23
+ ```
24
+
25
+ The interactive wizard:
26
+
27
+ 1. Asks which AI client(s) you use (auto-detected when possible).
28
+ 2. Prompts for your API Mapper site URL and MCP key.
29
+ 3. Runs an identity-probe handshake against your site.
30
+ 4. Patches the client's MCP config (`~/.claude.json`, `~/.cursor/mcp.json`,
31
+ VS Code `settings.json`, etc.) idempotently.
32
+ 5. Installs the bundled skill to `~/.claude/skills/apimapper/`.
33
+
34
+ Re-run any time — writers are idempotent. Use `--help` to see all
35
+ subcommands.
36
+
37
+ ### Option B — Claude Desktop (DXT bundle)
38
+
39
+ 1. Download `apimapper-mcp.dxt` from the latest
40
+ [GitHub Release](https://github.com/wootsup/api-mapper/releases?q=apimapper-mcp).
41
+ 2. Drag it onto the Claude Desktop window (or **Settings → Developer →
42
+ Install from file**).
43
+ 3. Enter your site URL, MCP key, and platform when prompted.
44
+
45
+ ## Setup (3 steps)
46
+
47
+ 1. **Install the API Mapper plugin** on your site:
48
+ - **WordPress:** plugin from
49
+ [wootsup.com](https://wootsup.com/products/api-mapper)
50
+ - **Joomla:** extension from
51
+ [wootsup.com](https://wootsup.com/products/api-mapper)
52
+ 2. **Generate an MCP key** in the admin:
53
+ - WordPress: click **API Mapper** in the WP admin menu — the flow
54
+ editor opens. In the editor header (top-right), click the **⋮**
55
+ (three-dot) menu → **Settings**. In the modal's left sidebar,
56
+ click **MCP Access** → **New API key**.
57
+ - Joomla: **Components → API Mapper** loads the same editor — use
58
+ the same **⋮** → **Settings** → **MCP Access** path.
59
+ - Token shape: `amk_live_…` (production) or `amk_test_…` (sandbox).
60
+ 3. **Run `npx -y @wootsup/mcp setup`** (or install the DXT) and paste
61
+ the key. The wizard verifies it with an HMAC-SHA256 identity probe
62
+ before writing config.
63
+
64
+ Verify in your AI client:
65
+
66
+ ```text
67
+ You: apimapper_health
68
+ LLM: ✅ status: ok, platform: wordpress, version: 2.0.7
69
+ ```
70
+
71
+ ## Common tools
72
+
73
+ A small set of high-leverage tools — the full 74-tool surface is
74
+ [documented in detail in the bundled skill](./skills/apimapper/SKILL.md).
75
+
76
+ | Tool | What it does |
77
+ |------|--------------|
78
+ | `apimapper_health` | Connectivity + auth probe. **Run this first.** |
79
+ | `apimapper_onboarding` | Lists platform, existing flows, next-step suggestions. |
80
+ | `apimapper_flow_setup_with_sources` | Composite: create flow + add sources + compile + publish. |
81
+ | `apimapper_connection_list` | List connections (paginated, table-formatted). |
82
+ | `apimapper_credential_create` | Add OAuth or Bearer credentials. |
83
+ | `apimapper_oauth_authorize_begin` | Start an OAuth 2.0 PKCE flow. |
84
+ | `apimapper_graph_preview` | Preview a flow's output without saving. |
85
+ | `apimapper_library_catalog` | Browse pre-built connection templates. |
86
+ | `apimapper_get_skill` | Fetch the bundled skill text on demand. |
87
+
88
+ See [`skills/apimapper/SKILL.md`](./skills/apimapper/SKILL.md) for the
89
+ canonical workflow guide, and
90
+ [`skills/apimapper/reference/`](./skills/apimapper/reference/) for OAuth,
91
+ Joomla, YOOtheme, and troubleshooting deep-dives.
92
+
93
+ ## Multi-platform: WordPress and Joomla
94
+
95
+ Every tool routes through a platform abstraction that detects WordPress
96
+ (`/wp-json/api-mapper/v1/*`) vs. Joomla (`/index.php?option=com_apimapper`)
97
+ from the site URL and platform setting. You write the same prompt; the
98
+ server speaks the right dialect — including the Joomla `com_ajax`
99
+ envelope unwrap.
100
+
101
+ ## Multi-client
102
+
103
+ Supported AI clients (auto-detected by the setup wizard):
104
+
105
+ - **Claude Desktop** — DXT bundle or `~/Library/Application Support/Claude/`
106
+ - **Claude Code** — `~/.claude.json`
107
+ - **Cursor** — `~/.cursor/mcp.json` (or project-local `.cursor/mcp.json`)
108
+ - **VS Code** — workspace `.vscode/settings.json` `mcp.servers`
109
+ - **Cline** — VS Code extension settings
110
+ - **Codex** — `~/.config/codex/mcp.json`
111
+ - **ChatGPT Desktop** — when MCP support ships
112
+
113
+ Both transports are supported: **stdio** (default, local install) and
114
+ **HTTP + OAuth 2.0** (remote use, see [`docs/architecture.md`](./docs/architecture.md)).
115
+
116
+ ## Known issues
117
+
118
+ ### `npm install` requires `--legacy-peer-deps` (developer-only)
119
+
120
+ **Most users don't need this.** If you install via:
121
+
122
+ - `npx @wootsup/mcp setup` — no action required.
123
+ - DXT bundle drag-and-drop into Claude Desktop — no action required.
124
+ - Claude Desktop one-click install — no action required.
125
+
126
+ …you can skip this section entirely. The `npx` and DXT paths ship a
127
+ pre-resolved dependency tree (no peer-dep resolution happens at install
128
+ or runtime), so the issue below cannot bite you.
129
+
130
+ **For developers who clone this repo:**
131
+
132
+ The dependency `@getimo/mcp-toolkit@1.0.0` declares a peer-dep on
133
+ `@pipeline-studio/screenshot-capture` with the `workspace:*` protocol.
134
+ That protocol is unresolvable outside the source monorepo, so a vanilla
135
+ `npm install` fails with `EUNSUPPORTEDPROTOCOL`. Workaround:
136
+
137
+ ```sh
138
+ npm install --legacy-peer-deps # local dev
139
+ npm ci --legacy-peer-deps # CI
140
+ ```
141
+
142
+ Tracked in the customgraph repo — fix lands in `@getimo/mcp-toolkit@1.0.1`,
143
+ at which point this section will be removed.
144
+
145
+ ## Troubleshooting
146
+
147
+ See [`skills/apimapper/reference/troubleshooting.md`](./skills/apimapper/reference/troubleshooting.md).
148
+ Common cases:
149
+
150
+ - `403 invalid_token` → token expired or wrong site URL. Re-run setup.
151
+ - `404` on every tool → plugin not installed or REST routes disabled.
152
+ - Joomla `0` envelope → SEF/htaccess intercepting `com_ajax`; check
153
+ the reference doc.
154
+
155
+ ## Contributing
156
+
157
+ PRs welcome. Source lives at
158
+ [github.com/wootsup/api-mapper](https://github.com/wootsup/api-mapper)
159
+ in `packages/apimapper-mcp/`. Run `npm test --workspace=@wootsup/mcp`
160
+ before opening a PR; the cross-platform CI matrix
161
+ ([`apimapper-mcp-ci.yml`](../../.github/workflows/apimapper-mcp-ci.yml))
162
+ re-runs on ubuntu, macOS, and windows.
163
+
164
+ For the security disclosure process, see [`SECURITY.md`](./SECURITY.md).
165
+
166
+ ## License
167
+
168
+ [MIT](./LICENSE) © 2026 WootsUp / getimo productions.
169
+
170
+ ## Links
171
+
172
+ - **Homepage:** <https://wootsup.com/products/api-mapper>
173
+ - **Plugin (WordPress + Joomla):** <https://wootsup.com/products/api-mapper>
174
+ - **Docs:** <https://docs.wootsup.com>
175
+ - **Issues:** <https://github.com/wootsup/api-mapper/issues>
176
+ - **Architecture:** [`docs/architecture.md`](./docs/architecture.md)
177
+ - **Security model:** [`docs/security.md`](./docs/security.md)
178
+ - **Tools reference:** [`docs/tools.md`](./docs/tools.md)
179
+ - **Changelog:** [`CHANGELOG.md`](./CHANGELOG.md)
package/SECURITY.md ADDED
@@ -0,0 +1,163 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a vulnerability
4
+
5
+ Email **security@wootsup.com** with details. We aim to respond within
6
+ 72 hours.
7
+
8
+ Please do not open public GitHub issues for security problems. If your
9
+ report is accepted we will coordinate disclosure and credit you in the
10
+ release notes (opt-in).
11
+
12
+ PGP key: available on request.
13
+
14
+ ## Supported versions
15
+
16
+ We patch security issues in the latest minor of `@wootsup/mcp`.
17
+ During the `0.x` development line, only the most recent published
18
+ version is supported.
19
+
20
+ | Version | Supported |
21
+ |---------|-----------|
22
+ | `0.1.x` | ✅ active |
23
+ | `< 0.1` | ❌ not yet published |
24
+
25
+ When `1.0.0` lands, the previous minor (`0.x`) will receive critical
26
+ security patches for 6 months.
27
+
28
+ ## Authentication model
29
+
30
+ `@wootsup/mcp` uses a **Stripe-style HMAC-SHA256 token system**.
31
+
32
+ ### Token format
33
+
34
+ ```
35
+ amk_<env>_<hex-key-id>.<base64url-signature>
36
+ ```
37
+
38
+ - `amk_live_…` — production keys (full scope).
39
+ - `amk_test_…` — sandbox keys (limited rate, no destructive ops).
40
+
41
+ Tokens carry an embedded HMAC signed by a server-side signing key. The
42
+ server validates the signature on every request before any business
43
+ logic runs — there is no "user lookup by token string". This means a
44
+ compromised replica of the database cannot mint valid tokens without
45
+ also possessing the signing key.
46
+
47
+ ### Server-only signing key
48
+
49
+ The signing key is generated on plugin install, stored once in:
50
+
51
+ - **WordPress:** `wp_options.apimapper_signing_key` (autoload = false)
52
+ - **Joomla:** `#__apimapper_settings.signing_key`
53
+
54
+ It is **never** returned by any REST endpoint, never logged, never
55
+ echoed in tool responses, and never written to the `@wootsup/mcp`
56
+ keychain. The MCP server only sees the public token string.
57
+
58
+ ### Identity probe (anti-phishing)
59
+
60
+ Before the setup wizard writes any config file, it issues a
61
+ `GET /api-mapper/v1/mcp/identity` request. The server responds with:
62
+
63
+ - the public `key_id`,
64
+ - a `siteSignature` (HMAC over `key_id + site_url + nonce`),
65
+ - and the user-visible site title.
66
+
67
+ The wizard re-computes the signature using the public token payload and
68
+ displays the site title + URL to the user for confirmation. A
69
+ copy-pasted token from a malicious actor cannot pass this probe because
70
+ the malicious server cannot forge the signature without the genuine
71
+ signing key.
72
+
73
+ ### Scope semantics
74
+
75
+ Tokens carry an embedded scope list:
76
+
77
+ - `read` — list/get/inspect tools.
78
+ - `write` — create/update/compile.
79
+ - `destructive` — delete, reset-demo, license-deactivate.
80
+ - `oauth` — credential creation + OAuth begin.
81
+
82
+ Server-side enforcement runs **before** the platform abstraction layer.
83
+ Frontend tool-listing additionally filters tools by available scopes,
84
+ so an LLM with a read-only token never sees destructive tools in its
85
+ tool-list (eliminates one class of confused-deputy risk).
86
+
87
+ ### No-secret-leak guarantees
88
+
89
+ | Endpoint / Tool | Returns token? |
90
+ |---|---|
91
+ | `GET /mcp/keys` (list) | ❌ key IDs + scopes + last-used only. **Never** the token string. |
92
+ | `POST /mcp/keys` (create) | ✅ **Only on creation.** Subsequent reads cannot retrieve it. |
93
+ | `apimapper_credential_*` | ❌ Stored OAuth/Bearer creds are returned with values redacted (`***`). |
94
+ | `apimapper_inspect_token` | Returns the **decoded payload** (key_id, scopes, env) but **not** the signature. |
95
+ | `apimapper_settings_get` | Always strips `signing_key`, OAuth client secrets, and Brandfetch keys. |
96
+
97
+ Server-side, the `CredentialSanitizer` runs on every response that
98
+ could possibly contain a credential value — see
99
+ [`src/modules/apimapper/credential-sanitizer.ts`](./src/modules/apimapper/credential-sanitizer.ts).
100
+ Unit tests pin the redaction surface.
101
+
102
+ ### Token rotation
103
+
104
+ - Rotate any time from **API Mapper → Connections → MCP Access →
105
+ Rotate**.
106
+ - Old tokens revoke immediately. The MCP server returns
107
+ `403 invalid_token` on the next request; the user re-runs
108
+ `npx @wootsup/mcp setup`.
109
+ - Rotation does **not** rotate the server-side signing key. The
110
+ signing key is rotated only on explicit "Reset all keys" — a
111
+ destructive op that requires re-issuing every active token.
112
+
113
+ ### Token revocation
114
+
115
+ - Single token: **API Mapper → Connections → MCP Access → Revoke**.
116
+ - All tokens: **API Mapper → Connections → MCP Access → Revoke all**
117
+ (also rotates the signing key).
118
+ - Both operations are immediate; there is no caching of token validity
119
+ on the MCP server side.
120
+
121
+ ### Keychain fallback
122
+
123
+ When OS keychain (`@napi-rs/keyring`) is unavailable (some Linux
124
+ distros, CI containers), tokens fall back to a profile file at
125
+ `~/.config/apimapper-mcp/profiles/<name>.json` with mode `0600`. The
126
+ file is plain JSON containing the token string — readable by the user
127
+ account only. If you operate in a hostile multi-user environment,
128
+ **use the OS keychain path** (the default on macOS and Windows).
129
+
130
+ ### OAuth 2.0 (HTTP transport)
131
+
132
+ When `@wootsup/mcp` runs in HTTP mode (`server-http.ts`), it acts as
133
+ both an MCP server and an OAuth 2.0 authorization server with **PKCE
134
+ required** (RFC 7636 S256). No implicit flow, no `code` grant without
135
+ PKCE. Bearer tokens are bound to the issuing site URL and rejected if
136
+ the `Origin` header differs.
137
+
138
+ ## Threat model summary
139
+
140
+ | Threat | Mitigation |
141
+ |---|---|
142
+ | Token leak via logs | Sanitizer strips on every response path; tokens never logged. |
143
+ | Token leak via tool output | List endpoints structurally exclude the token string. |
144
+ | Replay across sites | HMAC includes site URL; cross-site replay fails sig check. |
145
+ | Forged tokens | Server-side signing key never leaves the install. |
146
+ | Phishing setup link | Identity probe + site-title confirmation in wizard. |
147
+ | Confused-deputy / over-privileged LLM | Scope filter excludes destructive tools from token-restricted lists. |
148
+ | Local-fs token theft (no keychain) | `0600` perms on profile file; keychain default on macOS/Windows. |
149
+
150
+ See [`docs/security.md`](./docs/security.md) for the long-form threat
151
+ model.
152
+
153
+ ## Disclosure timeline
154
+
155
+ | Day | Action |
156
+ |---|---|
157
+ | 0 | Report received. Acknowledgement within 72h. |
158
+ | 0-14 | Triage + reproduction + patch development. |
159
+ | 14-30 | Coordinated patch release + security advisory. |
160
+ | 30+ | Public disclosure (CVE if applicable). |
161
+
162
+ For critical issues (active exploitation, supply chain) we will
163
+ expedite and ship out-of-band.
@@ -0,0 +1,47 @@
1
+ export interface Keychain {
2
+ set(ref: string, value: string): Promise<void>;
3
+ get(ref: string): Promise<string | null>;
4
+ delete(ref: string): Promise<void>;
5
+ }
6
+ export declare class SystemKeychain implements Keychain {
7
+ private readonly service;
8
+ constructor(service?: string);
9
+ set(ref: string, value: string): Promise<void>;
10
+ get(ref: string): Promise<string | null>;
11
+ delete(ref: string): Promise<void>;
12
+ }
13
+ export declare class EncryptedFileKeychain implements Keychain {
14
+ private readonly dir;
15
+ private readonly vaultPath;
16
+ private readonly saltPath;
17
+ private cachedKey?;
18
+ private writeChain;
19
+ constructor(configDir: string);
20
+ private deriveKey;
21
+ private readVault;
22
+ private writeVault;
23
+ private encrypt;
24
+ private decrypt;
25
+ set(ref: string, value: string): Promise<void>;
26
+ get(ref: string): Promise<string | null>;
27
+ delete(ref: string): Promise<void>;
28
+ }
29
+ export interface CreateKeychainOptions {
30
+ /** Directory holding the encrypted vault + salt for the file fallback. */
31
+ configDir: string;
32
+ /**
33
+ * Override for tests — injecting a throwing or stub System ctor exercises
34
+ * the fallback / preference logic deterministically. Defaults to the real
35
+ * SystemKeychain.
36
+ */
37
+ systemKeychainCtor?: typeof SystemKeychain;
38
+ /** Service name passed to SystemKeychain. Defaults to "@wootsup/mcp". */
39
+ service?: string;
40
+ /**
41
+ * When false (default), the factory writes a one-line warning to stderr if
42
+ * it falls back to the file impl. Tests set this to true to keep output
43
+ * clean.
44
+ */
45
+ silent?: boolean;
46
+ }
47
+ export declare function createKeychain(opts: CreateKeychainOptions): Promise<Keychain>;