@zykeco/sync-server 0.6.0 → 0.7.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/README.md +70 -0
- package/dist/app.js +3 -1
- package/dist/app.js.map +1 -1
- package/dist/mcp/auth-store.d.ts +25 -0
- package/dist/mcp/auth-store.js +51 -0
- package/dist/mcp/auth-store.js.map +1 -0
- package/dist/mcp/consent.d.ts +16 -0
- package/dist/mcp/consent.js +90 -0
- package/dist/mcp/consent.js.map +1 -0
- package/dist/mcp/oauth.d.ts +20 -0
- package/dist/mcp/oauth.js +60 -1
- package/dist/mcp/oauth.js.map +1 -1
- package/dist/routes/mcp.d.ts +12 -1
- package/dist/routes/mcp.js +239 -20
- package/dist/routes/mcp.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -102,6 +102,76 @@ reply: { wiped: { dailyMetrics, weeklyMetrics, sleepSessions: number }, serverNo
|
|
|
102
102
|
|
|
103
103
|
Deletes every row across the three sync namespaces (blobs untouched). The literal `confirm` string is enforced at the protocol layer.
|
|
104
104
|
|
|
105
|
+
## MCP server
|
|
106
|
+
|
|
107
|
+
The server ships an [MCP](https://modelcontextprotocol.io) endpoint at `POST /mcp` that exposes read-only tools over your synced data. Auth supports two OAuth 2.1 flows:
|
|
108
|
+
|
|
109
|
+
- **`authorization_code` + PKCE** — for interactive clients like the Claude.ai web app and Claude Desktop "Custom Connectors". Dynamic Client Registration (RFC 7591) is supported.
|
|
110
|
+
- **`client_credentials`** — for headless agents / CLIs that hold the `READ_SECRET` directly.
|
|
111
|
+
|
|
112
|
+
### Required env vars
|
|
113
|
+
|
|
114
|
+
| Var | Default | Purpose |
|
|
115
|
+
| ----------------------- | ------- | -------------------------------------------------------------------------------------------------- |
|
|
116
|
+
| `MCP_ENABLED` | `true` | Set `false` to disable the `/mcp` mount entirely. |
|
|
117
|
+
| `MCP_CLIENT_ID` | _req._ | Bootstrap client ID for the headless `client_credentials` grant. Public — pick anything memorable. |
|
|
118
|
+
| `MCP_TOKEN_SECRET` | _req._ | HMAC key for signing bearer tokens. ≥ 32 random bytes. Treat as a secret. |
|
|
119
|
+
| `MCP_TOKEN_TTL_SECONDS` | `3600` | Bearer token lifetime. |
|
|
120
|
+
|
|
121
|
+
### Endpoints
|
|
122
|
+
|
|
123
|
+
| Method | Path | Purpose |
|
|
124
|
+
| ------ | ----------------------------------------- | ------------------------------------------------------- |
|
|
125
|
+
| GET | `/.well-known/oauth-authorization-server` | RFC 8414 metadata (root-level, what MCP clients probe). |
|
|
126
|
+
| GET | `/.well-known/oauth-protected-resource` | RFC 9728 resource metadata pointing back to the AS. |
|
|
127
|
+
| POST | `/mcp/register` | Dynamic Client Registration (RFC 7591). |
|
|
128
|
+
| GET | `/mcp/authorize` | Consent screen (PKCE flow). |
|
|
129
|
+
| POST | `/mcp/authorize` | Consent form submit — issues an authorization code. |
|
|
130
|
+
| POST | `/mcp/oauth/token` | Token endpoint (both grants). |
|
|
131
|
+
| POST | `/mcp` | MCP JSON-RPC. Requires `Authorization: Bearer <token>`. |
|
|
132
|
+
|
|
133
|
+
### Connecting Claude.ai (web or desktop) as a custom connector
|
|
134
|
+
|
|
135
|
+
1. **Deploy your server with `MCP_*` env vars set** and confirm it answers on a public HTTPS URL. From a browser, `https://YOUR_HOST/.well-known/oauth-authorization-server` should return JSON. If you self-host behind a proxy, make sure that path is forwarded to the sync server.
|
|
136
|
+
2. **Open Claude.ai → Settings → Connectors → Add custom connector.**
|
|
137
|
+
3. **Server URL:** enter `https://YOUR_HOST/mcp` (the `/mcp` path matters — that's the JSON-RPC endpoint, not the host root).
|
|
138
|
+
4. **Click Connect.** Claude.ai will:
|
|
139
|
+
- Fetch the discovery doc at `/.well-known/oauth-authorization-server`.
|
|
140
|
+
- Self-register via `POST /mcp/register`.
|
|
141
|
+
- Open a new tab to `https://YOUR_HOST/mcp/authorize?...`.
|
|
142
|
+
5. **On the consent screen:** verify the "Redirects to" line shows `https://claude.ai/api/mcp/auth_callback`. Paste your `READ_SECRET` into the form and click **Authorize**.
|
|
143
|
+
6. **You're done.** Claude.ai redirects back, exchanges the code for a bearer token, and the connector goes online. The eight read tools (`list_daily_metrics`, `list_sleep_sessions`, `get_user_profile`, …) become available in the chat tool picker.
|
|
144
|
+
|
|
145
|
+
Claude Desktop's "Add custom connector" flow is identical — same form, same URL.
|
|
146
|
+
|
|
147
|
+
#### What if Claude.ai shows a 404 at `/authorize`?
|
|
148
|
+
|
|
149
|
+
That means it's hitting the host root instead of the discovered path. Two causes:
|
|
150
|
+
|
|
151
|
+
- The discovery doc isn't reachable. Curl `https://YOUR_HOST/.well-known/oauth-authorization-server` and confirm you get JSON, not your reverse proxy's 404 page. Add the path to your proxy rules.
|
|
152
|
+
- You're on `@zykeco/sync-server < 0.7.0`. Upgrade — the auth-code flow ships from 0.7.0 onward.
|
|
153
|
+
|
|
154
|
+
#### Token / client lifetime
|
|
155
|
+
|
|
156
|
+
- Bearer tokens expire after `MCP_TOKEN_TTL_SECONDS` (default 1 h). Claude.ai re-runs the consent flow when expired.
|
|
157
|
+
- DCR client registrations are **in-memory** — they don't survive a server restart. If you restart the server, remove the connector in Claude.ai and re-add it; takes ten seconds.
|
|
158
|
+
|
|
159
|
+
### Connecting from headless agents (`client_credentials`)
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# 1. Get a token using your READ_SECRET as the client secret.
|
|
163
|
+
curl -X POST https://YOUR_HOST/mcp/oauth/token \
|
|
164
|
+
-d grant_type=client_credentials \
|
|
165
|
+
-d client_id=$MCP_CLIENT_ID \
|
|
166
|
+
-d client_secret=$READ_SECRET
|
|
167
|
+
|
|
168
|
+
# 2. Use the access_token to call MCP.
|
|
169
|
+
curl -X POST https://YOUR_HOST/mcp \
|
|
170
|
+
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
171
|
+
-H "content-type: application/json" \
|
|
172
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
|
|
173
|
+
```
|
|
174
|
+
|
|
105
175
|
## Data model
|
|
106
176
|
|
|
107
177
|
- **`daily_metrics`**, **`weekly_metrics`** — `{ id (PK), isoDate / weekStartIsoDate, metricKey, value, createdAt, updatedAt }`. Composite unique on `(date, metricKey)`.
|
package/dist/app.js
CHANGED
|
@@ -49,7 +49,9 @@ export function buildApp(db, env) {
|
|
|
49
49
|
hrZoneHistory: hrZoneHistoryStore,
|
|
50
50
|
}, auth));
|
|
51
51
|
if (env.mcp) {
|
|
52
|
-
|
|
52
|
+
const { mcp, discovery } = mcpRoutes({ db, env, mcp: env.mcp });
|
|
53
|
+
app.route('/mcp', mcp);
|
|
54
|
+
app.route('/', discovery);
|
|
53
55
|
}
|
|
54
56
|
return app;
|
|
55
57
|
}
|
package/dist/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface RegisteredClient {
|
|
2
|
+
clientId: string;
|
|
3
|
+
redirectUris: string[];
|
|
4
|
+
clientName: string | null;
|
|
5
|
+
createdAt: number;
|
|
6
|
+
}
|
|
7
|
+
export interface AuthCodeRecord {
|
|
8
|
+
clientId: string;
|
|
9
|
+
redirectUri: string;
|
|
10
|
+
codeChallenge: string;
|
|
11
|
+
codeChallengeMethod: 'S256';
|
|
12
|
+
expiresAt: number;
|
|
13
|
+
}
|
|
14
|
+
export interface AuthStore {
|
|
15
|
+
bootstrap(clientId: string): void;
|
|
16
|
+
registerClient(input: {
|
|
17
|
+
redirectUris: string[];
|
|
18
|
+
clientName?: string | null;
|
|
19
|
+
}, nowMs?: number): RegisteredClient;
|
|
20
|
+
getClient(clientId: string): RegisteredClient | undefined;
|
|
21
|
+
issueCode(rec: Omit<AuthCodeRecord, 'expiresAt'>, nowMs?: number): string;
|
|
22
|
+
consumeCode(code: string, nowMs?: number): AuthCodeRecord | null;
|
|
23
|
+
clear(): void;
|
|
24
|
+
}
|
|
25
|
+
export declare function createAuthStore(): AuthStore;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
const AUTH_CODE_TTL_MS = 5 * 60 * 1000;
|
|
3
|
+
export function createAuthStore() {
|
|
4
|
+
const clients = new Map();
|
|
5
|
+
const codes = new Map();
|
|
6
|
+
return {
|
|
7
|
+
bootstrap(clientId) {
|
|
8
|
+
if (!clients.has(clientId)) {
|
|
9
|
+
clients.set(clientId, {
|
|
10
|
+
clientId,
|
|
11
|
+
redirectUris: [],
|
|
12
|
+
clientName: 'bootstrap (client_credentials only)',
|
|
13
|
+
createdAt: Date.now(),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
registerClient({ redirectUris, clientName = null }, nowMs = Date.now()) {
|
|
18
|
+
const clientId = `mcp_${randomBytes(18).toString('base64url')}`;
|
|
19
|
+
const client = {
|
|
20
|
+
clientId,
|
|
21
|
+
redirectUris: [...redirectUris],
|
|
22
|
+
clientName,
|
|
23
|
+
createdAt: nowMs,
|
|
24
|
+
};
|
|
25
|
+
clients.set(clientId, client);
|
|
26
|
+
return client;
|
|
27
|
+
},
|
|
28
|
+
getClient(clientId) {
|
|
29
|
+
return clients.get(clientId);
|
|
30
|
+
},
|
|
31
|
+
issueCode(rec, nowMs = Date.now()) {
|
|
32
|
+
const code = randomBytes(32).toString('base64url');
|
|
33
|
+
codes.set(code, { ...rec, expiresAt: nowMs + AUTH_CODE_TTL_MS });
|
|
34
|
+
return code;
|
|
35
|
+
},
|
|
36
|
+
consumeCode(code, nowMs = Date.now()) {
|
|
37
|
+
const rec = codes.get(code);
|
|
38
|
+
if (!rec)
|
|
39
|
+
return null;
|
|
40
|
+
codes.delete(code); // single-use
|
|
41
|
+
if (nowMs >= rec.expiresAt)
|
|
42
|
+
return null;
|
|
43
|
+
return rec;
|
|
44
|
+
},
|
|
45
|
+
clear() {
|
|
46
|
+
clients.clear();
|
|
47
|
+
codes.clear();
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=auth-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../src/mcp/auth-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiB1C,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAcvC,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEhD,OAAO;QACL,SAAS,CAAC,QAAQ;YAChB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3B,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE;oBACpB,QAAQ;oBACR,YAAY,EAAE,EAAE;oBAChB,UAAU,EAAE,qCAAqC;oBACjD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,cAAc,CAAC,EAAE,YAAY,EAAE,UAAU,GAAG,IAAI,EAAE,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;YACpE,MAAM,QAAQ,GAAG,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAChE,MAAM,MAAM,GAAqB;gBAC/B,QAAQ;gBACR,YAAY,EAAE,CAAC,GAAG,YAAY,CAAC;gBAC/B,UAAU;gBACV,SAAS,EAAE,KAAK;aACjB,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC9B,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,SAAS,CAAC,QAAQ;YAChB,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC/B,CAAC;QACD,SAAS,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;YAC/B,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YACnD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,KAAK,GAAG,gBAAgB,EAAE,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,WAAW,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;YAClC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC5B,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAC;YACtB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa;YACjC,IAAI,KAAK,IAAI,GAAG,CAAC,SAAS;gBAAE,OAAO,IAAI,CAAC;YACxC,OAAO,GAAG,CAAC;QACb,CAAC;QACD,KAAK;YACH,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HtmlEscapedString } from 'hono/utils/html';
|
|
2
|
+
export interface ConsentViewModel {
|
|
3
|
+
clientId: string;
|
|
4
|
+
redirectUri: string;
|
|
5
|
+
state: string;
|
|
6
|
+
codeChallenge: string;
|
|
7
|
+
codeChallengeMethod: 'S256';
|
|
8
|
+
scope: string;
|
|
9
|
+
clientName: string | null;
|
|
10
|
+
error: string | null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Render the consent screen. All user-controlled values are escaped by the
|
|
14
|
+
* `html` template tag — never inject raw strings into the template.
|
|
15
|
+
*/
|
|
16
|
+
export declare function renderConsent(vm: ConsentViewModel): HtmlEscapedString | Promise<HtmlEscapedString>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { html } from 'hono/html';
|
|
2
|
+
const STYLE = `
|
|
3
|
+
:root { color-scheme: light dark; }
|
|
4
|
+
body {
|
|
5
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
6
|
+
max-width: 28rem;
|
|
7
|
+
margin: 3rem auto;
|
|
8
|
+
padding: 0 1.5rem;
|
|
9
|
+
line-height: 1.5;
|
|
10
|
+
}
|
|
11
|
+
h1 { font-size: 1.25rem; margin-bottom: 0.5rem; }
|
|
12
|
+
.meta { font-size: 0.875rem; color: #666; margin-bottom: 1.5rem; }
|
|
13
|
+
.meta dt { font-weight: 600; }
|
|
14
|
+
.meta dd { margin: 0 0 0.5rem 0; word-break: break-all; font-family: ui-monospace, monospace; font-size: 0.8125rem; }
|
|
15
|
+
.warn {
|
|
16
|
+
border: 1px solid #d97706;
|
|
17
|
+
background: #fef3c7;
|
|
18
|
+
color: #78350f;
|
|
19
|
+
padding: 0.75rem 1rem;
|
|
20
|
+
border-radius: 0.375rem;
|
|
21
|
+
font-size: 0.875rem;
|
|
22
|
+
margin-bottom: 1.5rem;
|
|
23
|
+
}
|
|
24
|
+
@media (prefers-color-scheme: dark) {
|
|
25
|
+
.warn { background: #422006; color: #fde68a; border-color: #b45309; }
|
|
26
|
+
.meta { color: #aaa; }
|
|
27
|
+
}
|
|
28
|
+
label { display: block; font-weight: 600; margin-bottom: 0.25rem; }
|
|
29
|
+
input[type="password"] {
|
|
30
|
+
width: 100%; padding: 0.5rem 0.625rem; font-size: 1rem;
|
|
31
|
+
border: 1px solid #ccc; border-radius: 0.375rem; box-sizing: border-box;
|
|
32
|
+
}
|
|
33
|
+
button {
|
|
34
|
+
margin-top: 1rem; padding: 0.625rem 1rem;
|
|
35
|
+
background: #2563eb; color: white; border: 0;
|
|
36
|
+
border-radius: 0.375rem; font-size: 1rem; cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
button:hover { background: #1d4ed8; }
|
|
39
|
+
.err { color: #b91c1c; font-size: 0.875rem; margin-top: 0.5rem; }
|
|
40
|
+
`;
|
|
41
|
+
/**
|
|
42
|
+
* Render the consent screen. All user-controlled values are escaped by the
|
|
43
|
+
* `html` template tag — never inject raw strings into the template.
|
|
44
|
+
*/
|
|
45
|
+
export function renderConsent(vm) {
|
|
46
|
+
const errBlock = vm.error ? html `<p class="err">${vm.error}</p>` : html ``;
|
|
47
|
+
return html `<!doctype html>
|
|
48
|
+
<html lang="en">
|
|
49
|
+
<head>
|
|
50
|
+
<meta charset="utf-8" />
|
|
51
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
52
|
+
<title>Authorize MCP access</title>
|
|
53
|
+
<style>
|
|
54
|
+
${STYLE}
|
|
55
|
+
</style>
|
|
56
|
+
</head>
|
|
57
|
+
<body>
|
|
58
|
+
<main>
|
|
59
|
+
<h1>Authorize MCP access</h1>
|
|
60
|
+
<p class="meta">
|
|
61
|
+
An MCP client is requesting access to your Zyke data. Verify the redirect target before
|
|
62
|
+
continuing.
|
|
63
|
+
</p>
|
|
64
|
+
<dl class="meta">
|
|
65
|
+
<dt>Client</dt>
|
|
66
|
+
<dd>${vm.clientName ?? vm.clientId}</dd>
|
|
67
|
+
<dt>Redirects to</dt>
|
|
68
|
+
<dd>${vm.redirectUri}</dd>
|
|
69
|
+
</dl>
|
|
70
|
+
<p class="warn">
|
|
71
|
+
Only continue if the redirect target above is a domain you trust (e.g.
|
|
72
|
+
<code>https://claude.ai/api/mcp/auth_callback</code>).
|
|
73
|
+
</p>
|
|
74
|
+
<form method="POST" action="/mcp/authorize" autocomplete="off">
|
|
75
|
+
<label for="password">Read secret</label>
|
|
76
|
+
<input id="password" type="password" name="password" autofocus required />
|
|
77
|
+
<input type="hidden" name="client_id" value="${vm.clientId}" />
|
|
78
|
+
<input type="hidden" name="redirect_uri" value="${vm.redirectUri}" />
|
|
79
|
+
<input type="hidden" name="state" value="${vm.state}" />
|
|
80
|
+
<input type="hidden" name="code_challenge" value="${vm.codeChallenge}" />
|
|
81
|
+
<input type="hidden" name="code_challenge_method" value="${vm.codeChallengeMethod}" />
|
|
82
|
+
<input type="hidden" name="scope" value="${vm.scope}" />
|
|
83
|
+
<button type="submit">Authorize</button>
|
|
84
|
+
${errBlock}
|
|
85
|
+
</form>
|
|
86
|
+
</main>
|
|
87
|
+
</body>
|
|
88
|
+
</html>`;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=consent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/mcp/consent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAcjC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCb,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,EAAoB;IAEpB,MAAM,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,kBAAkB,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA,EAAE,CAAC;IAC1E,OAAO,IAAI,CAAA;;;;;;;YAOD,KAAK;;;;;;;;;;;;kBAYC,EAAE,CAAC,UAAU,IAAI,EAAE,CAAC,QAAQ;;kBAE5B,EAAE,CAAC,WAAW;;;;;;;;;2DAS2B,EAAE,CAAC,QAAQ;8DACR,EAAE,CAAC,WAAW;uDACrB,EAAE,CAAC,KAAK;gEACC,EAAE,CAAC,aAAa;uEACT,EAAE,CAAC,mBAAmB;uDACtC,EAAE,CAAC,KAAK;;cAEjD,QAAQ;;;;YAIV,CAAC;AACb,CAAC"}
|
package/dist/mcp/oauth.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { McpEnv } from '../env.js';
|
|
2
|
+
import type { AuthStore } from './auth-store.js';
|
|
2
3
|
export interface TokenIssueResult {
|
|
3
4
|
accessToken: string;
|
|
4
5
|
expiresIn: number;
|
|
@@ -39,3 +40,22 @@ export type GrantResult = {
|
|
|
39
40
|
* + the read secret. Returns the access token on success.
|
|
40
41
|
*/
|
|
41
42
|
export declare function grantClientCredentials(req: ClientCredentialsRequest, env: McpEnv, readSecret: string, nowMs?: number): GrantResult;
|
|
43
|
+
/**
|
|
44
|
+
* Compute the PKCE S256 code challenge for a verifier.
|
|
45
|
+
*
|
|
46
|
+
* RFC 7636 §4.2: `BASE64URL(SHA256(ASCII(verifier)))`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function pkceS256Challenge(verifier: string): string;
|
|
49
|
+
export interface AuthCodeRequest {
|
|
50
|
+
grantType: string;
|
|
51
|
+
code: string;
|
|
52
|
+
redirectUri: string;
|
|
53
|
+
clientId: string;
|
|
54
|
+
codeVerifier: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Validate an authorization_code grant + PKCE verifier and exchange it for a
|
|
58
|
+
* bearer token. The code is single-use — `consumeCode` deletes it regardless
|
|
59
|
+
* of validation outcome past the lookup.
|
|
60
|
+
*/
|
|
61
|
+
export declare function grantAuthorizationCode(req: AuthCodeRequest, env: McpEnv, store: AuthStore, nowMs?: number): GrantResult;
|
package/dist/mcp/oauth.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
1
|
+
import { createHash, createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
2
2
|
const PAYLOAD_RANDOM_BYTES = 16;
|
|
3
3
|
const PAYLOAD_EXPIRY_BYTES = 8;
|
|
4
4
|
const PAYLOAD_BYTES = PAYLOAD_RANDOM_BYTES + PAYLOAD_EXPIRY_BYTES;
|
|
@@ -87,4 +87,63 @@ export function grantClientCredentials(req, env, readSecret, nowMs = Date.now())
|
|
|
87
87
|
}
|
|
88
88
|
return { ok: true, token: issueToken(env, nowMs) };
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Compute the PKCE S256 code challenge for a verifier.
|
|
92
|
+
*
|
|
93
|
+
* RFC 7636 §4.2: `BASE64URL(SHA256(ASCII(verifier)))`.
|
|
94
|
+
*/
|
|
95
|
+
export function pkceS256Challenge(verifier) {
|
|
96
|
+
return b64urlEncode(createHash('sha256').update(verifier).digest());
|
|
97
|
+
}
|
|
98
|
+
function timingSafeEqualStr(a, b) {
|
|
99
|
+
if (a.length !== b.length)
|
|
100
|
+
return false;
|
|
101
|
+
return timingSafeEqual(Buffer.from(a), Buffer.from(b));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Validate an authorization_code grant + PKCE verifier and exchange it for a
|
|
105
|
+
* bearer token. The code is single-use — `consumeCode` deletes it regardless
|
|
106
|
+
* of validation outcome past the lookup.
|
|
107
|
+
*/
|
|
108
|
+
export function grantAuthorizationCode(req, env, store, nowMs = Date.now()) {
|
|
109
|
+
if (req.grantType !== 'authorization_code') {
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
status: 400,
|
|
113
|
+
error: 'unsupported_grant_type',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (!req.code || !req.clientId || !req.codeVerifier || !req.redirectUri) {
|
|
117
|
+
return { ok: false, status: 400, error: 'invalid_request', description: 'missing parameter' };
|
|
118
|
+
}
|
|
119
|
+
// RFC 7636: verifier is 43-128 chars of [A-Z a-z 0-9 - . _ ~]
|
|
120
|
+
if (!/^[A-Za-z0-9._~-]{43,128}$/.test(req.codeVerifier)) {
|
|
121
|
+
return {
|
|
122
|
+
ok: false,
|
|
123
|
+
status: 400,
|
|
124
|
+
error: 'invalid_grant',
|
|
125
|
+
description: 'malformed code_verifier',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const rec = store.consumeCode(req.code, nowMs);
|
|
129
|
+
if (!rec) {
|
|
130
|
+
return {
|
|
131
|
+
ok: false,
|
|
132
|
+
status: 400,
|
|
133
|
+
error: 'invalid_grant',
|
|
134
|
+
description: 'code unknown or expired',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (rec.clientId !== req.clientId) {
|
|
138
|
+
return { ok: false, status: 400, error: 'invalid_grant', description: 'client_id mismatch' };
|
|
139
|
+
}
|
|
140
|
+
if (rec.redirectUri !== req.redirectUri) {
|
|
141
|
+
return { ok: false, status: 400, error: 'invalid_grant', description: 'redirect_uri mismatch' };
|
|
142
|
+
}
|
|
143
|
+
const expected = pkceS256Challenge(req.codeVerifier);
|
|
144
|
+
if (!timingSafeEqualStr(expected, rec.codeChallenge)) {
|
|
145
|
+
return { ok: false, status: 400, error: 'invalid_grant', description: 'pkce mismatch' };
|
|
146
|
+
}
|
|
147
|
+
return { ok: true, token: issueToken(env, nowMs) };
|
|
148
|
+
}
|
|
90
149
|
//# sourceMappingURL=oauth.js.map
|
package/dist/mcp/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/mcp/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/mcp/oauth.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/mcp.d.ts
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import type { Env, McpEnv } from '../env.js';
|
|
3
|
+
import { type AuthStore } from '../mcp/auth-store.js';
|
|
3
4
|
import type { Db } from '../db/client.js';
|
|
4
5
|
export interface McpDeps {
|
|
5
6
|
db: Db;
|
|
6
7
|
env: Env;
|
|
7
8
|
mcp: McpEnv;
|
|
9
|
+
authStore?: AuthStore;
|
|
8
10
|
}
|
|
9
|
-
export
|
|
11
|
+
export interface McpAppRoutes {
|
|
12
|
+
mcp: Hono;
|
|
13
|
+
discovery: Hono;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build the MCP sub-apps. `mcp` is mounted under `/mcp`; `discovery` is
|
|
17
|
+
* mounted at `/` so RFC 8414 / RFC 9728 `.well-known` URLs sit at the root
|
|
18
|
+
* (which is what most MCP clients — including claude.ai — probe).
|
|
19
|
+
*/
|
|
20
|
+
export declare function mcpRoutes(deps: McpDeps): McpAppRoutes;
|
package/dist/routes/mcp.js
CHANGED
|
@@ -1,14 +1,156 @@
|
|
|
1
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
1
2
|
import { Hono } from 'hono';
|
|
2
|
-
import {
|
|
3
|
+
import { createAuthStore } from '../mcp/auth-store.js';
|
|
4
|
+
import { renderConsent } from '../mcp/consent.js';
|
|
5
|
+
import { grantAuthorizationCode, grantClientCredentials, verifyToken } from '../mcp/oauth.js';
|
|
3
6
|
import { createMcpServer } from '../mcp/server.js';
|
|
4
7
|
import { buildTools } from '../mcp/tools.js';
|
|
5
8
|
import { createTimezoneResolver } from '../mcp/timezones.js';
|
|
9
|
+
function issuerFrom(reqUrl) {
|
|
10
|
+
const u = new URL(reqUrl);
|
|
11
|
+
return `${u.protocol}//${u.host}`;
|
|
12
|
+
}
|
|
13
|
+
function authMetadata(issuer) {
|
|
14
|
+
return {
|
|
15
|
+
issuer,
|
|
16
|
+
authorization_endpoint: `${issuer}/mcp/authorize`,
|
|
17
|
+
token_endpoint: `${issuer}/mcp/oauth/token`,
|
|
18
|
+
registration_endpoint: `${issuer}/mcp/register`,
|
|
19
|
+
grant_types_supported: ['authorization_code', 'client_credentials'],
|
|
20
|
+
response_types_supported: ['code'],
|
|
21
|
+
code_challenge_methods_supported: ['S256'],
|
|
22
|
+
token_endpoint_auth_methods_supported: ['none', 'client_secret_post', 'client_secret_basic'],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function resourceMetadata(issuer) {
|
|
26
|
+
return {
|
|
27
|
+
resource: `${issuer}/mcp`,
|
|
28
|
+
authorization_servers: [issuer],
|
|
29
|
+
bearer_methods_supported: ['header'],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build the MCP sub-apps. `mcp` is mounted under `/mcp`; `discovery` is
|
|
34
|
+
* mounted at `/` so RFC 8414 / RFC 9728 `.well-known` URLs sit at the root
|
|
35
|
+
* (which is what most MCP clients — including claude.ai — probe).
|
|
36
|
+
*/
|
|
6
37
|
export function mcpRoutes(deps) {
|
|
7
38
|
const { db, env, mcp } = deps;
|
|
8
39
|
const tz = createTimezoneResolver(db);
|
|
9
40
|
const server = createMcpServer(buildTools(db, tz));
|
|
41
|
+
const store = deps.authStore ?? createAuthStore();
|
|
42
|
+
store.bootstrap(mcp.clientId);
|
|
10
43
|
const app = new Hono();
|
|
11
|
-
//
|
|
44
|
+
// Kept under `/mcp/oauth/...` for backward compat with older clients.
|
|
45
|
+
app.get('/oauth/.well-known/oauth-authorization-server', (c) => c.json(authMetadata(issuerFrom(c.req.url))));
|
|
46
|
+
// --- Dynamic Client Registration (RFC 7591) ------------------------------
|
|
47
|
+
app.post('/register', async (c) => {
|
|
48
|
+
let body;
|
|
49
|
+
try {
|
|
50
|
+
body = (await c.req.json());
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return c.json({ error: 'invalid_client_metadata', error_description: 'body must be JSON' }, 400);
|
|
54
|
+
}
|
|
55
|
+
const redirectUris = body.redirect_uris;
|
|
56
|
+
if (!Array.isArray(redirectUris) || redirectUris.length === 0) {
|
|
57
|
+
return c.json({ error: 'invalid_redirect_uri', error_description: 'redirect_uris is required' }, 400);
|
|
58
|
+
}
|
|
59
|
+
for (const u of redirectUris) {
|
|
60
|
+
if (typeof u !== 'string' || !isAcceptableRedirectUri(u)) {
|
|
61
|
+
return c.json({ error: 'invalid_redirect_uri' }, 400);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const clientName = typeof body.client_name === 'string' ? body.client_name : null;
|
|
65
|
+
const client = store.registerClient({
|
|
66
|
+
redirectUris: redirectUris,
|
|
67
|
+
clientName,
|
|
68
|
+
});
|
|
69
|
+
return c.json({
|
|
70
|
+
client_id: client.clientId,
|
|
71
|
+
client_id_issued_at: Math.floor(client.createdAt / 1000),
|
|
72
|
+
redirect_uris: client.redirectUris,
|
|
73
|
+
...(client.clientName ? { client_name: client.clientName } : {}),
|
|
74
|
+
grant_types: ['authorization_code'],
|
|
75
|
+
response_types: ['code'],
|
|
76
|
+
token_endpoint_auth_method: 'none',
|
|
77
|
+
}, 201);
|
|
78
|
+
});
|
|
79
|
+
// --- Authorization endpoint (auth code + PKCE) ---------------------------
|
|
80
|
+
app.get('/authorize', (c) => {
|
|
81
|
+
const q = c.req.query();
|
|
82
|
+
const v = validateAuthorizeParams(q, store);
|
|
83
|
+
if (v.kind === 'fatal')
|
|
84
|
+
return c.text(`authorization error: ${v.message}`, 400);
|
|
85
|
+
if (v.kind === 'redirect') {
|
|
86
|
+
return c.redirect(appendParams(v.redirectUri, {
|
|
87
|
+
error: v.error,
|
|
88
|
+
error_description: v.message,
|
|
89
|
+
state: q.state ?? '',
|
|
90
|
+
}), 302);
|
|
91
|
+
}
|
|
92
|
+
return c.html(renderConsent({
|
|
93
|
+
clientId: v.client.clientId,
|
|
94
|
+
clientName: v.client.clientName,
|
|
95
|
+
redirectUri: q.redirect_uri,
|
|
96
|
+
state: q.state ?? '',
|
|
97
|
+
codeChallenge: q.code_challenge,
|
|
98
|
+
codeChallengeMethod: 'S256',
|
|
99
|
+
scope: q.scope ?? '',
|
|
100
|
+
error: null,
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
app.post('/authorize', async (c) => {
|
|
104
|
+
const form = await c.req.parseBody();
|
|
105
|
+
const params = { response_type: 'code' };
|
|
106
|
+
for (const k of [
|
|
107
|
+
'client_id',
|
|
108
|
+
'redirect_uri',
|
|
109
|
+
'state',
|
|
110
|
+
'code_challenge',
|
|
111
|
+
'code_challenge_method',
|
|
112
|
+
'scope',
|
|
113
|
+
'password',
|
|
114
|
+
]) {
|
|
115
|
+
const val = form[k];
|
|
116
|
+
if (typeof val === 'string')
|
|
117
|
+
params[k] = val;
|
|
118
|
+
}
|
|
119
|
+
const v = validateAuthorizeParams(params, store);
|
|
120
|
+
if (v.kind === 'fatal')
|
|
121
|
+
return c.text(`authorization error: ${v.message}`, 400);
|
|
122
|
+
if (v.kind === 'redirect') {
|
|
123
|
+
return c.redirect(appendParams(v.redirectUri, {
|
|
124
|
+
error: v.error,
|
|
125
|
+
error_description: v.message,
|
|
126
|
+
state: params.state ?? '',
|
|
127
|
+
}), 302);
|
|
128
|
+
}
|
|
129
|
+
const password = params.password ?? '';
|
|
130
|
+
const a = Buffer.from(password);
|
|
131
|
+
const b = Buffer.from(env.readSecret);
|
|
132
|
+
const ok = a.length === b.length && timingSafeEqual(a, b);
|
|
133
|
+
if (!ok) {
|
|
134
|
+
return c.html(renderConsent({
|
|
135
|
+
clientId: v.client.clientId,
|
|
136
|
+
clientName: v.client.clientName,
|
|
137
|
+
redirectUri: params.redirect_uri,
|
|
138
|
+
state: params.state ?? '',
|
|
139
|
+
codeChallenge: params.code_challenge,
|
|
140
|
+
codeChallengeMethod: 'S256',
|
|
141
|
+
scope: params.scope ?? '',
|
|
142
|
+
error: 'Invalid read secret.',
|
|
143
|
+
}), 401);
|
|
144
|
+
}
|
|
145
|
+
const code = store.issueCode({
|
|
146
|
+
clientId: v.client.clientId,
|
|
147
|
+
redirectUri: params.redirect_uri,
|
|
148
|
+
codeChallenge: params.code_challenge,
|
|
149
|
+
codeChallengeMethod: 'S256',
|
|
150
|
+
});
|
|
151
|
+
return c.redirect(appendParams(params.redirect_uri, { code, state: params.state ?? '' }), 302);
|
|
152
|
+
});
|
|
153
|
+
// --- Token endpoint (both grants) ----------------------------------------
|
|
12
154
|
app.post('/oauth/token', async (c) => {
|
|
13
155
|
let params;
|
|
14
156
|
const ct = c.req.header('content-type') ?? '';
|
|
@@ -19,9 +161,9 @@ export function mcpRoutes(deps) {
|
|
|
19
161
|
else if (ct.includes('application/json')) {
|
|
20
162
|
const body = (await c.req.json());
|
|
21
163
|
params = new URLSearchParams();
|
|
22
|
-
for (const [k,
|
|
23
|
-
if (typeof
|
|
24
|
-
params.set(k,
|
|
164
|
+
for (const [k, val] of Object.entries(body)) {
|
|
165
|
+
if (typeof val === 'string')
|
|
166
|
+
params.set(k, val);
|
|
25
167
|
}
|
|
26
168
|
}
|
|
27
169
|
else {
|
|
@@ -31,6 +173,27 @@ export function mcpRoutes(deps) {
|
|
|
31
173
|
catch {
|
|
32
174
|
return c.json({ error: 'invalid_request', error_description: 'malformed body' }, 400);
|
|
33
175
|
}
|
|
176
|
+
const grantType = params.get('grant_type') ?? '';
|
|
177
|
+
if (grantType === 'authorization_code') {
|
|
178
|
+
const result = grantAuthorizationCode({
|
|
179
|
+
grantType,
|
|
180
|
+
code: params.get('code') ?? '',
|
|
181
|
+
redirectUri: params.get('redirect_uri') ?? '',
|
|
182
|
+
clientId: params.get('client_id') ?? '',
|
|
183
|
+
codeVerifier: params.get('code_verifier') ?? '',
|
|
184
|
+
}, mcp, store);
|
|
185
|
+
if (!result.ok) {
|
|
186
|
+
return c.json({
|
|
187
|
+
error: result.error,
|
|
188
|
+
...(result.description ? { error_description: result.description } : {}),
|
|
189
|
+
}, result.status);
|
|
190
|
+
}
|
|
191
|
+
return c.json({
|
|
192
|
+
access_token: result.token.accessToken,
|
|
193
|
+
token_type: 'Bearer',
|
|
194
|
+
expires_in: result.token.expiresIn,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
34
197
|
// RFC 6749 §2.3.1: client credentials may also be supplied via Basic auth.
|
|
35
198
|
let clientId = params.get('client_id') ?? '';
|
|
36
199
|
let clientSecret = params.get('client_secret') ?? '';
|
|
@@ -45,7 +208,7 @@ export function mcpRoutes(deps) {
|
|
|
45
208
|
clientSecret = decoded.slice(sep + 1);
|
|
46
209
|
}
|
|
47
210
|
}
|
|
48
|
-
const result = grantClientCredentials({ clientId, clientSecret, grantType
|
|
211
|
+
const result = grantClientCredentials({ clientId, clientSecret, grantType }, mcp, env.readSecret);
|
|
49
212
|
if (!result.ok) {
|
|
50
213
|
return c.json({
|
|
51
214
|
error: result.error,
|
|
@@ -58,27 +221,18 @@ export function mcpRoutes(deps) {
|
|
|
58
221
|
expires_in: result.token.expiresIn,
|
|
59
222
|
});
|
|
60
223
|
});
|
|
61
|
-
//
|
|
62
|
-
app.get('/oauth/.well-known/oauth-authorization-server', (c) => {
|
|
63
|
-
const base = new URL(c.req.url);
|
|
64
|
-
const issuer = `${base.protocol}//${base.host}`;
|
|
65
|
-
return c.json({
|
|
66
|
-
issuer,
|
|
67
|
-
token_endpoint: `${issuer}/mcp/oauth/token`,
|
|
68
|
-
grant_types_supported: ['client_credentials'],
|
|
69
|
-
token_endpoint_auth_methods_supported: ['client_secret_post', 'client_secret_basic'],
|
|
70
|
-
response_types_supported: [],
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
// MCP endpoint (JSON-RPC over POST). Requires Bearer token.
|
|
224
|
+
// --- MCP endpoint (JSON-RPC over POST). Requires Bearer token. -----------
|
|
74
225
|
app.post('/', async (c) => {
|
|
75
226
|
const auth = c.req.header('authorization') ?? '';
|
|
227
|
+
const issuer = issuerFrom(c.req.url);
|
|
76
228
|
if (!auth.toLowerCase().startsWith('bearer ')) {
|
|
229
|
+
c.header('WWW-Authenticate', `Bearer realm="MCP", resource_metadata="${issuer}/.well-known/oauth-protected-resource"`);
|
|
77
230
|
return c.json({ error: 'unauthorized' }, 401);
|
|
78
231
|
}
|
|
79
232
|
const token = auth.slice(7).trim();
|
|
80
233
|
const v = verifyToken(token, mcp);
|
|
81
234
|
if (!v.ok) {
|
|
235
|
+
c.header('WWW-Authenticate', `Bearer realm="MCP", error="invalid_token", resource_metadata="${issuer}/.well-known/oauth-protected-resource"`);
|
|
82
236
|
return c.json({ error: 'unauthorized', reason: v.reason }, 401);
|
|
83
237
|
}
|
|
84
238
|
let body;
|
|
@@ -91,6 +245,71 @@ export function mcpRoutes(deps) {
|
|
|
91
245
|
const response = await server.handle(body);
|
|
92
246
|
return c.json(response);
|
|
93
247
|
});
|
|
94
|
-
|
|
248
|
+
// --- Root-level discovery aliases ----------------------------------------
|
|
249
|
+
const discovery = new Hono();
|
|
250
|
+
discovery.get('/.well-known/oauth-authorization-server', (c) => c.json(authMetadata(issuerFrom(c.req.url))));
|
|
251
|
+
discovery.get('/.well-known/oauth-protected-resource', (c) => c.json(resourceMetadata(issuerFrom(c.req.url))));
|
|
252
|
+
// Per draft RFC 9728: the resource server may publish PRM at a path
|
|
253
|
+
// matching the resource URL, e.g. /.well-known/oauth-protected-resource/mcp.
|
|
254
|
+
discovery.get('/.well-known/oauth-protected-resource/mcp', (c) => c.json(resourceMetadata(issuerFrom(c.req.url))));
|
|
255
|
+
return { mcp: app, discovery };
|
|
256
|
+
}
|
|
257
|
+
function validateAuthorizeParams(q, store) {
|
|
258
|
+
const clientId = q.client_id;
|
|
259
|
+
const redirectUri = q.redirect_uri;
|
|
260
|
+
if (!clientId)
|
|
261
|
+
return { kind: 'fatal', message: 'missing client_id' };
|
|
262
|
+
if (!redirectUri)
|
|
263
|
+
return { kind: 'fatal', message: 'missing redirect_uri' };
|
|
264
|
+
const client = store.getClient(clientId);
|
|
265
|
+
if (!client)
|
|
266
|
+
return { kind: 'fatal', message: 'unknown client_id' };
|
|
267
|
+
if (!client.redirectUris.includes(redirectUri)) {
|
|
268
|
+
return { kind: 'fatal', message: 'redirect_uri not registered for this client_id' };
|
|
269
|
+
}
|
|
270
|
+
if (q.response_type !== 'code') {
|
|
271
|
+
return {
|
|
272
|
+
kind: 'redirect',
|
|
273
|
+
redirectUri,
|
|
274
|
+
error: 'unsupported_response_type',
|
|
275
|
+
message: 'only response_type=code is supported',
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
if (!q.code_challenge) {
|
|
279
|
+
return {
|
|
280
|
+
kind: 'redirect',
|
|
281
|
+
redirectUri,
|
|
282
|
+
error: 'invalid_request',
|
|
283
|
+
message: 'code_challenge is required (PKCE)',
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
if (q.code_challenge_method !== 'S256') {
|
|
287
|
+
return {
|
|
288
|
+
kind: 'redirect',
|
|
289
|
+
redirectUri,
|
|
290
|
+
error: 'invalid_request',
|
|
291
|
+
message: 'only code_challenge_method=S256 is supported',
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
return { kind: 'ok', client };
|
|
295
|
+
}
|
|
296
|
+
function appendParams(base, extra) {
|
|
297
|
+
const u = new URL(base);
|
|
298
|
+
for (const [k, v] of Object.entries(extra)) {
|
|
299
|
+
if (v !== '')
|
|
300
|
+
u.searchParams.set(k, v);
|
|
301
|
+
}
|
|
302
|
+
return u.toString();
|
|
303
|
+
}
|
|
304
|
+
function isAcceptableRedirectUri(uri) {
|
|
305
|
+
try {
|
|
306
|
+
const parsed = new URL(uri);
|
|
307
|
+
const isLoopback = parsed.protocol === 'http:' &&
|
|
308
|
+
(parsed.hostname === '127.0.0.1' || parsed.hostname === 'localhost');
|
|
309
|
+
return parsed.protocol === 'https:' || isLoopback;
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
95
314
|
}
|
|
96
315
|
//# sourceMappingURL=mcp.js.map
|
package/dist/routes/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/routes/mcp.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/routes/mcp.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zykeco/sync-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Self-hosted Zyke sync server (Hono + Drizzle + libsql). Imports to auto-start; ships a migrate CLI.",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"author": "P2LS9K GmbH <office@p2ls9k.com>",
|