@dain-os/mcp-server 0.12.0 → 0.15.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/dist/http-util.d.ts +24 -0
- package/dist/http-util.d.ts.map +1 -0
- package/dist/http-util.js +113 -0
- package/dist/http-util.js.map +1 -0
- package/dist/http.d.ts +5 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +89 -29
- package/dist/http.js.map +1 -1
- package/dist/meta.d.ts +1 -1
- package/dist/meta.js +1 -1
- package/dist/oauth/config.d.ts +57 -0
- package/dist/oauth/config.d.ts.map +1 -0
- package/dist/oauth/config.js +74 -0
- package/dist/oauth/config.js.map +1 -0
- package/dist/oauth/consent-page.d.ts +24 -0
- package/dist/oauth/consent-page.d.ts.map +1 -0
- package/dist/oauth/consent-page.js +98 -0
- package/dist/oauth/consent-page.js.map +1 -0
- package/dist/oauth/crypto.d.ts +48 -0
- package/dist/oauth/crypto.d.ts.map +1 -0
- package/dist/oauth/crypto.js +72 -0
- package/dist/oauth/crypto.js.map +1 -0
- package/dist/oauth/handlers.d.ts +89 -0
- package/dist/oauth/handlers.d.ts.map +1 -0
- package/dist/oauth/handlers.js +371 -0
- package/dist/oauth/handlers.js.map +1 -0
- package/dist/oauth/metadata.d.ts +29 -0
- package/dist/oauth/metadata.d.ts.map +1 -0
- package/dist/oauth/metadata.js +33 -0
- package/dist/oauth/metadata.js.map +1 -0
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +28 -4
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/semantic/developer.d.ts.map +1 -1
- package/dist/tools/semantic/developer.js +6 -0
- package/dist/tools/semantic/developer.js.map +1 -1
- package/dist/tools/semantic/tasks.d.ts.map +1 -1
- package/dist/tools/semantic/tasks.js +30 -7
- package/dist/tools/semantic/tasks.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.1 endpoint handlers for the paste-PAT bridge.
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* GET /.well-known/oauth-protected-resource metadata (RFC 9728)
|
|
6
|
+
* GET /.well-known/oauth-authorization-server metadata (RFC 8414)
|
|
7
|
+
* POST /register Dynamic Client Registration (RFC 7591)
|
|
8
|
+
* GET /authorize consent page (paste PAT)
|
|
9
|
+
* POST /authorize issue authorization code
|
|
10
|
+
* POST /token code -> token, refresh -> token
|
|
11
|
+
*
|
|
12
|
+
* The pure cores (validateAuthorizeRequest, createAuthorizationCode,
|
|
13
|
+
* exchangeAuthorizationCode, refreshTokens, recoverPat) are exported and unit
|
|
14
|
+
* tested directly; the handle* wrappers only do req/res plumbing.
|
|
15
|
+
*/
|
|
16
|
+
import { DainOsClient, DainOsApiError } from '../client.js';
|
|
17
|
+
import { PAT_PREFIX, SCOPE, ACCESS_TOKEN_TTL_SECONDS, } from './config.js';
|
|
18
|
+
import { issueAccessToken, issueAuthorizationCode, issueClientId, issueRefreshToken, readAccessToken, readAuthorizationCode, readClientId, readRefreshToken, verifyPkceS256, } from './crypto.js';
|
|
19
|
+
import { authorizationServerMetadata, protectedResourceMetadata } from './metadata.js';
|
|
20
|
+
import { renderConsentPage } from './consent-page.js';
|
|
21
|
+
import { parseFormBody, parseJsonBody, sendHtml, sendJson, sendRedirect, } from '../http-util.js';
|
|
22
|
+
/** An OAuth error renderable as an RFC 6749 error response. */
|
|
23
|
+
export class OAuthError extends Error {
|
|
24
|
+
error;
|
|
25
|
+
status;
|
|
26
|
+
constructor(error, description, status = 400) {
|
|
27
|
+
super(description);
|
|
28
|
+
this.name = 'OAuthError';
|
|
29
|
+
this.error = error;
|
|
30
|
+
this.status = status;
|
|
31
|
+
}
|
|
32
|
+
toBody() {
|
|
33
|
+
return { error: this.error, error_description: this.message };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Pure cores
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
/**
|
|
40
|
+
* Validate the inbound /authorize parameters and the dynamically-registered
|
|
41
|
+
* client. Returns a discriminated result rather than throwing so both the GET
|
|
42
|
+
* (render) and POST (submit) paths can branch cleanly.
|
|
43
|
+
*/
|
|
44
|
+
export async function validateAuthorizeRequest(params) {
|
|
45
|
+
const responseType = params['response_type'];
|
|
46
|
+
const clientId = params['client_id'];
|
|
47
|
+
const redirectUri = params['redirect_uri'];
|
|
48
|
+
const codeChallenge = params['code_challenge'];
|
|
49
|
+
const codeChallengeMethod = params['code_challenge_method'] ?? 'S256';
|
|
50
|
+
if (responseType !== undefined && responseType !== 'code') {
|
|
51
|
+
return { ok: false, error: 'unsupported_response_type', description: 'Only response_type=code is supported.' };
|
|
52
|
+
}
|
|
53
|
+
if (!clientId) {
|
|
54
|
+
return { ok: false, error: 'invalid_request', description: 'client_id is required.' };
|
|
55
|
+
}
|
|
56
|
+
if (!redirectUri) {
|
|
57
|
+
return { ok: false, error: 'invalid_request', description: 'redirect_uri is required.' };
|
|
58
|
+
}
|
|
59
|
+
if (!codeChallenge) {
|
|
60
|
+
return { ok: false, error: 'invalid_request', description: 'code_challenge is required (PKCE).' };
|
|
61
|
+
}
|
|
62
|
+
if (codeChallengeMethod !== 'S256') {
|
|
63
|
+
return { ok: false, error: 'invalid_request', description: 'code_challenge_method must be S256.' };
|
|
64
|
+
}
|
|
65
|
+
let allowedRedirects;
|
|
66
|
+
try {
|
|
67
|
+
const client = await readClientId(clientId);
|
|
68
|
+
allowedRedirects = client.redirect_uris ?? [];
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return { ok: false, error: 'invalid_client', description: 'Unknown or expired client_id. Re-register the connector.' };
|
|
72
|
+
}
|
|
73
|
+
if (!allowedRedirects.includes(redirectUri)) {
|
|
74
|
+
return { ok: false, error: 'invalid_request', description: 'redirect_uri does not match the registered client.' };
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
ok: true,
|
|
78
|
+
parsed: {
|
|
79
|
+
clientId,
|
|
80
|
+
redirectUri,
|
|
81
|
+
codeChallenge,
|
|
82
|
+
codeChallengeMethod,
|
|
83
|
+
state: params['state'],
|
|
84
|
+
scope: params['scope'],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Mint a short-lived authorization code embedding the PAT + PKCE challenge. */
|
|
89
|
+
export async function createAuthorizationCode(input) {
|
|
90
|
+
return issueAuthorizationCode({
|
|
91
|
+
pat: input.pat,
|
|
92
|
+
client_id: input.clientId,
|
|
93
|
+
redirect_uri: input.redirectUri,
|
|
94
|
+
code_challenge: input.codeChallenge,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async function buildTokenResponse(pat) {
|
|
98
|
+
const [access, refresh] = await Promise.all([
|
|
99
|
+
issueAccessToken({ pat }),
|
|
100
|
+
issueRefreshToken({ pat }),
|
|
101
|
+
]);
|
|
102
|
+
return {
|
|
103
|
+
access_token: access,
|
|
104
|
+
token_type: 'Bearer',
|
|
105
|
+
expires_in: ACCESS_TOKEN_TTL_SECONDS,
|
|
106
|
+
refresh_token: refresh,
|
|
107
|
+
scope: SCOPE,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/** authorization_code grant: verify the code + PKCE, return fresh tokens. */
|
|
111
|
+
export async function exchangeAuthorizationCode(form) {
|
|
112
|
+
const code = form['code'];
|
|
113
|
+
const verifier = form['code_verifier'];
|
|
114
|
+
if (!code)
|
|
115
|
+
throw new OAuthError('invalid_request', 'code is required.');
|
|
116
|
+
if (!verifier)
|
|
117
|
+
throw new OAuthError('invalid_request', 'code_verifier is required (PKCE).');
|
|
118
|
+
let claims;
|
|
119
|
+
try {
|
|
120
|
+
claims = await readAuthorizationCode(code);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
throw new OAuthError('invalid_grant', 'Authorization code is invalid or has expired.');
|
|
124
|
+
}
|
|
125
|
+
// OAuth 2.1 / RFC 9700: the client_id and redirect_uri presented here MUST
|
|
126
|
+
// match the values bound into the code. These are mandatory, not best-effort
|
|
127
|
+
// — skipping them when the fields are absent lets a code be redeemed by a
|
|
128
|
+
// client other than the one it was issued to.
|
|
129
|
+
const clientId = form['client_id'];
|
|
130
|
+
const redirectUri = form['redirect_uri'];
|
|
131
|
+
if (!clientId) {
|
|
132
|
+
throw new OAuthError('invalid_request', 'client_id is required.');
|
|
133
|
+
}
|
|
134
|
+
if (claims.client_id !== clientId) {
|
|
135
|
+
throw new OAuthError('invalid_grant', 'client_id does not match the authorization code.');
|
|
136
|
+
}
|
|
137
|
+
if (claims.redirect_uri !== redirectUri) {
|
|
138
|
+
throw new OAuthError('invalid_grant', 'redirect_uri does not match the authorization code.');
|
|
139
|
+
}
|
|
140
|
+
if (!verifyPkceS256(verifier, claims.code_challenge)) {
|
|
141
|
+
throw new OAuthError('invalid_grant', 'PKCE verification failed.');
|
|
142
|
+
}
|
|
143
|
+
return buildTokenResponse(claims.pat);
|
|
144
|
+
}
|
|
145
|
+
/** refresh_token grant: re-issue an access token (and rotate the refresh token). */
|
|
146
|
+
export async function refreshTokens(form) {
|
|
147
|
+
const refreshToken = form['refresh_token'];
|
|
148
|
+
if (!refreshToken)
|
|
149
|
+
throw new OAuthError('invalid_request', 'refresh_token is required.');
|
|
150
|
+
let claims;
|
|
151
|
+
try {
|
|
152
|
+
claims = await readRefreshToken(refreshToken);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
throw new OAuthError('invalid_grant', 'Refresh token is invalid or has expired.');
|
|
156
|
+
}
|
|
157
|
+
return buildTokenResponse(claims.pat);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Recover the underlying PAT from an inbound Authorization Bearer value.
|
|
161
|
+
*
|
|
162
|
+
* Accepts either a raw `dain_pat_...` (Claude Code path, unchanged) or an
|
|
163
|
+
* OAuth access token (encrypted JWT minted by /token). Returns null when the
|
|
164
|
+
* value is neither, so the caller can emit a 401 + WWW-Authenticate challenge.
|
|
165
|
+
*/
|
|
166
|
+
export async function recoverPat(bearer) {
|
|
167
|
+
if (!bearer)
|
|
168
|
+
return null;
|
|
169
|
+
if (bearer.startsWith(PAT_PREFIX))
|
|
170
|
+
return bearer;
|
|
171
|
+
try {
|
|
172
|
+
const { pat } = await readAccessToken(bearer);
|
|
173
|
+
return typeof pat === 'string' && pat.startsWith(PAT_PREFIX) ? pat : null;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Probe the pasted PAT against the API so an obviously wrong token fails on the
|
|
181
|
+
* consent page rather than silently later. A network blip returns 'unknown',
|
|
182
|
+
* which the caller treats as "let it through" so an API hiccup never blocks a
|
|
183
|
+
* genuine connection — the first /mcp call would still reject a bad token.
|
|
184
|
+
*/
|
|
185
|
+
async function validatePat(pat) {
|
|
186
|
+
// Reuse the vetted DainOS client (fixed allowlisted host derivation) rather
|
|
187
|
+
// than a raw fetch, so the only network egress in this package stays in one
|
|
188
|
+
// place. `/auth/me` is the cheapest PAT-authenticated endpoint.
|
|
189
|
+
const client = new DainOsClient(process.env['DAINOS_API_URL'], pat);
|
|
190
|
+
try {
|
|
191
|
+
await client.request('GET', '/auth/me');
|
|
192
|
+
return 'valid';
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
if (error instanceof DainOsApiError && (error.status === 401 || error.status === 403)) {
|
|
196
|
+
return 'invalid';
|
|
197
|
+
}
|
|
198
|
+
return 'unknown';
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// The only OAuth client of this server is Claude, so registered redirect URIs
|
|
202
|
+
// are locked to its callback domains (overridable via env for other clients or
|
|
203
|
+
// local testing). Without this, Dynamic Client Registration accepts ANY
|
|
204
|
+
// redirect_uri, so an attacker could register `https://attacker.example/cb`,
|
|
205
|
+
// phish a user into pasting their PAT on the consent page, and have the
|
|
206
|
+
// resulting authorization code (and thus an impersonating token) delivered to
|
|
207
|
+
// their own server.
|
|
208
|
+
const DEFAULT_REDIRECT_HOSTS = ['claude.ai', 'claude.com', 'anthropic.com'];
|
|
209
|
+
function allowedRedirectHosts() {
|
|
210
|
+
const env = process.env['MCP_ALLOWED_REDIRECT_HOSTS'];
|
|
211
|
+
if (env && env.trim()) {
|
|
212
|
+
return env.split(',').map((h) => h.trim().toLowerCase()).filter(Boolean);
|
|
213
|
+
}
|
|
214
|
+
return DEFAULT_REDIRECT_HOSTS;
|
|
215
|
+
}
|
|
216
|
+
function isLoopback(hostname) {
|
|
217
|
+
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]';
|
|
218
|
+
}
|
|
219
|
+
/** Accept https on an allowlisted host, or http on loopback (local testing). */
|
|
220
|
+
export function isAllowedRedirectUri(uri) {
|
|
221
|
+
let url;
|
|
222
|
+
try {
|
|
223
|
+
url = new URL(uri);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
const host = url.hostname.toLowerCase();
|
|
229
|
+
if (url.protocol === 'http:' && isLoopback(host))
|
|
230
|
+
return true;
|
|
231
|
+
if (url.protocol !== 'https:')
|
|
232
|
+
return false;
|
|
233
|
+
return allowedRedirectHosts().some((allowed) => host === allowed || host.endsWith(`.${allowed}`));
|
|
234
|
+
}
|
|
235
|
+
function extractRedirectUris(body) {
|
|
236
|
+
if (typeof body !== 'object' || body === null)
|
|
237
|
+
return [];
|
|
238
|
+
const record = body;
|
|
239
|
+
const raw = Array.isArray(record['redirect_uris'])
|
|
240
|
+
? record['redirect_uris']
|
|
241
|
+
: typeof record['redirect_uri'] === 'string'
|
|
242
|
+
? [record['redirect_uri']]
|
|
243
|
+
: [];
|
|
244
|
+
return raw.filter((u) => typeof u === 'string' && isAllowedRedirectUri(u));
|
|
245
|
+
}
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
// req/res handlers
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
export function handleProtectedResourceMetadata(res, baseUrl) {
|
|
250
|
+
sendJson(res, 200, protectedResourceMetadata(baseUrl));
|
|
251
|
+
}
|
|
252
|
+
export function handleAuthorizationServerMetadata(res, baseUrl) {
|
|
253
|
+
sendJson(res, 200, authorizationServerMetadata(baseUrl));
|
|
254
|
+
}
|
|
255
|
+
export async function handleRegister(req, res) {
|
|
256
|
+
let body;
|
|
257
|
+
try {
|
|
258
|
+
body = await parseJsonBody(req);
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
sendJson(res, 400, { error: 'invalid_request', error_description: 'Request body must be valid JSON.' });
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const redirectUris = extractRedirectUris(body);
|
|
265
|
+
if (redirectUris.length === 0) {
|
|
266
|
+
sendJson(res, 400, {
|
|
267
|
+
error: 'invalid_redirect_uri',
|
|
268
|
+
error_description: 'redirect_uris is required and must contain at least one URI.',
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const clientId = await issueClientId({ redirect_uris: redirectUris });
|
|
273
|
+
sendJson(res, 201, {
|
|
274
|
+
client_id: clientId,
|
|
275
|
+
client_id_issued_at: Math.floor(Date.now() / 1000),
|
|
276
|
+
redirect_uris: redirectUris,
|
|
277
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
278
|
+
response_types: ['code'],
|
|
279
|
+
token_endpoint_auth_method: 'none',
|
|
280
|
+
scope: SCOPE,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
function renderError(res, description) {
|
|
284
|
+
sendHtml(res, 400, `<!DOCTYPE html><html lang="en-GB"><head><meta charset="utf-8" /><title>Connection error</title></head>` +
|
|
285
|
+
`<body style="font-family:sans-serif;max-width:480px;margin:80px auto;padding:0 24px">` +
|
|
286
|
+
`<h1>Could not start the connection</h1><p>${description.replace(/</g, '<')}</p>` +
|
|
287
|
+
`<p>Please remove the connector and add it again.</p></body></html>`);
|
|
288
|
+
}
|
|
289
|
+
/** GET shows the paste-PAT page; POST validates the PAT and issues a code. */
|
|
290
|
+
export async function handleAuthorize(req, res, query) {
|
|
291
|
+
if (req.method === 'GET') {
|
|
292
|
+
const validation = await validateAuthorizeRequest(query);
|
|
293
|
+
if (!validation.ok) {
|
|
294
|
+
renderError(res, validation.description);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const { parsed } = validation;
|
|
298
|
+
sendHtml(res, 200, renderConsentPage({
|
|
299
|
+
clientId: parsed.clientId,
|
|
300
|
+
redirectUri: parsed.redirectUri,
|
|
301
|
+
codeChallenge: parsed.codeChallenge,
|
|
302
|
+
codeChallengeMethod: parsed.codeChallengeMethod,
|
|
303
|
+
state: parsed.state,
|
|
304
|
+
scope: parsed.scope,
|
|
305
|
+
}));
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
// POST — form submission from the consent page.
|
|
309
|
+
const form = await parseFormBody(req);
|
|
310
|
+
const validation = await validateAuthorizeRequest(form);
|
|
311
|
+
if (!validation.ok) {
|
|
312
|
+
renderError(res, validation.description);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const { parsed } = validation;
|
|
316
|
+
const pat = (form['pat'] ?? '').trim();
|
|
317
|
+
const reRender = (error) => sendHtml(res, 200, renderConsentPage({
|
|
318
|
+
clientId: parsed.clientId,
|
|
319
|
+
redirectUri: parsed.redirectUri,
|
|
320
|
+
codeChallenge: parsed.codeChallenge,
|
|
321
|
+
codeChallengeMethod: parsed.codeChallengeMethod,
|
|
322
|
+
state: parsed.state,
|
|
323
|
+
scope: parsed.scope,
|
|
324
|
+
error,
|
|
325
|
+
}));
|
|
326
|
+
if (!pat.startsWith(PAT_PREFIX)) {
|
|
327
|
+
reRender('That does not look like a DainOS API token. It should start with "dain_pat_".');
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const status = await validatePat(pat);
|
|
331
|
+
if (status === 'invalid') {
|
|
332
|
+
reRender('That token was rejected by DainOS. Create a fresh one and try again.');
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const code = await createAuthorizationCode({
|
|
336
|
+
pat,
|
|
337
|
+
clientId: parsed.clientId,
|
|
338
|
+
redirectUri: parsed.redirectUri,
|
|
339
|
+
codeChallenge: parsed.codeChallenge,
|
|
340
|
+
});
|
|
341
|
+
const redirect = new URL(parsed.redirectUri);
|
|
342
|
+
redirect.searchParams.set('code', code);
|
|
343
|
+
if (parsed.state !== undefined)
|
|
344
|
+
redirect.searchParams.set('state', parsed.state);
|
|
345
|
+
sendRedirect(res, redirect.toString());
|
|
346
|
+
}
|
|
347
|
+
export async function handleToken(req, res) {
|
|
348
|
+
const form = await parseFormBody(req);
|
|
349
|
+
const grantType = form['grant_type'];
|
|
350
|
+
try {
|
|
351
|
+
let tokens;
|
|
352
|
+
if (grantType === 'authorization_code') {
|
|
353
|
+
tokens = await exchangeAuthorizationCode(form);
|
|
354
|
+
}
|
|
355
|
+
else if (grantType === 'refresh_token') {
|
|
356
|
+
tokens = await refreshTokens(form);
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
throw new OAuthError('unsupported_grant_type', `Unsupported grant_type: ${String(grantType)}`);
|
|
360
|
+
}
|
|
361
|
+
sendJson(res, 200, tokens, { 'Cache-Control': 'no-store', Pragma: 'no-cache' });
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
if (error instanceof OAuthError) {
|
|
365
|
+
sendJson(res, error.status, error.toBody(), { 'Cache-Control': 'no-store' });
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
sendJson(res, 500, { error: 'server_error', error_description: 'Unexpected error issuing token.' });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/oauth/handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth discovery documents.
|
|
3
|
+
*
|
|
4
|
+
* Claude's browser connector bootstraps the flow by fetching:
|
|
5
|
+
* 1. /.well-known/oauth-protected-resource (RFC 9728) — points at the AS
|
|
6
|
+
* 2. /.well-known/oauth-authorization-server (RFC 8414) — lists endpoints
|
|
7
|
+
*
|
|
8
|
+
* For a single-origin server like ours, the protected resource and the
|
|
9
|
+
* authorization server are the same origin.
|
|
10
|
+
*/
|
|
11
|
+
export interface ProtectedResourceMetadata {
|
|
12
|
+
resource: string;
|
|
13
|
+
authorization_servers: string[];
|
|
14
|
+
scopes_supported: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface AuthorizationServerMetadata {
|
|
17
|
+
issuer: string;
|
|
18
|
+
authorization_endpoint: string;
|
|
19
|
+
token_endpoint: string;
|
|
20
|
+
registration_endpoint: string;
|
|
21
|
+
response_types_supported: string[];
|
|
22
|
+
grant_types_supported: string[];
|
|
23
|
+
code_challenge_methods_supported: string[];
|
|
24
|
+
token_endpoint_auth_methods_supported: string[];
|
|
25
|
+
scopes_supported: string[];
|
|
26
|
+
}
|
|
27
|
+
export declare function protectedResourceMetadata(baseUrl: string): ProtectedResourceMetadata;
|
|
28
|
+
export declare function authorizationServerMetadata(baseUrl: string): AuthorizationServerMetadata;
|
|
29
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/oauth/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,gCAAgC,EAAE,MAAM,EAAE,CAAC;IAC3C,qCAAqC,EAAE,MAAM,EAAE,CAAC;IAChD,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,yBAAyB,CAMpF;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,2BAA2B,CAaxF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth discovery documents.
|
|
3
|
+
*
|
|
4
|
+
* Claude's browser connector bootstraps the flow by fetching:
|
|
5
|
+
* 1. /.well-known/oauth-protected-resource (RFC 9728) — points at the AS
|
|
6
|
+
* 2. /.well-known/oauth-authorization-server (RFC 8414) — lists endpoints
|
|
7
|
+
*
|
|
8
|
+
* For a single-origin server like ours, the protected resource and the
|
|
9
|
+
* authorization server are the same origin.
|
|
10
|
+
*/
|
|
11
|
+
import { SCOPE } from './config.js';
|
|
12
|
+
export function protectedResourceMetadata(baseUrl) {
|
|
13
|
+
return {
|
|
14
|
+
resource: baseUrl,
|
|
15
|
+
authorization_servers: [baseUrl],
|
|
16
|
+
scopes_supported: [SCOPE],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function authorizationServerMetadata(baseUrl) {
|
|
20
|
+
return {
|
|
21
|
+
issuer: baseUrl,
|
|
22
|
+
authorization_endpoint: `${baseUrl}/authorize`,
|
|
23
|
+
token_endpoint: `${baseUrl}/token`,
|
|
24
|
+
registration_endpoint: `${baseUrl}/register`,
|
|
25
|
+
response_types_supported: ['code'],
|
|
26
|
+
grant_types_supported: ['authorization_code', 'refresh_token'],
|
|
27
|
+
code_challenge_methods_supported: ['S256'],
|
|
28
|
+
// Public client + PKCE. We do not issue client secrets.
|
|
29
|
+
token_endpoint_auth_methods_supported: ['none'],
|
|
30
|
+
scopes_supported: [SCOPE],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/oauth/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAoBpC,MAAM,UAAU,yBAAyB,CAAC,OAAe;IACvD,OAAO;QACL,QAAQ,EAAE,OAAO;QACjB,qBAAqB,EAAE,CAAC,OAAO,CAAC;QAChC,gBAAgB,EAAE,CAAC,KAAK,CAAC;KAC1B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,OAAe;IACzD,OAAO;QACL,MAAM,EAAE,OAAO;QACf,sBAAsB,EAAE,GAAG,OAAO,YAAY;QAC9C,cAAc,EAAE,GAAG,OAAO,QAAQ;QAClC,qBAAqB,EAAE,GAAG,OAAO,WAAW;QAC5C,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,qBAAqB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QAC9D,gCAAgC,EAAE,CAAC,MAAM,CAAC;QAC1C,wDAAwD;QACxD,qCAAqC,EAAE,CAAC,MAAM,CAAC;QAC/C,gBAAgB,EAAE,CAAC,KAAK,CAAC;KAC1B,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,KAAK,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAErF,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,qDAAqD;IACrD,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACpE,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;CACjE;AAKD,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,KAAK,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAErF,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,qDAAqD;IACrD,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACpE,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;IAC/B,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;CACjE;AAKD,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAoXjD,CAAC;AAEF,uFAAuF;AACvF,wBAAgB,iBAAiB,CAC/B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GACtC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQzB"}
|
package/dist/tools/registry.js
CHANGED
|
@@ -79,21 +79,31 @@ export const RESOURCES = {
|
|
|
79
79
|
descriptionJson: { type: 'json', description: 'Plate JSON for internal editor', nullable: true },
|
|
80
80
|
descriptionClientJson: { type: 'json', description: 'Plate JSON for client editor', nullable: true },
|
|
81
81
|
clientViewLocked: { type: 'boolean', description: 'Lock client view from auto-regen' },
|
|
82
|
-
status: { type: 'enum', description: 'Task status', filterable: true, enumValues: ['backlog', 'todo', 'in_progress', '
|
|
82
|
+
status: { type: 'enum', description: 'Task status', filterable: true, enumValues: ['backlog', 'todo', 'in_progress', 'review', 'production_ready', 'blocked', 'done', 'cancelled'] },
|
|
83
|
+
taskType: { type: 'enum', description: 'Conventional-commit type', filterable: true, nullable: true, enumValues: ['feat', 'fix', 'chore', 'refactor', 'docs', 'test'] },
|
|
83
84
|
projectId: { type: 'uuid', description: 'Parent project', filterable: true },
|
|
85
|
+
sprintId: { type: 'uuid', description: 'Parent sprint', filterable: true, nullable: true },
|
|
84
86
|
milestoneId: { type: 'uuid', description: 'Parent milestone', filterable: true, nullable: true },
|
|
87
|
+
parentTaskId: { type: 'uuid', description: 'Parent task (for subtasks)', filterable: true, nullable: true },
|
|
85
88
|
assigneeId: { type: 'uuid', description: 'Assigned user', filterable: true, nullable: true },
|
|
86
89
|
portalAssigneeId: { type: 'uuid', description: 'Portal-user assignee', nullable: true },
|
|
90
|
+
clientCompanyId: { type: 'uuid', description: 'Client company override', nullable: true },
|
|
87
91
|
priorityMoscow: { type: 'enum', description: 'MoSCoW priority', filterable: true, enumValues: ['must', 'should', 'could', 'wont'] },
|
|
92
|
+
priorityScore: { type: 'number', description: 'Priority score (0-100)' },
|
|
93
|
+
effortLevel: { type: 'enum', description: 'Effort estimate', filterable: true, nullable: true, enumValues: ['xs', 's', 'sm', 'm', 'ml', 'l', 'xl'] },
|
|
94
|
+
impactLevel: { type: 'enum', description: 'Impact estimate', filterable: true, nullable: true, enumValues: ['none', 'very_low', 'low', 'medium', 'high', 'very_high', 'maximum'] },
|
|
95
|
+
sizeEstimate: { type: 'enum', description: 'T-shirt size estimate', nullable: true, enumValues: ['xs', 's', 'm', 'l', 'xl'] },
|
|
88
96
|
storyPoints: { type: 'number', description: 'Story points (0-100)' },
|
|
89
97
|
estimatedHours: { type: 'number', description: 'Estimated hours' },
|
|
90
98
|
actualHoursDelta: { type: 'number', description: 'Additive hours increment. actual_hours += delta' },
|
|
91
99
|
isBillable: { type: 'boolean', description: 'Whether task is billable', filterable: true },
|
|
100
|
+
category: { type: 'string', description: 'Free-text category', filterable: true, nullable: true },
|
|
92
101
|
dueDate: { type: 'date', description: 'Due date (ISO 8601)', filterable: true, nullable: true },
|
|
93
102
|
startDate: { type: 'date', description: 'Start date (ISO 8601)', nullable: true },
|
|
94
103
|
completedAt: { type: 'date', description: 'Completion timestamp (auto-set on done)', nullable: true },
|
|
95
104
|
completedBy: { type: 'uuid', description: 'User who completed', nullable: true },
|
|
96
105
|
tags: { type: 'json', description: 'Array of string tags' },
|
|
106
|
+
pillarTags: { type: 'json', description: 'Array of pillar tag strings' },
|
|
97
107
|
},
|
|
98
108
|
},
|
|
99
109
|
task_comments: {
|
|
@@ -195,6 +205,8 @@ export const RESOURCES = {
|
|
|
195
205
|
product_id: { type: 'uuid', description: 'Linked product UUID', nullable: true },
|
|
196
206
|
task_ids: { type: 'json', description: 'Array of task UUIDs (max 100)', nullable: true },
|
|
197
207
|
operator_iam_user_id: { type: 'uuid', description: 'Operator IAM user UUID', nullable: true },
|
|
208
|
+
client_id: { type: 'uuid', description: 'DainOS client company UUID (crm.companies.id)', nullable: true },
|
|
209
|
+
project_ids: { type: 'json', description: 'Array of DainOS project UUIDs', nullable: true },
|
|
198
210
|
},
|
|
199
211
|
},
|
|
200
212
|
developer_changelog: {
|
|
@@ -220,18 +232,27 @@ export const RESOURCES = {
|
|
|
220
232
|
pr_number: { type: 'number', description: 'PR number', nullable: true },
|
|
221
233
|
pr_url: { type: 'string', description: 'PR URL', nullable: true },
|
|
222
234
|
tags: { type: 'json', description: 'Array of string tags', nullable: true },
|
|
235
|
+
client_id: { type: 'uuid', description: 'DainOS client company UUID (crm.companies.id)', nullable: true },
|
|
236
|
+
project_ids: { type: 'json', description: 'Array of DainOS project UUIDs', nullable: true },
|
|
237
|
+
task_ids: { type: 'json', description: 'Array of DainOS task UUIDs', nullable: true },
|
|
223
238
|
},
|
|
224
239
|
},
|
|
225
240
|
developer_knowledge_base: {
|
|
226
241
|
basePath: '/developer/knowledge-base',
|
|
227
|
-
description: 'Dev knowledge base: gotchas, patterns, lessons, decisions, workarounds.
|
|
242
|
+
description: 'Dev knowledge base: gotchas, patterns, lessons, decisions, workarounds. ' +
|
|
243
|
+
'Read with query — pass `search` for free-text (whitespace terms are ANDed across title+description), ' +
|
|
244
|
+
'or omit it to list recent entries. The `project` filter is OPTIONAL: omit it to search across ALL projects. ' +
|
|
245
|
+
'When you do pass `project` it must be a real slug (e.g. "dain-os", "herbert") — an unknown value returns a 422 ' +
|
|
246
|
+
'listing the valid slugs, not an empty result. Max 50 per call. For batch-inserting use log_knowledge_base_entry.',
|
|
228
247
|
searchable: true,
|
|
229
248
|
searchPath: '/developer/knowledge-base/search',
|
|
230
249
|
updateMethod: 'PATCH',
|
|
231
|
-
operations: ['update'],
|
|
250
|
+
operations: ['list', 'update'],
|
|
251
|
+
defaultLimit: 10,
|
|
252
|
+
maxLimit: 50,
|
|
232
253
|
fields: {
|
|
233
254
|
id: { type: 'uuid', description: 'Entry ID', writable: false },
|
|
234
|
-
project: { type: 'string', description: 'Project slug', filterable: true },
|
|
255
|
+
project: { type: 'string', description: 'Project slug, e.g. "dain-os". OPTIONAL filter — omit to search all projects. Unknown slug returns a 422 with the valid list.', filterable: true },
|
|
235
256
|
module: { type: 'string', description: 'Code module', filterable: true },
|
|
236
257
|
category: { type: 'enum', description: 'Entry category', filterable: true, enumValues: ['gotcha', 'pattern', 'lesson', 'decision', 'workaround'] },
|
|
237
258
|
severity: { type: 'enum', description: 'Severity', filterable: true, enumValues: ['critical', 'high', 'medium', 'low'] },
|
|
@@ -243,6 +264,9 @@ export const RESOURCES = {
|
|
|
243
264
|
source_refs: { type: 'json', description: 'Array of links/paths', nullable: true },
|
|
244
265
|
tags: { type: 'json', description: 'Array of tags', nullable: true },
|
|
245
266
|
platform: { type: 'string', description: 'e.g. "supabase"', nullable: true },
|
|
267
|
+
client_id: { type: 'uuid', description: 'DainOS client company UUID (crm.companies.id)', nullable: true },
|
|
268
|
+
project_ids: { type: 'json', description: 'Array of DainOS project UUIDs', nullable: true },
|
|
269
|
+
task_ids: { type: 'json', description: 'Array of DainOS task UUIDs', nullable: true },
|
|
246
270
|
},
|
|
247
271
|
},
|
|
248
272
|
// ── IAM ───────────────────────────────────────────────────────────
|