touchque-mcp-server 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 ADDED
@@ -0,0 +1,128 @@
1
+ # TouchQue MCP Server
2
+
3
+ An [MCP](https://modelcontextprotocol.io) server that gives AI coding
4
+ assistants (Claude, Cursor, …) accurate, up-to-date TouchQue SDK
5
+ documentation, TypeScript types, and an integration validator — so they stop
6
+ guessing at the API and stop generating the old, broken synchronous
7
+ integration pattern.
8
+
9
+ It's a small, local, **read-only** tool: it doesn't hold an API key, doesn't
10
+ call your TouchQue account, and doesn't need network access at all for its
11
+ docs/types tools (they're bundled with the package). The only network calls
12
+ it makes are ones you explicitly ask for (`ping_touchque_api`, pointed at a
13
+ URL you pass in).
14
+
15
+ ## What it gives an assistant
16
+
17
+ **Tools:**
18
+ - `get_touchque_docs` — the current `@touchque/node` README (install, the
19
+ `requireTouchQue` step-up model, framework adapters, error handling,
20
+ security).
21
+ - `get_sdk_types` — the SDK's TypeScript type definitions (`Config`,
22
+ `Step`/`StepState`, `StartOptions`, `CompleteExpectations`, resource
23
+ response types).
24
+ - `ping_touchque_api` — checks that a TouchQue backend URL you give it is
25
+ reachable, before the assistant blames the integration code for a network
26
+ problem.
27
+ - `validate_integration` — a static-analysis checklist on a pasted route
28
+ handler: is `@touchque/node` actually imported, is the route guarded with
29
+ the current `requireTouchQue`/`withTouchQue`/`touchqueRouter` API (as
30
+ opposed to the old, removed synchronous `tq.login.verify()` pattern), are
31
+ secrets kept out of source and read from the environment, is there error
32
+ handling.
33
+
34
+ **Prompts** (pre-built instruction sets an assistant can load):
35
+ - `integrate_touchque` — a step-by-step wizard for adding TouchQue to an
36
+ existing codebase without breaking anything.
37
+ - `audit_touchque_integration` — a formal security-review checklist for an
38
+ existing integration.
39
+ - `troubleshoot_touchque` — a triage decision tree for a broken integration.
40
+
41
+ ## Install
42
+
43
+ ### Claude Desktop / Claude Code
44
+
45
+ Add to your MCP config (`claude_desktop_config.json`, or `.mcp.json` for
46
+ Claude Code):
47
+
48
+ ```json
49
+ {
50
+ "mcpServers": {
51
+ "touchque": {
52
+ "command": "npx",
53
+ "args": ["-y", "touchque-mcp-server"]
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### Cursor
60
+
61
+ `~/.cursor/mcp.json` (or the project's `.cursor/mcp.json`):
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "touchque": {
67
+ "command": "npx",
68
+ "args": ["-y", "touchque-mcp-server"]
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ No API key, no environment variables, no separate server process to run —
75
+ `npx` fetches and runs it on demand over stdio, the same way you'd wire up
76
+ any other local MCP server.
77
+
78
+ ### Run it directly
79
+
80
+ ```bash
81
+ npx -y touchque-mcp-server
82
+ ```
83
+
84
+ It talks [MCP](https://modelcontextprotocol.io) over stdio (stdin/stdout) —
85
+ you won't see anything if you run it directly in a terminal and start typing;
86
+ it's meant to be launched by an MCP-aware client, not used interactively.
87
+
88
+ ## Local development
89
+
90
+ If you're editing this server (not consuming it), point it at a docs site
91
+ you're actively editing instead of the bundled copies:
92
+
93
+ ```bash
94
+ DOCS_BASE_URL=http://localhost:5176/docs npx touchque-mcp-server
95
+ ```
96
+
97
+ The server tries `DOCS_BASE_URL/sdk-documentation.md` and
98
+ `DOCS_BASE_URL/types.ts` first when that variable is set, and falls back to
99
+ the bundled copies under [`bundled/`](./bundled) if that fetch fails — so an
100
+ unset or unreachable override never breaks the tool. Keep the bundled copies
101
+ in sync with `sdks/touchque-node/README.md` and
102
+ `sdks/touchque-node/src/{types.ts,steps.ts}` when the SDK's public API
103
+ changes.
104
+
105
+ ## Testing
106
+
107
+ ```bash
108
+ npm test
109
+ ```
110
+
111
+ Tests spawn the actual server over stdio using the official MCP SDK's
112
+ `Client`/`StdioClientTransport` — the same path any real MCP client takes —
113
+ and check the real tool/prompt list, that the bundled docs/types load without
114
+ network access, and that `validate_integration` correctly distinguishes the
115
+ current step-up API from the old, removed synchronous one.
116
+
117
+ ## Security
118
+
119
+ This server is read-only dev tooling: it never touches a real TouchQue
120
+ account, never sees an API key, and never calls a TouchQue backend except a
121
+ URL you explicitly pass to `ping_touchque_api`. There is intentionally no
122
+ authentication on the server itself — it needs none. If that ever changes
123
+ (e.g. a future tool that reads real account data), auth must be added before
124
+ that tool ships.
125
+
126
+ ## License
127
+
128
+ MIT © [TouchQue](https://touchque.com)
@@ -0,0 +1,179 @@
1
+ # @touchque/node
2
+
3
+ The official Node.js server SDK for [TouchQue](https://touchque.com) — biometric push 2FA,
4
+ passkeys, and offline approval codes, added to any backend with one line per route.
5
+
6
+ [![npm version](https://img.shields.io/npm/v/@touchque/node.svg)](https://www.npmjs.com/package/@touchque/node)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ 📘 Full docs: **[authenticator.touchque.com/docs](https://authenticator.touchque.com/docs)**
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ npm install @touchque/node
16
+ ```
17
+
18
+ ## Setup
19
+
20
+ Get an API key and secret from your [TouchQue Dashboard](https://authenticator.touchque.com),
21
+ then set them as environment variables:
22
+
23
+ ```bash
24
+ TQ_API_KEY=tq_auth_your_key
25
+ TQ_API_SECRET=your_api_secret
26
+ ```
27
+
28
+ The client picks these up automatically — `new TouchQue()` with no arguments.
29
+
30
+ ## Quick start (Express)
31
+
32
+ ```typescript
33
+ import express from 'express';
34
+ import { requireTouchQue } from '@touchque/node';
35
+
36
+ const app = express();
37
+ app.use(express.json());
38
+
39
+ app.post('/transfer',
40
+ requireTouchQue('SEND_MONEY', {
41
+ details: (req) => ({ Amount: `${req.body.amount} EUR`, To: req.body.iban }),
42
+ }),
43
+ (req, res) => {
44
+ // Only reached once the user approved on their phone.
45
+ res.json({ ok: true, assurance: req.touchque.assurance });
46
+ }
47
+ );
48
+
49
+ app.listen(3000);
50
+ ```
51
+
52
+ That's the whole integration for one route. What actually happens:
53
+
54
+ 1. The first request comes in with no pending approval → the middleware calls
55
+ TouchQue, sends a push to the user's phone, and answers **`202 { touchque, token }`**
56
+ instead of running your handler.
57
+ 2. Your frontend shows `touchque` in its own UI — a matching number for the
58
+ user to tap on their phone, or a QR code the first time they link the app —
59
+ then sends the *same request* again with header `X-TouchQue-Token: <token>`
60
+ (see [`@touchque/web`](https://www.npmjs.com/package/@touchque/web), which does this loop for you).
61
+ 3. Once the user approves, that retried request reaches your handler exactly
62
+ once, with `req.touchque` populated (`assurance`, `approvalProof`, …).
63
+
64
+ No hosted page, no redirect, no new domain — you keep your own UI end to end.
65
+
66
+ ## The three primitives, if you don't use a framework adapter
67
+
68
+ ```typescript
69
+ import { TouchQue } from '@touchque/node';
70
+
71
+ const tq = new TouchQue(); // from TQ_API_KEY / TQ_API_SECRET
72
+
73
+ const step = await tq.start('SEND_MONEY', {
74
+ user: 'jane@acme.com',
75
+ details: { Amount: '250 EUR', To: 'DE89...' },
76
+ });
77
+ // step.state: 'waiting' (show step.number) | 'enroll' (show step.enroll.qrCodeDataUrl)
78
+ // | 'approved' | 'rejected' | 'expired' | 'passkey_required' | 'frozen' | 'blocked'
79
+
80
+ const latest = await tq.check(step.id);
81
+
82
+ // Once approved, consume it exactly once, right before doing the protected thing:
83
+ const approval = await tq.complete(step.id, {
84
+ user: 'jane@acme.com',
85
+ action: 'SEND_MONEY',
86
+ details: { Amount: '250 EUR', To: 'DE89...' },
87
+ });
88
+ ```
89
+
90
+ `complete()` verifies the approval was actually issued for this user, action
91
+ and transaction — it will not let an approval for a different amount or
92
+ recipient be replayed against this call, and consuming it twice fails on the
93
+ second call.
94
+
95
+ ## Framework adapters
96
+
97
+ - **Express**: `requireTouchQue(action, options?)` — shown above.
98
+ - **Next.js / Fetch API route handlers**: `withTouchQue(action, options?)`.
99
+ - **`touchqueRouter`**: mounts every relay route a frontend needs
100
+ (`POST /login`, enrollment, passkey ceremonies, offline codes) so you don't
101
+ hand-write them.
102
+
103
+ ```typescript
104
+ import { touchqueRouter } from '@touchque/node';
105
+
106
+ app.use(touchqueRouter(tq, {
107
+ getUserId: (req) => req.session.user?.email,
108
+ }));
109
+ ```
110
+
111
+ ## Passkeys (phishing-resistant)
112
+
113
+ Push approval and offline codes stop password reuse and push fatigue, but a
114
+ real-time phishing proxy can still relay them. A passkey can't be phished: the
115
+ browser signs your site's real origin and TouchQue refuses any other
116
+ (NIST SP 800-63B-4 §3.2.5).
117
+
118
+ 1. Set your passkey domain in the Dashboard (Security Policy → Passkeys).
119
+ 2. Let users register one via `tq.webauthn` (server) + `@touchque/web`'s
120
+ `passkeys.register()` (browser).
121
+ 3. Optionally require it for critical actions or every sign-in — TouchQue then
122
+ skips the push and your route resolves `passkey_required` instead.
123
+ 4. Check `assurance.phishingResistant` before treating a session as high-assurance.
124
+
125
+ ## Offline approval (no internet on the phone)
126
+
127
+ ```typescript
128
+ const ch = await tq.offline.challenge({
129
+ user: 'jane@acme.com',
130
+ type: 'WITHDRAW',
131
+ details: { Amount: '1,250.00 USD', Recipient: 'Jane Doe' },
132
+ });
133
+ // show ch.qrDataUrl — the phone scans it offline and shows a 7-character code
134
+
135
+ const { approved } = await tq.offline.verify({ challengeId: ch.challengeId, code });
136
+ ```
137
+
138
+ ## Webhooks
139
+
140
+ ```typescript
141
+ app.post('/webhooks/touchque', express.raw({ type: 'application/json' }), (req, res) => {
142
+ try {
143
+ const event = tq.webhook.verify({
144
+ rawBody: req.body.toString(),
145
+ signature: req.headers['x-touchque-signature'] as string,
146
+ });
147
+ // handle event.event: 'login.confirmed' | 'login.rejected' | …
148
+ res.sendStatus(200);
149
+ } catch {
150
+ res.sendStatus(403); // not from TouchQue
151
+ }
152
+ });
153
+ ```
154
+
155
+ ## Errors
156
+
157
+ All SDK errors extend `TouchQueError`: `TouchQueAPIError`, `TouchQueNetworkError`,
158
+ `TouchQueRejectedError`, `TouchQueTimeoutError`, `TouchQueWebhookSignatureError`,
159
+ `TouchQueConfigError`, `TouchQuePasskeyRequiredError`.
160
+
161
+ ## Security
162
+
163
+ - Every API request is signed HMAC-SHA256 (method, path+query, timestamp, nonce, body hash).
164
+ - The `X-TouchQue-Token` a frontend echoes back is itself signed and bound to
165
+ one user + action + transaction digest — it can't be replayed for a
166
+ different amount, recipient or user.
167
+ - An approval is consumed exactly once, server-side.
168
+ - Your API secret never leaves your server.
169
+
170
+ See [SECURITY.md](./SECURITY.md) to report a vulnerability.
171
+
172
+ ## Requirements
173
+
174
+ - Node.js 18+
175
+ - A [TouchQue Dashboard](https://authenticator.touchque.com) account
176
+
177
+ ## License
178
+
179
+ MIT © [TouchQue](https://touchque.com)