@obov/mext 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/approval.d.ts +33 -0
- package/dist/approval.js +36 -0
- package/dist/approval.js.map +1 -0
- package/dist/audit.d.ts +123 -0
- package/dist/audit.js +221 -0
- package/dist/audit.js.map +1 -0
- package/dist/build-cli.d.ts +1 -0
- package/dist/build-cli.js.map +1 -1
- package/dist/build.d.ts +2 -0
- package/dist/build.js +30 -3
- package/dist/build.js.map +1 -1
- package/dist/caller.d.ts +53 -0
- package/dist/caller.js +51 -0
- package/dist/caller.js.map +1 -0
- package/dist/cli/build.js +4 -2
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev-audit.d.ts +25 -0
- package/dist/cli/dev-audit.js +84 -0
- package/dist/cli/dev-audit.js.map +1 -0
- package/dist/cli/dev-lock.d.ts +3 -1
- package/dist/cli/dev-lock.js +12 -5
- package/dist/cli/dev-lock.js.map +1 -1
- package/dist/cli/dev-server.d.ts +9 -0
- package/dist/cli/dev-server.js +24 -1
- package/dist/cli/dev-server.js.map +1 -1
- package/dist/cli/dev-tap.d.ts +20 -0
- package/dist/cli/dev-tap.js +70 -0
- package/dist/cli/dev-tap.js.map +1 -0
- package/dist/cli/dev.js +16 -4
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/help.js +2 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/inspect.d.ts +7 -0
- package/dist/cli/inspect.js +699 -0
- package/dist/cli/inspect.js.map +1 -0
- package/dist/cli/main.js +8 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js +3 -2
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/run.js +28 -4
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/types.d.ts +9 -0
- package/dist/cli/types.js +77 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/client/index.d.ts +10 -0
- package/dist/client/index.js +7 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/manifest.js +6 -2
- package/dist/client/manifest.js.map +1 -1
- package/dist/client/runner.js +37 -3
- package/dist/client/runner.js.map +1 -1
- package/dist/client/typed.d.ts +54 -0
- package/dist/client/typed.js +490 -0
- package/dist/client/typed.js.map +1 -0
- package/dist/client/types.d.ts +196 -0
- package/dist/client/types.js +2 -0
- package/dist/client/types.js.map +1 -0
- package/dist/command.d.ts +61 -5
- package/dist/command.js +42 -1
- package/dist/command.js.map +1 -1
- package/dist/config.d.ts +42 -10
- package/dist/config.js +32 -7
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +21 -3
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -1
- package/dist/expose.d.ts +9 -0
- package/dist/expose.js +52 -0
- package/dist/expose.js.map +1 -0
- package/dist/index.d.ts +15 -6
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/inspect/agent.d.ts +104 -0
- package/dist/inspect/agent.js +125 -0
- package/dist/inspect/agent.js.map +1 -0
- package/dist/inspect/audit.d.ts +46 -0
- package/dist/inspect/audit.js +133 -0
- package/dist/inspect/audit.js.map +1 -0
- package/dist/inspect/compare.d.ts +12 -0
- package/dist/inspect/compare.js +31 -0
- package/dist/inspect/compare.js.map +1 -0
- package/dist/inspect/index.d.ts +17 -0
- package/dist/inspect/index.js +12 -0
- package/dist/inspect/index.js.map +1 -0
- package/dist/inspect/inspector.d.ts +168 -0
- package/dist/inspect/inspector.js +392 -0
- package/dist/inspect/inspector.js.map +1 -0
- package/dist/inspect/profiles.d.ts +95 -0
- package/dist/inspect/profiles.js +235 -0
- package/dist/inspect/profiles.js.map +1 -0
- package/dist/inspect/scenario.d.ts +126 -0
- package/dist/inspect/scenario.js +555 -0
- package/dist/inspect/scenario.js.map +1 -0
- package/dist/inspect/ui-server.d.ts +31 -0
- package/dist/inspect/ui-server.js +378 -0
- package/dist/inspect/ui-server.js.map +1 -0
- package/dist/inspect/ui.html +917 -0
- package/dist/instrumentation.d.ts +13 -2
- package/dist/instrumentation.js +11 -1
- package/dist/instrumentation.js.map +1 -1
- package/dist/invoke.d.ts +32 -5
- package/dist/invoke.js +150 -16
- package/dist/invoke.js.map +1 -1
- package/dist/manifest.d.ts +13 -2
- package/dist/manifest.js +5 -1
- package/dist/manifest.js.map +1 -1
- package/dist/mcp/constants.d.ts +5 -0
- package/dist/mcp/constants.js +5 -0
- package/dist/mcp/constants.js.map +1 -1
- package/dist/mcp/dispatch.d.ts +1 -1
- package/dist/mcp/dispatch.js +14 -3
- package/dist/mcp/dispatch.js.map +1 -1
- package/dist/mcp/help.d.ts +2 -0
- package/dist/mcp/help.js +6 -1
- package/dist/mcp/help.js.map +1 -1
- package/dist/mcp/http.d.ts +16 -2
- package/dist/mcp/http.js +76 -7
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts +12 -1
- package/dist/mcp/server.js +63 -17
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.d.ts +4 -0
- package/dist/mcp/stdio.js +3 -0
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/mcp/tasks.d.ts +3 -1
- package/dist/mcp/tasks.js +6 -3
- package/dist/mcp/tasks.js.map +1 -1
- package/dist/principal.d.ts +22 -0
- package/dist/principal.js +29 -0
- package/dist/principal.js.map +1 -1
- package/dist/registry.d.ts +5 -0
- package/dist/registry.js +21 -0
- package/dist/registry.js.map +1 -1
- package/dist/remote/client.d.ts +2 -0
- package/dist/remote/client.js +3 -2
- package/dist/remote/client.js.map +1 -1
- package/dist/remote/oauth.d.ts +1 -1
- package/dist/remote/oauth.js +1 -1
- package/dist/remote/oauth.js.map +1 -1
- package/dist/start.js +6 -2
- package/dist/start.js.map +1 -1
- package/dist/suggest.js +1 -1
- package/dist/suggest.js.map +1 -1
- package/dist/typegen.d.ts +27 -0
- package/dist/typegen.js +62 -0
- package/dist/typegen.js.map +1 -0
- package/dist/version-constant.d.ts +5 -0
- package/dist/version-constant.js +6 -0
- package/dist/version-constant.js.map +1 -0
- package/dist/version.d.ts +1 -2
- package/dist/version.js +1 -2
- package/dist/version.js.map +1 -1
- package/package.json +12 -2
package/dist/mcp/http.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
2
|
import { Readable } from "node:stream";
|
|
3
|
-
import { createMcpHandler, InMemoryServerEventBus, isLegacyRequest } from "@modelcontextprotocol/server";
|
|
3
|
+
import { CLIENT_INFO_META_KEY, createMcpHandler, InMemoryServerEventBus, isLegacyRequest } from "@modelcontextprotocol/server";
|
|
4
|
+
import { auditHidden } from "../audit.js";
|
|
4
5
|
import { isMextError } from "../errors.js";
|
|
5
|
-
import {
|
|
6
|
+
import { defaultSurface, reportedClient, surfaceOf } from "../caller.js";
|
|
7
|
+
import { exposedRegistry } from "../expose.js";
|
|
8
|
+
import { ANONYMOUS, assertCallerFields } from "../principal.js";
|
|
6
9
|
import { createRouteDispatcher, onceApp } from "../route.js";
|
|
7
10
|
import { DEFAULT_HOST, DEFAULT_PORT, MCP_PATH } from "./constants.js";
|
|
8
11
|
import { createMcpServerFactory, principalAuthInfo } from "./server.js";
|
|
@@ -39,6 +42,8 @@ export function createMcpFetchHandler(options) {
|
|
|
39
42
|
...(options.state ? { state: options.state } : {}),
|
|
40
43
|
...(options.taskTiming ? { taskTiming: options.taskTiming } : {}),
|
|
41
44
|
...(options.taskExecution ? { taskExecution: options.taskExecution } : {}),
|
|
45
|
+
...(options.audit ? { audit: options.audit } : {}),
|
|
46
|
+
...(options.approval ? { approval: options.approval } : {}),
|
|
42
47
|
transport: "http",
|
|
43
48
|
});
|
|
44
49
|
const tasks = options.state?.store !== undefined && hasTaskCommands(options.registry);
|
|
@@ -85,7 +90,14 @@ export function createMcpFetchHandler(options) {
|
|
|
85
90
|
let principal = ANONYMOUS;
|
|
86
91
|
if (options.auth) {
|
|
87
92
|
try {
|
|
88
|
-
principal = await options.auth({
|
|
93
|
+
principal = await options.auth({
|
|
94
|
+
authorization: request.headers.get("authorization") ?? undefined,
|
|
95
|
+
headers: new Headers(request.headers),
|
|
96
|
+
surface: defaultSurface("http"),
|
|
97
|
+
client: reportedClientOf(parsed),
|
|
98
|
+
});
|
|
99
|
+
// actor · surface 형식 오류 = auth 예외와 같음 (500 + onerror)
|
|
100
|
+
assertCallerFields(principal, "auth");
|
|
89
101
|
}
|
|
90
102
|
catch (error) {
|
|
91
103
|
if (isMextError(error, "UNAUTHENTICATED")) {
|
|
@@ -111,8 +123,24 @@ export function createMcpFetchHandler(options) {
|
|
|
111
123
|
void done.then(() => listenBodies.delete(done));
|
|
112
124
|
return response;
|
|
113
125
|
}
|
|
126
|
+
// tools: "command" 의 숨긴 명령어 호출 = SDK 가 등록되지 않은 도구로 거부해 mext 콜백이 없다 → 본문을 넘기기 전에 기록
|
|
127
|
+
// (§11.1 includeHidden). 응답은 그대로 SDK 가 만들고, 전달은 기다리지 않는다
|
|
128
|
+
if (options.audit?.includeHidden === true && options.tools === "command") {
|
|
129
|
+
const hidden = hiddenToolCall(options.registry, principal, parsedBody);
|
|
130
|
+
const work = hidden &&
|
|
131
|
+
auditHidden(hidden, {
|
|
132
|
+
audit: options.audit,
|
|
133
|
+
principal,
|
|
134
|
+
transport: "http",
|
|
135
|
+
...optional("client", reportedClientOf(parsedBody)),
|
|
136
|
+
...optional("traceContext", metaOf(parsedBody)),
|
|
137
|
+
});
|
|
138
|
+
if (work)
|
|
139
|
+
context?.waitUntil?.(work);
|
|
140
|
+
}
|
|
114
141
|
// task 가 될 수 있는 tools/call = application/json (CreateTaskResult, §12.6)
|
|
115
|
-
|
|
142
|
+
// 대상 판정 = 주체의 표면에서 보이는 명령어 (숨긴 task 명령어는 없는 명령어와 같은 응답 형식, §4 expose)
|
|
143
|
+
const sse = !legacy && hasProgressToken(parsedBody) && !(tasks && requestsTask(exposedRegistry(options.registry, surfaceOf(principal, "http")), parsedBody));
|
|
116
144
|
const handler = sse ? sseHandler : jsonHandler;
|
|
117
145
|
return handler.fetch(sdkRequest, {
|
|
118
146
|
authInfo: principalAuthInfo(principal, context?.waitUntil),
|
|
@@ -232,7 +260,12 @@ export async function startMcpHttpServer(options) {
|
|
|
232
260
|
}
|
|
233
261
|
/* Origin */
|
|
234
262
|
const LOOPBACK_HOSTNAMES = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
235
|
-
/**
|
|
263
|
+
/** allowedOrigins 의 loopback 항목 (미지정일 때의 기본 허용을 목록에 포함) */
|
|
264
|
+
const LOOPBACK_ENTRY = "loopback";
|
|
265
|
+
/**
|
|
266
|
+
* Origin 허용 여부. allowed 미지정 = loopback 만, 지정 = 목록의 origin 과 정확히 일치 ("*" = 전체, "loopback" = loopback).
|
|
267
|
+
* http · https 외 scheme (chrome-extension://<id>) = URL.origin 이 "null" 이라 목록과 문자열 비교
|
|
268
|
+
*/
|
|
236
269
|
export function originAllowed(origin, allowed) {
|
|
237
270
|
if (allowed?.includes("*"))
|
|
238
271
|
return true;
|
|
@@ -244,9 +277,11 @@ export function originAllowed(origin, allowed) {
|
|
|
244
277
|
return false;
|
|
245
278
|
}
|
|
246
279
|
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
247
|
-
return false;
|
|
280
|
+
return allowed?.includes(origin) ?? false;
|
|
281
|
+
if (LOOPBACK_HOSTNAMES.has(url.hostname) && (allowed === undefined || allowed.includes(LOOPBACK_ENTRY)))
|
|
282
|
+
return true;
|
|
248
283
|
if (allowed === undefined)
|
|
249
|
-
return
|
|
284
|
+
return false;
|
|
250
285
|
return allowed.some((entry) => normalizeOrigin(entry) === url.origin);
|
|
251
286
|
}
|
|
252
287
|
function normalizeOrigin(entry) {
|
|
@@ -411,6 +446,40 @@ function requestId(body) {
|
|
|
411
446
|
return null;
|
|
412
447
|
return typeof id === "string" || typeof id === "number" ? id : null;
|
|
413
448
|
}
|
|
449
|
+
/** 요청 본문 params._meta 의 clientInfo (2026-07-28 envelope). 자가 신고 값. 없음 · 형식 오류 = undefined */
|
|
450
|
+
function reportedClientOf(body) {
|
|
451
|
+
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
452
|
+
return undefined;
|
|
453
|
+
const meta = body.params?._meta;
|
|
454
|
+
if (meta === null || typeof meta !== "object")
|
|
455
|
+
return undefined;
|
|
456
|
+
return reportedClient(meta[CLIENT_INFO_META_KEY]);
|
|
457
|
+
}
|
|
458
|
+
/** tools/call 의 params._meta (traceparent 등) */
|
|
459
|
+
function metaOf(body) {
|
|
460
|
+
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
461
|
+
return undefined;
|
|
462
|
+
const meta = body.params?._meta;
|
|
463
|
+
return meta !== null && typeof meta === "object" && !Array.isArray(meta) ? meta : undefined;
|
|
464
|
+
}
|
|
465
|
+
function optional(key, value) {
|
|
466
|
+
return (value === undefined ? {} : { [key]: value });
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* tools: "command" 의 tools/call 이 가리키는 명령어가 주체의 표면에서 숨긴 명령어면 그 항목. 도구 이름 = 정식 ID 만 (별칭은 도구가 아니다).
|
|
470
|
+
* 보이는 명령어 · 없는 이름 = undefined
|
|
471
|
+
*/
|
|
472
|
+
function hiddenToolCall(registry, principal, body) {
|
|
473
|
+
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
474
|
+
return undefined;
|
|
475
|
+
const { method, params } = body;
|
|
476
|
+
if (method !== "tools/call" || typeof params?.name !== "string")
|
|
477
|
+
return undefined;
|
|
478
|
+
const entry = registry.commands.get(params.name);
|
|
479
|
+
if (!entry)
|
|
480
|
+
return undefined;
|
|
481
|
+
return exposedRegistry(registry, surfaceOf(principal, "http")).commands.has(entry.id) ? undefined : entry;
|
|
482
|
+
}
|
|
414
483
|
function hasProgressToken(body) {
|
|
415
484
|
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
416
485
|
return false;
|
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 { createMcpHandler, InMemoryServerEventBus, isLegacyRequest, type McpHttpHandler } from \"@modelcontextprotocol/server\"\nimport type { MextApp } from \"../command.ts\"\nimport { isMextError, type MextError } from \"../errors.ts\"\nimport { ANONYMOUS, type Principal } from \"../principal.ts\"\nimport type { 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\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 형식, \"*\" = 전체).\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}\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 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({ authorization: request.headers.get(\"authorization\") ?? undefined })\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 // task 가 될 수 있는 tools/call = application/json (CreateTaskResult, §12.6)\n const sse = !legacy && hasProgressToken(parsedBody) && !(tasks && requestsTask(options.registry, 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/** Origin 허용 여부. allowed 미지정 = loopback 만, 지정 = 목록의 origin 과 정확히 일치 (\"*\" = 전체) */\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 false\n if (allowed === undefined) return LOOPBACK_HOSTNAMES.has(url.hostname)\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\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 { 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"]}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { COMMAND_META_KEY, DEFAULT_HOST, DEFAULT_PORT, MANIFEST_HASH_META_KEY, MCP_PATH, TOOLS_META_KEY } from "./constants.ts";
|
|
1
|
+
export { APPROVAL_META_KEY, COMMAND_META_KEY, DEFAULT_HOST, DEFAULT_PORT, MANIFEST_HASH_META_KEY, MCP_PATH, TOOLS_META_KEY } from "./constants.ts";
|
|
2
2
|
export { callDispatcher, dispatcherInputSchema, dispatcherTools, errorResult, EXECUTION_ERROR, findDispatcherTool, valueResult, } from "./dispatch.ts";
|
|
3
3
|
export type { DispatcherAnnotations, DispatcherTool, DispatcherToolName, DispatchOptions, DispatchResult, TextContent, ToolCallResult, ToolExposure, } from "./dispatch.ts";
|
|
4
4
|
export { formatHelp, help, HELP_COMMAND } from "./help.ts";
|
package/dist/mcp/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { COMMAND_META_KEY, DEFAULT_HOST, DEFAULT_PORT, MANIFEST_HASH_META_KEY, MCP_PATH, TOOLS_META_KEY } from "./constants.js";
|
|
1
|
+
export { APPROVAL_META_KEY, COMMAND_META_KEY, DEFAULT_HOST, DEFAULT_PORT, MANIFEST_HASH_META_KEY, MCP_PATH, TOOLS_META_KEY } from "./constants.js";
|
|
2
2
|
export { callDispatcher, dispatcherInputSchema, dispatcherTools, errorResult, EXECUTION_ERROR, findDispatcherTool, valueResult, } from "./dispatch.js";
|
|
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";
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAClJ,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,WAAW,GACZ,MAAM,eAAe,CAAA;AAWtB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAU1D,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,aAAa,CAAA;AAEpB,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,aAAa,EACb,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAElI,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,YAAY,EACZ,qBAAqB,GACtB,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAErG,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1D,OAAO,EACL,cAAc,EACd,SAAS,EACT,wBAAwB,EACxB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,WAAW,CAAA;AAYlB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,YAAY,EACZ,SAAS,EACT,WAAW,EACX,eAAe,GAChB,MAAM,YAAY,CAAA","sourcesContent":["export { APPROVAL_META_KEY, COMMAND_META_KEY, DEFAULT_HOST, DEFAULT_PORT, MANIFEST_HASH_META_KEY, MCP_PATH, TOOLS_META_KEY } from \"./constants.ts\"\nexport {\n callDispatcher,\n dispatcherInputSchema,\n dispatcherTools,\n errorResult,\n EXECUTION_ERROR,\n findDispatcherTool,\n valueResult,\n} from \"./dispatch.ts\"\nexport type {\n DispatcherAnnotations,\n DispatcherTool,\n DispatcherToolName,\n DispatchOptions,\n DispatchResult,\n TextContent,\n ToolCallResult,\n ToolExposure,\n} from \"./dispatch.ts\"\nexport { formatHelp, help, HELP_COMMAND } from \"./help.ts\"\nexport type {\n CommandHelp,\n Help,\n HelpCommandSummary,\n HelpNamespaceSummary,\n HelpOptions,\n NamespaceHelp,\n RootHelp,\n} from \"./help.ts\"\nexport {\n createMcpServerFactory,\n principalAuthInfo,\n principalFromAuthInfo,\n PROGRESS_INTERVAL_MS,\n registryManifestHash,\n TOOLS_LIST_CACHE,\n} from \"./server.ts\"\nexport type { McpCoreOptions, MextServerFactory } from \"./server.ts\"\nexport {\n createMcpFetchHandler,\n createMcpHttpHandler,\n MAX_BODY_BYTES,\n originAllowed,\n PROTECTED_RESOURCE_METADATA_PATH,\n startMcpHttpServer,\n} from \"./http.ts\"\nexport type { McpAuthRequest, McpFetchContext, McpFetchHandler, McpHttpListener, McpHttpOptions, McpHttpServer, OAuthResourceOptions } from \"./http.ts\"\nexport { DECLARED_ERROR_RPC_CODE, installResourceHandlers, PERMISSION_DENIED_RPC_CODE, RESOURCE_READ_CACHE } from \"./resources.ts\"\nexport type { ResourceHandlerOptions } from \"./resources.ts\"\nexport {\n narrowListenRequest,\n RESOURCE_UPDATED_CHANNEL,\n resourceUpdates,\n subscribable,\n subscriptionPermitted,\n} from \"./subscriptions.ts\"\nexport type { ResourceUpdates, SubscriptionOptions } from \"./subscriptions.ts\"\nexport { COMPLETION_MAX_VALUES, installCompletionHandler, installPromptHandlers } from \"./prompts.ts\"\nexport type { CompletionHandlerOptions, PromptHandlerOptions } from \"./prompts.ts\"\nexport { mcpInstallText } from \"./install.ts\"\nexport type { McpInstallOptions } from \"./install.ts\"\nexport { redirectStdout, serveMcpStdio } from \"./stdio.ts\"\nexport type { McpStdioOptions, McpStdioServer, StdoutRedirect } from \"./stdio.ts\"\nexport {\n ASK_KEY_PREFIX,\n askAnswer,\n CONFIRM_REQUESTED_SCHEMA,\n createAskSession,\n createRequestStateSigner,\n InputRequiredSignal,\n REQUEST_STATE_TTL_MS,\n} from \"./mrtr.ts\"\nexport type {\n AskSession,\n ElicitationModes,\n ElicitationRequest,\n ElicitResultValue,\n InputRequiredResult,\n InputRound,\n RequestStateBinding,\n RequestStateSigner,\n RequestStateSignerOptions,\n} from \"./mrtr.ts\"\nexport {\n createTaskRuntime,\n declaresTasks,\n hasTaskCommands,\n installTaskHandlers,\n requestsTask,\n TASK_LOST,\n TASK_TIMING,\n TASKS_EXTENSION,\n} from \"./tasks.ts\"\nexport type {\n CreateTaskResult,\n TaskRequest,\n TaskRequestOptions,\n TaskRuntime,\n TaskRuntimeOptions,\n TaskStatus,\n TaskTiming,\n TaskView,\n} from \"./tasks.ts\"\n"]}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type AuthInfo, type McpRequestContext, type McpServerFactory } from "@modelcontextprotocol/server";
|
|
2
|
+
import { type ApprovalConfig } from "../approval.ts";
|
|
3
|
+
import type { AuditConfig } from "../audit.ts";
|
|
2
4
|
import type { MextApp } from "../command.ts";
|
|
3
5
|
import type { McpCapabilities } from "../config.ts";
|
|
4
6
|
import type { Instrumentation, Transport } from "../instrumentation.ts";
|
|
@@ -7,11 +9,16 @@ import type { Registry } from "../registry.ts";
|
|
|
7
9
|
import { type ToolExposure } from "./dispatch.ts";
|
|
8
10
|
import type { MextState } from "../state.ts";
|
|
9
11
|
import { type TaskTiming } from "./tasks.ts";
|
|
10
|
-
/** tools/list · server/discover 캐시 힌트. 도구 정의는 principal 과 무관하게 고정 → public */
|
|
12
|
+
/** tools/list · server/discover 캐시 힌트. 도구 정의는 principal 과 무관하게 고정 → public (expose 가 없을 때) */
|
|
11
13
|
export declare const TOOLS_LIST_CACHE: {
|
|
12
14
|
readonly ttlMs: 300000;
|
|
13
15
|
readonly cacheScope: "public";
|
|
14
16
|
};
|
|
17
|
+
/** expose 를 쓰는 Registry 의 tools/list · server/discover 캐시 힌트. 목록 · manifestHash 가 호출자의 표면별 → private (§4) */
|
|
18
|
+
export declare const EXPOSED_TOOLS_LIST_CACHE: {
|
|
19
|
+
readonly ttlMs: 300000;
|
|
20
|
+
readonly cacheScope: "private";
|
|
21
|
+
};
|
|
15
22
|
/** resources/list · templates/list 캐시 힌트. ttlMs = tools/list, 결과가 scopes 로 주체별 필터 → private */
|
|
16
23
|
export declare const RESOURCE_LIST_CACHE: {
|
|
17
24
|
readonly ttlMs: 300000;
|
|
@@ -52,6 +59,10 @@ export interface McpCoreOptions {
|
|
|
52
59
|
instrumentation?: Instrumentation;
|
|
53
60
|
/** onCommandError · span 의 transport. HTTP · stdio 어댑터가 지정 */
|
|
54
61
|
transport?: Transport;
|
|
62
|
+
/** 감사 (config.audit, §11.1) */
|
|
63
|
+
audit?: AuditConfig;
|
|
64
|
+
/** 승인의 표면별 확인 방식 (config.approval, §4 승인) */
|
|
65
|
+
approval?: ApprovalConfig;
|
|
55
66
|
/**
|
|
56
67
|
* _meta["dev.mext/manifestHash"] 값. 기본 = registry 명령어로 계산 (mext dev = 스캔 결과).
|
|
57
68
|
* mext start = manifest.json 의 manifestHash (같은 함수로 계산한 값)
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { CLIENT_CAPABILITIES_META_KEY, McpServer, ProtocolError, ProtocolErrorCode, } from "@modelcontextprotocol/server";
|
|
2
|
+
import { CLIENT_CAPABILITIES_META_KEY, CLIENT_INFO_META_KEY, McpServer, ProtocolError, ProtocolErrorCode, } from "@modelcontextprotocol/server";
|
|
3
|
+
import { isApprovalMark } from "../approval.js";
|
|
4
|
+
import { reportedClient, surfaceOf } from "../caller.js";
|
|
5
|
+
import { exposedRegistry, hasExposure } from "../expose.js";
|
|
3
6
|
import { ANONYMOUS } from "../principal.js";
|
|
4
7
|
import { VERSION } from "../index.js";
|
|
5
8
|
import { describeCommand, manifestHash } from "../manifest.js";
|
|
6
9
|
import { resourceEntries } from "../resource.js";
|
|
7
|
-
import { MANIFEST_HASH_META_KEY, TOOLS_META_KEY } from "./constants.js";
|
|
10
|
+
import { APPROVAL_META_KEY, MANIFEST_HASH_META_KEY, TOOLS_META_KEY } from "./constants.js";
|
|
8
11
|
import { callDispatcher, dispatcherTools } from "./dispatch.js";
|
|
9
12
|
import { createRequestStateSigner } from "./mrtr.js";
|
|
10
13
|
import { installCompletionHandler, installPromptHandlers } from "./prompts.js";
|
|
11
14
|
import { installResourceHandlers, RESOURCE_READ_CACHE } from "./resources.js";
|
|
12
15
|
import { installSubscriptions, resourceUpdatedFn } from "./subscriptions.js";
|
|
13
16
|
import { createTaskRuntime, declaresTasks, hasTaskCommands, installTaskHandlers } from "./tasks.js";
|
|
14
|
-
/** tools/list · server/discover 캐시 힌트. 도구 정의는 principal 과 무관하게 고정 → public */
|
|
17
|
+
/** tools/list · server/discover 캐시 힌트. 도구 정의는 principal 과 무관하게 고정 → public (expose 가 없을 때) */
|
|
15
18
|
export const TOOLS_LIST_CACHE = { ttlMs: 300_000, cacheScope: "public" };
|
|
19
|
+
/** expose 를 쓰는 Registry 의 tools/list · server/discover 캐시 힌트. 목록 · manifestHash 가 호출자의 표면별 → private (§4) */
|
|
20
|
+
export const EXPOSED_TOOLS_LIST_CACHE = { ttlMs: TOOLS_LIST_CACHE.ttlMs, cacheScope: "private" };
|
|
16
21
|
/** resources/list · templates/list 캐시 힌트. ttlMs = tools/list, 결과가 scopes 로 주체별 필터 → private */
|
|
17
22
|
export const RESOURCE_LIST_CACHE = { ttlMs: TOOLS_LIST_CACHE.ttlMs, cacheScope: "private" };
|
|
18
23
|
/**
|
|
@@ -25,12 +30,28 @@ export const PROGRESS_INTERVAL_MS = 15_000;
|
|
|
25
30
|
* HTTP 의 createMcpHandler 와 stdio 의 serveStdio 가 같은 factory 를 쓴다.
|
|
26
31
|
*/
|
|
27
32
|
export function createMcpServerFactory(options) {
|
|
28
|
-
const
|
|
33
|
+
const exposure = options.tools ?? "execute";
|
|
34
|
+
const transport = options.transport ?? "local";
|
|
35
|
+
/**
|
|
36
|
+
* expose (§4): 요청 주체의 표면에서 보이는 Registry 와 그 도구 · manifestHash (보기별 1회 계산).
|
|
37
|
+
* 숨긴 명령어가 없으면 보기 = options.registry (expose 없는 프로젝트 = 항상 같은 목록 · 같은 해시)
|
|
38
|
+
*/
|
|
39
|
+
const perView = new WeakMap();
|
|
40
|
+
const viewOf = (principal) => {
|
|
41
|
+
const registry = exposedRegistry(options.registry, surfaceOf(principal, transport));
|
|
42
|
+
let cached = perView.get(registry);
|
|
43
|
+
if (!cached) {
|
|
44
|
+
const hash = registry === options.registry && options.manifestHash !== undefined ? options.manifestHash : registryManifestHash(registry);
|
|
45
|
+
cached = { tools: dispatcherTools(registry, exposure), meta: { [MANIFEST_HASH_META_KEY]: hash }, tasks: hasTaskCommands(registry) };
|
|
46
|
+
perView.set(registry, cached);
|
|
47
|
+
}
|
|
48
|
+
return { registry, ...cached };
|
|
49
|
+
};
|
|
50
|
+
// 목록이 호출자별이면 공유 캐시 금지
|
|
51
|
+
const toolsListCache = hasExposure(options.registry) ? EXPOSED_TOOLS_LIST_CACHE : TOOLS_LIST_CACHE;
|
|
29
52
|
const getApp = memoizeApp(options.app);
|
|
30
53
|
const serverInfo = { name: options.name ?? "mext", version: options.version ?? VERSION };
|
|
31
54
|
const signer = createRequestStateSigner(options.requestStateKey === undefined ? {} : { key: options.requestStateKey });
|
|
32
|
-
const meta = { [MANIFEST_HASH_META_KEY]: options.manifestHash ?? registryManifestHash(options.registry) };
|
|
33
|
-
const discoverMeta = { ...meta, [TOOLS_META_KEY]: options.tools ?? "execute" };
|
|
34
55
|
const experimental = options.capabilities?.experimental;
|
|
35
56
|
const resourceUpdated = resourceUpdatedFn(options.state);
|
|
36
57
|
const capabilities = {
|
|
@@ -38,19 +59,26 @@ export function createMcpServerFactory(options) {
|
|
|
38
59
|
tools: { listChanged: false },
|
|
39
60
|
};
|
|
40
61
|
const tasks = options.state?.store && hasTaskCommands(options.registry)
|
|
41
|
-
? createTaskRuntime({ state: options.state,
|
|
62
|
+
? createTaskRuntime({ state: options.state, ...(options.taskTiming ? { timing: options.taskTiming } : {}) })
|
|
42
63
|
: undefined;
|
|
43
64
|
const factory = (requestContext) => {
|
|
44
65
|
const principal = resolvePrincipal(options.principal, requestContext);
|
|
66
|
+
const view = viewOf(principal);
|
|
67
|
+
const { tools, meta } = view;
|
|
68
|
+
const discoverMeta = { ...meta, [TOOLS_META_KEY]: exposure };
|
|
69
|
+
// 이 주체에게 보이는 task 명령어가 있을 때만 (숨긴 task 명령어는 선언 · 응답 형식에 드러나지 않는다)
|
|
70
|
+
const viewTasks = view.tasks ? tasks : undefined;
|
|
45
71
|
const waitUntil = waitUntilFromAuthInfo(requestContext.authInfo);
|
|
72
|
+
// 숨긴 명령어 호출 시도의 감사 전달 (§11.1): 응답은 기다리지 않는다. handler.js = waitUntil 로 실행 유지
|
|
73
|
+
const background = (work) => waitUntil?.(work);
|
|
46
74
|
// 생성 가능 = runtime + (process 실행 또는 요청의 waitUntil)
|
|
47
|
-
const taskCreation =
|
|
75
|
+
const taskCreation = viewTasks && (options.taskExecution !== "waitUntil" || waitUntil) ? { runtime: viewTasks, waitUntil, meta } : undefined;
|
|
48
76
|
const server = new McpServer(serverInfo, {
|
|
49
77
|
capabilities,
|
|
50
78
|
...(options.instructions !== undefined && options.instructions !== "" ? { instructions: options.instructions } : {}),
|
|
51
79
|
cacheHints: {
|
|
52
|
-
"tools/list":
|
|
53
|
-
"server/discover":
|
|
80
|
+
"tools/list": toolsListCache,
|
|
81
|
+
"server/discover": toolsListCache,
|
|
54
82
|
"resources/list": RESOURCE_LIST_CACHE,
|
|
55
83
|
"resources/templates/list": RESOURCE_LIST_CACHE,
|
|
56
84
|
"resources/read": RESOURCE_READ_CACHE,
|
|
@@ -85,8 +113,8 @@ export function createMcpServerFactory(options) {
|
|
|
85
113
|
deliver: options.transport === "stdio",
|
|
86
114
|
...(options.onerror ? { onerror: options.onerror } : {}),
|
|
87
115
|
});
|
|
88
|
-
if (
|
|
89
|
-
installTaskHandlers(server,
|
|
116
|
+
if (viewTasks)
|
|
117
|
+
installTaskHandlers(server, viewTasks, principal, taskCreation !== undefined);
|
|
90
118
|
for (const tool of tools) {
|
|
91
119
|
server.registerTool(tool.name, {
|
|
92
120
|
title: tool.annotations.title,
|
|
@@ -96,7 +124,11 @@ export function createMcpServerFactory(options) {
|
|
|
96
124
|
...(tool.outputSchema ? { outputSchema: passthroughSchema(tool.outputSchema) } : {}),
|
|
97
125
|
annotations: tool.annotations,
|
|
98
126
|
...(tool._meta ? { _meta: tool._meta } : {}),
|
|
99
|
-
}, async (args, ctx) =>
|
|
127
|
+
}, async (args, ctx) => {
|
|
128
|
+
// 자가 신고 clientInfo: 2026-07-28 = 요청 _meta, 2025 stdio = initialize (HTTP 2025 = 요청별 인스턴스라 없음)
|
|
129
|
+
const client = reportedClient(requestEnvelope(ctx)?.[CLIENT_INFO_META_KEY]) ?? reportedClient(server.server.getClientVersion());
|
|
130
|
+
return withMeta(await runTool(options, tools, tool, args, ctx, principal, client, getApp, signer, resourceUpdated, taskCreation, background), meta);
|
|
131
|
+
});
|
|
100
132
|
}
|
|
101
133
|
return server;
|
|
102
134
|
};
|
|
@@ -158,7 +190,7 @@ function withDiscoverMeta(server, meta) {
|
|
|
158
190
|
return withMeta(original.call(inner), meta);
|
|
159
191
|
};
|
|
160
192
|
}
|
|
161
|
-
async function runTool(options, tools, tool, args, ctx, principal, getApp, signer, resourceUpdated, taskCreation) {
|
|
193
|
+
async function runTool(options, tools, tool, args, ctx, principal, client, getApp, signer, resourceUpdated, taskCreation, background) {
|
|
162
194
|
const progress = progressReporter(ctx, options.progressInterval ?? PROGRESS_INTERVAL_MS);
|
|
163
195
|
try {
|
|
164
196
|
const app = await getApp();
|
|
@@ -168,19 +200,30 @@ async function runTool(options, tools, tool, args, ctx, principal, getApp, signe
|
|
|
168
200
|
? taskCreation.runtime.request({
|
|
169
201
|
principal,
|
|
170
202
|
modes: { form: round.elicitation, url: round.urlElicitation === true },
|
|
203
|
+
meta: taskCreation.meta,
|
|
171
204
|
...(taskCreation.waitUntil ? { waitUntil: taskCreation.waitUntil } : {}),
|
|
172
205
|
})
|
|
173
206
|
: undefined;
|
|
207
|
+
const carrier = traceCarrier(ctx);
|
|
208
|
+
// registry = 전체. 주체의 표면 판정 (help · 실행 · 숨긴 명령어 기록) 은 callDispatcher · invoke 가 한다 (§4 expose)
|
|
174
209
|
const result = await callDispatcher(options.registry, tool, args, {
|
|
175
210
|
principal,
|
|
211
|
+
background,
|
|
212
|
+
...(client ? { client } : {}),
|
|
176
213
|
signal: ctx.mcpReq.signal,
|
|
177
214
|
...(progress ? { progress: progress.report } : {}),
|
|
178
215
|
app,
|
|
179
216
|
tools,
|
|
180
217
|
input: { ...round, signer },
|
|
181
218
|
resourceUpdated,
|
|
182
|
-
...(options.instrumentation ? { instrumentation: options.instrumentation
|
|
219
|
+
...(options.instrumentation ? { instrumentation: options.instrumentation } : {}),
|
|
220
|
+
// 요청의 trace context = span 의 부모 (instrumentation) · 감사 이벤트의 traceId (§11.1: span 이 없어도 남긴다)
|
|
221
|
+
...(carrier ? { traceContext: carrier } : {}),
|
|
183
222
|
...(options.transport ? { transport: options.transport } : {}),
|
|
223
|
+
...(options.audit ? { audit: options.audit } : {}),
|
|
224
|
+
...(options.approval ? { approval: options.approval } : {}),
|
|
225
|
+
// 요청 _meta 의 확인 표시 (§4 승인). 인정 여부는 invoke 가 표면의 확인 방식 · 행위자로 판정한다
|
|
226
|
+
confirmed: isApprovalMark(ctx.mcpReq._meta?.[APPROVAL_META_KEY]),
|
|
184
227
|
...(task ? { detach: task.detach } : {}),
|
|
185
228
|
});
|
|
186
229
|
// task 생성 중 store 예외 = 요청 실패 (-32603, §12.1). McpServer 의 도구 오류 변환을 rethrowStoreErrors 가 건너뛴다
|
|
@@ -192,10 +235,13 @@ async function runTool(options, tools, tool, args, ctx, principal, getApp, signe
|
|
|
192
235
|
progress?.stop();
|
|
193
236
|
}
|
|
194
237
|
}
|
|
238
|
+
/** 요청 _meta envelope (SDK 가 분리). 2025 레거시 = 없음 */
|
|
239
|
+
function requestEnvelope(ctx) {
|
|
240
|
+
return ctx.mcpReq.envelope;
|
|
241
|
+
}
|
|
195
242
|
/** 요청 _meta 의 clientCapabilities (2025 레거시 = envelope 없음 → undefined) */
|
|
196
243
|
function clientCapabilities(ctx) {
|
|
197
|
-
|
|
198
|
-
return envelope?.[CLIENT_CAPABILITIES_META_KEY];
|
|
244
|
+
return requestEnvelope(ctx)?.[CLIENT_CAPABILITIES_META_KEY];
|
|
199
245
|
}
|
|
200
246
|
/** 요청의 MRTR 입력: elicitation (form · url) 선언 · inputResponses · requestState (SDK 가 params 에서 분리) */
|
|
201
247
|
function inputRound(ctx) {
|