signupgenius-mcp 1.0.1 → 1.0.2
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/README.md +13 -5
- package/dist/auth.js +163 -0
- package/dist/bundle.js +8959 -3100
- package/dist/client.js +17 -3
- package/dist/index.js +18 -8
- package/package.json +3 -2
- package/server.json +8 -2
- /package/dist/{session-login.js → auth-session-login.js} +0 -0
package/README.md
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
MCP server for [SignUpGenius](https://www.signupgenius.com). 13 read tools and 1 write across profile, groups, sign-ups, and reports.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Three auth modes (tried in this priority order — first match wins):
|
|
6
|
+
1. **Pro key mode.** Uses the documented Pro API key. Required only for the slot REPORT tools (filled/available/all-participants). Pro subscription needed.
|
|
7
|
+
2. **Session mode.** Logs in with your normal email/password to call the same web API the signupgenius.com dashboard uses. **Free accounts work.** No SSO/2FA.
|
|
8
|
+
3. **fetchproxy fallback (no env vars needed).** When no env vars are set, the server reads `accessToken` / `cfid` / `cftoken` cookies once at startup from your already-signed-in `signupgenius.com` tab via the [fetchproxy](https://github.com/chrischall/fetchproxy) browser extension. After that one read, all SignUpGenius API calls go directly from Node — the extension is **not** in the request hot path. Install the extension once, sign into SignUpGenius, and the MCP just works.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
Set `SIGNUPGENIUS_DISABLE_FETCHPROXY=1` to opt out of the fallback (turns missing credentials into a hard error — useful in headless CI).
|
|
10
11
|
|
|
11
12
|
## Tools
|
|
12
13
|
|
|
@@ -45,9 +46,15 @@ SIGNUPGENIUS_NAME=PTA Org # optional
|
|
|
45
46
|
|
|
46
47
|
Find the user key in SignUpGenius under **Pro Tools → API Management**.
|
|
47
48
|
|
|
49
|
+
### fetchproxy fallback (no env vars)
|
|
50
|
+
|
|
51
|
+
Install the [fetchproxy extension](https://github.com/chrischall/fetchproxy) (Chrome Web Store / Safari `.dmg`), sign into [signupgenius.com](https://www.signupgenius.com), and remove the env block from your MCP config. The MCP reads `accessToken` / `cfid` / `cftoken` cookies once at startup and uses them like a session-mode login. No password copy-paste required.
|
|
52
|
+
|
|
53
|
+
The slot REPORT tools still require Pro key mode — `SIGNUPGENIUS_USER_KEY` is the only path that hits the documented v2/k Pro API.
|
|
54
|
+
|
|
48
55
|
### Both at once
|
|
49
56
|
|
|
50
|
-
Set both. Key mode wins. Useful if you have Pro for some accounts and want reports while still using your normal login elsewhere.
|
|
57
|
+
Set both Pro key and email/password. Key mode wins. Useful if you have Pro for some accounts and want reports while still using your normal login elsewhere.
|
|
51
58
|
|
|
52
59
|
### Advanced overrides
|
|
53
60
|
|
|
@@ -56,6 +63,7 @@ Set both. Key mode wins. Useful if you have Pro for some accounts and want repor
|
|
|
56
63
|
| `SIGNUPGENIUS_BASE_URL` | key: `https://api.signupgenius.com/v2/k`<br>session: `https://api.signupgenius.com/v3` | Override the JSON API base. |
|
|
57
64
|
| `SIGNUPGENIUS_LEGACY_BASE_URL` | `https://www.signupgenius.com` | Override the host for `/SUGboxAPI.cfm?go=…` legacy calls. |
|
|
58
65
|
| `SIGNUPGENIUS_LOGIN_URL` | `https://www.signupgenius.com` | Override the login form host. |
|
|
66
|
+
| `SIGNUPGENIUS_DISABLE_FETCHPROXY` | unset | Set to `1` to skip the fetchproxy fallback (missing creds become a hard error). |
|
|
59
67
|
|
|
60
68
|
## ToS caveat
|
|
61
69
|
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// Auth resolution — Pattern A template
|
|
3
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// SignUpGenius supports three auth paths. This file picks one, in priority
|
|
6
|
+
// order, and hands the chosen path to `SignUpGeniusClient`. It mirrors the
|
|
7
|
+
// Pattern A shape used by ofw-mcp/src/auth.ts so all sibling MCPs in this
|
|
8
|
+
// family stay structurally aligned.
|
|
9
|
+
//
|
|
10
|
+
// THE THREE PATHS, in priority order:
|
|
11
|
+
//
|
|
12
|
+
// 1. Pro API key (existing)
|
|
13
|
+
// SIGNUPGENIUS_USER_KEY set → stateless `Authorization: <key>` against
|
|
14
|
+
// the documented v2/k Pro API. The only path that can call slot reports.
|
|
15
|
+
// Unchanged from pre-fetchproxy behavior.
|
|
16
|
+
//
|
|
17
|
+
// 2. Session-login (existing)
|
|
18
|
+
// SIGNUPGENIUS_EMAIL + SIGNUPGENIUS_PASSWORD set → POST the login form,
|
|
19
|
+
// scrape `csrfToken`, capture `accessToken` (JWT) + `cfid`/`cftoken`
|
|
20
|
+
// cookies. Calls go to the v3 web API (Bearer) and the legacy
|
|
21
|
+
// `/SUGboxAPI.cfm` dispatcher (cookies). Unchanged from pre-fetchproxy
|
|
22
|
+
// behavior.
|
|
23
|
+
//
|
|
24
|
+
// 3. fetchproxy fallback (new)
|
|
25
|
+
// When no env vars are set, lift the user's session out of their
|
|
26
|
+
// already-signed-in signupgenius.com browser tab. `@fetchproxy/bootstrap`
|
|
27
|
+
// opens a one-shot WebSocket bridge, asks the extension for the
|
|
28
|
+
// `accessToken` / `MTOKEN` / `cfid` / `cftoken` cookies (all declared
|
|
29
|
+
// upfront — that's the security boundary), and closes the bridge.
|
|
30
|
+
// Subsequent SignUpGenius calls go out via plain Node `fetch()` with
|
|
31
|
+
// those cookies attached — fetchproxy is NOT in the request hot path.
|
|
32
|
+
//
|
|
33
|
+
// Note: `accessToken` and `MTOKEN` carry the same JWT value (verified
|
|
34
|
+
// via DevTools); we accept either and prefer `accessToken` if both are
|
|
35
|
+
// present.
|
|
36
|
+
//
|
|
37
|
+
// Users opt out with SIGNUPGENIUS_DISABLE_FETCHPROXY=1 (anyone who
|
|
38
|
+
// wants the old behavior of "fail loudly when creds are missing").
|
|
39
|
+
//
|
|
40
|
+
// 4. Error
|
|
41
|
+
// Nothing to authenticate with. We throw a message that names both
|
|
42
|
+
// escape hatches: set creds OR install the extension and sign in.
|
|
43
|
+
//
|
|
44
|
+
// Testability:
|
|
45
|
+
// - `@fetchproxy/bootstrap` is mocked at the module boundary in tests.
|
|
46
|
+
// - `loadAccount()` (the existing env-var resolver) is reused as-is so the
|
|
47
|
+
// legacy paths keep working unchanged.
|
|
48
|
+
import { bootstrap } from '@fetchproxy/bootstrap';
|
|
49
|
+
import { loadAccount } from './config.js';
|
|
50
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
51
|
+
function readEnv(key) {
|
|
52
|
+
const raw = process.env[key];
|
|
53
|
+
if (typeof raw !== 'string')
|
|
54
|
+
return undefined;
|
|
55
|
+
const trimmed = raw.trim();
|
|
56
|
+
if (trimmed.length === 0)
|
|
57
|
+
return undefined;
|
|
58
|
+
if (trimmed === 'undefined' || trimmed === 'null')
|
|
59
|
+
return undefined;
|
|
60
|
+
if (/^\$\{[^}]*\}$/.test(trimmed))
|
|
61
|
+
return undefined;
|
|
62
|
+
return trimmed;
|
|
63
|
+
}
|
|
64
|
+
function fetchproxyDisabled() {
|
|
65
|
+
const raw = readEnv('SIGNUPGENIUS_DISABLE_FETCHPROXY');
|
|
66
|
+
if (raw === undefined)
|
|
67
|
+
return false;
|
|
68
|
+
return ['1', 'true', 'yes', 'on'].includes(raw.toLowerCase());
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The exact error message `loadAccount()` throws when NO auth env vars are
|
|
72
|
+
* set. We catch this specific string so partial-config errors (which the
|
|
73
|
+
* user MUST fix) still propagate, but the "you didn't set anything at all"
|
|
74
|
+
* case falls through to fetchproxy.
|
|
75
|
+
*/
|
|
76
|
+
const NO_ENV_CONFIG_MARKER = 'Missing SignUpGenius auth config';
|
|
77
|
+
/**
|
|
78
|
+
* Resolve SignUpGenius auth using the three-path priority described at the
|
|
79
|
+
* top of this file. Throws with an actionable message when no path succeeds.
|
|
80
|
+
*/
|
|
81
|
+
export async function resolveAuth() {
|
|
82
|
+
// ── Paths 1 & 2: env-var credentials. loadAccount() handles precedence,
|
|
83
|
+
// partial-config errors, and env-var sanitization for us.
|
|
84
|
+
try {
|
|
85
|
+
const account = loadAccount();
|
|
86
|
+
return { account, source: 'env' };
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
// `loadAccount()` only ever throws plain Error instances (validated by
|
|
90
|
+
// tests in config.test.ts). Partial-config errors (missing one of the
|
|
91
|
+
// EMAIL/PASSWORD pair, non-https override URL, etc.) are USER MISTAKES
|
|
92
|
+
// and should propagate. Only the "nothing set at all" case is allowed
|
|
93
|
+
// to fall through to fetchproxy.
|
|
94
|
+
if (!e.message.startsWith(NO_ENV_CONFIG_MARKER)) {
|
|
95
|
+
throw e;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// ── Path 3: fetchproxy fallback.
|
|
99
|
+
if (!fetchproxyDisabled()) {
|
|
100
|
+
try {
|
|
101
|
+
const session = await bootstrap({
|
|
102
|
+
serverName: pkg.name,
|
|
103
|
+
version: pkg.version,
|
|
104
|
+
domains: ['signupgenius.com'],
|
|
105
|
+
declare: {
|
|
106
|
+
// Declare ALL the cookies we might need. The 0.3.0 read_cookies
|
|
107
|
+
// capability uses chrome.cookies.get (HttpOnly-visible) — the
|
|
108
|
+
// security gate is this declared key list, not HttpOnly status.
|
|
109
|
+
// MTOKEN is signupgenius.com's older name for the JWT; on some
|
|
110
|
+
// browsers/sessions one shows up first. accessToken takes priority
|
|
111
|
+
// when both are present.
|
|
112
|
+
cookies: ['MTOKEN', 'accessToken', 'cfid', 'cftoken'],
|
|
113
|
+
localStorage: [],
|
|
114
|
+
sessionStorage: [],
|
|
115
|
+
captureHeaders: [],
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
const accessToken = session.cookies['accessToken'] ?? session.cookies['MTOKEN'];
|
|
119
|
+
if (!accessToken) {
|
|
120
|
+
throw new Error('accessToken cookie missing on signupgenius.com. ' +
|
|
121
|
+
'Sign into signupgenius.com in your browser (with the fetchproxy extension installed) and retry.');
|
|
122
|
+
}
|
|
123
|
+
// Build the cookie header the legacy /SUGboxAPI.cfm dispatcher expects.
|
|
124
|
+
// accessToken first (the JWT also lives in this cookie jar) then the CF
|
|
125
|
+
// pair if present. Anything else gets ignored.
|
|
126
|
+
const parts = [`accessToken=${accessToken}`];
|
|
127
|
+
const cfid = session.cookies['cfid'];
|
|
128
|
+
const cftoken = session.cookies['cftoken'];
|
|
129
|
+
if (cfid)
|
|
130
|
+
parts.push(`cfid=${cfid}`);
|
|
131
|
+
if (cftoken)
|
|
132
|
+
parts.push(`cftoken=${cftoken}`);
|
|
133
|
+
const cookieHeader = parts.join('; ');
|
|
134
|
+
// Synthesize a session account with empty creds — the client will see
|
|
135
|
+
// `preloaded` and skip the form login. The bases match the defaults
|
|
136
|
+
// used by `loadAccount()` so behavior is identical from here on.
|
|
137
|
+
const account = {
|
|
138
|
+
mode: 'session',
|
|
139
|
+
name: 'signupgenius.com (browser)',
|
|
140
|
+
baseUrl: 'https://api.signupgenius.com/v3',
|
|
141
|
+
legacyBaseUrl: 'https://www.signupgenius.com',
|
|
142
|
+
loginBaseUrl: 'https://www.signupgenius.com',
|
|
143
|
+
email: '',
|
|
144
|
+
password: '',
|
|
145
|
+
};
|
|
146
|
+
return {
|
|
147
|
+
account,
|
|
148
|
+
preloaded: { accessToken, cookieHeader },
|
|
149
|
+
source: 'fetchproxy',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
154
|
+
throw new Error('SignUpGenius auth: no SIGNUPGENIUS_USER_KEY or SIGNUPGENIUS_EMAIL/PASSWORD set, ' +
|
|
155
|
+
`and fetchproxy fallback failed: ${msg}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// ── Path 4: nothing configured and fetchproxy explicitly disabled.
|
|
159
|
+
throw new Error('Missing SignUpGenius auth config. Set SIGNUPGENIUS_USER_KEY (Pro API), ' +
|
|
160
|
+
'or SIGNUPGENIUS_EMAIL + SIGNUPGENIUS_PASSWORD (session mode, free accounts), ' +
|
|
161
|
+
'or install the fetchproxy extension and sign into signupgenius.com ' +
|
|
162
|
+
'(unset SIGNUPGENIUS_DISABLE_FETCHPROXY if it is set).');
|
|
163
|
+
}
|