fastr-mcp-suite 1.0.0 → 1.2.0
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.
- package/LICENSE.md +19 -103
- package/README.md +61 -45
- package/dist/auth.d.ts +16 -27
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +15 -138
- package/dist/auth.js.map +1 -1
- package/dist/cards/fluentcart/tools.d.ts +1 -2
- package/dist/cards/fluentcart/tools.d.ts.map +1 -1
- package/dist/cards/fluentcart/tools.js +109 -53
- package/dist/cards/fluentcart/tools.js.map +1 -1
- package/dist/cards/lemonsqueezy/tools.d.ts +1 -2
- package/dist/cards/lemonsqueezy/tools.d.ts.map +1 -1
- package/dist/cards/lemonsqueezy/tools.js +110 -13
- package/dist/cards/lemonsqueezy/tools.js.map +1 -1
- package/dist/http.js +9 -6
- package/dist/http.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/reference-reader.d.ts +38 -0
- package/dist/reference-reader.d.ts.map +1 -0
- package/dist/reference-reader.js +140 -0
- package/dist/reference-reader.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +65 -38
- package/dist/server.js.map +1 -1
- package/dist/skills/fastr-mcp-suite/SKILL.md +273 -0
- package/dist/skills/fluentcart-developer/SKILL.md +28 -5
- package/dist/skills/fluentcart-developer/examples/sample-custom-addon/fluentcart-custom-addon.php +0 -1
- package/dist/skills/fluentcart-developer/examples/sample-custom-payment-gateway/fluentcart-custom-gateway-example.php +0 -1
- package/dist/skills/fluentcart-developer/examples/sample-shipping-carrier/fluentcart-custom-shipping-carrier.php +0 -1
- package/dist/skills/fluentcart-developer/references/action-hooks-admin-templates.md +2 -2
- package/dist/skills/fluentcart-developer/references/filter-hooks-customers-subscriptions.md +3 -3
- package/dist/skills/fluentcart-developer/references/filter-hooks-orders-payments.md +1 -1
- package/dist/skills/fluentcart-developer/references/hooks-complete-index.md +834 -0
- package/dist/skills/fluentcart-developer/references/models-complete-index.md +912 -0
- package/dist/skills/fluentcart-developer/references/paddle-gateway-case-study.md +27 -21
- package/dist/skills/fluentcart-developer/references/rest-api-checkout.md +15 -13
- package/dist/skills/fluentcart-developer/references/rest-api-coupons.md +69 -62
- package/dist/skills/fluentcart-developer/references/rest-api-orders.md +221 -0
- package/dist/skills/fluentcart-developer/references/rest-api-products.md +163 -29
- package/dist/skills/fluentcart-developer/references/rest-api-subscriptions.md +332 -0
- package/dist/skills/lemonsqueezy-developer/SKILL.md +70 -57
- package/dist/skills/lemonsqueezy-developer/references/api-reference.md +591 -585
- package/dist/skills/lemonsqueezy-developer/references/checkouts-and-orders.md +135 -129
- package/dist/skills/lemonsqueezy-developer/references/developer-guide.md +60 -53
- package/dist/skills/lemonsqueezy-developer/references/go-live-guide.md +94 -87
- package/dist/skills/lemonsqueezy-developer/references/license-keys-and-activation.md +97 -91
- package/dist/skills/lemonsqueezy-developer/references/subscriptions-lifecycle.md +85 -79
- package/dist/skills/lemonsqueezy-developer/references/webhooks-and-security.md +152 -143
- package/dist/version.d.ts +13 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +13 -0
- package/dist/version.js.map +1 -0
- package/package.json +2 -2
- package/smithery.config.json +2 -9
package/LICENSE.md
CHANGED
|
@@ -1,110 +1,26 @@
|
|
|
1
|
-
# License
|
|
1
|
+
# MIT License
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
on the terms below. The skill content under the repository's `skills/` directory
|
|
5
|
-
is a separate work, licensed MIT, and is not part of the Licensed Work.
|
|
3
|
+
Copyright (c) 2026 Atif Jubaer (Fastrsoft)
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Parameters
|
|
15
|
-
|
|
16
|
-
Licensor: Atif Jubaer (Fastrsoft)
|
|
17
|
-
Licensed Work: The Fastr MCP Suite server implementation — the contents of
|
|
18
|
-
the `server/` directory of this repository, including its
|
|
19
|
-
source code, build scripts, configuration and any bundled
|
|
20
|
-
copies of the skill documents. The Licensed Work is
|
|
21
|
-
(c) 2026 Atif Jubaer (Fastrsoft).
|
|
22
|
-
Additional Use Grant: You may make production use of the Licensed Work, provided
|
|
23
|
-
Your use does not include offering the Licensed Work to third
|
|
24
|
-
parties on a hosted or embedded basis in order to compete with
|
|
25
|
-
the Licensor's paid version(s) of the Licensed Work, and does
|
|
26
|
-
not include reselling, sublicensing or private-labelling the
|
|
27
|
-
Licensed Work as a paid MCP server, paid distribution or
|
|
28
|
-
commercial hosted service.
|
|
29
|
-
Change Date: Four years from the date each version of the Licensed Work is
|
|
30
|
-
first publicly distributed.
|
|
31
|
-
Change License: MIT License
|
|
32
|
-
|
|
33
|
-
Terms
|
|
34
|
-
|
|
35
|
-
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
36
|
-
works, redistribute, and make non-production use of the Licensed Work. The
|
|
37
|
-
Licensor may make an Additional Use Grant, above, permitting limited production use.
|
|
38
|
-
|
|
39
|
-
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
40
|
-
available distribution of a specific version of the Licensed Work under this
|
|
41
|
-
License, whichever comes first, the Licensor hereby grants you rights under
|
|
42
|
-
the terms of the Change License, and the rights granted in the paragraph
|
|
43
|
-
above terminate.
|
|
44
|
-
|
|
45
|
-
If your use of the Licensed Work does not comply with the requirements
|
|
46
|
-
currently in effect as described in this License, you must purchase a
|
|
47
|
-
commercial license from the Licensor, its affiliated entities, or authorized
|
|
48
|
-
resellers, or you must refrain from using the Licensed Work.
|
|
49
|
-
|
|
50
|
-
All copies of the original and modified Licensed Work, and derivative works
|
|
51
|
-
of the Licensed Work, are subject to this License. This License applies
|
|
52
|
-
separately for each version of the Licensed Work and the Change Date may vary
|
|
53
|
-
for each version of the Licensed Work released by Licensor.
|
|
54
|
-
|
|
55
|
-
You must conspicuously display this License on each original or modified copy
|
|
56
|
-
of the Licensed Work. If you receive the Licensed Work in original or
|
|
57
|
-
modified form from a third party, the terms and conditions set forth in this
|
|
58
|
-
License apply to your use of that work.
|
|
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:
|
|
59
11
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
versions of the Licensed Work.
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
63
14
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
72
|
-
TITLE.
|
|
73
|
-
Covenants of Licensor
|
|
74
|
-
|
|
75
|
-
In consideration of the right to use this License's text and the "Business Source
|
|
76
|
-
License" name and trademark, Licensor covenants to MariaDB, and to all other
|
|
77
|
-
recipients of the licensed work to be provided by Licensor:
|
|
78
|
-
|
|
79
|
-
To specify as the Change License the GPL Version 2.0 or any later version, or a
|
|
80
|
-
license that is compatible with GPL Version 2.0 or a later version, where
|
|
81
|
-
"compatible" means that software provided under the Change License can be
|
|
82
|
-
included in a program with software provided under GPL Version 2.0 or a later
|
|
83
|
-
version. Licensor may specify additional Change Licenses without limitation.
|
|
84
|
-
|
|
85
|
-
To either: (a) specify an additional grant of rights to use that does not impose
|
|
86
|
-
any additional restriction on the right granted in this License, as the
|
|
87
|
-
Additional Use Grant; or (b) insert the text "None".
|
|
88
|
-
|
|
89
|
-
To specify a Change Date.
|
|
90
|
-
|
|
91
|
-
Not to modify this License in any other way.
|
|
92
|
-
|
|
93
|
-
Notice
|
|
94
|
-
|
|
95
|
-
The Business Source License (this document, or the "License") is not an Open
|
|
96
|
-
Source license. However, the Licensed Work will eventually be made available
|
|
97
|
-
under an Open Source License, as stated in this License.
|
|
98
|
-
|
|
99
|
-
For more information on the use of the Business Source License for MariaDB
|
|
100
|
-
products, please visit the MariaDB Business Source License FAQ
|
|
101
|
-
<https://mariadb.com/bsl-faq-mariadb/>. For more information on the use of the
|
|
102
|
-
Business Source License generally, please visit the Adopting and Developing
|
|
103
|
-
Business Source License FAQ <https://mariadb.com/bsl-faq-adopting/>.
|
|
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.
|
|
104
22
|
|
|
105
23
|
---
|
|
106
24
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
For paid distribution, resale, private-label or hosted use outside the Additional
|
|
110
|
-
Use Grant, contact the Licensor for a commercial license.
|
|
25
|
+
The server and the skill content under `skills/` are both MIT. There is no
|
|
26
|
+
commercial tier, no licence key, and no restriction on hosting a modified copy.
|
package/README.md
CHANGED
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
# Fastr MCP Suite
|
|
2
2
|
|
|
3
|
-
One MCP server that ships the Playing Cards — **FluentCart
|
|
3
|
+
One MCP server that ships the Playing Cards — **FluentCart Developer Agent** and **Lemon Squeezy Developer Agent** — as executable tools plus a skills catalog, so an agent pulls only the slice of documentation it needs instead of loading 239 KB of markdown into the context window.
|
|
4
|
+
|
|
5
|
+
**Free and MIT-licensed.** All ten tools are registered for every caller on every transport: no licence key, no account, no subscription, no request quota. Nothing in this server validates a purchase, because there is nothing to purchase.
|
|
4
6
|
|
|
5
7
|
Protocol: MCP `2026-07-28` (stateless, per-request `_meta` envelope) with a `2025-11-25` legacy fallback. Transports: `stdio` for local clients, Streamable HTTP for marketplaces and hosted deploys.
|
|
6
8
|
|
|
7
9
|
## Run it
|
|
8
10
|
|
|
11
|
+
### From npm
|
|
12
|
+
|
|
13
|
+
Published as [`fastr-mcp-suite`](https://www.npmjs.com/package/fastr-mcp-suite) — Node 22+, no clone and no build:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx -y fastr-mcp-suite
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Client config (Claude Code / Cursor / Windsurf):
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"mcpServers": {
|
|
24
|
+
"fastr-suite": {
|
|
25
|
+
"command": "npx",
|
|
26
|
+
"args": ["-y", "fastr-mcp-suite"]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
claude mcp add fastr-suite -- npx -y fastr-mcp-suite
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The npm package ships the stdio entry point only. The Streamable HTTP transport needs the source tree or the Docker image.
|
|
37
|
+
|
|
38
|
+
### From source
|
|
39
|
+
|
|
9
40
|
```bash
|
|
10
41
|
npm install
|
|
11
42
|
npm run build # tsc + bundles both skill folders into dist/skills
|
|
@@ -14,76 +45,61 @@ node dist/index.js # stdio
|
|
|
14
45
|
node dist/http.js # Streamable HTTP on :8080 (POST /mcp, GET /health)
|
|
15
46
|
```
|
|
16
47
|
|
|
17
|
-
|
|
48
|
+
Point a client at the built file:
|
|
18
49
|
|
|
19
50
|
```json
|
|
20
51
|
{
|
|
21
52
|
"mcpServers": {
|
|
22
53
|
"fastr-suite": {
|
|
23
54
|
"command": "node",
|
|
24
|
-
"args": ["/absolute/path/to/server/dist/index.js"]
|
|
25
|
-
"env": { "PRO_LICENSE_KEY": "optional-license-key" }
|
|
55
|
+
"args": ["/absolute/path/to/server/dist/index.js"]
|
|
26
56
|
}
|
|
27
57
|
}
|
|
28
58
|
}
|
|
29
59
|
```
|
|
30
60
|
|
|
31
|
-
##
|
|
32
|
-
|
|
33
|
-
| Tier | What is registered |
|
|
34
|
-
| --- | --- |
|
|
35
|
-
| `core` (free) | `ls_search_docs`, `ls_get_schema`, `fc_search_hooks`, `fc_get_db_schema`, `suite_get_pro_info`, plus `skills/list` and `resources/read` for both skills |
|
|
36
|
-
| `pro` (paid) | everything above **and** `ls_verify_webhook`, `ls_validate_license`, `fc_generate_payment_gateway_boilerplate` |
|
|
61
|
+
## Tools
|
|
37
62
|
|
|
38
|
-
|
|
63
|
+
Ten tools, all free. `suite_get_info` reports the same list at runtime, scoped by card.
|
|
39
64
|
|
|
40
|
-
|
|
65
|
+
| Card | Tool | Answers |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| FluentCart | `fc_search_hooks` | A hook name, when it fires, its arguments |
|
|
68
|
+
| FluentCart | `fc_get_db_schema` | A `wp_fct_*` table, its columns, the Eloquent model |
|
|
69
|
+
| FluentCart | `fc_get_reference` | Any of the 49 reference files, whole or by heading |
|
|
70
|
+
| FluentCart | `fc_generate_payment_gateway_boilerplate` | A complete PHP gateway class, settings schema and webhook entry point |
|
|
71
|
+
| Lemon Squeezy | `ls_search_docs` | Webhook signatures, checkout payloads, subscription states |
|
|
72
|
+
| Lemon Squeezy | `ls_get_schema` | The exact JSON:API body for an endpoint |
|
|
73
|
+
| Lemon Squeezy | `ls_get_reference` | Any of the 7 Lemon Squeezy reference files, whole or by heading |
|
|
74
|
+
| Lemon Squeezy | `ls_verify_webhook` | Timing-safe HMAC-SHA256 check against a raw payload |
|
|
75
|
+
| Lemon Squeezy | `ls_validate_license` | A live licence key, validated against Lemon Squeezy's API |
|
|
76
|
+
| Suite | `suite_get_info` | What this server is, which tools serve which card, and its licence |
|
|
41
77
|
|
|
42
|
-
|
|
43
|
-
- **HTTP** — every request carries `Authorization: Bearer <token>`:
|
|
44
|
-
1. token in `VALID_LICENSE_KEYS` → Pro (ops/CI seats)
|
|
45
|
-
2. equals `MCPIZE_GATEWAY_SECRET` → Pro (constant-time compare)
|
|
46
|
-
3. equals `AGENSI_GATEWAY_SECRET` → Pro (constant-time compare)
|
|
47
|
-
4. otherwise validated live against `https://api.lemonsqueezy.com/v1/licenses/validate`, cached 10 minutes, active status and store id checked. Any failure fails closed to core.
|
|
78
|
+
The skills catalog is attached as an MCP extension, so clients that understand it also get `skills/list` and `resources/read` over the same 64 files.
|
|
48
79
|
|
|
49
|
-
|
|
80
|
+
`ls_validate_license` is the only tool that reaches the network. It is cached for 60 s, bounded to 32 concurrent calls and times out at 5 s, so a public deploy does not become an unbounded relay into Lemon Squeezy's API.
|
|
50
81
|
|
|
51
82
|
## Deploy
|
|
52
83
|
|
|
53
|
-
Docker
|
|
84
|
+
### Docker
|
|
54
85
|
|
|
55
86
|
```bash
|
|
56
|
-
docker build -
|
|
57
|
-
docker run -p 8080:8080
|
|
87
|
+
docker build -t fastr-mcp-suite .
|
|
88
|
+
docker run -p 8080:8080 -e ALLOWED_HOSTS=your-host.example fastr-mcp-suite
|
|
58
89
|
```
|
|
59
90
|
|
|
60
|
-
|
|
91
|
+
`ALLOWED_HOSTS` is the only environment variable worth setting: a comma-separated Host allowlist for DNS-rebinding protection. `PORT` overrides `8080`. Nothing else is read.
|
|
61
92
|
|
|
62
|
-
|
|
93
|
+
Any host that accepts a long-running HTTP process works — Railway, Render, Fly.io, a VPS. Mount `/health` as the liveness probe: it returns the protocol version, the card list and the licence.
|
|
63
94
|
|
|
64
|
-
|
|
95
|
+
### MCPize
|
|
65
96
|
|
|
66
|
-
|
|
67
|
-
npx -y smithery mcp publish "https://<your-host>/mcp" -n <namespace>/fastr-mcp-suite \
|
|
68
|
-
--config-schema "$(cat server/smithery.config.json)"
|
|
69
|
-
```
|
|
97
|
+
[`mcpize.yaml`](../mcpize.yaml) at the repository root is the deployment manifest; `npx mcpize deploy` builds and publishes from there. MCPize authenticates callers at its own edge, but that credential no longer changes what the server registers — a caller with or without it sees the same ten tools.
|
|
70
98
|
|
|
71
|
-
|
|
99
|
+
## Not affiliated
|
|
72
100
|
|
|
73
|
-
|
|
101
|
+
This is an independent developer tool. It does not connect to a WordPress database, does not modify a FluentCart store, and is not published by either vendor. Documentation in `skills/` is compiled from their public references.
|
|
74
102
|
|
|
75
|
-
|
|
76
|
-
src/
|
|
77
|
-
auth.ts tier resolution (stdio env + HTTP license validation)
|
|
78
|
-
paths.ts skills folder resolution (bundled dist/skills → repo skills/)
|
|
79
|
-
server.ts server factory, catalog attach, Pro info tool
|
|
80
|
-
index.ts stdio entry
|
|
81
|
-
http.ts Streamable HTTP entry + /health
|
|
82
|
-
cards/lemonsqueezy/tools.ts Card 2 tools
|
|
83
|
-
cards/fluentcart/tools.ts Card 1 tools
|
|
84
|
-
scripts/
|
|
85
|
-
copy-skills.mjs bundles skills/* into dist/skills for npm
|
|
86
|
-
verify-stdio.mjs end-to-end protocol, tier-gating and era probe
|
|
87
|
-
```
|
|
103
|
+
## Licence
|
|
88
104
|
|
|
89
|
-
|
|
105
|
+
MIT — see [`LICENSE.md`](./LICENSE.md). Fork it, host it, adapt it.
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,31 +1,20 @@
|
|
|
1
|
-
export type Tier = 'core' | 'pro';
|
|
2
|
-
export interface AuthContext {
|
|
3
|
-
tier: Tier;
|
|
4
|
-
userId?: string;
|
|
5
|
-
source: 'stdio' | 'lemonsqueezy' | 'mcpize' | 'agensi' | 'none';
|
|
6
|
-
/** Human-readable explanation, surfaced by `suite_get_pro_info` and logs. */
|
|
7
|
-
reason: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Local (stdio) tier resolution.
|
|
11
|
-
*
|
|
12
|
-
* Setting `PRO_LICENSE_KEY` in the environment unlocks Pro. This is a local
|
|
13
|
-
* trust boundary, not a security boundary: anyone who controls the machine can
|
|
14
|
-
* set the variable. The paid gate that matters is the HTTP transport, where
|
|
15
|
-
* every request is validated server-side. Commercial terms are enforced by the
|
|
16
|
-
* BSL-1.1 licence in `server/LICENSE`.
|
|
17
|
-
*/
|
|
18
|
-
export declare function resolveLocalAuth(): AuthContext;
|
|
19
1
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* 3. Agensi gateway token, checked against `AGENSI_GATEWAY_SECRET`.
|
|
25
|
-
* 4. Everything else is treated as a Lemon Squeezy licence key and validated live.
|
|
2
|
+
* The suite is free and MIT-licensed: every tool is registered for every caller
|
|
3
|
+
* on every transport. There is no tier to resolve, no licence key to validate,
|
|
4
|
+
* and no outbound call to make before a session can work — so this module no
|
|
5
|
+
* longer authenticates anything.
|
|
26
6
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
7
|
+
* `AuthContext` survives as a small descriptor of the session. It is what
|
|
8
|
+
* `createServerInstance` receives and what `suite_get_info` reports, which is
|
|
9
|
+
* still useful when diagnosing which transport a client actually reached.
|
|
29
10
|
*/
|
|
30
|
-
export
|
|
11
|
+
export type CardId = 'fluentcart' | 'lemonsqueezy';
|
|
12
|
+
export interface AuthContext {
|
|
13
|
+
/** Always `free`. Kept as a literal so a future gate has one obvious seam. */
|
|
14
|
+
tier: 'free';
|
|
15
|
+
cards: CardId[];
|
|
16
|
+
source: 'stdio' | 'http';
|
|
17
|
+
reason: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function fullAccess(source: 'stdio' | 'http'): AuthContext;
|
|
31
20
|
//# sourceMappingURL=auth.d.ts.map
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,cAAc,CAAC;AAInD,MAAM,WAAW,WAAW;IAC1B,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,CAOhE"}
|
package/dist/auth.js
CHANGED
|
@@ -1,143 +1,20 @@
|
|
|
1
|
-
import crypto from 'node:crypto';
|
|
2
|
-
const LS_VALIDATE_URL = 'https://api.lemonsqueezy.com/v1/licenses/validate';
|
|
3
|
-
const LICENSE_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
4
|
-
/** token -> resolution, so a busy client does not hit Lemon Squeezy on every request. */
|
|
5
|
-
const licenseCache = new Map();
|
|
6
|
-
/** Unauthenticated callers can send arbitrary tokens, so the cache is bounded. */
|
|
7
|
-
const LICENSE_CACHE_MAX = 5000;
|
|
8
|
-
/** A failed validation is cached briefly: it bounds upstream load during an outage. */
|
|
9
|
-
const NEGATIVE_CACHE_TTL_MS = 30 * 1000;
|
|
10
|
-
/** Beyond this many concurrent validations the answer is "core" without calling out. */
|
|
11
|
-
const MAX_INFLIGHT_VALIDATIONS = 64;
|
|
12
|
-
let inFlightValidations = 0;
|
|
13
|
-
function cacheResolution(token, tier, ttlMs) {
|
|
14
|
-
if (licenseCache.size >= LICENSE_CACHE_MAX) {
|
|
15
|
-
// Map iteration is insertion-ordered, so the first key is the oldest entry.
|
|
16
|
-
const oldest = licenseCache.keys().next().value;
|
|
17
|
-
if (oldest !== undefined)
|
|
18
|
-
licenseCache.delete(oldest);
|
|
19
|
-
}
|
|
20
|
-
licenseCache.set(token, { tier, expiresAt: Date.now() + ttlMs });
|
|
21
|
-
}
|
|
22
|
-
function timingSafeEqualStrings(a, b) {
|
|
23
|
-
const left = Buffer.from(a, 'utf8');
|
|
24
|
-
const right = Buffer.from(b, 'utf8');
|
|
25
|
-
return left.length === right.length && crypto.timingSafeEqual(left, right);
|
|
26
|
-
}
|
|
27
|
-
function bearerToken(authorization) {
|
|
28
|
-
if (!authorization)
|
|
29
|
-
return '';
|
|
30
|
-
return authorization.replace(/^Bearer\s+/i, '').trim();
|
|
31
|
-
}
|
|
32
1
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* set the variable. The paid gate that matters is the HTTP transport, where
|
|
38
|
-
* every request is validated server-side. Commercial terms are enforced by the
|
|
39
|
-
* BSL-1.1 licence in `server/LICENSE`.
|
|
40
|
-
*/
|
|
41
|
-
export function resolveLocalAuth() {
|
|
42
|
-
const key = process.env.PRO_LICENSE_KEY?.trim();
|
|
43
|
-
if (key && key.length >= 16) {
|
|
44
|
-
return { tier: 'pro', source: 'stdio', reason: 'PRO_LICENSE_KEY present in environment' };
|
|
45
|
-
}
|
|
46
|
-
return { tier: 'core', source: 'stdio', reason: 'stdio session without PRO_LICENSE_KEY' };
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Validate a licence key against Lemon Squeezy. Results are cached for 10
|
|
50
|
-
* minutes. Any network or parsing failure fails closed (core tier).
|
|
51
|
-
*/
|
|
52
|
-
async function validateLicenseKey(licenseKey) {
|
|
53
|
-
const cached = licenseCache.get(licenseKey);
|
|
54
|
-
if (cached && cached.expiresAt > Date.now()) {
|
|
55
|
-
return {
|
|
56
|
-
tier: cached.tier,
|
|
57
|
-
source: 'lemonsqueezy',
|
|
58
|
-
reason: cached.tier === 'pro' ? 'license key valid (cached)' : 'license key invalid (cached)'
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
// Any caller can present an unknown token. Without this cap, a burst of junk
|
|
62
|
-
// tokens becomes a burst of 5-second outbound requests.
|
|
63
|
-
if (inFlightValidations >= MAX_INFLIGHT_VALIDATIONS) {
|
|
64
|
-
return {
|
|
65
|
-
tier: 'core',
|
|
66
|
-
source: 'lemonsqueezy',
|
|
67
|
-
reason: 'license validation concurrency limit reached'
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
inFlightValidations += 1;
|
|
71
|
-
try {
|
|
72
|
-
const res = await fetch(LS_VALIDATE_URL, {
|
|
73
|
-
method: 'POST',
|
|
74
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },
|
|
75
|
-
body: new URLSearchParams({ license_key: licenseKey }),
|
|
76
|
-
signal: AbortSignal.timeout(5000)
|
|
77
|
-
});
|
|
78
|
-
const data = (await res.json());
|
|
79
|
-
const expectedStore = process.env.LS_STORE_ID;
|
|
80
|
-
const storeMatches = !expectedStore || String(data.license_key?.store_id ?? '') === String(expectedStore);
|
|
81
|
-
const active = data.valid === true && data.license_key?.status === 'active' && storeMatches;
|
|
82
|
-
const tier = active ? 'pro' : 'core';
|
|
83
|
-
cacheResolution(licenseKey, tier, LICENSE_CACHE_TTL_MS);
|
|
84
|
-
return {
|
|
85
|
-
tier,
|
|
86
|
-
source: 'lemonsqueezy',
|
|
87
|
-
reason: active ? 'active Lemon Squeezy license' : 'license inactive, unknown, or wrong store'
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
// Fail closed, but remember the failure for a moment: an outage must not
|
|
92
|
-
// turn every request from every client into another outbound attempt.
|
|
93
|
-
cacheResolution(licenseKey, 'core', NEGATIVE_CACHE_TTL_MS);
|
|
94
|
-
return {
|
|
95
|
-
tier: 'core',
|
|
96
|
-
source: 'lemonsqueezy',
|
|
97
|
-
reason: `license validation unavailable: ${err.message}`
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
finally {
|
|
101
|
-
inFlightValidations -= 1;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Resolve the tier for one HTTP request.
|
|
106
|
-
*
|
|
107
|
-
* 1. `VALID_LICENSE_KEYS` allowlist (ops escape hatch, e.g. internal seats).
|
|
108
|
-
* 2. MCPize gateway token, checked against `MCPIZE_GATEWAY_SECRET`.
|
|
109
|
-
* 3. Agensi gateway token, checked against `AGENSI_GATEWAY_SECRET`.
|
|
110
|
-
* 4. Everything else is treated as a Lemon Squeezy licence key and validated live.
|
|
2
|
+
* The suite is free and MIT-licensed: every tool is registered for every caller
|
|
3
|
+
* on every transport. There is no tier to resolve, no licence key to validate,
|
|
4
|
+
* and no outbound call to make before a session can work — so this module no
|
|
5
|
+
* longer authenticates anything.
|
|
111
6
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
7
|
+
* `AuthContext` survives as a small descriptor of the session. It is what
|
|
8
|
+
* `createServerInstance` receives and what `suite_get_info` reports, which is
|
|
9
|
+
* still useful when diagnosing which transport a client actually reached.
|
|
114
10
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.filter(Boolean);
|
|
124
|
-
// Compared in constant time like the gateway secrets, and without stopping at
|
|
125
|
-
// the first match so the loop's duration does not reveal an entry's position.
|
|
126
|
-
let allowlisted = false;
|
|
127
|
-
for (const candidate of allowlist) {
|
|
128
|
-
allowlisted = timingSafeEqualStrings(token, candidate) || allowlisted;
|
|
129
|
-
}
|
|
130
|
-
if (allowlisted) {
|
|
131
|
-
return { tier: 'pro', source: 'lemonsqueezy', reason: 'token in VALID_LICENSE_KEYS allowlist' };
|
|
132
|
-
}
|
|
133
|
-
const mcpizeSecret = process.env.MCPIZE_GATEWAY_SECRET?.trim();
|
|
134
|
-
if (mcpizeSecret && timingSafeEqualStrings(token, mcpizeSecret)) {
|
|
135
|
-
return { tier: 'pro', source: 'mcpize', reason: 'MCPize gateway secret matched' };
|
|
136
|
-
}
|
|
137
|
-
const agensiSecret = process.env.AGENSI_GATEWAY_SECRET?.trim();
|
|
138
|
-
if (agensiSecret && timingSafeEqualStrings(token, agensiSecret)) {
|
|
139
|
-
return { tier: 'pro', source: 'agensi', reason: 'Agensi gateway secret matched' };
|
|
140
|
-
}
|
|
141
|
-
return validateLicenseKey(token);
|
|
11
|
+
const ALL_CARDS = ['fluentcart', 'lemonsqueezy'];
|
|
12
|
+
export function fullAccess(source) {
|
|
13
|
+
return {
|
|
14
|
+
tier: 'free',
|
|
15
|
+
cards: [...ALL_CARDS],
|
|
16
|
+
source,
|
|
17
|
+
reason: 'the whole suite is free — no licence key, account, or purchase required'
|
|
18
|
+
};
|
|
142
19
|
}
|
|
143
20
|
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,SAAS,GAAsB,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;AAUpE,MAAM,UAAU,UAAU,CAAC,MAAwB;IACjD,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC;QACrB,MAAM;QACN,MAAM,EAAE,yEAAyE;KAClF,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
-
|
|
3
|
-
export declare function registerFluentCartTools(server: McpServer, auth: AuthContext): void;
|
|
2
|
+
export declare function registerFluentCartTools(server: McpServer): void;
|
|
4
3
|
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/cards/fluentcart/tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/cards/fluentcart/tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAK9D,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuO/D"}
|