@dain-os/mcp-server 0.12.0 → 0.13.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.
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Low-level HTTP helpers shared by the MCP JSON-RPC handler and the OAuth
3
+ * endpoints. Centralises the CORS headers and the handful of response shapes
4
+ * we emit (JSON, HTML, redirect, no-content) plus tolerant body parsing.
5
+ */
6
+ import type { IncomingMessage, ServerResponse } from 'node:http';
7
+ export declare const CORS_HEADERS: Record<string, string>;
8
+ export declare function sendJson(res: ServerResponse, status: number, body: unknown, extraHeaders?: Record<string, string>): void;
9
+ export declare function sendHtml(res: ServerResponse, status: number, html: string): void;
10
+ export declare function sendRedirect(res: ServerResponse, location: string): void;
11
+ export declare function sendNoContent(res: ServerResponse, status: number): void;
12
+ interface WithBody {
13
+ body?: unknown;
14
+ }
15
+ /**
16
+ * Parse an `application/x-www-form-urlencoded` (or JSON) body into a flat
17
+ * string map. Tolerant of @vercel/node having already parsed `req.body` into
18
+ * an object, a string, or nothing.
19
+ */
20
+ export declare function parseFormBody(req: IncomingMessage & WithBody): Promise<Record<string, string>>;
21
+ /** Parse a JSON body, preserving arrays/objects (used by Dynamic Client Registration). */
22
+ export declare function parseJsonBody(req: IncomingMessage & WithBody): Promise<unknown>;
23
+ export {};
24
+ //# sourceMappingURL=http-util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-util.d.ts","sourceRoot":"","sources":["../src/http-util.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI/C,CAAC;AAMF,wBAAgB,QAAQ,CACtB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EACb,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,IAAI,CAMN;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAOhF;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAKxE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAIvE;AAmBD,UAAU,QAAQ;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsBpG;AAED,0FAA0F;AAC1F,wBAAsB,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAerF"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Low-level HTTP helpers shared by the MCP JSON-RPC handler and the OAuth
3
+ * endpoints. Centralises the CORS headers and the handful of response shapes
4
+ * we emit (JSON, HTML, redirect, no-content) plus tolerant body parsing.
5
+ */
6
+ export const CORS_HEADERS = {
7
+ 'Access-Control-Allow-Origin': '*',
8
+ 'Access-Control-Allow-Methods': 'POST, GET, DELETE, OPTIONS',
9
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization, Mcp-Session-Id',
10
+ };
11
+ function applyCors(res) {
12
+ for (const [k, v] of Object.entries(CORS_HEADERS))
13
+ res.setHeader(k, v);
14
+ }
15
+ export function sendJson(res, status, body, extraHeaders) {
16
+ applyCors(res);
17
+ if (extraHeaders)
18
+ for (const [k, v] of Object.entries(extraHeaders))
19
+ res.setHeader(k, v);
20
+ res.setHeader('Content-Type', 'application/json');
21
+ res.writeHead(status);
22
+ res.end(JSON.stringify(body));
23
+ }
24
+ export function sendHtml(res, status, html) {
25
+ applyCors(res);
26
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
27
+ // The consent page must never be cached: it carries per-request OAuth params.
28
+ res.setHeader('Cache-Control', 'no-store');
29
+ res.writeHead(status);
30
+ res.end(html);
31
+ }
32
+ export function sendRedirect(res, location) {
33
+ applyCors(res);
34
+ res.setHeader('Cache-Control', 'no-store');
35
+ res.writeHead(302, { Location: location });
36
+ res.end();
37
+ }
38
+ export function sendNoContent(res, status) {
39
+ applyCors(res);
40
+ res.writeHead(status);
41
+ res.end();
42
+ }
43
+ function recordFromObject(obj) {
44
+ const out = {};
45
+ for (const [k, v] of Object.entries(obj)) {
46
+ if (v === undefined || v === null)
47
+ continue;
48
+ out[k] = Array.isArray(v) ? String(v[0]) : String(v);
49
+ }
50
+ return out;
51
+ }
52
+ async function readRawBody(req) {
53
+ const chunks = [];
54
+ for await (const chunk of req) {
55
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
56
+ }
57
+ return Buffer.concat(chunks).toString('utf8');
58
+ }
59
+ /**
60
+ * Parse an `application/x-www-form-urlencoded` (or JSON) body into a flat
61
+ * string map. Tolerant of @vercel/node having already parsed `req.body` into
62
+ * an object, a string, or nothing.
63
+ */
64
+ export async function parseFormBody(req) {
65
+ const body = req.body;
66
+ if (body && typeof body === 'object' && !Buffer.isBuffer(body)) {
67
+ return recordFromObject(body);
68
+ }
69
+ let raw;
70
+ if (typeof body === 'string')
71
+ raw = body;
72
+ else if (Buffer.isBuffer(body))
73
+ raw = body.toString('utf8');
74
+ else
75
+ raw = await readRawBody(req);
76
+ const trimmed = raw.trim();
77
+ if (trimmed.startsWith('{')) {
78
+ try {
79
+ return recordFromObject(JSON.parse(trimmed));
80
+ }
81
+ catch {
82
+ // fall through to urlencoded parsing
83
+ }
84
+ }
85
+ const out = {};
86
+ for (const [k, v] of new URLSearchParams(raw))
87
+ out[k] = v;
88
+ return out;
89
+ }
90
+ /** Parse a JSON body, preserving arrays/objects (used by Dynamic Client Registration). */
91
+ export async function parseJsonBody(req) {
92
+ const body = req.body;
93
+ if (body && typeof body === 'object' && !Buffer.isBuffer(body))
94
+ return body;
95
+ let raw;
96
+ if (typeof body === 'string')
97
+ raw = body;
98
+ else if (Buffer.isBuffer(body))
99
+ raw = body.toString('utf8');
100
+ else
101
+ raw = await readRawBody(req);
102
+ if (!raw.trim())
103
+ return {};
104
+ // Never let a raw SyntaxError escape to the top-level handler (it would
105
+ // surface as a 500 + stack trace). Callers turn this into a structured 400.
106
+ try {
107
+ return JSON.parse(raw);
108
+ }
109
+ catch {
110
+ throw new SyntaxError('Invalid JSON in request body');
111
+ }
112
+ }
113
+ //# sourceMappingURL=http-util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-util.js","sourceRoot":"","sources":["../src/http-util.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts CHANGED
@@ -8,6 +8,11 @@
8
8
  *
9
9
  * Implements the MCP Streamable HTTP protocol subset needed for stateless
10
10
  * tool servers: initialize, notifications/initialized, tools/list, tools/call.
11
+ *
12
+ * Authentication accepts EITHER:
13
+ * - a raw `dain_pat_...` Bearer token (Claude Code / stdio clients), or
14
+ * - an OAuth access token minted by the embedded authorization server
15
+ * (Claude in the browser, which only speaks OAuth). See ./oauth/*.
11
16
  */
12
17
  import type { IncomingMessage, ServerResponse } from 'node:http';
13
18
  interface VercelRequest extends IncomingMessage {
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAcjE,UAAU,aAAc,SAAQ,eAAe;IAC7C,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAyFD,wBAA8B,OAAO,CACnC,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAiEf"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAkBjE,UAAU,aAAc,SAAQ,eAAe;IAC7C,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA2JD,wBAA8B,OAAO,CACnC,GAAG,EAAE,aAAa,EAClB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAmEf"}
package/dist/http.js CHANGED
@@ -8,24 +8,20 @@
8
8
  *
9
9
  * Implements the MCP Streamable HTTP protocol subset needed for stateless
10
10
  * tool servers: initialize, notifications/initialized, tools/list, tools/call.
11
+ *
12
+ * Authentication accepts EITHER:
13
+ * - a raw `dain_pat_...` Bearer token (Claude Code / stdio clients), or
14
+ * - an OAuth access token minted by the embedded authorization server
15
+ * (Claude in the browser, which only speaks OAuth). See ./oauth/*.
11
16
  */
12
17
  import { DainOsClient, DainOsApiError } from './client.js';
13
18
  import { allTools, getTool } from './tools/index.js';
14
19
  import { toJsonSchema } from './tools/types.js';
15
20
  import { SERVER_NAME, SERVER_VERSION, SERVER_INSTRUCTIONS } from './meta.js';
21
+ import { CORS_HEADERS, sendJson, sendNoContent } from './http-util.js';
22
+ import { isOAuthConfigured, resolveBaseUrl } from './oauth/config.js';
23
+ import { handleAuthorizationServerMetadata, handleAuthorize, handleProtectedResourceMetadata, handleRegister, handleToken, recoverPat, } from './oauth/handlers.js';
16
24
  const PROTOCOL_VERSION = '2025-03-26';
17
- const CORS_HEADERS = {
18
- 'Access-Control-Allow-Origin': '*',
19
- 'Access-Control-Allow-Methods': 'POST, GET, DELETE, OPTIONS',
20
- 'Access-Control-Allow-Headers': 'Content-Type, Authorization, Mcp-Session-Id',
21
- };
22
- function sendJson(res, status, body) {
23
- for (const [k, v] of Object.entries(CORS_HEADERS))
24
- res.setHeader(k, v);
25
- res.setHeader('Content-Type', 'application/json');
26
- res.writeHead(status);
27
- res.end(JSON.stringify(body));
28
- }
29
25
  function jsonRpcResult(id, result) {
30
26
  return { jsonrpc: '2.0', result, id: id ?? null };
31
27
  }
@@ -83,24 +79,23 @@ async function handleToolsCall(req, client) {
83
79
  });
84
80
  }
85
81
  }
86
- export default async function handler(req, res) {
87
- if (req.method === 'OPTIONS') {
88
- for (const [k, v] of Object.entries(CORS_HEADERS))
89
- res.setHeader(k, v);
90
- res.writeHead(200);
91
- res.end();
92
- return;
93
- }
94
- if (req.method === 'GET' || req.method === 'DELETE') {
95
- sendJson(res, 405, jsonRpcError(null, -32000, 'Method not allowed. Use POST for MCP requests.'));
96
- return;
97
- }
82
+ /**
83
+ * Build the WWW-Authenticate challenge that tells an OAuth-capable client where
84
+ * to find this server's protected-resource metadata, kicking off the flow.
85
+ */
86
+ function bearerChallenge(baseUrl) {
87
+ return (`Bearer resource_metadata="${baseUrl}/.well-known/oauth-protected-resource", ` +
88
+ 'error="invalid_token", error_description="Authentication required"');
89
+ }
90
+ async function handleMcp(req, res, baseUrl) {
98
91
  const authHeader = req.headers['authorization'];
99
- const token = typeof authHeader === 'string' && authHeader.startsWith('Bearer ')
92
+ const bearer = typeof authHeader === 'string' && authHeader.startsWith('Bearer ')
100
93
  ? authHeader.slice(7)
101
94
  : null;
102
- if (!token || !token.startsWith('dain_pat_')) {
103
- sendJson(res, 401, jsonRpcError(null, -32001, 'Missing or invalid DAINOS_API_TOKEN. Include Bearer dain_pat_... in Authorization header.'));
95
+ const pat = await recoverPat(bearer);
96
+ if (!pat) {
97
+ const extra = isOAuthConfigured() ? { 'WWW-Authenticate': bearerChallenge(baseUrl) } : undefined;
98
+ sendJson(res, 401, jsonRpcError(null, -32001, 'Missing or invalid credentials. Provide a Bearer dain_pat_... token, or connect via OAuth.'), extra);
104
99
  return;
105
100
  }
106
101
  const body = req.body;
@@ -109,7 +104,7 @@ export default async function handler(req, res) {
109
104
  return;
110
105
  }
111
106
  const apiUrl = process.env['DAINOS_API_URL'];
112
- const client = new DainOsClient(apiUrl, token);
107
+ const client = new DainOsClient(apiUrl, pat);
113
108
  // Handle batch requests (array) and single requests
114
109
  const requests = Array.isArray(body) ? body : [body];
115
110
  const responses = [];
@@ -136,9 +131,74 @@ export default async function handler(req, res) {
136
131
  }
137
132
  if (responses.length === 0) {
138
133
  // All requests were notifications
139
- sendJson(res, 202, {});
134
+ sendNoContent(res, 202);
140
135
  return;
141
136
  }
142
137
  sendJson(res, 200, Array.isArray(body) ? responses : responses[0]);
143
138
  }
139
+ export default async function handler(req, res) {
140
+ if (req.method === 'OPTIONS') {
141
+ for (const [k, v] of Object.entries(CORS_HEADERS))
142
+ res.setHeader(k, v);
143
+ res.writeHead(200);
144
+ res.end();
145
+ return;
146
+ }
147
+ const baseUrl = resolveBaseUrl();
148
+ const url = new URL(req.url ?? '/', baseUrl);
149
+ const path = url.pathname;
150
+ const oauthOn = isOAuthConfigured();
151
+ if (path === '/health') {
152
+ sendJson(res, 200, { status: 'ok', server: SERVER_NAME, version: SERVER_VERSION });
153
+ return;
154
+ }
155
+ // OAuth discovery + endpoints. Only advertised when configured, so a
156
+ // deployment without MCP_OAUTH_SECRET behaves exactly as before (raw PAT).
157
+ if (oauthOn) {
158
+ if (path.startsWith('/.well-known/oauth-protected-resource')) {
159
+ handleProtectedResourceMetadata(res, baseUrl);
160
+ return;
161
+ }
162
+ if (path.startsWith('/.well-known/oauth-authorization-server')) {
163
+ handleAuthorizationServerMetadata(res, baseUrl);
164
+ return;
165
+ }
166
+ if (path === '/register') {
167
+ if (req.method !== 'POST') {
168
+ sendJson(res, 405, { error: 'invalid_request', error_description: 'Use POST to register.' });
169
+ return;
170
+ }
171
+ await handleRegister(req, res);
172
+ return;
173
+ }
174
+ if (path === '/authorize') {
175
+ if (req.method !== 'GET' && req.method !== 'POST') {
176
+ sendJson(res, 405, { error: 'invalid_request', error_description: 'Use GET or POST.' });
177
+ return;
178
+ }
179
+ const query = {};
180
+ for (const [k, v] of url.searchParams)
181
+ query[k] = v;
182
+ await handleAuthorize(req, res, query);
183
+ return;
184
+ }
185
+ if (path === '/token') {
186
+ if (req.method !== 'POST') {
187
+ sendJson(res, 405, { error: 'invalid_request', error_description: 'Use POST for the token endpoint.' });
188
+ return;
189
+ }
190
+ await handleToken(req, res);
191
+ return;
192
+ }
193
+ }
194
+ if (path === '/mcp' || path === '/') {
195
+ if (req.method === 'GET' || req.method === 'DELETE') {
196
+ sendJson(res, 405, jsonRpcError(null, -32000, 'Method not allowed. Use POST for MCP requests.'));
197
+ return;
198
+ }
199
+ await handleMcp(req, res, baseUrl);
200
+ return;
201
+ }
202
+ sendJson(res, 404, jsonRpcError(null, -32601, `Not found: ${path}`));
203
+ }
144
204
  //# sourceMappingURL=http.js.map
package/dist/http.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAE7E,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAEtC,MAAM,YAAY,GAA2B;IAC3C,6BAA6B,EAAE,GAAG;IAClC,8BAA8B,EAAE,4BAA4B;IAC5D,8BAA8B,EAAE,6CAA6C;CAC9E,CAAC;AAaF,SAAS,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAClE,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;QAAE,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAClD,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACtB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,EAAsC,EAAE,MAAe;IAC5E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,YAAY,CACnB,EAAsC,EACtC,IAAY,EACZ,OAAe;IAEf,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC;AACtE,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAmB;IAC3C,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE;QAC3B,eAAe,EAAE,gBAAgB;QACjC,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;QAC1D,YAAY,EAAE,mBAAmB;KAClC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,GAAmB;IAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,WAAW,EAAE,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC;KAC5C,CAAC,CAAC,CAAC;IACJ,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,GAAmB,EACnB,MAAoB;IAEpB,MAAM,MAAM,GAAG,GAAG,CAAC,MAA4E,CAAC;IAChG,MAAM,QAAQ,GAAG,MAAM,EAAE,IAAI,CAAC;IAC9B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,kCAAkC,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,iBAAiB,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,qBAAqB,QAAQ,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,IAAI,GACR,MAAM,KAAK,SAAS;YAClB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACtC,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE;YAC3B,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GACX,KAAK,YAAY,cAAc;YAC7B,CAAC,CAAC,KAAK,CAAC,OAAO;YACf,CAAC,CAAC,KAAK,YAAY,KAAK;gBACtB,CAAC,CAAC,KAAK,CAAC,OAAO;gBACf,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtB,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE;YAC3B,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC1C,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,OAAO,CACnC,GAAkB,EAClB,GAAmB;IAEnB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;YAAE,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACvE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,EAAE,CAAC;QACV,OAAO;IACT,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACpD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,gDAAgD,CAAC,CAAC,CAAC;QACjG,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAChD,MAAM,KAAK,GACT,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC;QAChE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QACrB,CAAC,CAAC,IAAI,CAAC;IAEX,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,CAC7B,IAAI,EACJ,CAAC,KAAK,EACN,2FAA2F,CAC5F,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,IAAqD,CAAC;IACvE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,yBAAyB,CAAC,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAE/C,oDAAoD;IACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,SAAS,GAAc,EAAE,CAAC;IAEhC,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;YACnC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,KAAK,2BAA2B,EAAE,CAAC;YACzD,+CAA+C;YAC/C,SAAS;QACX,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;YAC1C,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1C,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;YAC1C,SAAS,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QACxD,CAAC;aAAM,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACpC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/C,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,qBAAqB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,kCAAkC;QAClC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACvB,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
package/dist/meta.d.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * it here removes that drift between the two transports.
10
10
  */
11
11
  export declare const SERVER_NAME = "dainos";
12
- export declare const SERVER_VERSION = "0.12.0";
12
+ export declare const SERVER_VERSION = "0.13.0";
13
13
  /**
14
14
  * Instructions advertised to MCP clients in the `initialize` response.
15
15
  *
package/dist/meta.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * it here removes that drift between the two transports.
10
10
  */
11
11
  export const SERVER_NAME = 'dainos';
12
- export const SERVER_VERSION = '0.12.0';
12
+ export const SERVER_VERSION = '0.13.0';
13
13
  /**
14
14
  * Instructions advertised to MCP clients in the `initialize` response.
15
15
  *
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Configuration for the MCP server's embedded OAuth 2.1 authorization server.
3
+ *
4
+ * The cloud endpoint (mcp.dainos.app) is reachable from Claude in the browser,
5
+ * which only speaks OAuth — it has no field for a static Bearer token. So this
6
+ * server acts as a minimal, STATELESS OAuth authorization server that bridges
7
+ * the browser's OAuth flow onto the existing DainOS Personal Access Token (PAT)
8
+ * model:
9
+ *
10
+ * - The user pastes a `dain_pat_...` token on the consent page (`/authorize`).
11
+ * - We issue an OAuth authorization code, then access/refresh tokens, each of
12
+ * which is an ENCRYPTED JWT (JWE) that embeds the PAT.
13
+ * - On `/mcp`, we decrypt the access token to recover the PAT and call
14
+ * api.dainos.app exactly as the Claude Code (raw-PAT) path does today.
15
+ *
16
+ * Statelessness is deliberate: the Vercel function has no datastore. Every
17
+ * token carries its own state, signed + encrypted under MCP_OAUTH_SECRET.
18
+ */
19
+ /** Env var holding the canonical public origin, e.g. `https://mcp.dainos.app`. */
20
+ export declare const PUBLIC_URL_ENV = "MCP_PUBLIC_URL";
21
+ export declare const DEFAULT_PUBLIC_URL = "https://mcp.dainos.app";
22
+ /** Env var holding the symmetric secret used to encrypt every issued token. */
23
+ export declare const OAUTH_SECRET_ENV = "MCP_OAUTH_SECRET";
24
+ /** Token lifetimes (seconds). */
25
+ export declare const ACCESS_TOKEN_TTL_SECONDS: number;
26
+ export declare const REFRESH_TOKEN_TTL_SECONDS: number;
27
+ export declare const AUTH_CODE_TTL_SECONDS = 30;
28
+ export declare const CLIENT_REG_TTL_SECONDS: number;
29
+ /** The single scope this server understands. */
30
+ export declare const SCOPE = "mcp";
31
+ /** The DainOS PAT prefix. Kept in lock-step with the API's `PAT_PREFIX`. */
32
+ export declare const PAT_PREFIX = "dain_pat_";
33
+ /** Where users mint a PAT. Surfaced on the consent page. */
34
+ export declare const PAT_SETTINGS_URL = "https://dainos.app/settings/api-tokens";
35
+ /**
36
+ * Resolve this server's public base URL.
37
+ *
38
+ * Pinned to the configured canonical origin (MCP_PUBLIC_URL, default
39
+ * mcp.dainos.app). The inbound `Host` header is deliberately NOT trusted: it is
40
+ * attacker-controllable (a direct request to the raw function URL can carry any
41
+ * Host), and letting it set the issuer / authorization_endpoint / token_endpoint
42
+ * in the discovery documents (and the resource_metadata in the WWW-Authenticate
43
+ * challenge) would let a spoofed Host point an OAuth client's token fetch at an
44
+ * attacker-controlled endpoint. The connector always targets the canonical URL,
45
+ * so pinning is also correct, not just safe.
46
+ */
47
+ export declare function resolveBaseUrl(): string;
48
+ /**
49
+ * Derive a 32-byte AES key from MCP_OAUTH_SECRET via SHA-256.
50
+ *
51
+ * @throws if the secret is missing or too short. The caller turns this into a
52
+ * clear 500/oauth-disabled response rather than leaking a stack trace.
53
+ */
54
+ export declare function getEncryptionKey(): Uint8Array;
55
+ /** True when the OAuth layer is configured and able to issue/verify tokens. */
56
+ export declare function isOAuthConfigured(): boolean;
57
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/oauth/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,kFAAkF;AAClF,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAC/C,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAE3D,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,iCAAiC;AACjC,eAAO,MAAM,wBAAwB,QAAU,CAAC;AAChD,eAAO,MAAM,yBAAyB,QAAoB,CAAC;AAK3D,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,sBAAsB,QAAqB,CAAC;AAEzD,gDAAgD;AAChD,eAAO,MAAM,KAAK,QAAQ,CAAC;AAE3B,4EAA4E;AAC5E,eAAO,MAAM,UAAU,cAAc,CAAC;AAEtC,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,2CAA2C,CAAC;AAEzE;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAS7C;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,IAAI,OAAO,CAG3C"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Configuration for the MCP server's embedded OAuth 2.1 authorization server.
3
+ *
4
+ * The cloud endpoint (mcp.dainos.app) is reachable from Claude in the browser,
5
+ * which only speaks OAuth — it has no field for a static Bearer token. So this
6
+ * server acts as a minimal, STATELESS OAuth authorization server that bridges
7
+ * the browser's OAuth flow onto the existing DainOS Personal Access Token (PAT)
8
+ * model:
9
+ *
10
+ * - The user pastes a `dain_pat_...` token on the consent page (`/authorize`).
11
+ * - We issue an OAuth authorization code, then access/refresh tokens, each of
12
+ * which is an ENCRYPTED JWT (JWE) that embeds the PAT.
13
+ * - On `/mcp`, we decrypt the access token to recover the PAT and call
14
+ * api.dainos.app exactly as the Claude Code (raw-PAT) path does today.
15
+ *
16
+ * Statelessness is deliberate: the Vercel function has no datastore. Every
17
+ * token carries its own state, signed + encrypted under MCP_OAUTH_SECRET.
18
+ */
19
+ import { createHash } from 'node:crypto';
20
+ /** Env var holding the canonical public origin, e.g. `https://mcp.dainos.app`. */
21
+ export const PUBLIC_URL_ENV = 'MCP_PUBLIC_URL';
22
+ export const DEFAULT_PUBLIC_URL = 'https://mcp.dainos.app';
23
+ /** Env var holding the symmetric secret used to encrypt every issued token. */
24
+ export const OAUTH_SECRET_ENV = 'MCP_OAUTH_SECRET';
25
+ /** Token lifetimes (seconds). */
26
+ export const ACCESS_TOKEN_TTL_SECONDS = 60 * 60; // 1 hour
27
+ export const REFRESH_TOKEN_TTL_SECONDS = 60 * 60 * 24 * 90; // 90 days
28
+ // 30 seconds. NOTE: a stateless server cannot mark a code consumed, so a code
29
+ // is technically replayable inside this window. PKCE bounds the risk (a code is
30
+ // useless without the matching verifier, held only by the originating client),
31
+ // and the short TTL shrinks the window. True single-use would require a store.
32
+ export const AUTH_CODE_TTL_SECONDS = 30;
33
+ export const CLIENT_REG_TTL_SECONDS = 60 * 60 * 24 * 365; // 1 year
34
+ /** The single scope this server understands. */
35
+ export const SCOPE = 'mcp';
36
+ /** The DainOS PAT prefix. Kept in lock-step with the API's `PAT_PREFIX`. */
37
+ export const PAT_PREFIX = 'dain_pat_';
38
+ /** Where users mint a PAT. Surfaced on the consent page. */
39
+ export const PAT_SETTINGS_URL = 'https://dainos.app/settings/api-tokens';
40
+ /**
41
+ * Resolve this server's public base URL.
42
+ *
43
+ * Pinned to the configured canonical origin (MCP_PUBLIC_URL, default
44
+ * mcp.dainos.app). The inbound `Host` header is deliberately NOT trusted: it is
45
+ * attacker-controllable (a direct request to the raw function URL can carry any
46
+ * Host), and letting it set the issuer / authorization_endpoint / token_endpoint
47
+ * in the discovery documents (and the resource_metadata in the WWW-Authenticate
48
+ * challenge) would let a spoofed Host point an OAuth client's token fetch at an
49
+ * attacker-controlled endpoint. The connector always targets the canonical URL,
50
+ * so pinning is also correct, not just safe.
51
+ */
52
+ export function resolveBaseUrl() {
53
+ return process.env[PUBLIC_URL_ENV] ?? DEFAULT_PUBLIC_URL;
54
+ }
55
+ /**
56
+ * Derive a 32-byte AES key from MCP_OAUTH_SECRET via SHA-256.
57
+ *
58
+ * @throws if the secret is missing or too short. The caller turns this into a
59
+ * clear 500/oauth-disabled response rather than leaking a stack trace.
60
+ */
61
+ export function getEncryptionKey() {
62
+ const secret = process.env[OAUTH_SECRET_ENV];
63
+ if (!secret || secret.length < 16) {
64
+ throw new Error(`${OAUTH_SECRET_ENV} is not set (need at least 16 characters). ` +
65
+ 'The OAuth endpoints are disabled until it is configured on the deployment.');
66
+ }
67
+ return new Uint8Array(createHash('sha256').update(secret).digest());
68
+ }
69
+ /** True when the OAuth layer is configured and able to issue/verify tokens. */
70
+ export function isOAuthConfigured() {
71
+ const secret = process.env[OAUTH_SECRET_ENV];
72
+ return typeof secret === 'string' && secret.length >= 16;
73
+ }
74
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/oauth/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,kFAAkF;AAClF,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAC;AAC/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AAE3D,+EAA+E;AAC/E,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAEnD,iCAAiC;AACjC,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS;AAC1D,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU;AACtE,8EAA8E;AAC9E,gFAAgF;AAChF,+EAA+E;AAC/E,+EAA+E;AAC/E,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AACxC,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,SAAS;AAEnE,gDAAgD;AAChD,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC;AAE3B,4EAA4E;AAC5E,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC;AAEtC,4DAA4D;AAC5D,MAAM,CAAC,MAAM,gBAAgB,GAAG,wCAAwC,CAAC;AAEzE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,kBAAkB,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CACb,GAAG,gBAAgB,6CAA6C;YAC9D,4EAA4E,CAC/E,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,iBAAiB;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC7C,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The paste-PAT consent page served at GET /authorize.
3
+ *
4
+ * This is the one human-facing surface of the OAuth bridge. The user mints a
5
+ * DainOS API token, pastes it here, and the form POSTs back to /authorize,
6
+ * which issues an authorization code. All copy follows the project copy-style
7
+ * rule: UK English, no em/en dashes, plain ASCII punctuation.
8
+ *
9
+ * Every interpolated value originates from the OAuth client request, so it is
10
+ * HTML-escaped before it lands in an attribute. The PAT field is never
11
+ * pre-filled and is rendered as a password input.
12
+ */
13
+ export interface ConsentPageParams {
14
+ clientId: string;
15
+ redirectUri: string;
16
+ codeChallenge: string;
17
+ codeChallengeMethod: string;
18
+ state?: string;
19
+ scope?: string;
20
+ /** Optional error banner shown after a rejected submission. */
21
+ error?: string;
22
+ }
23
+ export declare function renderConsentPage(params: ConsentPageParams): string;
24
+ //# sourceMappingURL=consent-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-page.d.ts","sourceRoot":"","sources":["../../src/oauth/consent-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgBD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAuEnE"}