@assetlab/mcp-server 1.0.2 → 1.1.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 +3 -3
- package/dist/client.d.ts +9 -0
- package/dist/client.js +18 -0
- package/dist/client.js.map +1 -1
- package/dist/oauth.d.ts +20 -0
- package/dist/oauth.js +331 -0
- package/dist/oauth.js.map +1 -0
- package/dist/tools.js +790 -16
- package/dist/tools.js.map +1 -1
- package/dist/worker.d.ts +19 -0
- package/dist/worker.js +121 -0
- package/dist/worker.js.map +1 -0
- package/package.json +13 -5
package/README.md
CHANGED
|
@@ -26,14 +26,14 @@ Connect [Claude](https://claude.ai) to your [AssetLab](https://assetlab.ca) acco
|
|
|
26
26
|
"args": ["-y", "@assetlab/mcp-server"],
|
|
27
27
|
"env": {
|
|
28
28
|
"ASSETLAB_API_KEY": "al_live_...",
|
|
29
|
-
"ASSETLAB_API_URL": "
|
|
29
|
+
"ASSETLAB_API_URL": "your-api-url"
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
> **Tip:** The easiest way to get
|
|
36
|
+
> **Tip:** The easiest way to get this config is to click **Copy Claude Config** directly on your API key in **AssetLab Settings → API Keys** — it pre-fills your key and API URL automatically.
|
|
37
37
|
|
|
38
38
|
3. Restart Claude Desktop. You should see the AssetLab tools available.
|
|
39
39
|
|
|
@@ -42,7 +42,7 @@ Connect [Claude](https://claude.ai) to your [AssetLab](https://assetlab.ca) acco
|
|
|
42
42
|
```bash
|
|
43
43
|
claude mcp add assetlab npx @assetlab/mcp-server \
|
|
44
44
|
-e ASSETLAB_API_KEY=al_live_... \
|
|
45
|
-
-e ASSETLAB_API_URL=
|
|
45
|
+
-e ASSETLAB_API_URL=your-api-url
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
## Example prompts
|
package/dist/client.d.ts
CHANGED
|
@@ -30,6 +30,15 @@ export declare class AssetLabClient {
|
|
|
30
30
|
constructor(config: AssetLabConfig);
|
|
31
31
|
get<T = Record<string, unknown>>(path: string, params?: Record<string, string | number | undefined>): Promise<T>;
|
|
32
32
|
list<T = Record<string, unknown>>(resource: string, params?: Record<string, string | number | undefined>): Promise<PaginatedResponse<T>>;
|
|
33
|
+
/**
|
|
34
|
+
* Fetch all pages of a paginated resource automatically.
|
|
35
|
+
* Uses per_page=1000 to minimize round-trips, then follows
|
|
36
|
+
* pagination until all rows are collected.
|
|
37
|
+
*/
|
|
38
|
+
listAll<T = Record<string, unknown>>(resource: string, params?: Record<string, string | number | undefined>): Promise<{
|
|
39
|
+
data: T[];
|
|
40
|
+
total: number;
|
|
41
|
+
}>;
|
|
33
42
|
getOne<T = Record<string, unknown>>(resource: string, id: string): Promise<SingleResponse<T>>;
|
|
34
43
|
}
|
|
35
44
|
export declare function loadConfig(): AssetLabConfig;
|
package/dist/client.js
CHANGED
|
@@ -66,6 +66,24 @@ export class AssetLabClient {
|
|
|
66
66
|
async list(resource, params) {
|
|
67
67
|
return this.get(`/${resource}`, params);
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Fetch all pages of a paginated resource automatically.
|
|
71
|
+
* Uses per_page=1000 to minimize round-trips, then follows
|
|
72
|
+
* pagination until all rows are collected.
|
|
73
|
+
*/
|
|
74
|
+
async listAll(resource, params) {
|
|
75
|
+
const allData = [];
|
|
76
|
+
let page = 1;
|
|
77
|
+
const perPage = 1000;
|
|
78
|
+
while (true) {
|
|
79
|
+
const result = await this.list(resource, { ...params, page, per_page: perPage });
|
|
80
|
+
allData.push(...result.data);
|
|
81
|
+
if (page >= result.pagination.total_pages)
|
|
82
|
+
break;
|
|
83
|
+
page++;
|
|
84
|
+
}
|
|
85
|
+
return { data: allData, total: allData.length };
|
|
86
|
+
}
|
|
69
87
|
async getOne(resource, id) {
|
|
70
88
|
return this.get(`/${resource}/${id}`);
|
|
71
89
|
}
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal OAuth 2.0 Authorization Server for Claude.ai MCP integration.
|
|
3
|
+
*
|
|
4
|
+
* Implements just enough of OAuth 2.0 + PKCE to satisfy Claude.ai's connector flow:
|
|
5
|
+
* 1. Dynamic client registration (RFC 7591)
|
|
6
|
+
* 2. Authorization endpoint (shows "paste your API key" page)
|
|
7
|
+
* 3. Token endpoint (exchanges auth code for access token)
|
|
8
|
+
*
|
|
9
|
+
* The user's AssetLab API key becomes the OAuth access_token, so the existing
|
|
10
|
+
* MCP handler works unchanged (it reads Bearer token from Authorization header).
|
|
11
|
+
*
|
|
12
|
+
* Authorization codes are encrypted with AES-GCM using OAUTH_SECRET — fully
|
|
13
|
+
* stateless, no KV or Durable Objects needed.
|
|
14
|
+
*/
|
|
15
|
+
export declare function protectedResourceMetadata(origin: string): Response;
|
|
16
|
+
export declare function authServerMetadata(origin: string): Response;
|
|
17
|
+
export declare function handleRegister(request: Request): Promise<Response>;
|
|
18
|
+
export declare function handleAuthorizeGet(request: Request): Response;
|
|
19
|
+
export declare function handleAuthorizePost(request: Request, secret: string): Promise<Response>;
|
|
20
|
+
export declare function handleToken(request: Request, secret: string): Promise<Response>;
|
package/dist/oauth.js
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal OAuth 2.0 Authorization Server for Claude.ai MCP integration.
|
|
3
|
+
*
|
|
4
|
+
* Implements just enough of OAuth 2.0 + PKCE to satisfy Claude.ai's connector flow:
|
|
5
|
+
* 1. Dynamic client registration (RFC 7591)
|
|
6
|
+
* 2. Authorization endpoint (shows "paste your API key" page)
|
|
7
|
+
* 3. Token endpoint (exchanges auth code for access token)
|
|
8
|
+
*
|
|
9
|
+
* The user's AssetLab API key becomes the OAuth access_token, so the existing
|
|
10
|
+
* MCP handler works unchanged (it reads Bearer token from Authorization header).
|
|
11
|
+
*
|
|
12
|
+
* Authorization codes are encrypted with AES-GCM using OAUTH_SECRET — fully
|
|
13
|
+
* stateless, no KV or Durable Objects needed.
|
|
14
|
+
*/
|
|
15
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
16
|
+
function base64url(buf) {
|
|
17
|
+
const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
|
|
18
|
+
let binary = '';
|
|
19
|
+
for (const b of bytes)
|
|
20
|
+
binary += String.fromCharCode(b);
|
|
21
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
22
|
+
}
|
|
23
|
+
function fromBase64url(s) {
|
|
24
|
+
const padded = s.replace(/-/g, '+').replace(/_/g, '/') + '=='.slice(0, (4 - (s.length % 4)) % 4);
|
|
25
|
+
const binary = atob(padded);
|
|
26
|
+
const bytes = new Uint8Array(binary.length);
|
|
27
|
+
for (let i = 0; i < binary.length; i++)
|
|
28
|
+
bytes[i] = binary.charCodeAt(i);
|
|
29
|
+
return bytes;
|
|
30
|
+
}
|
|
31
|
+
async function deriveKey(secret) {
|
|
32
|
+
const raw = new TextEncoder().encode(secret);
|
|
33
|
+
const hash = await crypto.subtle.digest('SHA-256', raw);
|
|
34
|
+
return crypto.subtle.importKey('raw', hash, 'AES-GCM', false, ['encrypt', 'decrypt']);
|
|
35
|
+
}
|
|
36
|
+
async function encrypt(payload, secret) {
|
|
37
|
+
const key = await deriveKey(secret);
|
|
38
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
39
|
+
const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, new TextEncoder().encode(payload));
|
|
40
|
+
const combined = new Uint8Array(iv.length + new Uint8Array(ciphertext).length);
|
|
41
|
+
combined.set(iv);
|
|
42
|
+
combined.set(new Uint8Array(ciphertext), iv.length);
|
|
43
|
+
return base64url(combined);
|
|
44
|
+
}
|
|
45
|
+
async function decrypt(code, secret) {
|
|
46
|
+
const data = fromBase64url(code);
|
|
47
|
+
const iv = data.slice(0, 12);
|
|
48
|
+
const ciphertext = data.slice(12);
|
|
49
|
+
const key = await deriveKey(secret);
|
|
50
|
+
const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);
|
|
51
|
+
return new TextDecoder().decode(decrypted);
|
|
52
|
+
}
|
|
53
|
+
// ── CORS ─────────────────────────────────────────────────────────────────────
|
|
54
|
+
const CORS = {
|
|
55
|
+
'Access-Control-Allow-Origin': '*',
|
|
56
|
+
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
|
|
57
|
+
'Access-Control-Allow-Headers': 'Authorization, Content-Type, MCP-Protocol-Version, Accept',
|
|
58
|
+
};
|
|
59
|
+
function json(body, status = 200, extra = {}) {
|
|
60
|
+
return new Response(JSON.stringify(body), {
|
|
61
|
+
status,
|
|
62
|
+
headers: { 'Content-Type': 'application/json', ...CORS, ...extra },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
// ── Discovery endpoints ─────────────────────────────────────────────────────
|
|
66
|
+
export function protectedResourceMetadata(origin) {
|
|
67
|
+
const resource = origin.endsWith('/') ? origin : `${origin}/`;
|
|
68
|
+
return json({
|
|
69
|
+
resource,
|
|
70
|
+
authorization_servers: [origin],
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export function authServerMetadata(origin) {
|
|
74
|
+
return json({
|
|
75
|
+
issuer: origin,
|
|
76
|
+
authorization_endpoint: `${origin}/authorize`,
|
|
77
|
+
token_endpoint: `${origin}/token`,
|
|
78
|
+
registration_endpoint: `${origin}/register`,
|
|
79
|
+
response_types_supported: ['code'],
|
|
80
|
+
grant_types_supported: ['authorization_code'],
|
|
81
|
+
scopes_supported: ['claudeai', 'mcp'],
|
|
82
|
+
code_challenge_methods_supported: ['S256'],
|
|
83
|
+
token_endpoint_auth_methods_supported: ['none'],
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// ── Dynamic client registration (RFC 7591) ──────────────────────────────────
|
|
87
|
+
export async function handleRegister(request) {
|
|
88
|
+
const body = await request.json();
|
|
89
|
+
const clientId = crypto.randomUUID();
|
|
90
|
+
return json({
|
|
91
|
+
client_id: clientId,
|
|
92
|
+
client_name: body.client_name ?? 'Claude.ai',
|
|
93
|
+
redirect_uris: body.redirect_uris ?? [],
|
|
94
|
+
grant_types: body.grant_types ?? ['authorization_code'],
|
|
95
|
+
response_types: body.response_types ?? ['code'],
|
|
96
|
+
token_endpoint_auth_method: 'none',
|
|
97
|
+
}, 201);
|
|
98
|
+
}
|
|
99
|
+
// ── Authorization endpoint ──────────────────────────────────────────────────
|
|
100
|
+
export function handleAuthorizeGet(request) {
|
|
101
|
+
const url = new URL(request.url);
|
|
102
|
+
const state = url.searchParams.get('state') ?? '';
|
|
103
|
+
const redirectUri = url.searchParams.get('redirect_uri') ?? '';
|
|
104
|
+
const codeChallenge = url.searchParams.get('code_challenge') ?? '';
|
|
105
|
+
const clientId = url.searchParams.get('client_id') ?? '';
|
|
106
|
+
const scope = url.searchParams.get('scope') ?? '';
|
|
107
|
+
const html = `<!DOCTYPE html>
|
|
108
|
+
<html lang="en">
|
|
109
|
+
<head>
|
|
110
|
+
<meta charset="utf-8"/>
|
|
111
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
112
|
+
<title>Connect to AssetLab</title>
|
|
113
|
+
<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
|
114
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
|
|
115
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Lexend:wght@400;500;600&display=swap" rel="stylesheet"/>
|
|
116
|
+
<style>
|
|
117
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
118
|
+
body{font-family:'Inter',system-ui,sans-serif;background:rgb(3,6,22);color:#fff;
|
|
119
|
+
min-height:100vh;display:flex;flex-direction:column;align-items:center;
|
|
120
|
+
justify-content:center;padding:1rem;position:relative;overflow:hidden}
|
|
121
|
+
/* base grid - white, faded on edges */
|
|
122
|
+
.grid-base{position:fixed;inset:0;pointer-events:none;z-index:0;opacity:.04;
|
|
123
|
+
background-image:linear-gradient(rgba(255,255,255,.4) 1px,transparent 1px),
|
|
124
|
+
linear-gradient(90deg,rgba(255,255,255,.4) 1px,transparent 1px);
|
|
125
|
+
background-size:60px 60px;
|
|
126
|
+
-webkit-mask-image:radial-gradient(ellipse 60% 60% at 50% 50%,black 0%,transparent 100%);
|
|
127
|
+
mask-image:radial-gradient(ellipse 60% 60% at 50% 50%,black 0%,transparent 100%)}
|
|
128
|
+
/* mouse hover glow on grid */
|
|
129
|
+
.grid-glow{position:fixed;inset:0;pointer-events:none;z-index:0;
|
|
130
|
+
background-image:linear-gradient(rgba(106,208,157,.3) 1px,transparent 1px),
|
|
131
|
+
linear-gradient(90deg,rgba(106,208,157,.3) 1px,transparent 1px);
|
|
132
|
+
background-size:60px 60px;transition:opacity .3s;
|
|
133
|
+
-webkit-mask-image:radial-gradient(circle 120px at 0px 0px,black 0%,transparent 100%);
|
|
134
|
+
mask-image:radial-gradient(circle 120px at 0px 0px,black 0%,transparent 100%)}
|
|
135
|
+
.logo{display:flex;align-items:center;gap:.625rem;margin-bottom:2rem;position:relative;z-index:1}
|
|
136
|
+
.logo svg{width:48px;height:48px}
|
|
137
|
+
.logo-text{font-family:'Lexend',sans-serif;font-size:1.5rem;font-weight:500;letter-spacing:-.025em}
|
|
138
|
+
.logo-text .lab{color:#45c28b}
|
|
139
|
+
.card{background:transparent;backdrop-filter:blur(4px);border-radius:1rem;
|
|
140
|
+
border:1px solid rgba(255,255,255,.2);max-width:420px;width:100%;
|
|
141
|
+
padding:2rem;position:relative;z-index:1}
|
|
142
|
+
h1{font-family:'Lexend',sans-serif;font-size:1.25rem;font-weight:500;margin-bottom:.25rem;
|
|
143
|
+
letter-spacing:-.025em}
|
|
144
|
+
.sub{color:#d1d5db;font-size:.875rem;margin-bottom:1.5rem}
|
|
145
|
+
label{display:flex;align-items:center;gap:.5rem;color:#e5e7eb;font-weight:500;
|
|
146
|
+
font-size:.875rem;margin-bottom:.375rem}
|
|
147
|
+
label svg{width:16px;height:16px;color:#9ca3af;flex-shrink:0}
|
|
148
|
+
input[type="password"]{width:100%;padding:.625rem .75rem;background:transparent;
|
|
149
|
+
border:1px solid rgba(255,255,255,.2);border-radius:.5rem;font-size:.875rem;
|
|
150
|
+
font-family:'JetBrains Mono',monospace;color:#fff;outline:none;transition:border-color .15s,box-shadow .15s}
|
|
151
|
+
input[type="password"]::placeholder{color:#6b7280}
|
|
152
|
+
input[type="password"]:focus{border-color:rgb(106,208,157);
|
|
153
|
+
box-shadow:0 0 0 3px rgba(106,208,157,.15)}
|
|
154
|
+
.help{color:#6b7280;font-size:.75rem;margin-top:.375rem}
|
|
155
|
+
button{width:100%;margin-top:1.25rem;padding:.625rem;
|
|
156
|
+
background:rgb(106,208,157);color:rgb(3,6,22);border:none;border-radius:.5rem;
|
|
157
|
+
font-family:'Inter',sans-serif;font-size:.875rem;font-weight:600;cursor:pointer;
|
|
158
|
+
transition:background .15s}
|
|
159
|
+
button:hover{background:rgb(86,188,137)}
|
|
160
|
+
button:disabled{background:#4b5563;color:#9ca3af;cursor:not-allowed}
|
|
161
|
+
.footer{text-align:center;margin-top:1rem;font-size:.75rem;color:#6b7280}
|
|
162
|
+
/* subtle glow behind card */
|
|
163
|
+
.glow{position:fixed;width:400px;height:400px;border-radius:50%;
|
|
164
|
+
background:radial-gradient(circle,rgba(106,208,157,.08),transparent 70%);
|
|
165
|
+
top:50%;left:50%;transform:translate(-50%,-50%);pointer-events:none;z-index:0}
|
|
166
|
+
</style>
|
|
167
|
+
</head>
|
|
168
|
+
<body>
|
|
169
|
+
<div class="grid-base"></div>
|
|
170
|
+
<div class="grid-glow" id="gridGlow"></div>
|
|
171
|
+
<div class="glow"></div>
|
|
172
|
+
<div class="logo">
|
|
173
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 292.3 292.3">
|
|
174
|
+
<g transform="translate(95.414,86.487)">
|
|
175
|
+
<circle fill="#45c28b" cx="-74.77" cy="-51.34" r="20"/>
|
|
176
|
+
<circle fill="#45c28b" cx="-74.53" cy="1.19" r="20"/>
|
|
177
|
+
<circle fill="#45c28b" cx="-22.24" cy="-28.91" r="20"/>
|
|
178
|
+
<circle fill="#fbd04e" cx="-74.67" cy="56.37" r="20"/>
|
|
179
|
+
<circle fill="#fbd04e" cx="-74.58" cy="120.34" r="20"/>
|
|
180
|
+
<circle fill="#fbd04e" cx="-74.49" cy="172.05" r="20"/>
|
|
181
|
+
<circle fill="#fbd04e" cx="-23.77" cy="26.56" r="20"/>
|
|
182
|
+
<circle fill="#fbd04e" cx="22.72" cy="-7.36" r="15"/>
|
|
183
|
+
<circle fill="#fbd04e" cx="-21.38" cy="89.52" r="17"/>
|
|
184
|
+
<circle fill="#fbd04e" cx="30.77" cy="51.30" r="20"/>
|
|
185
|
+
<circle fill="#fbd04e" cx="-21.89" cy="159.66" r="17"/>
|
|
186
|
+
<circle fill="#fbd04e" cx="22.92" cy="173.41" r="15"/>
|
|
187
|
+
<circle fill="#fbd04e" cx="35.15" cy="119.00" r="20"/>
|
|
188
|
+
<circle fill="#fbd04e" cx="79.51" cy="79.64" r="15"/>
|
|
189
|
+
<circle fill="#f78265" cx="72.59" cy="161.68" r="20"/>
|
|
190
|
+
<circle fill="#f78265" cx="110.66" cy="131.00" r="12"/>
|
|
191
|
+
<circle fill="#f78265" cx="121.37" cy="86.82" r="12"/>
|
|
192
|
+
<circle fill="#f78265" cx="155.50" cy="110.89" r="15"/>
|
|
193
|
+
<circle fill="#f78265" cx="136.27" cy="172.43" r="15"/>
|
|
194
|
+
<circle fill="#f78265" cx="182.53" cy="154.52" r="15"/>
|
|
195
|
+
</g>
|
|
196
|
+
</svg>
|
|
197
|
+
<span class="logo-text">Asset<span class="lab">Lab</span></span>
|
|
198
|
+
</div>
|
|
199
|
+
<div class="card">
|
|
200
|
+
<h1>Connect to AssetLab</h1>
|
|
201
|
+
<p class="sub">Claude.ai wants to access your AssetLab workspace via MCP.</p>
|
|
202
|
+
<form method="POST" action="/authorize" id="form">
|
|
203
|
+
<input type="hidden" name="state" value="${escapeHtml(state)}"/>
|
|
204
|
+
<input type="hidden" name="redirect_uri" value="${escapeHtml(redirectUri)}"/>
|
|
205
|
+
<input type="hidden" name="code_challenge" value="${escapeHtml(codeChallenge)}"/>
|
|
206
|
+
<input type="hidden" name="client_id" value="${escapeHtml(clientId)}"/>
|
|
207
|
+
<input type="hidden" name="scope" value="${escapeHtml(scope)}"/>
|
|
208
|
+
<label for="api_key">
|
|
209
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21 2-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0 3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>
|
|
210
|
+
API Key
|
|
211
|
+
</label>
|
|
212
|
+
<input type="password" id="api_key" name="api_key" placeholder="al_live_..." required
|
|
213
|
+
pattern="al_(live|test)_.+" title="Must start with al_live_ or al_test_"/>
|
|
214
|
+
<p class="help">Find this in AssetLab → Settings → API Keys</p>
|
|
215
|
+
<button type="submit" id="btn">Authorize</button>
|
|
216
|
+
</form>
|
|
217
|
+
<p class="footer">Your key is sent directly to AssetLab and never stored by this server.</p>
|
|
218
|
+
</div>
|
|
219
|
+
<script>
|
|
220
|
+
document.getElementById('form').addEventListener('submit',()=>{
|
|
221
|
+
document.getElementById('btn').disabled=true;
|
|
222
|
+
document.getElementById('btn').textContent='Connecting…';
|
|
223
|
+
});
|
|
224
|
+
(function(){
|
|
225
|
+
var g=document.getElementById('gridGlow');
|
|
226
|
+
document.addEventListener('mousemove',function(e){
|
|
227
|
+
var m='radial-gradient(circle 120px at '+e.clientX+'px '+e.clientY+'px,black 0%,transparent 100%)';
|
|
228
|
+
g.style.webkitMaskImage=m;g.style.maskImage=m;
|
|
229
|
+
});
|
|
230
|
+
})();
|
|
231
|
+
</script>
|
|
232
|
+
</body>
|
|
233
|
+
</html>`;
|
|
234
|
+
return new Response(html, {
|
|
235
|
+
status: 200,
|
|
236
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8', ...CORS },
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
export async function handleAuthorizePost(request, secret) {
|
|
240
|
+
const form = await request.formData();
|
|
241
|
+
const apiKey = form.get('api_key')?.trim();
|
|
242
|
+
const state = form.get('state');
|
|
243
|
+
const redirectUri = form.get('redirect_uri');
|
|
244
|
+
const codeChallenge = form.get('code_challenge');
|
|
245
|
+
const scope = form.get('scope') ?? '';
|
|
246
|
+
console.log('[authorize POST]', JSON.stringify({ hasApiKey: !!apiKey, state, redirectUri, codeChallenge, scope }));
|
|
247
|
+
if (!apiKey || !redirectUri) {
|
|
248
|
+
return json({ error: 'missing_parameters' }, 400);
|
|
249
|
+
}
|
|
250
|
+
const payload = {
|
|
251
|
+
apiKey,
|
|
252
|
+
codeChallenge,
|
|
253
|
+
redirectUri,
|
|
254
|
+
scope,
|
|
255
|
+
exp: Date.now() + 600_000, // 10 minutes
|
|
256
|
+
};
|
|
257
|
+
const code = await encrypt(JSON.stringify(payload), secret);
|
|
258
|
+
const target = new URL(redirectUri);
|
|
259
|
+
target.searchParams.set('code', code);
|
|
260
|
+
if (state)
|
|
261
|
+
target.searchParams.set('state', state);
|
|
262
|
+
console.log('[authorize POST] redirecting to', target.toString().slice(0, 100));
|
|
263
|
+
return Response.redirect(target.toString(), 302);
|
|
264
|
+
}
|
|
265
|
+
// ── Token endpoint ──────────────────────────────────────────────────────────
|
|
266
|
+
export async function handleToken(request, secret) {
|
|
267
|
+
let params;
|
|
268
|
+
const ct = request.headers.get('Content-Type') ?? '';
|
|
269
|
+
if (ct.includes('application/json')) {
|
|
270
|
+
const body = await request.json();
|
|
271
|
+
params = new URLSearchParams(body);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
params = new URLSearchParams(await request.text());
|
|
275
|
+
}
|
|
276
|
+
const code = params.get('code');
|
|
277
|
+
const codeVerifier = params.get('code_verifier');
|
|
278
|
+
const redirectUri = params.get('redirect_uri');
|
|
279
|
+
const grantType = params.get('grant_type');
|
|
280
|
+
console.log('[token]', JSON.stringify({
|
|
281
|
+
grantType, hasCode: !!code, hasVerifier: !!codeVerifier, redirectUri,
|
|
282
|
+
contentType: ct,
|
|
283
|
+
}));
|
|
284
|
+
if (!code)
|
|
285
|
+
return json({ error: 'invalid_request', error_description: 'Missing code' }, 400);
|
|
286
|
+
let payload;
|
|
287
|
+
try {
|
|
288
|
+
payload = JSON.parse(await decrypt(code, secret));
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
console.log('[token] decrypt failed:', err instanceof Error ? err.message : err);
|
|
292
|
+
return json({ error: 'invalid_grant', error_description: 'Invalid or expired code' }, 400);
|
|
293
|
+
}
|
|
294
|
+
console.log('[token] decrypted payload:', JSON.stringify({
|
|
295
|
+
hasApiKey: !!payload.apiKey,
|
|
296
|
+
codeChallenge: payload.codeChallenge,
|
|
297
|
+
redirectUri: payload.redirectUri,
|
|
298
|
+
exp: payload.exp,
|
|
299
|
+
now: Date.now(),
|
|
300
|
+
}));
|
|
301
|
+
if (Date.now() > payload.exp) {
|
|
302
|
+
console.log('[token] code expired');
|
|
303
|
+
return json({ error: 'invalid_grant', error_description: 'Code expired' }, 400);
|
|
304
|
+
}
|
|
305
|
+
if (redirectUri && payload.redirectUri !== redirectUri) {
|
|
306
|
+
console.log('[token] redirect URI mismatch:', payload.redirectUri, '!=', redirectUri);
|
|
307
|
+
return json({ error: 'invalid_grant', error_description: 'Redirect URI mismatch' }, 400);
|
|
308
|
+
}
|
|
309
|
+
// Verify PKCE
|
|
310
|
+
if (payload.codeChallenge && codeVerifier) {
|
|
311
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier));
|
|
312
|
+
const expected = base64url(digest);
|
|
313
|
+
console.log('[token] PKCE check:', expected, '===', payload.codeChallenge, '→', expected === payload.codeChallenge);
|
|
314
|
+
if (expected !== payload.codeChallenge) {
|
|
315
|
+
return json({ error: 'invalid_grant', error_description: 'PKCE verification failed' }, 400);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
console.log('[token] success, returning access_token');
|
|
319
|
+
// The API key IS the access token — the MCP handler already reads it from Bearer header
|
|
320
|
+
return json({
|
|
321
|
+
access_token: payload.apiKey,
|
|
322
|
+
token_type: 'Bearer',
|
|
323
|
+
expires_in: 3600,
|
|
324
|
+
scope: payload.scope || 'mcp',
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
// ── Utility ─────────────────────────────────────────────────────────────────
|
|
328
|
+
function escapeHtml(s) {
|
|
329
|
+
return s.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
|