@obov/mext 0.6.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.js +16 -2
- package/dist/build.js.map +1 -1
- package/dist/cli/args.js +1 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/build.js +22 -2
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev-server.js +3 -2
- package/dist/cli/dev-server.js.map +1 -1
- package/dist/cli/dev.d.ts +6 -0
- package/dist/cli/dev.js +4 -4
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/main.js +2 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/media.d.ts +19 -0
- package/dist/cli/media.js +77 -0
- package/dist/cli/media.js.map +1 -0
- package/dist/cli/run.js +5 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/serve.d.ts +10 -0
- package/dist/cli/serve.js +114 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/runner.js +3 -0
- package/dist/client/runner.js.map +1 -1
- package/dist/client/typed.d.ts +3 -1
- package/dist/client/typed.js +39 -3
- package/dist/client/typed.js.map +1 -1
- package/dist/client/types.d.ts +31 -2
- package/dist/client/types.js.map +1 -1
- package/dist/config.d.ts +17 -0
- package/dist/config.js +36 -1
- package/dist/config.js.map +1 -1
- package/dist/content.d.ts +65 -0
- package/dist/content.js +99 -0
- package/dist/content.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/invoke.d.ts +4 -0
- package/dist/invoke.js +12 -5
- package/dist/invoke.js.map +1 -1
- package/dist/manifest.d.ts +6 -1
- package/dist/manifest.js.map +1 -1
- package/dist/mcp/constants.d.ts +2 -0
- package/dist/mcp/constants.js +2 -0
- package/dist/mcp/constants.js.map +1 -1
- package/dist/mcp/dispatch.d.ts +9 -3
- package/dist/mcp/dispatch.js +10 -4
- package/dist/mcp/dispatch.js.map +1 -1
- package/dist/mcp/host.d.ts +14 -0
- package/dist/mcp/host.js +48 -0
- package/dist/mcp/host.js.map +1 -0
- package/dist/mcp/http.d.ts +22 -5
- package/dist/mcp/http.js +154 -19
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/tasks.js +1 -1
- package/dist/mcp/tasks.js.map +1 -1
- package/dist/remote/client.d.ts +24 -1
- package/dist/remote/client.js +177 -53
- package/dist/remote/client.js.map +1 -1
- package/dist/remote/index.d.ts +1 -1
- package/dist/remote/index.js.map +1 -1
- package/dist/route.d.ts +40 -2
- package/dist/route.js +128 -8
- package/dist/route.js.map +1 -1
- package/dist/start.js +3 -2
- package/dist/start.js.map +1 -1
- package/dist/version-constant.d.ts +1 -1
- package/dist/version-constant.js +1 -1
- package/dist/version-constant.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp/http.d.ts
CHANGED
|
@@ -3,13 +3,13 @@ import type { MextApp } from "../command.ts";
|
|
|
3
3
|
import { type BuiltinSurface, type ReportedClient } from "../caller.ts";
|
|
4
4
|
import { type Principal } from "../principal.ts";
|
|
5
5
|
import type { Registry } from "../registry.ts";
|
|
6
|
-
import { type RouteEntry } from "../route.ts";
|
|
6
|
+
import { type RouteEntry, type RouteMethod, type RouteOptions } from "../route.ts";
|
|
7
|
+
import { MAX_BODY_BYTES } from "./constants.ts";
|
|
7
8
|
import type { Instrumentation } from "../instrumentation.ts";
|
|
8
9
|
import type { ToolExposure } from "./dispatch.ts";
|
|
9
10
|
import { type McpCoreOptions } from "./server.ts";
|
|
10
11
|
import type { MextState } from "../state.ts";
|
|
11
|
-
|
|
12
|
-
export declare const MAX_BODY_BYTES: number;
|
|
12
|
+
export { MAX_BODY_BYTES };
|
|
13
13
|
export interface McpAuthRequest {
|
|
14
14
|
/** Authorization 헤더 원문 */
|
|
15
15
|
authorization: string | undefined;
|
|
@@ -19,6 +19,11 @@ export interface McpAuthRequest {
|
|
|
19
19
|
surface: BuiltinSurface;
|
|
20
20
|
/** 요청 _meta 의 clientInfo (2026-07-28). 자가 신고 값: 주체 · 행위자 · 표면 판정에 쓰지 않는다 */
|
|
21
21
|
client: ReportedClient | undefined;
|
|
22
|
+
/** routes/ 요청 (export auth, §12.4) 만. method = 요청 메서드 (HEAD = GET), path = route 파일 패턴 ("/items/[id]"). POST /mcp = 없음 */
|
|
23
|
+
route?: {
|
|
24
|
+
method: RouteMethod;
|
|
25
|
+
path: string;
|
|
26
|
+
};
|
|
22
27
|
}
|
|
23
28
|
export interface McpHttpOptions {
|
|
24
29
|
registry: Registry;
|
|
@@ -39,6 +44,13 @@ export interface McpHttpOptions {
|
|
|
39
44
|
* 미지정 = loopback (localhost · 127.0.0.1 · [::1], 포트 무관) 만. Origin 헤더 없는 요청은 항상 통과
|
|
40
45
|
*/
|
|
41
46
|
allowedOrigins?: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Host 허용 목록 (api.example.com = 모든 포트 · api.example.com:8443 = 그 포트만, "loopback" = loopback, "*" = 전체).
|
|
49
|
+
* 미지정 = 검사 없음. 지정 = 목록 밖 Host 의 모든 요청 (/mcp · routes · well-known) = 403 (DNS rebinding 방어)
|
|
50
|
+
*/
|
|
51
|
+
allowedHosts?: string[];
|
|
52
|
+
/** POST /mcp 본문 상한 (바이트). 기본 MAX_BODY_BYTES (4 MiB). 넘으면 413. route 의 export maxBodyBytes = true 도 이 값 */
|
|
53
|
+
maxBodyBytes?: number;
|
|
42
54
|
};
|
|
43
55
|
/** serverInfo.name · 안내 문구. 기본 "mext" */
|
|
44
56
|
name?: string;
|
|
@@ -62,8 +74,13 @@ export interface McpHttpOptions {
|
|
|
62
74
|
* 클라이언트 (mext login · MCP 클라이언트) 가 인가 서버를 찾는 데 쓴다
|
|
63
75
|
*/
|
|
64
76
|
oauth?: OAuthResourceOptions;
|
|
65
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* routes/ (§12.4). MCP 엔드포인트 밖 경로. ctx.app = MCP 와 같은 인스턴스.
|
|
79
|
+
* Origin 검사 · auth = 기본 없음. 모듈의 export origin · auth (없으면 routeDefaults) 가 있으면 allowedOrigins · auth 를 /mcp 와 같은 규칙으로
|
|
80
|
+
*/
|
|
66
81
|
routes?: readonly RouteEntry[];
|
|
82
|
+
/** 설정 routes (§12.4): 모든 route 의 auth · origin · maxBodyBytes 기본값. 모듈 export 가 덮어쓴다 */
|
|
83
|
+
routeDefaults?: RouteOptions;
|
|
67
84
|
/** 주입 state (§12.1). 자원 구독 · ctx.resourceUpdated (§12.5) */
|
|
68
85
|
state?: MextState;
|
|
69
86
|
/** McpCoreOptions.taskTiming (테스트) */
|
|
@@ -105,7 +122,7 @@ export interface McpFetchHandler {
|
|
|
105
122
|
}
|
|
106
123
|
/**
|
|
107
124
|
* Streamable HTTP (2026-07-28) 의 transport 무관 처리 (Web Request → Response).
|
|
108
|
-
* 순서: 경로 (routes · 404) → Origin (403) → 메서드 (POST 외 405) → 본문 (413) → auth (401) → SDK createMcpHandler.
|
|
125
|
+
* 순서: Host (allowedHosts, 모든 경로 403) → 경로 (routes · 404) → Origin (403) → 메서드 (POST 외 405) → 본문 (413) → auth (401) → SDK createMcpHandler.
|
|
109
126
|
* SDK 가 요청별 버전 · 헤더 검증 (-32020) · server/discover · Mcp-Param-Command · 2025 레거시 stateless 를 처리.
|
|
110
127
|
* progressToken 있는 2026-07-28 요청 = SSE 응답 (진행률 알림), 그 외 = JSON.
|
|
111
128
|
*/
|
package/dist/mcp/http.js
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
|
-
import { Readable } from "node:stream";
|
|
3
2
|
import { CLIENT_INFO_META_KEY, createMcpHandler, InMemoryServerEventBus, isLegacyRequest } from "@modelcontextprotocol/server";
|
|
4
3
|
import { auditHidden } from "../audit.js";
|
|
5
|
-
import { isMextError } from "../errors.js";
|
|
4
|
+
import { isMextError, unauthenticated } from "../errors.js";
|
|
6
5
|
import { defaultSurface, reportedClient, surfaceOf } from "../caller.js";
|
|
7
6
|
import { exposedRegistry } from "../expose.js";
|
|
8
7
|
import { ANONYMOUS, assertCallerFields } from "../principal.js";
|
|
9
8
|
import { createRouteDispatcher, onceApp } from "../route.js";
|
|
10
|
-
import { DEFAULT_HOST, DEFAULT_PORT, MCP_PATH } from "./constants.js";
|
|
9
|
+
import { DEFAULT_HOST, DEFAULT_PORT, MAX_BODY_BYTES, MCP_PATH } from "./constants.js";
|
|
10
|
+
import { hostAllowed, LOOPBACK_ENTRY, LOOPBACK_HOSTNAMES } from "./host.js";
|
|
11
11
|
import { createMcpServerFactory, principalAuthInfo } from "./server.js";
|
|
12
12
|
import { bridgeResourceUpdates, narrowListenRequest, resourceUpdatedFn, trackBody } from "./subscriptions.js";
|
|
13
13
|
import { hasTaskCommands, requestsTask } from "./tasks.js";
|
|
14
|
-
|
|
15
|
-
export const MAX_BODY_BYTES = 4 * 1024 * 1024;
|
|
14
|
+
export { MAX_BODY_BYTES };
|
|
16
15
|
/** RFC 9728 well-known 경로 */
|
|
17
16
|
export const PROTECTED_RESOURCE_METADATA_PATH = "/.well-known/oauth-protected-resource";
|
|
18
17
|
/**
|
|
19
18
|
* Streamable HTTP (2026-07-28) 의 transport 무관 처리 (Web Request → Response).
|
|
20
|
-
* 순서: 경로 (routes · 404) → Origin (403) → 메서드 (POST 외 405) → 본문 (413) → auth (401) → SDK createMcpHandler.
|
|
19
|
+
* 순서: Host (allowedHosts, 모든 경로 403) → 경로 (routes · 404) → Origin (403) → 메서드 (POST 외 405) → 본문 (413) → auth (401) → SDK createMcpHandler.
|
|
21
20
|
* SDK 가 요청별 버전 · 헤더 검증 (-32020) · server/discover · Mcp-Param-Command · 2025 레거시 stateless 를 처리.
|
|
22
21
|
* progressToken 있는 2026-07-28 요청 = SSE 응답 (진행률 알림), 그 외 = JSON.
|
|
23
22
|
*/
|
|
@@ -25,8 +24,17 @@ export function createMcpFetchHandler(options) {
|
|
|
25
24
|
// ctx.app = 프로세스당 1회. 명령어 · route 가 공유
|
|
26
25
|
const app = options.app ? onceApp(options.app) : undefined;
|
|
27
26
|
const resourceUpdated = resourceUpdatedFn(options.state);
|
|
27
|
+
const report = reporter(options.onerror);
|
|
28
|
+
const allowedOrigins = options.server?.allowedOrigins;
|
|
28
29
|
const routes = options.routes?.length
|
|
29
|
-
? createRouteDispatcher({
|
|
30
|
+
? createRouteDispatcher({
|
|
31
|
+
routes: options.routes,
|
|
32
|
+
app: onceApp(app),
|
|
33
|
+
resourceUpdated,
|
|
34
|
+
guard: routeGuard(options, report),
|
|
35
|
+
maxBodyBytes: options.server?.maxBodyBytes ?? MAX_BODY_BYTES,
|
|
36
|
+
...(options.routeDefaults ? { defaults: options.routeDefaults } : {}),
|
|
37
|
+
})
|
|
30
38
|
: undefined;
|
|
31
39
|
const factory = createMcpServerFactory({
|
|
32
40
|
registry: options.registry,
|
|
@@ -47,8 +55,8 @@ export function createMcpFetchHandler(options) {
|
|
|
47
55
|
transport: "http",
|
|
48
56
|
});
|
|
49
57
|
const tasks = options.state?.store !== undefined && hasTaskCommands(options.registry);
|
|
50
|
-
const
|
|
51
|
-
const sdkOptions = options.onerror ? { onerror: report } : {};
|
|
58
|
+
const maxBodyBytes = options.server?.maxBodyBytes ?? MAX_BODY_BYTES;
|
|
59
|
+
const sdkOptions = { ...(options.onerror ? { onerror: report } : {}), maxRequestBodySize: maxBodyBytes };
|
|
52
60
|
// subscriptions/listen (§12.5) = 전용 SDK handler (ack · 15초 keepalive · 완료 result). 갱신 = state 허브 → SDK bus
|
|
53
61
|
const listenBus = new InMemoryServerEventBus(report);
|
|
54
62
|
const subscriptions = { state: options.state, resources: options.registry.resources };
|
|
@@ -59,9 +67,19 @@ export function createMcpFetchHandler(options) {
|
|
|
59
67
|
// 진행률 없는 요청 = JSON (auto: 관련 메시지가 없으면 단일 JSON), 진행률 있는 요청 = SSE
|
|
60
68
|
const jsonHandler = createMcpHandler(factory, { ...sdkOptions, responseMode: "auto" });
|
|
61
69
|
const sseHandler = createMcpHandler(factory, { ...sdkOptions, responseMode: "sse" });
|
|
62
|
-
const
|
|
70
|
+
const allowedHosts = options.server?.allowedHosts;
|
|
63
71
|
const handle = async (request, context) => {
|
|
64
72
|
const url = new URL(request.url);
|
|
73
|
+
if (allowedHosts !== undefined) {
|
|
74
|
+
const host = request.headers.get("host") ?? url.host;
|
|
75
|
+
if (!hostAllowed(host, allowedHosts)) {
|
|
76
|
+
await request.body?.cancel().catch(() => { });
|
|
77
|
+
const message = `Forbidden: host ${host} is not allowed.`;
|
|
78
|
+
if (url.pathname === MCP_PATH)
|
|
79
|
+
return jsonResponse(403, rpcError(-32_000, message));
|
|
80
|
+
return jsonResponse(403, { error: { code: "REQUEST_REJECTED", message, reason: "host" } });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
65
83
|
const oauth = options.oauth;
|
|
66
84
|
if (oauth && (url.pathname === PROTECTED_RESOURCE_METADATA_PATH || url.pathname === protectedResourceMetadataPath())) {
|
|
67
85
|
if (request.method !== "GET")
|
|
@@ -82,7 +100,7 @@ export function createMcpFetchHandler(options) {
|
|
|
82
100
|
if (request.method !== "POST") {
|
|
83
101
|
return jsonResponse(405, rpcError(-32_000, "Method not allowed."), { Allow: "POST" });
|
|
84
102
|
}
|
|
85
|
-
const body = await readBody(request.body,
|
|
103
|
+
const body = await readBody(request.body, maxBodyBytes);
|
|
86
104
|
if (body === "too-large")
|
|
87
105
|
return jsonResponse(413, rpcError(-32_000, "Request body too large."));
|
|
88
106
|
const parsed = parseJson(body);
|
|
@@ -115,7 +133,7 @@ export function createMcpFetchHandler(options) {
|
|
|
115
133
|
});
|
|
116
134
|
const parsedBody = parsed === NOT_JSON ? undefined : parsed;
|
|
117
135
|
// 2025-11-25 이하 (envelope 없음) = SDK stateless 레거시 경로. 진행률 기반 SSE 전환은 2026-07-28 요청만
|
|
118
|
-
const legacy = await isLegacyRequest(sdkRequest, parsedBody, { maxRequestBodySize:
|
|
136
|
+
const legacy = await isLegacyRequest(sdkRequest, parsedBody, { maxRequestBodySize: maxBodyBytes });
|
|
119
137
|
const listen = legacy ? undefined : narrowListenRequest(parsedBody, subscriptions, principal);
|
|
120
138
|
if (listen !== undefined) {
|
|
121
139
|
const { response, done } = trackBody(await listenHandler.fetch(sdkRequest, { authInfo: principalAuthInfo(principal), parsedBody: listen }));
|
|
@@ -193,15 +211,24 @@ export function createMcpHttpHandler(options) {
|
|
|
193
211
|
inflight.delete(controller);
|
|
194
212
|
});
|
|
195
213
|
const hasBody = req.method !== "GET" && req.method !== "HEAD";
|
|
214
|
+
const body = hasBody ? nodeBody(req) : undefined;
|
|
215
|
+
// 응답이 끝났는데 읽지 않은 본문 (413 · 403 · 401 · 404 · 본문을 읽지 않는 핸들러) = 버리며 읽어 keep-alive 연결을 살린다
|
|
216
|
+
if (body)
|
|
217
|
+
res.once("finish", () => body.discard(res));
|
|
196
218
|
const request = new Request(requestUrl(req), {
|
|
197
219
|
method: req.method ?? "GET",
|
|
198
220
|
headers: nodeHeaders(req),
|
|
199
|
-
...(
|
|
221
|
+
...(body ? { body: body.stream, duplex: "half" } : {}),
|
|
200
222
|
signal: controller.signal,
|
|
201
223
|
});
|
|
202
224
|
core
|
|
203
225
|
.fetch(request)
|
|
204
|
-
.then((response) =>
|
|
226
|
+
.then((response) => {
|
|
227
|
+
// 남은 본문이 버림 상한보다 크다고 선언됨 = 읽지 않고 응답 후 연결 종료
|
|
228
|
+
if (body && !req.complete && Number(req.headers["content-length"] ?? 0) > DISCARD_BODY_BYTES)
|
|
229
|
+
res.setHeader("Connection", "close");
|
|
230
|
+
return sendResponse(res, response);
|
|
231
|
+
})
|
|
205
232
|
.catch((error) => {
|
|
206
233
|
report(error);
|
|
207
234
|
if (!res.headersSent && !res.destroyed)
|
|
@@ -233,6 +260,56 @@ function reporter(onerror) {
|
|
|
233
260
|
}
|
|
234
261
|
};
|
|
235
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* routes/ 의 export origin · auth 판정 (§12.4). /mcp 와 같은 allowedOrigins · auth · WWW-Authenticate.
|
|
265
|
+
* 본문 = { error: { code, message, ...details } } (specs/http.md §3.3 오류 본문 모양)
|
|
266
|
+
*/
|
|
267
|
+
function routeGuard(options, report) {
|
|
268
|
+
const warned = new Set();
|
|
269
|
+
const challenge = (error, request) => {
|
|
270
|
+
const metadata = options.oauth ? resourceMetadataUrl(options.oauth, new URL(request.url)) : undefined;
|
|
271
|
+
return jsonResponse(401, { error: error.toJSON() }, { "WWW-Authenticate": bearerChallenge(error, metadata) });
|
|
272
|
+
};
|
|
273
|
+
return {
|
|
274
|
+
origin(request) {
|
|
275
|
+
const origin = request.headers.get("origin") ?? undefined;
|
|
276
|
+
if (origin === undefined || origin === "" || originAllowed(origin, options.server?.allowedOrigins))
|
|
277
|
+
return undefined;
|
|
278
|
+
return jsonResponse(403, { error: { code: "REQUEST_REJECTED", message: `Forbidden: origin ${origin} is not allowed.`, reason: "origin" } });
|
|
279
|
+
},
|
|
280
|
+
async authenticate(request, mode, route) {
|
|
281
|
+
if (!options.auth) {
|
|
282
|
+
if (mode === "optional")
|
|
283
|
+
return ANONYMOUS;
|
|
284
|
+
if (!warned.has(route.path)) {
|
|
285
|
+
warned.add(route.path);
|
|
286
|
+
report(new Error(`route ${route.path}: auth = true (export auth or routes.auth) but mext.config.ts has no auth. Every request is 401`));
|
|
287
|
+
}
|
|
288
|
+
return challenge(unauthenticated("missing_token"), request);
|
|
289
|
+
}
|
|
290
|
+
let principal;
|
|
291
|
+
try {
|
|
292
|
+
principal = await options.auth({
|
|
293
|
+
authorization: request.headers.get("authorization") ?? undefined,
|
|
294
|
+
headers: new Headers(request.headers),
|
|
295
|
+
surface: defaultSurface("http"),
|
|
296
|
+
client: undefined,
|
|
297
|
+
route,
|
|
298
|
+
});
|
|
299
|
+
assertCallerFields(principal, "auth");
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
if (isMextError(error, "UNAUTHENTICATED"))
|
|
303
|
+
return challenge(error, request);
|
|
304
|
+
report(error);
|
|
305
|
+
return new Response("Internal Server Error\n", { status: 500, headers: { "Content-Type": "text/plain; charset=utf-8" } });
|
|
306
|
+
}
|
|
307
|
+
if (mode === true && principal.kind === "anonymous")
|
|
308
|
+
return challenge(unauthenticated("missing_token"), request);
|
|
309
|
+
return principal;
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
236
313
|
/** createMcpHttpHandler + node:http listen. 기본 127.0.0.1:3100 */
|
|
237
314
|
export async function startMcpHttpServer(options) {
|
|
238
315
|
const listener = createMcpHttpHandler(options);
|
|
@@ -259,9 +336,6 @@ export async function startMcpHttpServer(options) {
|
|
|
259
336
|
};
|
|
260
337
|
}
|
|
261
338
|
/* Origin */
|
|
262
|
-
const LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
263
|
-
/** allowedOrigins 의 loopback 항목 (미지정일 때의 기본 허용을 목록에 포함) */
|
|
264
|
-
const LOOPBACK_ENTRY = "loopback";
|
|
265
339
|
/**
|
|
266
340
|
* Origin 허용 여부. allowed 미지정 = loopback 만, 지정 = 목록의 origin 과 정확히 일치 ("*" = 전체, "loopback" = loopback).
|
|
267
341
|
* http · https 외 scheme (chrome-extension://<id>) = URL.origin 이 "null" 이라 목록과 문자열 비교
|
|
@@ -301,6 +375,64 @@ function statelessHeaders(source) {
|
|
|
301
375
|
headers.delete(name);
|
|
302
376
|
return headers;
|
|
303
377
|
}
|
|
378
|
+
/** 응답 후 버리며 읽는 남은 요청 본문의 상한 (바이트). 넘으면 연결 종료 */
|
|
379
|
+
const DISCARD_BODY_BYTES = 64 * 1024 * 1024;
|
|
380
|
+
/**
|
|
381
|
+
* IncomingMessage → 요청 본문 스트림 (backpressure = pause · resume).
|
|
382
|
+
* Readable.toWeb 대신 직접: Node 22 의 toWeb 스트림은 cancel (413 · 403 조기 거부) 뒤 남은 본문이 도착하면
|
|
383
|
+
* 닫힌 controller 에 enqueue 해 프로세스가 죽는다 (ERR_INVALID_STATE). cancel = 남은 본문 버림.
|
|
384
|
+
* discard = 응답 후 남은 본문을 버리며 읽는다 (pause 된 채 두면 클라이언트의 본문 쓰기가 멈추고 같은 연결의 다음 요청이
|
|
385
|
+
* 처리되지 않는다). DISCARD_BODY_BYTES 를 넘으면 연결 종료
|
|
386
|
+
*/
|
|
387
|
+
function nodeBody(req) {
|
|
388
|
+
let done = false;
|
|
389
|
+
const discard = (res) => {
|
|
390
|
+
done = true;
|
|
391
|
+
if (req.complete || req.destroyed)
|
|
392
|
+
return;
|
|
393
|
+
let size = 0;
|
|
394
|
+
req.on("data", (chunk) => {
|
|
395
|
+
size += chunk.byteLength;
|
|
396
|
+
if (size > DISCARD_BODY_BYTES)
|
|
397
|
+
req.socket.destroy();
|
|
398
|
+
});
|
|
399
|
+
// Connection: close 응답 = Node 가 응답 후 연결을 닫는다. 남은 본문을 읽을 필요 없음
|
|
400
|
+
if (res.getHeader("connection") !== "close")
|
|
401
|
+
req.resume();
|
|
402
|
+
};
|
|
403
|
+
const stream = new ReadableStream({
|
|
404
|
+
start(controller) {
|
|
405
|
+
req.on("data", (chunk) => {
|
|
406
|
+
if (done)
|
|
407
|
+
return;
|
|
408
|
+
controller.enqueue(new Uint8Array(chunk));
|
|
409
|
+
if ((controller.desiredSize ?? 0) <= 0)
|
|
410
|
+
req.pause();
|
|
411
|
+
});
|
|
412
|
+
req.once("end", () => {
|
|
413
|
+
if (done)
|
|
414
|
+
return;
|
|
415
|
+
done = true;
|
|
416
|
+
controller.close();
|
|
417
|
+
});
|
|
418
|
+
req.once("error", (error) => {
|
|
419
|
+
if (done)
|
|
420
|
+
return;
|
|
421
|
+
done = true;
|
|
422
|
+
controller.error(error);
|
|
423
|
+
});
|
|
424
|
+
req.pause();
|
|
425
|
+
},
|
|
426
|
+
pull() {
|
|
427
|
+
req.resume();
|
|
428
|
+
},
|
|
429
|
+
cancel() {
|
|
430
|
+
done = true;
|
|
431
|
+
req.resume();
|
|
432
|
+
},
|
|
433
|
+
});
|
|
434
|
+
return { stream, discard };
|
|
435
|
+
}
|
|
304
436
|
function nodeHeaders(req) {
|
|
305
437
|
const headers = new Headers();
|
|
306
438
|
for (const [name, value] of Object.entries(req.headers)) {
|
|
@@ -393,13 +525,16 @@ function jsonResponse(status, body, headers = {}) {
|
|
|
393
525
|
return new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json", ...headers } });
|
|
394
526
|
}
|
|
395
527
|
function unauthenticatedResponse(error, id, resourceMetadata) {
|
|
528
|
+
return jsonResponse(401, rpcError(-32_001, error.message, error.toJSON(), id), { "WWW-Authenticate": bearerChallenge(error, resourceMetadata) });
|
|
529
|
+
}
|
|
530
|
+
/** 401 의 WWW-Authenticate (/mcp · routes 공통) */
|
|
531
|
+
function bearerChallenge(error, resourceMetadata) {
|
|
396
532
|
const params = [];
|
|
397
533
|
if (error.details.reason === "invalid_token")
|
|
398
534
|
params.push('error="invalid_token"');
|
|
399
535
|
if (resourceMetadata !== undefined)
|
|
400
536
|
params.push(`resource_metadata="${resourceMetadata}"`);
|
|
401
|
-
|
|
402
|
-
return jsonResponse(401, rpcError(-32_001, error.message, error.toJSON(), id), { "WWW-Authenticate": challenge });
|
|
537
|
+
return params.length > 0 ? `Bearer ${params.join(", ")}` : "Bearer";
|
|
403
538
|
}
|
|
404
539
|
/* OAuth 보호 자원 메타데이터 (RFC 9728) */
|
|
405
540
|
/** MCP 엔드포인트 경로를 삽입한 well-known 경로 (/.well-known/oauth-protected-resource/mcp) */
|
package/dist/mcp/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/mcp/http.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport type { AddressInfo } from \"node:net\"\nimport { Readable } from \"node:stream\"\nimport { CLIENT_INFO_META_KEY, createMcpHandler, InMemoryServerEventBus, isLegacyRequest, type McpHttpHandler } from \"@modelcontextprotocol/server\"\nimport { auditHidden } from \"../audit.ts\"\nimport type { MextApp } from \"../command.ts\"\nimport { isMextError, type MextError } from \"../errors.ts\"\nimport { defaultSurface, reportedClient, surfaceOf, type BuiltinSurface, type ReportedClient } from \"../caller.ts\"\nimport { exposedRegistry } from \"../expose.ts\"\nimport { ANONYMOUS, assertCallerFields, type Principal } from \"../principal.ts\"\nimport type { RegisteredCommand, Registry } from \"../registry.ts\"\nimport { createRouteDispatcher, onceApp, type RouteEntry } from \"../route.ts\"\nimport { DEFAULT_HOST, DEFAULT_PORT, MCP_PATH } from \"./constants.ts\"\nimport type { Instrumentation } from \"../instrumentation.ts\"\nimport type { ToolExposure } from \"./dispatch.ts\"\nimport { createMcpServerFactory, principalAuthInfo, type McpCoreOptions } from \"./server.ts\"\nimport type { MextState } from \"../state.ts\"\nimport { bridgeResourceUpdates, narrowListenRequest, resourceUpdatedFn, trackBody } from \"./subscriptions.ts\"\nimport { hasTaskCommands, requestsTask } from \"./tasks.ts\"\n\n/** 요청 본문 상한 (SDK 기본과 같음) */\nexport const MAX_BODY_BYTES = 4 * 1024 * 1024\n\nexport interface McpAuthRequest {\n /** Authorization 헤더 원문 */\n authorization: string | undefined\n /** 요청 헤더 (세션 쿠키 · 프록시가 붙인 헤더). 복사본 */\n headers: Headers\n /** 어댑터 기본 표면. POST /mcp = \"mcp\". 반환 Principal.surface 로 논리 표면을 바꿀 수 있다 */\n surface: BuiltinSurface\n /** 요청 _meta 의 clientInfo (2026-07-28). 자가 신고 값: 주체 · 행위자 · 표면 판정에 쓰지 않는다 */\n client: ReportedClient | undefined\n}\n\nexport interface McpHttpOptions {\n registry: Registry\n app?: () => MextApp | Promise<MextApp>\n /**\n * 요청마다 Authorization → Principal. 없으면 모든 요청 = ANONYMOUS (readOnly 명령어만).\n * 잘못된 토큰은 unauthenticated() 를 던진다 → HTTP 401. anonymous 로 낮추지 않는다\n */\n auth?: (req: McpAuthRequest) => Principal | Promise<Principal>\n tools?: ToolExposure\n server?: {\n /** 기본 127.0.0.1 */\n host?: string\n /** 기본 3100. 0 = 임의 포트 */\n port?: number\n /**\n * Origin 허용 목록 (https://app.example.com · chrome-extension://<id> 형식, \"*\" = 전체, \"loopback\" = loopback).\n * 미지정 = loopback (localhost · 127.0.0.1 · [::1], 포트 무관) 만. Origin 헤더 없는 요청은 항상 통과\n */\n allowedOrigins?: string[]\n }\n /** serverInfo.name · 안내 문구. 기본 \"mext\" */\n name?: string\n /** initialize · server/discover 결과 instructions */\n instructions?: string\n /** 서버 capabilities 에 병합 (experimental) */\n capabilities?: McpCoreOptions[\"capabilities\"]\n /** 응답에 영향 없는 오류 보고 (auth 예외 · SDK 내부 오류) */\n onerror?: (error: Error) => void\n /** MRTR requestState 서명 키. McpCoreOptions.requestStateKey */\n requestStateKey?: McpCoreOptions[\"requestStateKey\"]\n /** 주기 progress 간격 (ms). McpCoreOptions.progressInterval */\n progressInterval?: number\n /** loadInstrumentation 결과 (onCommandError · span, transport = \"http\") */\n instrumentation?: Instrumentation\n /** _meta[\"dev.mext/manifestHash\"]. McpCoreOptions.manifestHash (기본 = registry 로 계산) */\n manifestHash?: string\n /**\n * OAuth 보호 자원 메타데이터 (RFC 9728). 지정하면 GET /.well-known/oauth-protected-resource/mcp ·\n * /.well-known/oauth-protected-resource 응답, 401 의 WWW-Authenticate 에 resource_metadata.\n * 클라이언트 (mext login · MCP 클라이언트) 가 인가 서버를 찾는 데 쓴다\n */\n oauth?: OAuthResourceOptions\n /** routes/ (§12.4). MCP 엔드포인트 밖 경로. Origin 검사 · auth 없음. ctx.app = MCP 와 같은 인스턴스 */\n routes?: readonly RouteEntry[]\n /** 주입 state (§12.1). 자원 구독 · ctx.resourceUpdated (§12.5) */\n state?: MextState\n /** McpCoreOptions.taskTiming (테스트) */\n taskTiming?: McpCoreOptions[\"taskTiming\"]\n /** McpCoreOptions.taskExecution. handler.js = \"waitUntil\" */\n taskExecution?: McpCoreOptions[\"taskExecution\"]\n /** 감사 (config.audit, §11.1) */\n audit?: McpCoreOptions[\"audit\"]\n /** 승인의 표면별 확인 방식 (config.approval, §4 승인) */\n approval?: McpCoreOptions[\"approval\"]\n}\n\n/** fetch 의 두 번째 인자. waitUntil = 응답 후 실행 유지 (handler.js 플랫폼, tasks §10) */\nexport interface McpFetchContext {\n waitUntil?: (promise: Promise<unknown>) => void\n}\n\nexport interface OAuthResourceOptions {\n /** 인가 서버 issuer URL (1개 이상) */\n authorizationServers: string[]\n scopesSupported?: string[]\n /** 토큰 대상 자원 ID (RFC 8707). 기본 = 요청 Host 기준 http://<host>/mcp (프록시 · TLS 뒤에서는 지정) */\n resource?: string\n}\n\n/** RFC 9728 well-known 경로 */\nexport const PROTECTED_RESOURCE_METADATA_PATH = \"/.well-known/oauth-protected-resource\"\n\nexport type McpHttpListener = ((req: IncomingMessage, res: ServerResponse) => void) & {\n /** subscriptions/listen 스트림을 완료 result 후 닫고 → 진행 중인 요청 abort · SDK handler 정리 */\n close(): Promise<void>\n /** subscriptions/listen 스트림만 완료 result 후 닫는다 (mext dev 자식 교체). 이후 listen 요청은 계속 받는다 */\n closeSubscriptions(): Promise<void>\n}\n\n/** Web 표준 (Request → Response) MCP 처리기. handler.js · 다른 런타임 · node:http 어댑터가 공유 */\nexport interface McpFetchHandler {\n /** 거부하지 않는다 (내부 오류 = 500 JSON-RPC 오류). request.signal abort = 핸들러 ctx.signal abort (task 제외) */\n fetch(request: Request, context?: McpFetchContext): Promise<Response>\n /** SDK handler 정리 (subscriptions/listen 스트림 = 완료 result 후 닫음) · 실행 중 task 취소 (상한 5초) */\n close(): Promise<void>\n /** 열린 subscriptions/listen 스트림을 완료 result 후 닫는다. 소비자가 끝까지 읽으면 resolve (상한 1초) */\n closeSubscriptions(): Promise<void>\n}\n\n/**\n * Streamable HTTP (2026-07-28) 의 transport 무관 처리 (Web Request → Response).\n * 순서: 경로 (routes · 404) → Origin (403) → 메서드 (POST 외 405) → 본문 (413) → auth (401) → SDK createMcpHandler.\n * SDK 가 요청별 버전 · 헤더 검증 (-32020) · server/discover · Mcp-Param-Command · 2025 레거시 stateless 를 처리.\n * progressToken 있는 2026-07-28 요청 = SSE 응답 (진행률 알림), 그 외 = JSON.\n */\nexport function createMcpFetchHandler(options: McpHttpOptions): McpFetchHandler {\n // ctx.app = 프로세스당 1회. 명령어 · route 가 공유\n const app = options.app ? onceApp(options.app) : undefined\n const resourceUpdated = resourceUpdatedFn(options.state)\n const routes = options.routes?.length\n ? createRouteDispatcher({ routes: options.routes, app: onceApp(app), resourceUpdated })\n : undefined\n const factory = createMcpServerFactory({\n registry: options.registry,\n ...(app ? { app } : {}),\n ...(options.tools ? { tools: options.tools } : {}),\n ...(options.name ? { name: options.name } : {}),\n ...(options.instructions !== undefined ? { instructions: options.instructions } : {}),\n ...(options.capabilities ? { capabilities: options.capabilities } : {}),\n ...(options.requestStateKey !== undefined ? { requestStateKey: options.requestStateKey } : {}),\n ...(options.progressInterval !== undefined ? { progressInterval: options.progressInterval } : {}),\n ...(options.instrumentation ? { instrumentation: options.instrumentation } : {}),\n ...(options.manifestHash !== undefined ? { manifestHash: options.manifestHash } : {}),\n ...(options.state ? { state: options.state } : {}),\n ...(options.taskTiming ? { taskTiming: options.taskTiming } : {}),\n ...(options.taskExecution ? { taskExecution: options.taskExecution } : {}),\n ...(options.audit ? { audit: options.audit } : {}),\n ...(options.approval ? { approval: options.approval } : {}),\n transport: \"http\",\n })\n const tasks = options.state?.store !== undefined && hasTaskCommands(options.registry)\n const report = reporter(options.onerror)\n const sdkOptions = options.onerror ? { onerror: report } : {}\n // subscriptions/listen (§12.5) = 전용 SDK handler (ack · 15초 keepalive · 완료 result). 갱신 = state 허브 → SDK bus\n const listenBus = new InMemoryServerEventBus(report)\n const subscriptions = { state: options.state, resources: options.registry.resources }\n const unbridge = bridgeResourceUpdates(listenBus, { ...subscriptions, onerror: report })\n const createListenHandler = (): McpHttpHandler => createMcpHandler(factory, { ...sdkOptions, bus: listenBus })\n let listenHandler = createListenHandler()\n const listenBodies = new Set<Promise<void>>()\n // 진행률 없는 요청 = JSON (auto: 관련 메시지가 없으면 단일 JSON), 진행률 있는 요청 = SSE\n const jsonHandler = createMcpHandler(factory, { ...sdkOptions, responseMode: \"auto\" })\n const sseHandler = createMcpHandler(factory, { ...sdkOptions, responseMode: \"sse\" })\n const allowedOrigins = options.server?.allowedOrigins\n\n const handle = async (request: Request, context: McpFetchContext | undefined): Promise<Response> => {\n const url = new URL(request.url)\n const oauth = options.oauth\n if (oauth && (url.pathname === PROTECTED_RESOURCE_METADATA_PATH || url.pathname === protectedResourceMetadataPath())) {\n if (request.method !== \"GET\") return jsonResponse(405, { error: \"method_not_allowed\" }, { Allow: \"GET\" })\n return jsonResponse(200, protectedResourceMetadata(oauth, url))\n }\n if (routes && url.pathname !== MCP_PATH) {\n const routed = await routes(request, url)\n if (routed) return routed\n }\n if (url.pathname !== MCP_PATH) return jsonResponse(404, rpcError(-32_000, `Not found. The MCP endpoint is POST ${MCP_PATH}.`))\n const origin = request.headers.get(\"origin\") ?? undefined\n if (origin !== undefined && origin !== \"\" && !originAllowed(origin, allowedOrigins)) {\n return jsonResponse(403, rpcError(-32_000, `Forbidden: origin ${origin} is not allowed.`))\n }\n if (request.method !== \"POST\") {\n return jsonResponse(405, rpcError(-32_000, \"Method not allowed.\"), { Allow: \"POST\" })\n }\n\n const body = await readBody(request.body, MAX_BODY_BYTES)\n if (body === \"too-large\") return jsonResponse(413, rpcError(-32_000, \"Request body too large.\"))\n const parsed = parseJson(body)\n const id = requestId(parsed)\n\n let principal: Principal = ANONYMOUS\n if (options.auth) {\n try {\n principal = await options.auth({\n authorization: request.headers.get(\"authorization\") ?? undefined,\n headers: new Headers(request.headers),\n surface: defaultSurface(\"http\"),\n client: reportedClientOf(parsed),\n })\n // actor · surface 형식 오류 = auth 예외와 같음 (500 + onerror)\n assertCallerFields(principal, \"auth\")\n } catch (error) {\n if (isMextError(error, \"UNAUTHENTICATED\")) {\n return unauthenticatedResponse(error, id, oauth ? resourceMetadataUrl(oauth, url) : undefined)\n }\n report(error)\n return jsonResponse(500, rpcError(-32_603, \"Internal server error\", undefined, id))\n }\n }\n\n const sdkRequest = new Request(url, {\n method: \"POST\",\n headers: statelessHeaders(request.headers),\n body,\n signal: request.signal,\n })\n const parsedBody = parsed === NOT_JSON ? undefined : parsed\n // 2025-11-25 이하 (envelope 없음) = SDK stateless 레거시 경로. 진행률 기반 SSE 전환은 2026-07-28 요청만\n const legacy = await isLegacyRequest(sdkRequest, parsedBody, { maxRequestBodySize: MAX_BODY_BYTES })\n const listen = legacy ? undefined : narrowListenRequest(parsedBody, subscriptions, principal)\n if (listen !== undefined) {\n const { response, done } = trackBody(await listenHandler.fetch(sdkRequest, { authInfo: principalAuthInfo(principal), parsedBody: listen }))\n listenBodies.add(done)\n void done.then(() => listenBodies.delete(done))\n return response\n }\n // tools: \"command\" 의 숨긴 명령어 호출 = SDK 가 등록되지 않은 도구로 거부해 mext 콜백이 없다 → 본문을 넘기기 전에 기록\n // (§11.1 includeHidden). 응답은 그대로 SDK 가 만들고, 전달은 기다리지 않는다\n if (options.audit?.includeHidden === true && options.tools === \"command\") {\n const hidden = hiddenToolCall(options.registry, principal, parsedBody)\n const work =\n hidden &&\n auditHidden(hidden, {\n audit: options.audit,\n principal,\n transport: \"http\",\n ...optional(\"client\", reportedClientOf(parsedBody)),\n ...optional(\"traceContext\", metaOf(parsedBody)),\n })\n if (work) context?.waitUntil?.(work)\n }\n // task 가 될 수 있는 tools/call = application/json (CreateTaskResult, §12.6)\n // 대상 판정 = 주체의 표면에서 보이는 명령어 (숨긴 task 명령어는 없는 명령어와 같은 응답 형식, §4 expose)\n const sse =\n !legacy && hasProgressToken(parsedBody) && !(tasks && requestsTask(exposedRegistry(options.registry, surfaceOf(principal, \"http\")), parsedBody))\n const handler: McpHttpHandler = sse ? sseHandler : jsonHandler\n return handler.fetch(sdkRequest, {\n authInfo: principalAuthInfo(principal, context?.waitUntil),\n ...(parsedBody !== undefined ? { parsedBody } : {}),\n })\n }\n\n return {\n async fetch(request, context) {\n try {\n return await handle(request, context)\n } catch (error) {\n report(error)\n return jsonResponse(500, rpcError(-32_603, \"Internal server error\"))\n }\n },\n closeSubscriptions,\n async close() {\n unbridge()\n await closeSubscriptions()\n await Promise.all([listenHandler.close(), jsonHandler.close(), sseHandler.close(), factory.close()])\n },\n }\n\n async function closeSubscriptions(): Promise<void> {\n // SDK handler.close = 열린 listen 스트림마다 완료 result 후 닫음. 이후 listen 은 새 handler 가 받는다\n const closing = listenHandler\n listenHandler = createListenHandler()\n await closing.close()\n const pending = [...listenBodies]\n if (pending.length === 0) return\n let timer: ReturnType<typeof setTimeout> | undefined\n await Promise.race([Promise.all(pending), new Promise<void>((resolve) => (timer = setTimeout(resolve, LISTEN_DRAIN_MS)))])\n clearTimeout(timer)\n }\n}\n\n/** 서버 종료 시 listen 스트림의 완료 result 를 클라이언트가 읽기까지 기다리는 상한 (ms) */\nconst LISTEN_DRAIN_MS = 1_000\n\n/** createMcpFetchHandler 의 node:http 어댑터. 응답 · SSE 를 스트리밍, 클라이언트 연결 종료 = request.signal abort */\nexport function createMcpHttpHandler(options: McpHttpOptions): McpHttpListener {\n const core = createMcpFetchHandler(options)\n const report = reporter(options.onerror)\n const inflight = new Set<AbortController>()\n\n const listener = ((req: IncomingMessage, res: ServerResponse) => {\n const controller = new AbortController()\n inflight.add(controller)\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort()\n inflight.delete(controller)\n })\n const hasBody = req.method !== \"GET\" && req.method !== \"HEAD\"\n const request = new Request(requestUrl(req), {\n method: req.method ?? \"GET\",\n headers: nodeHeaders(req),\n ...(hasBody ? { body: Readable.toWeb(req) as ReadableStream<Uint8Array>, duplex: \"half\" as const } : {}),\n signal: controller.signal,\n })\n core\n .fetch(request)\n .then((response) => sendResponse(res, response))\n .catch((error: unknown) => {\n report(error)\n if (!res.headersSent && !res.destroyed) sendJson(res, 500, rpcError(-32_603, \"Internal server error\"))\n else res.destroy()\n })\n }) as McpHttpListener\n listener.closeSubscriptions = () => core.closeSubscriptions()\n listener.close = async () => {\n await core.closeSubscriptions()\n // 완료 result 를 쓴 응답의 end (sendResponse) 가 연결 정리 전에 실행되도록\n await new Promise<void>((resolve) => setImmediate(resolve))\n for (const c of inflight) c.abort()\n inflight.clear()\n await core.close()\n }\n return listener\n}\n\n/** 응답에 영향 없는 오류 보고 (보고 자체의 예외는 삼킨다) */\nfunction reporter(onerror: ((error: Error) => void) | undefined): (error: unknown) => void {\n return (error) => {\n try {\n onerror?.(error instanceof Error ? error : new Error(String(error)))\n } catch {\n // 보고는 응답을 바꾸지 않는다\n }\n }\n}\n\nexport interface McpHttpServer {\n /** http://<host>:<port>/mcp */\n url: string\n host: string\n port: number\n close(): Promise<void>\n}\n\n/** createMcpHttpHandler + node:http listen. 기본 127.0.0.1:3100 */\nexport async function startMcpHttpServer(options: McpHttpOptions): Promise<McpHttpServer> {\n const listener = createMcpHttpHandler(options)\n const server = createServer(listener)\n const host = options.server?.host ?? DEFAULT_HOST\n const port = options.server?.port ?? DEFAULT_PORT\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(port, host, () => {\n server.off(\"error\", reject)\n resolve()\n })\n })\n const address = server.address() as AddressInfo\n return {\n url: `http://${formatHost(host)}:${address.port}${MCP_PATH}`,\n host,\n port: address.port,\n async close() {\n await listener.close()\n server.closeAllConnections()\n await new Promise<void>((resolve) => server.close(() => resolve()))\n },\n }\n}\n\n/* Origin */\n\nconst LOOPBACK_HOSTNAMES = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"])\n\n/** allowedOrigins 의 loopback 항목 (미지정일 때의 기본 허용을 목록에 포함) */\nconst LOOPBACK_ENTRY = \"loopback\"\n\n/**\n * Origin 허용 여부. allowed 미지정 = loopback 만, 지정 = 목록의 origin 과 정확히 일치 (\"*\" = 전체, \"loopback\" = loopback).\n * http · https 외 scheme (chrome-extension://<id>) = URL.origin 이 \"null\" 이라 목록과 문자열 비교\n */\nexport function originAllowed(origin: string, allowed: readonly string[] | undefined): boolean {\n if (allowed?.includes(\"*\")) return true\n let url: URL\n try {\n url = new URL(origin)\n } catch {\n return false\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return allowed?.includes(origin) ?? false\n if (LOOPBACK_HOSTNAMES.has(url.hostname) && (allowed === undefined || allowed.includes(LOOPBACK_ENTRY))) return true\n if (allowed === undefined) return false\n return allowed.some((entry) => normalizeOrigin(entry) === url.origin)\n}\n\nfunction normalizeOrigin(entry: string): string | undefined {\n try {\n return new URL(entry).origin\n } catch {\n return undefined\n }\n}\n\n/* node:http ↔ fetch */\n\n/** 무시하는 헤더 (stateless): 세션 · SSE 재개 */\nconst DROPPED_HEADERS = new Set([\"mcp-session-id\", \"last-event-id\"])\n\nfunction statelessHeaders(source: Headers): Headers {\n const headers = new Headers(source)\n for (const name of DROPPED_HEADERS) headers.delete(name)\n return headers\n}\n\nfunction nodeHeaders(req: IncomingMessage): Headers {\n const headers = new Headers()\n for (const [name, value] of Object.entries(req.headers)) {\n if (value === undefined || name.startsWith(\":\")) continue\n if (Array.isArray(value)) for (const v of value) headers.append(name, v)\n else headers.set(name, value)\n }\n return headers\n}\n\nfunction requestUrl(req: IncomingMessage): URL {\n try {\n return new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`)\n } catch {\n return new URL(req.url ?? \"/\", \"http://localhost\")\n }\n}\n\n/** 본문을 limit 바이트까지. 넘으면 스트림 취소 후 \"too-large\" */\nasync function readBody(body: ReadableStream<Uint8Array> | null, limit: number): Promise<Uint8Array<ArrayBuffer> | \"too-large\"> {\n if (body === null) return new Uint8Array(0)\n const chunks: Uint8Array[] = []\n let size = 0\n const reader = body.getReader()\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n size += value.byteLength\n if (size > limit) {\n await reader.cancel().catch(() => {})\n return \"too-large\"\n }\n chunks.push(value)\n }\n const out = new Uint8Array(size)\n let offset = 0\n for (const c of chunks) {\n out.set(c, offset)\n offset += c.byteLength\n }\n return out\n}\n\nasync function sendResponse(res: ServerResponse, response: Response): Promise<void> {\n if (res.destroyed) {\n await response.body?.cancel().catch(() => {})\n return\n }\n res.statusCode = response.status\n response.headers.forEach((value, name) => res.setHeader(name, value))\n if (response.body === null) {\n res.end()\n return\n }\n const reader = response.body.getReader()\n // 클라이언트가 SSE 스트림을 닫으면 = 취소. SDK 가 transport 를 닫고 핸들러 signal 을 abort, 이후 메시지는 버린다\n const onClose = () => {\n if (!res.writableFinished) void reader.cancel().catch(() => {})\n }\n res.on(\"close\", onClose)\n res.flushHeaders()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done || res.destroyed) break\n res.write(value)\n }\n } catch {\n // 스트림 취소 · 생산자 오류: 아래에서 응답을 닫는다\n } finally {\n res.off(\"close\", onClose)\n }\n if (!res.destroyed) res.end()\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown, headers: Record<string, string> = {}): void {\n const text = JSON.stringify(body)\n res.writeHead(status, { \"Content-Type\": \"application/json\", \"Content-Length\": Buffer.byteLength(text), ...headers })\n res.end(text)\n}\n\nfunction jsonResponse(status: number, body: unknown, headers: Record<string, string> = {}): Response {\n return new Response(JSON.stringify(body), { status, headers: { \"Content-Type\": \"application/json\", ...headers } })\n}\n\nfunction unauthenticatedResponse(\n error: MextError<\"UNAUTHENTICATED\">,\n id: string | number | null,\n resourceMetadata: string | undefined,\n): Response {\n const params: string[] = []\n if (error.details.reason === \"invalid_token\") params.push('error=\"invalid_token\"')\n if (resourceMetadata !== undefined) params.push(`resource_metadata=\"${resourceMetadata}\"`)\n const challenge = params.length > 0 ? `Bearer ${params.join(\", \")}` : \"Bearer\"\n return jsonResponse(401, rpcError(-32_001, error.message, error.toJSON(), id), { \"WWW-Authenticate\": challenge })\n}\n\n/* OAuth 보호 자원 메타데이터 (RFC 9728) */\n\n/** MCP 엔드포인트 경로를 삽입한 well-known 경로 (/.well-known/oauth-protected-resource/mcp) */\nfunction protectedResourceMetadataPath(): string {\n return `${PROTECTED_RESOURCE_METADATA_PATH}${MCP_PATH}`\n}\n\nfunction resourceOf(oauth: OAuthResourceOptions, url: URL): string {\n return oauth.resource ?? `${url.origin}${MCP_PATH}`\n}\n\nfunction resourceMetadataUrl(oauth: OAuthResourceOptions, url: URL): string {\n const resource = new URL(resourceOf(oauth, url))\n const path = resource.pathname.replace(/\\/$/, \"\")\n return `${resource.origin}${PROTECTED_RESOURCE_METADATA_PATH}${path}`\n}\n\nfunction protectedResourceMetadata(oauth: OAuthResourceOptions, url: URL): Record<string, unknown> {\n const doc: Record<string, unknown> = {\n resource: resourceOf(oauth, url),\n authorization_servers: [...oauth.authorizationServers],\n bearer_methods_supported: [\"header\"],\n }\n if (oauth.scopesSupported) doc.scopes_supported = [...oauth.scopesSupported]\n return doc\n}\n\nfunction rpcError(code: number, message: string, data?: unknown, id: string | number | null = null) {\n return { jsonrpc: \"2.0\", id, error: data === undefined ? { code, message } : { code, message, data } }\n}\n\nconst NOT_JSON = Symbol(\"not-json\")\n\nfunction parseJson(body: Uint8Array): unknown {\n if (body.length === 0) return NOT_JSON\n try {\n return JSON.parse(new TextDecoder().decode(body))\n } catch {\n return NOT_JSON\n }\n}\n\nfunction requestId(body: unknown): string | number | null {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return null\n const { id, method } = body as { id?: unknown; method?: unknown }\n if (typeof method !== \"string\") return null\n return typeof id === \"string\" || typeof id === \"number\" ? id : null\n}\n\n/** 요청 본문 params._meta 의 clientInfo (2026-07-28 envelope). 자가 신고 값. 없음 · 형식 오류 = undefined */\nfunction reportedClientOf(body: unknown): ReportedClient | undefined {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return undefined\n const meta = (body as { params?: { _meta?: unknown } }).params?._meta\n if (meta === null || typeof meta !== \"object\") return undefined\n return reportedClient((meta as Record<string, unknown>)[CLIENT_INFO_META_KEY])\n}\n\n/** tools/call 의 params._meta (traceparent 등) */\nfunction metaOf(body: unknown): Record<string, unknown> | undefined {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return undefined\n const meta = (body as { params?: { _meta?: unknown } }).params?._meta\n return meta !== null && typeof meta === \"object\" && !Array.isArray(meta) ? (meta as Record<string, unknown>) : undefined\n}\n\nfunction optional<K extends string, V>(key: K, value: V | undefined): { [P in K]?: V } {\n return (value === undefined ? {} : { [key]: value }) as { [P in K]?: V }\n}\n\n/**\n * tools: \"command\" 의 tools/call 이 가리키는 명령어가 주체의 표면에서 숨긴 명령어면 그 항목. 도구 이름 = 정식 ID 만 (별칭은 도구가 아니다).\n * 보이는 명령어 · 없는 이름 = undefined\n */\nfunction hiddenToolCall(registry: Registry, principal: Principal, body: unknown): RegisteredCommand | undefined {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return undefined\n const { method, params } = body as { method?: unknown; params?: { name?: unknown } | null }\n if (method !== \"tools/call\" || typeof params?.name !== \"string\") return undefined\n const entry = registry.commands.get(params.name)\n if (!entry) return undefined\n return exposedRegistry(registry, surfaceOf(principal, \"http\")).commands.has(entry.id) ? undefined : entry\n}\n\nfunction hasProgressToken(body: unknown): boolean {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return false\n const meta = (body as { params?: { _meta?: { progressToken?: unknown } } }).params?._meta\n return meta !== null && typeof meta === \"object\" && meta.progressToken !== undefined\n}\n\nfunction formatHost(host: string): string {\n return host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host\n}\n"]}
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/mcp/http.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport type { AddressInfo } from \"node:net\"\nimport { CLIENT_INFO_META_KEY, createMcpHandler, InMemoryServerEventBus, isLegacyRequest, type McpHttpHandler } from \"@modelcontextprotocol/server\"\nimport { auditHidden } from \"../audit.ts\"\nimport type { MextApp } from \"../command.ts\"\nimport { isMextError, unauthenticated, type MextError } from \"../errors.ts\"\nimport { defaultSurface, reportedClient, surfaceOf, type BuiltinSurface, type ReportedClient } from \"../caller.ts\"\nimport { exposedRegistry } from \"../expose.ts\"\nimport { ANONYMOUS, assertCallerFields, type Principal } from \"../principal.ts\"\nimport type { RegisteredCommand, Registry } from \"../registry.ts\"\nimport { createRouteDispatcher, onceApp, type RouteEntry, type RouteGuard, type RouteMethod, type RouteOptions } from \"../route.ts\"\nimport { DEFAULT_HOST, DEFAULT_PORT, MAX_BODY_BYTES, MCP_PATH } from \"./constants.ts\"\nimport { hostAllowed, LOOPBACK_ENTRY, LOOPBACK_HOSTNAMES } from \"./host.ts\"\nimport type { Instrumentation } from \"../instrumentation.ts\"\nimport type { ToolExposure } from \"./dispatch.ts\"\nimport { createMcpServerFactory, principalAuthInfo, type McpCoreOptions } from \"./server.ts\"\nimport type { MextState } from \"../state.ts\"\nimport { bridgeResourceUpdates, narrowListenRequest, resourceUpdatedFn, trackBody } from \"./subscriptions.ts\"\nimport { hasTaskCommands, requestsTask } from \"./tasks.ts\"\n\nexport { MAX_BODY_BYTES }\n\nexport interface McpAuthRequest {\n /** Authorization 헤더 원문 */\n authorization: string | undefined\n /** 요청 헤더 (세션 쿠키 · 프록시가 붙인 헤더). 복사본 */\n headers: Headers\n /** 어댑터 기본 표면. POST /mcp = \"mcp\". 반환 Principal.surface 로 논리 표면을 바꿀 수 있다 */\n surface: BuiltinSurface\n /** 요청 _meta 의 clientInfo (2026-07-28). 자가 신고 값: 주체 · 행위자 · 표면 판정에 쓰지 않는다 */\n client: ReportedClient | undefined\n /** routes/ 요청 (export auth, §12.4) 만. method = 요청 메서드 (HEAD = GET), path = route 파일 패턴 (\"/items/[id]\"). POST /mcp = 없음 */\n route?: { method: RouteMethod; path: string }\n}\n\nexport interface McpHttpOptions {\n registry: Registry\n app?: () => MextApp | Promise<MextApp>\n /**\n * 요청마다 Authorization → Principal. 없으면 모든 요청 = ANONYMOUS (readOnly 명령어만).\n * 잘못된 토큰은 unauthenticated() 를 던진다 → HTTP 401. anonymous 로 낮추지 않는다\n */\n auth?: (req: McpAuthRequest) => Principal | Promise<Principal>\n tools?: ToolExposure\n server?: {\n /** 기본 127.0.0.1 */\n host?: string\n /** 기본 3100. 0 = 임의 포트 */\n port?: number\n /**\n * Origin 허용 목록 (https://app.example.com · chrome-extension://<id> 형식, \"*\" = 전체, \"loopback\" = loopback).\n * 미지정 = loopback (localhost · 127.0.0.1 · [::1], 포트 무관) 만. Origin 헤더 없는 요청은 항상 통과\n */\n allowedOrigins?: string[]\n /**\n * Host 허용 목록 (api.example.com = 모든 포트 · api.example.com:8443 = 그 포트만, \"loopback\" = loopback, \"*\" = 전체).\n * 미지정 = 검사 없음. 지정 = 목록 밖 Host 의 모든 요청 (/mcp · routes · well-known) = 403 (DNS rebinding 방어)\n */\n allowedHosts?: string[]\n /** POST /mcp 본문 상한 (바이트). 기본 MAX_BODY_BYTES (4 MiB). 넘으면 413. route 의 export maxBodyBytes = true 도 이 값 */\n maxBodyBytes?: number\n }\n /** serverInfo.name · 안내 문구. 기본 \"mext\" */\n name?: string\n /** initialize · server/discover 결과 instructions */\n instructions?: string\n /** 서버 capabilities 에 병합 (experimental) */\n capabilities?: McpCoreOptions[\"capabilities\"]\n /** 응답에 영향 없는 오류 보고 (auth 예외 · SDK 내부 오류) */\n onerror?: (error: Error) => void\n /** MRTR requestState 서명 키. McpCoreOptions.requestStateKey */\n requestStateKey?: McpCoreOptions[\"requestStateKey\"]\n /** 주기 progress 간격 (ms). McpCoreOptions.progressInterval */\n progressInterval?: number\n /** loadInstrumentation 결과 (onCommandError · span, transport = \"http\") */\n instrumentation?: Instrumentation\n /** _meta[\"dev.mext/manifestHash\"]. McpCoreOptions.manifestHash (기본 = registry 로 계산) */\n manifestHash?: string\n /**\n * OAuth 보호 자원 메타데이터 (RFC 9728). 지정하면 GET /.well-known/oauth-protected-resource/mcp ·\n * /.well-known/oauth-protected-resource 응답, 401 의 WWW-Authenticate 에 resource_metadata.\n * 클라이언트 (mext login · MCP 클라이언트) 가 인가 서버를 찾는 데 쓴다\n */\n oauth?: OAuthResourceOptions\n /**\n * routes/ (§12.4). MCP 엔드포인트 밖 경로. ctx.app = MCP 와 같은 인스턴스.\n * Origin 검사 · auth = 기본 없음. 모듈의 export origin · auth (없으면 routeDefaults) 가 있으면 allowedOrigins · auth 를 /mcp 와 같은 규칙으로\n */\n routes?: readonly RouteEntry[]\n /** 설정 routes (§12.4): 모든 route 의 auth · origin · maxBodyBytes 기본값. 모듈 export 가 덮어쓴다 */\n routeDefaults?: RouteOptions\n /** 주입 state (§12.1). 자원 구독 · ctx.resourceUpdated (§12.5) */\n state?: MextState\n /** McpCoreOptions.taskTiming (테스트) */\n taskTiming?: McpCoreOptions[\"taskTiming\"]\n /** McpCoreOptions.taskExecution. handler.js = \"waitUntil\" */\n taskExecution?: McpCoreOptions[\"taskExecution\"]\n /** 감사 (config.audit, §11.1) */\n audit?: McpCoreOptions[\"audit\"]\n /** 승인의 표면별 확인 방식 (config.approval, §4 승인) */\n approval?: McpCoreOptions[\"approval\"]\n}\n\n/** fetch 의 두 번째 인자. waitUntil = 응답 후 실행 유지 (handler.js 플랫폼, tasks §10) */\nexport interface McpFetchContext {\n waitUntil?: (promise: Promise<unknown>) => void\n}\n\nexport interface OAuthResourceOptions {\n /** 인가 서버 issuer URL (1개 이상) */\n authorizationServers: string[]\n scopesSupported?: string[]\n /** 토큰 대상 자원 ID (RFC 8707). 기본 = 요청 Host 기준 http://<host>/mcp (프록시 · TLS 뒤에서는 지정) */\n resource?: string\n}\n\n/** RFC 9728 well-known 경로 */\nexport const PROTECTED_RESOURCE_METADATA_PATH = \"/.well-known/oauth-protected-resource\"\n\nexport type McpHttpListener = ((req: IncomingMessage, res: ServerResponse) => void) & {\n /** subscriptions/listen 스트림을 완료 result 후 닫고 → 진행 중인 요청 abort · SDK handler 정리 */\n close(): Promise<void>\n /** subscriptions/listen 스트림만 완료 result 후 닫는다 (mext dev 자식 교체). 이후 listen 요청은 계속 받는다 */\n closeSubscriptions(): Promise<void>\n}\n\n/** Web 표준 (Request → Response) MCP 처리기. handler.js · 다른 런타임 · node:http 어댑터가 공유 */\nexport interface McpFetchHandler {\n /** 거부하지 않는다 (내부 오류 = 500 JSON-RPC 오류). request.signal abort = 핸들러 ctx.signal abort (task 제외) */\n fetch(request: Request, context?: McpFetchContext): Promise<Response>\n /** SDK handler 정리 (subscriptions/listen 스트림 = 완료 result 후 닫음) · 실행 중 task 취소 (상한 5초) */\n close(): Promise<void>\n /** 열린 subscriptions/listen 스트림을 완료 result 후 닫는다. 소비자가 끝까지 읽으면 resolve (상한 1초) */\n closeSubscriptions(): Promise<void>\n}\n\n/**\n * Streamable HTTP (2026-07-28) 의 transport 무관 처리 (Web Request → Response).\n * 순서: Host (allowedHosts, 모든 경로 403) → 경로 (routes · 404) → Origin (403) → 메서드 (POST 외 405) → 본문 (413) → auth (401) → SDK createMcpHandler.\n * SDK 가 요청별 버전 · 헤더 검증 (-32020) · server/discover · Mcp-Param-Command · 2025 레거시 stateless 를 처리.\n * progressToken 있는 2026-07-28 요청 = SSE 응답 (진행률 알림), 그 외 = JSON.\n */\nexport function createMcpFetchHandler(options: McpHttpOptions): McpFetchHandler {\n // ctx.app = 프로세스당 1회. 명령어 · route 가 공유\n const app = options.app ? onceApp(options.app) : undefined\n const resourceUpdated = resourceUpdatedFn(options.state)\n const report = reporter(options.onerror)\n const allowedOrigins = options.server?.allowedOrigins\n const routes = options.routes?.length\n ? createRouteDispatcher({\n routes: options.routes,\n app: onceApp(app),\n resourceUpdated,\n guard: routeGuard(options, report),\n maxBodyBytes: options.server?.maxBodyBytes ?? MAX_BODY_BYTES,\n ...(options.routeDefaults ? { defaults: options.routeDefaults } : {}),\n })\n : undefined\n const factory = createMcpServerFactory({\n registry: options.registry,\n ...(app ? { app } : {}),\n ...(options.tools ? { tools: options.tools } : {}),\n ...(options.name ? { name: options.name } : {}),\n ...(options.instructions !== undefined ? { instructions: options.instructions } : {}),\n ...(options.capabilities ? { capabilities: options.capabilities } : {}),\n ...(options.requestStateKey !== undefined ? { requestStateKey: options.requestStateKey } : {}),\n ...(options.progressInterval !== undefined ? { progressInterval: options.progressInterval } : {}),\n ...(options.instrumentation ? { instrumentation: options.instrumentation } : {}),\n ...(options.manifestHash !== undefined ? { manifestHash: options.manifestHash } : {}),\n ...(options.state ? { state: options.state } : {}),\n ...(options.taskTiming ? { taskTiming: options.taskTiming } : {}),\n ...(options.taskExecution ? { taskExecution: options.taskExecution } : {}),\n ...(options.audit ? { audit: options.audit } : {}),\n ...(options.approval ? { approval: options.approval } : {}),\n transport: \"http\",\n })\n const tasks = options.state?.store !== undefined && hasTaskCommands(options.registry)\n const maxBodyBytes = options.server?.maxBodyBytes ?? MAX_BODY_BYTES\n const sdkOptions = { ...(options.onerror ? { onerror: report } : {}), maxRequestBodySize: maxBodyBytes }\n // subscriptions/listen (§12.5) = 전용 SDK handler (ack · 15초 keepalive · 완료 result). 갱신 = state 허브 → SDK bus\n const listenBus = new InMemoryServerEventBus(report)\n const subscriptions = { state: options.state, resources: options.registry.resources }\n const unbridge = bridgeResourceUpdates(listenBus, { ...subscriptions, onerror: report })\n const createListenHandler = (): McpHttpHandler => createMcpHandler(factory, { ...sdkOptions, bus: listenBus })\n let listenHandler = createListenHandler()\n const listenBodies = new Set<Promise<void>>()\n // 진행률 없는 요청 = JSON (auto: 관련 메시지가 없으면 단일 JSON), 진행률 있는 요청 = SSE\n const jsonHandler = createMcpHandler(factory, { ...sdkOptions, responseMode: \"auto\" })\n const sseHandler = createMcpHandler(factory, { ...sdkOptions, responseMode: \"sse\" })\n\n const allowedHosts = options.server?.allowedHosts\n\n const handle = async (request: Request, context: McpFetchContext | undefined): Promise<Response> => {\n const url = new URL(request.url)\n if (allowedHosts !== undefined) {\n const host = request.headers.get(\"host\") ?? url.host\n if (!hostAllowed(host, allowedHosts)) {\n await request.body?.cancel().catch(() => {})\n const message = `Forbidden: host ${host} is not allowed.`\n if (url.pathname === MCP_PATH) return jsonResponse(403, rpcError(-32_000, message))\n return jsonResponse(403, { error: { code: \"REQUEST_REJECTED\", message, reason: \"host\" } })\n }\n }\n const oauth = options.oauth\n if (oauth && (url.pathname === PROTECTED_RESOURCE_METADATA_PATH || url.pathname === protectedResourceMetadataPath())) {\n if (request.method !== \"GET\") return jsonResponse(405, { error: \"method_not_allowed\" }, { Allow: \"GET\" })\n return jsonResponse(200, protectedResourceMetadata(oauth, url))\n }\n if (routes && url.pathname !== MCP_PATH) {\n const routed = await routes(request, url)\n if (routed) return routed\n }\n if (url.pathname !== MCP_PATH) return jsonResponse(404, rpcError(-32_000, `Not found. The MCP endpoint is POST ${MCP_PATH}.`))\n const origin = request.headers.get(\"origin\") ?? undefined\n if (origin !== undefined && origin !== \"\" && !originAllowed(origin, allowedOrigins)) {\n return jsonResponse(403, rpcError(-32_000, `Forbidden: origin ${origin} is not allowed.`))\n }\n if (request.method !== \"POST\") {\n return jsonResponse(405, rpcError(-32_000, \"Method not allowed.\"), { Allow: \"POST\" })\n }\n\n const body = await readBody(request.body, maxBodyBytes)\n if (body === \"too-large\") return jsonResponse(413, rpcError(-32_000, \"Request body too large.\"))\n const parsed = parseJson(body)\n const id = requestId(parsed)\n\n let principal: Principal = ANONYMOUS\n if (options.auth) {\n try {\n principal = await options.auth({\n authorization: request.headers.get(\"authorization\") ?? undefined,\n headers: new Headers(request.headers),\n surface: defaultSurface(\"http\"),\n client: reportedClientOf(parsed),\n })\n // actor · surface 형식 오류 = auth 예외와 같음 (500 + onerror)\n assertCallerFields(principal, \"auth\")\n } catch (error) {\n if (isMextError(error, \"UNAUTHENTICATED\")) {\n return unauthenticatedResponse(error, id, oauth ? resourceMetadataUrl(oauth, url) : undefined)\n }\n report(error)\n return jsonResponse(500, rpcError(-32_603, \"Internal server error\", undefined, id))\n }\n }\n\n const sdkRequest = new Request(url, {\n method: \"POST\",\n headers: statelessHeaders(request.headers),\n body,\n signal: request.signal,\n })\n const parsedBody = parsed === NOT_JSON ? undefined : parsed\n // 2025-11-25 이하 (envelope 없음) = SDK stateless 레거시 경로. 진행률 기반 SSE 전환은 2026-07-28 요청만\n const legacy = await isLegacyRequest(sdkRequest, parsedBody, { maxRequestBodySize: maxBodyBytes })\n const listen = legacy ? undefined : narrowListenRequest(parsedBody, subscriptions, principal)\n if (listen !== undefined) {\n const { response, done } = trackBody(await listenHandler.fetch(sdkRequest, { authInfo: principalAuthInfo(principal), parsedBody: listen }))\n listenBodies.add(done)\n void done.then(() => listenBodies.delete(done))\n return response\n }\n // tools: \"command\" 의 숨긴 명령어 호출 = SDK 가 등록되지 않은 도구로 거부해 mext 콜백이 없다 → 본문을 넘기기 전에 기록\n // (§11.1 includeHidden). 응답은 그대로 SDK 가 만들고, 전달은 기다리지 않는다\n if (options.audit?.includeHidden === true && options.tools === \"command\") {\n const hidden = hiddenToolCall(options.registry, principal, parsedBody)\n const work =\n hidden &&\n auditHidden(hidden, {\n audit: options.audit,\n principal,\n transport: \"http\",\n ...optional(\"client\", reportedClientOf(parsedBody)),\n ...optional(\"traceContext\", metaOf(parsedBody)),\n })\n if (work) context?.waitUntil?.(work)\n }\n // task 가 될 수 있는 tools/call = application/json (CreateTaskResult, §12.6)\n // 대상 판정 = 주체의 표면에서 보이는 명령어 (숨긴 task 명령어는 없는 명령어와 같은 응답 형식, §4 expose)\n const sse =\n !legacy && hasProgressToken(parsedBody) && !(tasks && requestsTask(exposedRegistry(options.registry, surfaceOf(principal, \"http\")), parsedBody))\n const handler: McpHttpHandler = sse ? sseHandler : jsonHandler\n return handler.fetch(sdkRequest, {\n authInfo: principalAuthInfo(principal, context?.waitUntil),\n ...(parsedBody !== undefined ? { parsedBody } : {}),\n })\n }\n\n return {\n async fetch(request, context) {\n try {\n return await handle(request, context)\n } catch (error) {\n report(error)\n return jsonResponse(500, rpcError(-32_603, \"Internal server error\"))\n }\n },\n closeSubscriptions,\n async close() {\n unbridge()\n await closeSubscriptions()\n await Promise.all([listenHandler.close(), jsonHandler.close(), sseHandler.close(), factory.close()])\n },\n }\n\n async function closeSubscriptions(): Promise<void> {\n // SDK handler.close = 열린 listen 스트림마다 완료 result 후 닫음. 이후 listen 은 새 handler 가 받는다\n const closing = listenHandler\n listenHandler = createListenHandler()\n await closing.close()\n const pending = [...listenBodies]\n if (pending.length === 0) return\n let timer: ReturnType<typeof setTimeout> | undefined\n await Promise.race([Promise.all(pending), new Promise<void>((resolve) => (timer = setTimeout(resolve, LISTEN_DRAIN_MS)))])\n clearTimeout(timer)\n }\n}\n\n/** 서버 종료 시 listen 스트림의 완료 result 를 클라이언트가 읽기까지 기다리는 상한 (ms) */\nconst LISTEN_DRAIN_MS = 1_000\n\n/** createMcpFetchHandler 의 node:http 어댑터. 응답 · SSE 를 스트리밍, 클라이언트 연결 종료 = request.signal abort */\nexport function createMcpHttpHandler(options: McpHttpOptions): McpHttpListener {\n const core = createMcpFetchHandler(options)\n const report = reporter(options.onerror)\n const inflight = new Set<AbortController>()\n\n const listener = ((req: IncomingMessage, res: ServerResponse) => {\n const controller = new AbortController()\n inflight.add(controller)\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort()\n inflight.delete(controller)\n })\n const hasBody = req.method !== \"GET\" && req.method !== \"HEAD\"\n const body = hasBody ? nodeBody(req) : undefined\n // 응답이 끝났는데 읽지 않은 본문 (413 · 403 · 401 · 404 · 본문을 읽지 않는 핸들러) = 버리며 읽어 keep-alive 연결을 살린다\n if (body) res.once(\"finish\", () => body.discard(res))\n const request = new Request(requestUrl(req), {\n method: req.method ?? \"GET\",\n headers: nodeHeaders(req),\n ...(body ? { body: body.stream, duplex: \"half\" as const } : {}),\n signal: controller.signal,\n })\n core\n .fetch(request)\n .then((response) => {\n // 남은 본문이 버림 상한보다 크다고 선언됨 = 읽지 않고 응답 후 연결 종료\n if (body && !req.complete && Number(req.headers[\"content-length\"] ?? 0) > DISCARD_BODY_BYTES) res.setHeader(\"Connection\", \"close\")\n return sendResponse(res, response)\n })\n .catch((error: unknown) => {\n report(error)\n if (!res.headersSent && !res.destroyed) sendJson(res, 500, rpcError(-32_603, \"Internal server error\"))\n else res.destroy()\n })\n }) as McpHttpListener\n listener.closeSubscriptions = () => core.closeSubscriptions()\n listener.close = async () => {\n await core.closeSubscriptions()\n // 완료 result 를 쓴 응답의 end (sendResponse) 가 연결 정리 전에 실행되도록\n await new Promise<void>((resolve) => setImmediate(resolve))\n for (const c of inflight) c.abort()\n inflight.clear()\n await core.close()\n }\n return listener\n}\n\n/** 응답에 영향 없는 오류 보고 (보고 자체의 예외는 삼킨다) */\nfunction reporter(onerror: ((error: Error) => void) | undefined): (error: unknown) => void {\n return (error) => {\n try {\n onerror?.(error instanceof Error ? error : new Error(String(error)))\n } catch {\n // 보고는 응답을 바꾸지 않는다\n }\n }\n}\n\n/**\n * routes/ 의 export origin · auth 판정 (§12.4). /mcp 와 같은 allowedOrigins · auth · WWW-Authenticate.\n * 본문 = { error: { code, message, ...details } } (specs/http.md §3.3 오류 본문 모양)\n */\nfunction routeGuard(options: McpHttpOptions, report: (error: unknown) => void): RouteGuard {\n const warned = new Set<string>()\n const challenge = (error: MextError<\"UNAUTHENTICATED\">, request: Request): Response => {\n const metadata = options.oauth ? resourceMetadataUrl(options.oauth, new URL(request.url)) : undefined\n return jsonResponse(401, { error: error.toJSON() }, { \"WWW-Authenticate\": bearerChallenge(error, metadata) })\n }\n return {\n origin(request) {\n const origin = request.headers.get(\"origin\") ?? undefined\n if (origin === undefined || origin === \"\" || originAllowed(origin, options.server?.allowedOrigins)) return undefined\n return jsonResponse(403, { error: { code: \"REQUEST_REJECTED\", message: `Forbidden: origin ${origin} is not allowed.`, reason: \"origin\" } })\n },\n async authenticate(request, mode, route) {\n if (!options.auth) {\n if (mode === \"optional\") return ANONYMOUS\n if (!warned.has(route.path)) {\n warned.add(route.path)\n report(new Error(`route ${route.path}: auth = true (export auth or routes.auth) but mext.config.ts has no auth. Every request is 401`))\n }\n return challenge(unauthenticated(\"missing_token\"), request)\n }\n let principal: Principal\n try {\n principal = await options.auth({\n authorization: request.headers.get(\"authorization\") ?? undefined,\n headers: new Headers(request.headers),\n surface: defaultSurface(\"http\"),\n client: undefined,\n route,\n })\n assertCallerFields(principal, \"auth\")\n } catch (error) {\n if (isMextError(error, \"UNAUTHENTICATED\")) return challenge(error, request)\n report(error)\n return new Response(\"Internal Server Error\\n\", { status: 500, headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } })\n }\n if (mode === true && principal.kind === \"anonymous\") return challenge(unauthenticated(\"missing_token\"), request)\n return principal\n },\n }\n}\n\nexport interface McpHttpServer {\n /** http://<host>:<port>/mcp */\n url: string\n host: string\n port: number\n close(): Promise<void>\n}\n\n/** createMcpHttpHandler + node:http listen. 기본 127.0.0.1:3100 */\nexport async function startMcpHttpServer(options: McpHttpOptions): Promise<McpHttpServer> {\n const listener = createMcpHttpHandler(options)\n const server = createServer(listener)\n const host = options.server?.host ?? DEFAULT_HOST\n const port = options.server?.port ?? DEFAULT_PORT\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(port, host, () => {\n server.off(\"error\", reject)\n resolve()\n })\n })\n const address = server.address() as AddressInfo\n return {\n url: `http://${formatHost(host)}:${address.port}${MCP_PATH}`,\n host,\n port: address.port,\n async close() {\n await listener.close()\n server.closeAllConnections()\n await new Promise<void>((resolve) => server.close(() => resolve()))\n },\n }\n}\n\n/* Origin */\n\n\n/**\n * Origin 허용 여부. allowed 미지정 = loopback 만, 지정 = 목록의 origin 과 정확히 일치 (\"*\" = 전체, \"loopback\" = loopback).\n * http · https 외 scheme (chrome-extension://<id>) = URL.origin 이 \"null\" 이라 목록과 문자열 비교\n */\nexport function originAllowed(origin: string, allowed: readonly string[] | undefined): boolean {\n if (allowed?.includes(\"*\")) return true\n let url: URL\n try {\n url = new URL(origin)\n } catch {\n return false\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return allowed?.includes(origin) ?? false\n if (LOOPBACK_HOSTNAMES.has(url.hostname) && (allowed === undefined || allowed.includes(LOOPBACK_ENTRY))) return true\n if (allowed === undefined) return false\n return allowed.some((entry) => normalizeOrigin(entry) === url.origin)\n}\n\nfunction normalizeOrigin(entry: string): string | undefined {\n try {\n return new URL(entry).origin\n } catch {\n return undefined\n }\n}\n\n/* node:http ↔ fetch */\n\n/** 무시하는 헤더 (stateless): 세션 · SSE 재개 */\nconst DROPPED_HEADERS = new Set([\"mcp-session-id\", \"last-event-id\"])\n\nfunction statelessHeaders(source: Headers): Headers {\n const headers = new Headers(source)\n for (const name of DROPPED_HEADERS) headers.delete(name)\n return headers\n}\n\n/** 응답 후 버리며 읽는 남은 요청 본문의 상한 (바이트). 넘으면 연결 종료 */\nconst DISCARD_BODY_BYTES = 64 * 1024 * 1024\n\n/**\n * IncomingMessage → 요청 본문 스트림 (backpressure = pause · resume).\n * Readable.toWeb 대신 직접: Node 22 의 toWeb 스트림은 cancel (413 · 403 조기 거부) 뒤 남은 본문이 도착하면\n * 닫힌 controller 에 enqueue 해 프로세스가 죽는다 (ERR_INVALID_STATE). cancel = 남은 본문 버림.\n * discard = 응답 후 남은 본문을 버리며 읽는다 (pause 된 채 두면 클라이언트의 본문 쓰기가 멈추고 같은 연결의 다음 요청이\n * 처리되지 않는다). DISCARD_BODY_BYTES 를 넘으면 연결 종료\n */\nfunction nodeBody(req: IncomingMessage): { stream: ReadableStream<Uint8Array>; discard(res: ServerResponse): void } {\n let done = false\n const discard = (res: ServerResponse): void => {\n done = true\n if (req.complete || req.destroyed) return\n let size = 0\n req.on(\"data\", (chunk: Buffer) => {\n size += chunk.byteLength\n if (size > DISCARD_BODY_BYTES) req.socket.destroy()\n })\n // Connection: close 응답 = Node 가 응답 후 연결을 닫는다. 남은 본문을 읽을 필요 없음\n if (res.getHeader(\"connection\") !== \"close\") req.resume()\n }\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n req.on(\"data\", (chunk: Buffer) => {\n if (done) return\n controller.enqueue(new Uint8Array(chunk))\n if ((controller.desiredSize ?? 0) <= 0) req.pause()\n })\n req.once(\"end\", () => {\n if (done) return\n done = true\n controller.close()\n })\n req.once(\"error\", (error) => {\n if (done) return\n done = true\n controller.error(error)\n })\n req.pause()\n },\n pull() {\n req.resume()\n },\n cancel() {\n done = true\n req.resume()\n },\n })\n return { stream, discard }\n}\n\nfunction nodeHeaders(req: IncomingMessage): Headers {\n const headers = new Headers()\n for (const [name, value] of Object.entries(req.headers)) {\n if (value === undefined || name.startsWith(\":\")) continue\n if (Array.isArray(value)) for (const v of value) headers.append(name, v)\n else headers.set(name, value)\n }\n return headers\n}\n\nfunction requestUrl(req: IncomingMessage): URL {\n try {\n return new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`)\n } catch {\n return new URL(req.url ?? \"/\", \"http://localhost\")\n }\n}\n\n/** 본문을 limit 바이트까지. 넘으면 스트림 취소 후 \"too-large\" */\nasync function readBody(body: ReadableStream<Uint8Array> | null, limit: number): Promise<Uint8Array<ArrayBuffer> | \"too-large\"> {\n if (body === null) return new Uint8Array(0)\n const chunks: Uint8Array[] = []\n let size = 0\n const reader = body.getReader()\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n size += value.byteLength\n if (size > limit) {\n await reader.cancel().catch(() => {})\n return \"too-large\"\n }\n chunks.push(value)\n }\n const out = new Uint8Array(size)\n let offset = 0\n for (const c of chunks) {\n out.set(c, offset)\n offset += c.byteLength\n }\n return out\n}\n\nasync function sendResponse(res: ServerResponse, response: Response): Promise<void> {\n if (res.destroyed) {\n await response.body?.cancel().catch(() => {})\n return\n }\n res.statusCode = response.status\n response.headers.forEach((value, name) => res.setHeader(name, value))\n if (response.body === null) {\n res.end()\n return\n }\n const reader = response.body.getReader()\n // 클라이언트가 SSE 스트림을 닫으면 = 취소. SDK 가 transport 를 닫고 핸들러 signal 을 abort, 이후 메시지는 버린다\n const onClose = () => {\n if (!res.writableFinished) void reader.cancel().catch(() => {})\n }\n res.on(\"close\", onClose)\n res.flushHeaders()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done || res.destroyed) break\n res.write(value)\n }\n } catch {\n // 스트림 취소 · 생산자 오류: 아래에서 응답을 닫는다\n } finally {\n res.off(\"close\", onClose)\n }\n if (!res.destroyed) res.end()\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown, headers: Record<string, string> = {}): void {\n const text = JSON.stringify(body)\n res.writeHead(status, { \"Content-Type\": \"application/json\", \"Content-Length\": Buffer.byteLength(text), ...headers })\n res.end(text)\n}\n\nfunction jsonResponse(status: number, body: unknown, headers: Record<string, string> = {}): Response {\n return new Response(JSON.stringify(body), { status, headers: { \"Content-Type\": \"application/json\", ...headers } })\n}\n\nfunction unauthenticatedResponse(\n error: MextError<\"UNAUTHENTICATED\">,\n id: string | number | null,\n resourceMetadata: string | undefined,\n): Response {\n return jsonResponse(401, rpcError(-32_001, error.message, error.toJSON(), id), { \"WWW-Authenticate\": bearerChallenge(error, resourceMetadata) })\n}\n\n/** 401 의 WWW-Authenticate (/mcp · routes 공통) */\nfunction bearerChallenge(error: MextError<\"UNAUTHENTICATED\">, resourceMetadata: string | undefined): string {\n const params: string[] = []\n if (error.details.reason === \"invalid_token\") params.push('error=\"invalid_token\"')\n if (resourceMetadata !== undefined) params.push(`resource_metadata=\"${resourceMetadata}\"`)\n return params.length > 0 ? `Bearer ${params.join(\", \")}` : \"Bearer\"\n}\n\n/* OAuth 보호 자원 메타데이터 (RFC 9728) */\n\n/** MCP 엔드포인트 경로를 삽입한 well-known 경로 (/.well-known/oauth-protected-resource/mcp) */\nfunction protectedResourceMetadataPath(): string {\n return `${PROTECTED_RESOURCE_METADATA_PATH}${MCP_PATH}`\n}\n\nfunction resourceOf(oauth: OAuthResourceOptions, url: URL): string {\n return oauth.resource ?? `${url.origin}${MCP_PATH}`\n}\n\nfunction resourceMetadataUrl(oauth: OAuthResourceOptions, url: URL): string {\n const resource = new URL(resourceOf(oauth, url))\n const path = resource.pathname.replace(/\\/$/, \"\")\n return `${resource.origin}${PROTECTED_RESOURCE_METADATA_PATH}${path}`\n}\n\nfunction protectedResourceMetadata(oauth: OAuthResourceOptions, url: URL): Record<string, unknown> {\n const doc: Record<string, unknown> = {\n resource: resourceOf(oauth, url),\n authorization_servers: [...oauth.authorizationServers],\n bearer_methods_supported: [\"header\"],\n }\n if (oauth.scopesSupported) doc.scopes_supported = [...oauth.scopesSupported]\n return doc\n}\n\nfunction rpcError(code: number, message: string, data?: unknown, id: string | number | null = null) {\n return { jsonrpc: \"2.0\", id, error: data === undefined ? { code, message } : { code, message, data } }\n}\n\nconst NOT_JSON = Symbol(\"not-json\")\n\nfunction parseJson(body: Uint8Array): unknown {\n if (body.length === 0) return NOT_JSON\n try {\n return JSON.parse(new TextDecoder().decode(body))\n } catch {\n return NOT_JSON\n }\n}\n\nfunction requestId(body: unknown): string | number | null {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return null\n const { id, method } = body as { id?: unknown; method?: unknown }\n if (typeof method !== \"string\") return null\n return typeof id === \"string\" || typeof id === \"number\" ? id : null\n}\n\n/** 요청 본문 params._meta 의 clientInfo (2026-07-28 envelope). 자가 신고 값. 없음 · 형식 오류 = undefined */\nfunction reportedClientOf(body: unknown): ReportedClient | undefined {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return undefined\n const meta = (body as { params?: { _meta?: unknown } }).params?._meta\n if (meta === null || typeof meta !== \"object\") return undefined\n return reportedClient((meta as Record<string, unknown>)[CLIENT_INFO_META_KEY])\n}\n\n/** tools/call 의 params._meta (traceparent 등) */\nfunction metaOf(body: unknown): Record<string, unknown> | undefined {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return undefined\n const meta = (body as { params?: { _meta?: unknown } }).params?._meta\n return meta !== null && typeof meta === \"object\" && !Array.isArray(meta) ? (meta as Record<string, unknown>) : undefined\n}\n\nfunction optional<K extends string, V>(key: K, value: V | undefined): { [P in K]?: V } {\n return (value === undefined ? {} : { [key]: value }) as { [P in K]?: V }\n}\n\n/**\n * tools: \"command\" 의 tools/call 이 가리키는 명령어가 주체의 표면에서 숨긴 명령어면 그 항목. 도구 이름 = 정식 ID 만 (별칭은 도구가 아니다).\n * 보이는 명령어 · 없는 이름 = undefined\n */\nfunction hiddenToolCall(registry: Registry, principal: Principal, body: unknown): RegisteredCommand | undefined {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return undefined\n const { method, params } = body as { method?: unknown; params?: { name?: unknown } | null }\n if (method !== \"tools/call\" || typeof params?.name !== \"string\") return undefined\n const entry = registry.commands.get(params.name)\n if (!entry) return undefined\n return exposedRegistry(registry, surfaceOf(principal, \"http\")).commands.has(entry.id) ? undefined : entry\n}\n\nfunction hasProgressToken(body: unknown): boolean {\n if (body === null || typeof body !== \"object\" || Array.isArray(body)) return false\n const meta = (body as { params?: { _meta?: { progressToken?: unknown } } }).params?._meta\n return meta !== null && typeof meta === \"object\" && meta.progressToken !== undefined\n}\n\nfunction formatHost(host: string): string {\n return host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host\n}\n"]}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { createMcpServerFactory, principalAuthInfo, principalFromAuthInfo, PROGR
|
|
|
7
7
|
export type { McpCoreOptions, MextServerFactory } from "./server.ts";
|
|
8
8
|
export { createMcpFetchHandler, createMcpHttpHandler, MAX_BODY_BYTES, originAllowed, PROTECTED_RESOURCE_METADATA_PATH, startMcpHttpServer, } from "./http.ts";
|
|
9
9
|
export type { McpAuthRequest, McpFetchContext, McpFetchHandler, McpHttpListener, McpHttpOptions, McpHttpServer, OAuthResourceOptions } from "./http.ts";
|
|
10
|
+
export { hostAllowed } from "./host.ts";
|
|
10
11
|
export { DECLARED_ERROR_RPC_CODE, installResourceHandlers, PERMISSION_DENIED_RPC_CODE, RESOURCE_READ_CACHE } from "./resources.ts";
|
|
11
12
|
export type { ResourceHandlerOptions } from "./resources.ts";
|
|
12
13
|
export { narrowListenRequest, RESOURCE_UPDATED_CHANNEL, resourceUpdates, subscribable, subscriptionPermitted, } from "./subscriptions.ts";
|
package/dist/mcp/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { callDispatcher, dispatcherInputSchema, dispatcherTools, errorResult, EX
|
|
|
3
3
|
export { formatHelp, help, HELP_COMMAND } from "./help.js";
|
|
4
4
|
export { createMcpServerFactory, principalAuthInfo, principalFromAuthInfo, PROGRESS_INTERVAL_MS, registryManifestHash, TOOLS_LIST_CACHE, } from "./server.js";
|
|
5
5
|
export { createMcpFetchHandler, createMcpHttpHandler, MAX_BODY_BYTES, originAllowed, PROTECTED_RESOURCE_METADATA_PATH, startMcpHttpServer, } from "./http.js";
|
|
6
|
+
export { hostAllowed } from "./host.js";
|
|
6
7
|
export { DECLARED_ERROR_RPC_CODE, installResourceHandlers, PERMISSION_DENIED_RPC_CODE, RESOURCE_READ_CACHE } from "./resources.js";
|
|
7
8
|
export { narrowListenRequest, RESOURCE_UPDATED_CHANNEL, resourceUpdates, subscribable, subscriptionPermitted, } from "./subscriptions.js";
|
|
8
9
|
export { COMPLETION_MAX_VALUES, installCompletionHandler, installPromptHandlers } from "./prompts.js";
|