@obov/mext 0.1.0 → 0.3.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/build-cli.d.ts +2 -1
- package/dist/build-cli.js +24 -14
- package/dist/build-cli.js.map +1 -1
- package/dist/build.d.ts +23 -3
- package/dist/build.js +58 -5
- package/dist/build.js.map +1 -1
- package/dist/cli/build.js +5 -0
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev-server.js +2 -1
- package/dist/cli/dev-server.js.map +1 -1
- package/dist/cli/dev.js +2 -1
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/output.d.ts +45 -1
- package/dist/cli/output.js +60 -3
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/run.d.ts +26 -0
- package/dist/cli/run.js +41 -20
- package/dist/cli/run.js.map +1 -1
- package/dist/client/main.d.ts +8 -2
- package/dist/client/main.js +4 -3
- package/dist/client/main.js.map +1 -1
- package/dist/client/runner.d.ts +3 -0
- package/dist/client/runner.js +13 -12
- package/dist/client/runner.js.map +1 -1
- package/dist/config.d.ts +67 -2
- package/dist/config.js +89 -4
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +19 -1
- package/dist/errors.js +47 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/instrumentation.d.ts +2 -2
- package/dist/instrumentation.js +5 -5
- package/dist/instrumentation.js.map +1 -1
- package/dist/local-bin.d.ts +20 -0
- package/dist/local-bin.js +102 -0
- package/dist/local-bin.js.map +1 -0
- package/dist/mcp/dispatch.d.ts +1 -1
- package/dist/mcp/dispatch.js +3 -3
- package/dist/mcp/dispatch.js.map +1 -1
- package/dist/mcp/http.d.ts +4 -0
- package/dist/mcp/http.js +2 -0
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/install.d.ts +2 -2
- package/dist/mcp/install.js +18 -0
- package/dist/mcp/install.js.map +1 -1
- package/dist/mcp/server.d.ts +5 -0
- package/dist/mcp/server.js +7 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.d.ts +18 -0
- package/dist/mcp/stdio.js +155 -12
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/start.d.ts +2 -1
- package/dist/start.js +13 -1
- package/dist/start.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\"\nimport { isAbsolute, join, resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport { isMextError } from \"./errors.ts\"\nimport type { Principal } from \"./principal.ts\"\n\n/**\n * instrumentation.ts (프로젝트 루트, 선택) · OpenTelemetry span (§11).\n * register() = 프로세스당 1회, 첫 명령어 실행 전. onCommandError = 핸들러 예외 보고.\n * span = @opentelemetry/api (선택 peer) 가 있을 때만. 없으면 no-op (실패한 import 1회 캐시).\n */\n\nexport const INSTRUMENTATION_FILE = \"instrumentation.ts\"\n\n/** 핸들러를 실행한 어댑터. 원격 CLI 는 핸들러를 실행하지 않으므로 없다 */\nexport type Transport = \"http\" | \"stdio\" | \"local\"\n\nexport interface CommandErrorInfo {\n /** 정식 명령어 ID */\n command: string\n transport: Transport\n /** scopes · claims 는 넘기지 않는다 */\n principal: { id: string; kind: Principal[\"kind\"] }\n}\n\n/** instrumentation.ts 의 export */\nexport interface InstrumentationModule {\n register?: () => unknown\n onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown\n}\n\n/** 어댑터가 InvokeOptions.instrumentation 으로 넘기는 로드 결과 */\nexport interface Instrumentation {\n /** 핸들러 예외 (MextError 외, 취소 · MRTR 대기 제외). 자체 예외는 stderr 로 보고하고 응답은 바꾸지 않는다 */\n onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown\n /** @opentelemetry/api. undefined = span 없음 */\n otel?: OtelApi\n /** onCommandError 의 예외 보고. 기본 stderr */\n onerror?: (error: unknown) => void\n}\n\nexport interface LoadInstrumentationOptions {\n /** @opentelemetry/api 로더 (테스트 주입). 기본 = 동적 import, 결과는 프로세스당 캐시 */\n importOtel?: () => Promise<unknown>\n onerror?: (error: unknown) => void\n}\n\n/** mext 가 쓰는 @opentelemetry/api 의 부분 (타입 의존 없이) */\nexport interface OtelApi {\n trace: { getTracer(name: string, version?: string): OtelTracer }\n context: { active(): unknown }\n propagation: { extract(context: unknown, carrier: unknown): unknown }\n SpanStatusCode: { ERROR: number }\n}\n\ninterface OtelTracer {\n startActiveSpan<T>(name: string, options: { attributes: Record<string, string> }, context: unknown, fn: (span: OtelSpan) => T): T\n}\n\ninterface OtelSpan {\n setAttribute(key: string, value: string): unknown\n setStatus(status: { code: number; message?: string }): unknown\n recordException(exception: unknown): unknown\n end(): void\n}\n\n/** cwd 의 instrumentation.ts 절대 경로. 없으면 undefined */\nexport function findInstrumentation(cwd: string = process.cwd()): string | undefined {\n const file = join(resolve(cwd), INSTRUMENTATION_FILE)\n return existsSync(file) ? file : undefined\n}\n\n/** findInstrumentation(cwd) → loadInstrumentation. mext dev · mext run (로컬) · stdio 용 */\nexport function loadProjectInstrumentation(\n cwd: string = process.cwd(),\n options: LoadInstrumentationOptions = {},\n): Promise<Instrumentation> {\n return loadInstrumentation(findInstrumentation(cwd), options)\n}\n\nconst loaded = new Map<string, Promise<InstrumentationModule>>()\nconst loadedModules = new WeakMap<object, Promise<InstrumentationModule>>()\n\n/**\n * instrumentation 모듈 (파일 경로 · URL · import 된 모듈) 을 프로세스당 1회 import 하고 register() 를 await.\n * 같은 모듈의 두 번째 호출 = register 재호출 없이 같은 hooks. register 실패 = reject (다음 호출에서 재시도).\n * source 없음 = hooks 없이 span 만. 빌드 산출물 (.mext/server/instrumentation.js) 도 같은 함수.\n */\nexport async function loadInstrumentation(\n source?: string | URL | InstrumentationModule,\n options: LoadInstrumentationOptions = {},\n): Promise<Instrumentation> {\n const [mod, otel] = await Promise.all([\n source === undefined ? Promise.resolve<InstrumentationModule>({}) : registerOnce(source),\n options.importOtel ? resolveOtel(options.importOtel) : defaultOtel(),\n ])\n return {\n ...(mod.onCommandError ? { onCommandError: mod.onCommandError } : {}),\n ...(otel ? { otel } : {}),\n ...(options.onerror ? { onerror: options.onerror } : {}),\n }\n}\n\nfunction registerOnce(source: string | URL | InstrumentationModule): Promise<InstrumentationModule> {\n if (typeof source === \"string\" || source instanceof URL) {\n const isPath = typeof source === \"string\" && (isAbsolute(source) || !/^[a-z][a-z0-9+.-]+:/i.test(source))\n const href = isPath ? pathToFileURL(resolve(source as string)).href : String(source)\n return memo(loaded, href, () => import(href).then((m: unknown) => register(m, href)))\n }\n return memo(loadedModules, source, () => register(source, \"instrumentation\"))\n}\n\nfunction memo<K>(\n cache: { get(k: K): Promise<InstrumentationModule> | undefined; set(k: K, v: Promise<InstrumentationModule>): unknown; delete(k: K): unknown },\n key: K,\n load: () => Promise<InstrumentationModule>,\n): Promise<InstrumentationModule> {\n let pending = cache.get(key)\n if (!pending) {\n pending = load().catch((error: unknown) => {\n cache.delete(key)\n throw error\n })\n cache.set(key, pending)\n }\n return pending\n}\n\nasync function register(value: unknown, label: string): Promise<InstrumentationModule> {\n const mod = (value ?? {}) as Record<string, unknown>\n for (const key of [\"register\", \"onCommandError\"]) {\n if (mod[key] !== undefined && typeof mod[key] !== \"function\") {\n throw new TypeError(`${label}: export ${key} must be a function`)\n }\n }\n const hooks = mod as InstrumentationModule\n await hooks.register?.()\n return hooks\n}\n\n/* @opentelemetry/api (선택 peer). 번들러가 해석 · 포함하지 않도록 specifier 는 변수 (R5) */\n\nconst OTEL_API = \"@opentelemetry/api\"\nlet otelDefault: Promise<OtelApi | undefined> | undefined\n\nfunction defaultOtel(): Promise<OtelApi | undefined> {\n otelDefault ??= resolveOtel(() => import(OTEL_API))\n return otelDefault\n}\n\nasync function resolveOtel(importer: () => Promise<unknown>): Promise<OtelApi | undefined> {\n try {\n const mod = (await importer()) as Partial<OtelApi> & { default?: Partial<OtelApi> }\n const api = mod.trace ? mod : mod.default\n return api?.trace && api.context && api.propagation && api.SpanStatusCode ? (api as OtelApi) : undefined\n } catch {\n return undefined\n }\n}\n\n/* invoke 에서 사용 */\n\nconst TRACER_NAME = \"@obov/mext\"\n\nexport interface ObserveOptions {\n instrumentation?: Instrumentation\n transport?: Transport\n principal: Principal\n /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate) */\n traceContext?: Record<string, unknown>\n}\n\n/**\n * 명령어 실행 1회를 `mext.command <id>` span 으로 감싼다 (otel 있을 때만, 없으면 fn 그대로).\n * 속성 = mext.command.id · mext.transport · mext.principal.kind. 인자 · 결과 · 토큰은 기록하지 않는다.\n * 실패: status ERROR + mext.error.code. 핸들러 예외만 recordException (MextError 메시지는 입력 일부를 담을 수 있어 제외).\n * 취소 (signal abort · MRTR 대기) = status 없음.\n */\nexport function observeCommand<T>(\n command: string,\n options: ObserveOptions,\n signal: () => AbortSignal | undefined,\n fn: () => Promise<T>,\n): Promise<T> {\n const otel = options.instrumentation?.otel\n if (!otel) return fn()\n const parent = options.traceContext ? otel.propagation.extract(otel.context.active(), options.traceContext) : otel.context.active()\n const attributes = {\n \"mext.command.id\": command,\n \"mext.transport\": options.transport ?? \"local\",\n \"mext.principal.kind\": options.principal.kind,\n }\n const tracer = otel.trace.getTracer(TRACER_NAME)\n return tracer.startActiveSpan(`mext.command ${command}`, { attributes }, parent, async (span) => {\n try {\n return await fn()\n } catch (error) {\n if (!signal()?.aborted) {\n if (isMextError(error)) {\n span.setAttribute(\"mext.error.code\", error.code)\n span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error.code })\n } else {\n span.setAttribute(\"mext.error.code\", \"EXECUTION_ERROR\")\n span.recordException(error)\n span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : String(error) })\n }\n }\n throw error\n } finally {\n span.end()\n }\n })\n}\n\n/**\n * 핸들러 예외 → onCommandError (await). MextError · 취소 · MRTR 대기는 보고하지 않는다.\n * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.\n */\nexport async function reportCommandError(\n error: unknown,\n command: string,\n options: ObserveOptions,\n signal: AbortSignal | undefined,\n): Promise<void> {\n const hook = options.instrumentation?.onCommandError\n if (!hook || isMextError(error) || signal?.aborted) return\n const info: CommandErrorInfo = {\n command,\n transport: options.transport ?? \"local\",\n principal: { id: options.principal.id, kind: options.principal.kind },\n }\n try {\n await hook(error, info)\n } catch (hookError) {\n const onerror = options.instrumentation?.onerror ?? defaultOnError\n try {\n onerror(hookError)\n } catch {\n // 보고는 응답을 바꾸지 않는다\n }\n }\n}\n\nfunction defaultOnError(error: unknown): void {\n const message = error instanceof Error ? (error.stack ?? error.message) : String(error)\n process.stderr.write(`mext: onCommandError threw: ${message}\\n`)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\"\nimport { isAbsolute, join, resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport { isDeclaredError } from \"./errors.ts\"\nimport type { Principal } from \"./principal.ts\"\n\n/**\n * instrumentation.ts (프로젝트 루트, 선택) · OpenTelemetry span (§11).\n * register() = 프로세스당 1회, 첫 명령어 실행 전. onCommandError = 핸들러 예외 보고.\n * span = @opentelemetry/api (선택 peer) 가 있을 때만. 없으면 no-op (실패한 import 1회 캐시).\n */\n\nexport const INSTRUMENTATION_FILE = \"instrumentation.ts\"\n\n/** 핸들러를 실행한 어댑터. 원격 CLI 는 핸들러를 실행하지 않으므로 없다 */\nexport type Transport = \"http\" | \"stdio\" | \"local\"\n\nexport interface CommandErrorInfo {\n /** 정식 명령어 ID */\n command: string\n transport: Transport\n /** scopes · claims 는 넘기지 않는다 */\n principal: { id: string; kind: Principal[\"kind\"] }\n}\n\n/** instrumentation.ts 의 export */\nexport interface InstrumentationModule {\n register?: () => unknown\n onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown\n}\n\n/** 어댑터가 InvokeOptions.instrumentation 으로 넘기는 로드 결과 */\nexport interface Instrumentation {\n /** 핸들러 예외 (MextError 외, 취소 · MRTR 대기 제외). 자체 예외는 stderr 로 보고하고 응답은 바꾸지 않는다 */\n onCommandError?: (error: unknown, info: CommandErrorInfo) => unknown\n /** @opentelemetry/api. undefined = span 없음 */\n otel?: OtelApi\n /** onCommandError 의 예외 보고. 기본 stderr */\n onerror?: (error: unknown) => void\n}\n\nexport interface LoadInstrumentationOptions {\n /** @opentelemetry/api 로더 (테스트 주입). 기본 = 동적 import, 결과는 프로세스당 캐시 */\n importOtel?: () => Promise<unknown>\n onerror?: (error: unknown) => void\n}\n\n/** mext 가 쓰는 @opentelemetry/api 의 부분 (타입 의존 없이) */\nexport interface OtelApi {\n trace: { getTracer(name: string, version?: string): OtelTracer }\n context: { active(): unknown }\n propagation: { extract(context: unknown, carrier: unknown): unknown }\n SpanStatusCode: { ERROR: number }\n}\n\ninterface OtelTracer {\n startActiveSpan<T>(name: string, options: { attributes: Record<string, string> }, context: unknown, fn: (span: OtelSpan) => T): T\n}\n\ninterface OtelSpan {\n setAttribute(key: string, value: string): unknown\n setStatus(status: { code: number; message?: string }): unknown\n recordException(exception: unknown): unknown\n end(): void\n}\n\n/** cwd 의 instrumentation.ts 절대 경로. 없으면 undefined */\nexport function findInstrumentation(cwd: string = process.cwd()): string | undefined {\n const file = join(resolve(cwd), INSTRUMENTATION_FILE)\n return existsSync(file) ? file : undefined\n}\n\n/** findInstrumentation(cwd) → loadInstrumentation. mext dev · mext run (로컬) · stdio 용 */\nexport function loadProjectInstrumentation(\n cwd: string = process.cwd(),\n options: LoadInstrumentationOptions = {},\n): Promise<Instrumentation> {\n return loadInstrumentation(findInstrumentation(cwd), options)\n}\n\nconst loaded = new Map<string, Promise<InstrumentationModule>>()\nconst loadedModules = new WeakMap<object, Promise<InstrumentationModule>>()\n\n/**\n * instrumentation 모듈 (파일 경로 · URL · import 된 모듈) 을 프로세스당 1회 import 하고 register() 를 await.\n * 같은 모듈의 두 번째 호출 = register 재호출 없이 같은 hooks. register 실패 = reject (다음 호출에서 재시도).\n * source 없음 = hooks 없이 span 만. 빌드 산출물 (.mext/server/instrumentation.js) 도 같은 함수.\n */\nexport async function loadInstrumentation(\n source?: string | URL | InstrumentationModule,\n options: LoadInstrumentationOptions = {},\n): Promise<Instrumentation> {\n const [mod, otel] = await Promise.all([\n source === undefined ? Promise.resolve<InstrumentationModule>({}) : registerOnce(source),\n options.importOtel ? resolveOtel(options.importOtel) : defaultOtel(),\n ])\n return {\n ...(mod.onCommandError ? { onCommandError: mod.onCommandError } : {}),\n ...(otel ? { otel } : {}),\n ...(options.onerror ? { onerror: options.onerror } : {}),\n }\n}\n\nfunction registerOnce(source: string | URL | InstrumentationModule): Promise<InstrumentationModule> {\n if (typeof source === \"string\" || source instanceof URL) {\n const isPath = typeof source === \"string\" && (isAbsolute(source) || !/^[a-z][a-z0-9+.-]+:/i.test(source))\n const href = isPath ? pathToFileURL(resolve(source as string)).href : String(source)\n return memo(loaded, href, () => import(href).then((m: unknown) => register(m, href)))\n }\n return memo(loadedModules, source, () => register(source, \"instrumentation\"))\n}\n\nfunction memo<K>(\n cache: { get(k: K): Promise<InstrumentationModule> | undefined; set(k: K, v: Promise<InstrumentationModule>): unknown; delete(k: K): unknown },\n key: K,\n load: () => Promise<InstrumentationModule>,\n): Promise<InstrumentationModule> {\n let pending = cache.get(key)\n if (!pending) {\n pending = load().catch((error: unknown) => {\n cache.delete(key)\n throw error\n })\n cache.set(key, pending)\n }\n return pending\n}\n\nasync function register(value: unknown, label: string): Promise<InstrumentationModule> {\n const mod = (value ?? {}) as Record<string, unknown>\n for (const key of [\"register\", \"onCommandError\"]) {\n if (mod[key] !== undefined && typeof mod[key] !== \"function\") {\n throw new TypeError(`${label}: export ${key} must be a function`)\n }\n }\n const hooks = mod as InstrumentationModule\n await hooks.register?.()\n return hooks\n}\n\n/* @opentelemetry/api (선택 peer). 번들러가 해석 · 포함하지 않도록 specifier 는 변수 (R5) */\n\nconst OTEL_API = \"@opentelemetry/api\"\nlet otelDefault: Promise<OtelApi | undefined> | undefined\n\nfunction defaultOtel(): Promise<OtelApi | undefined> {\n otelDefault ??= resolveOtel(() => import(OTEL_API))\n return otelDefault\n}\n\nasync function resolveOtel(importer: () => Promise<unknown>): Promise<OtelApi | undefined> {\n try {\n const mod = (await importer()) as Partial<OtelApi> & { default?: Partial<OtelApi> }\n const api = mod.trace ? mod : mod.default\n return api?.trace && api.context && api.propagation && api.SpanStatusCode ? (api as OtelApi) : undefined\n } catch {\n return undefined\n }\n}\n\n/* invoke 에서 사용 */\n\nconst TRACER_NAME = \"@obov/mext\"\n\nexport interface ObserveOptions {\n instrumentation?: Instrumentation\n transport?: Transport\n principal: Principal\n /** W3C trace context carrier (MCP params._meta 의 traceparent · tracestate) */\n traceContext?: Record<string, unknown>\n}\n\n/**\n * 명령어 실행 1회를 `mext.command <id>` span 으로 감싼다 (otel 있을 때만, 없으면 fn 그대로).\n * 속성 = mext.command.id · mext.transport · mext.principal.kind. 인자 · 결과 · 토큰은 기록하지 않는다.\n * 실패: status ERROR + mext.error.code. 핸들러 예외만 recordException (MextError · CommandError 메시지는 입력 일부를 담을 수 있어 제외).\n * 취소 (signal abort · MRTR 대기) = status 없음.\n */\nexport function observeCommand<T>(\n command: string,\n options: ObserveOptions,\n signal: () => AbortSignal | undefined,\n fn: () => Promise<T>,\n): Promise<T> {\n const otel = options.instrumentation?.otel\n if (!otel) return fn()\n const parent = options.traceContext ? otel.propagation.extract(otel.context.active(), options.traceContext) : otel.context.active()\n const attributes = {\n \"mext.command.id\": command,\n \"mext.transport\": options.transport ?? \"local\",\n \"mext.principal.kind\": options.principal.kind,\n }\n const tracer = otel.trace.getTracer(TRACER_NAME)\n return tracer.startActiveSpan(`mext.command ${command}`, { attributes }, parent, async (span) => {\n try {\n return await fn()\n } catch (error) {\n if (!signal()?.aborted) {\n if (isDeclaredError(error)) {\n span.setAttribute(\"mext.error.code\", error.code)\n span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error.code })\n } else {\n span.setAttribute(\"mext.error.code\", \"EXECUTION_ERROR\")\n span.recordException(error)\n span.setStatus({ code: otel.SpanStatusCode.ERROR, message: error instanceof Error ? error.message : String(error) })\n }\n }\n throw error\n } finally {\n span.end()\n }\n })\n}\n\n/**\n * 핸들러 예외 → onCommandError (await). MextError · CommandError · 취소 · MRTR 대기는 보고하지 않는다.\n * onCommandError 자체의 예외 = onerror (기본 stderr), 호출자에게 전파하지 않는다.\n */\nexport async function reportCommandError(\n error: unknown,\n command: string,\n options: ObserveOptions,\n signal: AbortSignal | undefined,\n): Promise<void> {\n const hook = options.instrumentation?.onCommandError\n if (!hook || isDeclaredError(error) || signal?.aborted) return\n const info: CommandErrorInfo = {\n command,\n transport: options.transport ?? \"local\",\n principal: { id: options.principal.id, kind: options.principal.kind },\n }\n try {\n await hook(error, info)\n } catch (hookError) {\n const onerror = options.instrumentation?.onerror ?? defaultOnError\n try {\n onerror(hookError)\n } catch {\n // 보고는 응답을 바꾸지 않는다\n }\n }\n}\n\nfunction defaultOnError(error: unknown): void {\n const message = error instanceof Error ? (error.stack ?? error.message) : String(error)\n process.stderr.write(`mext: onCommandError threw: ${message}\\n`)\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type CliIo } from "./cli/io.ts";
|
|
2
|
+
/**
|
|
3
|
+
* 로컬 bin (cli.local, §5). .mext/bin.js 가 호출하는 런타임 (@obov/mext/start).
|
|
4
|
+
* 생성 파일 계약 (mext build 가 쓰는 bin.js, 바꾸면 기존 빌드가 깨진다):
|
|
5
|
+
* await mainLocalBin(new URL(".", import.meta.url), { bin, version, errors? })
|
|
6
|
+
* 명령: <bin> help · <bin> <ns> <cmd> [flags] · <bin> mcp serve · <bin> mcp install · <bin> --version.
|
|
7
|
+
* 명령어 실행 = mext run (로컬) 과 같은 코어 (cli/run.ts runLocalCommand), Registry = .mext/manifest.json (소스 · TypeScript 없음)
|
|
8
|
+
*/
|
|
9
|
+
export interface LocalBinOptions {
|
|
10
|
+
/** 실행 파일 이름 (cli.bin) */
|
|
11
|
+
bin: string;
|
|
12
|
+
/** --version (cli.version > 도입 프로젝트 package.json version) */
|
|
13
|
+
version: string;
|
|
14
|
+
/** .mext/ 기준 cli.errors 번들 모듈 (예: "cli-errors.js") */
|
|
15
|
+
errors?: string;
|
|
16
|
+
}
|
|
17
|
+
/** 로컬 bin 실행. argv = 실행 파일 뒤 인자. 반환 = exit code */
|
|
18
|
+
export declare function runLocalBin(dir: string | URL, options: LocalBinOptions, argv: readonly string[], partialIo?: Partial<CliIo>): Promise<number>;
|
|
19
|
+
/** 프로세스 진입점 (bin.js). 첫 SIGINT = ctx.signal abort (exit 130), 두 번째 = 즉시 종료 */
|
|
20
|
+
export declare function mainLocalBin(dir: string | URL, options: LocalBinOptions): Promise<void>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { resolve } from "node:path";
|
|
10
|
+
import { pathToFileURL } from "node:url";
|
|
11
|
+
import { cliSpecFromJsonSchema, defineCliSpec } from "./cli/args.js";
|
|
12
|
+
import { table } from "./cli/help.js";
|
|
13
|
+
import { resolveIo } from "./cli/io.js";
|
|
14
|
+
import { EXIT } from "./cli/output.js";
|
|
15
|
+
import { runLocalCommand } from "./cli/run.js";
|
|
16
|
+
import { mcpInstallText } from "./mcp/install.js";
|
|
17
|
+
import { loadBuild, startFromBuild } from "./start.js";
|
|
18
|
+
/** 로컬 bin 실행. argv = 실행 파일 뒤 인자. 반환 = exit code */
|
|
19
|
+
export async function runLocalBin(dir, options, argv, partialIo = {}) {
|
|
20
|
+
const io = resolveIo(partialIo);
|
|
21
|
+
const [first, ...rest] = argv;
|
|
22
|
+
if (first === "--version" || first === "-v") {
|
|
23
|
+
io.stdout.write(`${options.version}\n`);
|
|
24
|
+
return EXIT.ok;
|
|
25
|
+
}
|
|
26
|
+
if (first === "mcp")
|
|
27
|
+
return mcp(dir, options, rest, io);
|
|
28
|
+
return runLocalCommand(argv, io, buildSource(dir, options));
|
|
29
|
+
}
|
|
30
|
+
/** 프로세스 진입점 (bin.js). 첫 SIGINT = ctx.signal abort (exit 130), 두 번째 = 즉시 종료 */
|
|
31
|
+
export async function mainLocalBin(dir, options) {
|
|
32
|
+
const controller = new AbortController();
|
|
33
|
+
process.on("SIGINT", () => {
|
|
34
|
+
if (controller.signal.aborted)
|
|
35
|
+
process.exit(130);
|
|
36
|
+
controller.abort();
|
|
37
|
+
});
|
|
38
|
+
const code = await runLocalBin(dir, options, process.argv.slice(2), { signal: controller.signal });
|
|
39
|
+
process.stdout.write("", () => process.stderr.write("", () => process.exit(code)));
|
|
40
|
+
}
|
|
41
|
+
/** .mext/ → 로컬 실행 코어 입력. CLI 필드 = manifest 입력 스키마 (JSON Schema) 분석 (고객 CLI 와 같음) */
|
|
42
|
+
function buildSource(dir, options) {
|
|
43
|
+
return {
|
|
44
|
+
prog: options.bin,
|
|
45
|
+
footer: builtinHelp(options.bin),
|
|
46
|
+
async load(setFormatter) {
|
|
47
|
+
const build = await loadBuild(dir);
|
|
48
|
+
if (options.errors !== undefined)
|
|
49
|
+
setFormatter(await loadFormatter(dir, options.errors));
|
|
50
|
+
for (const entry of build.registry.commands.values()) {
|
|
51
|
+
defineCliSpec(entry, cliSpecFromJsonSchema(entry.inputSchema, entry.command.positional));
|
|
52
|
+
}
|
|
53
|
+
return { instrumentation: build.instrumentation, config: build.config, registry: build.registry };
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function loadFormatter(dir, file) {
|
|
58
|
+
const href = typeof dir === "string" ? pathToFileURL(resolve(dir, file)).href : new URL(file, dir.href.endsWith("/") ? dir : `${dir.href}/`).href;
|
|
59
|
+
const mod = (await import(__rewriteRelativeImportExtension(href)));
|
|
60
|
+
if (typeof mod.default !== "function")
|
|
61
|
+
throw new TypeError(`${file}: default export must be a function (CliErrorFormatter)`);
|
|
62
|
+
return mod.default;
|
|
63
|
+
}
|
|
64
|
+
async function mcp(dir, options, argv, io) {
|
|
65
|
+
const { bin } = options;
|
|
66
|
+
const [sub, ...rest] = argv;
|
|
67
|
+
const isHelp = (t) => t === "--help" || t === "-h";
|
|
68
|
+
const usage = [
|
|
69
|
+
"Usage:",
|
|
70
|
+
...table([
|
|
71
|
+
[`${bin} mcp serve`, "Run the MCP server over stdio (handlers run on this machine)"],
|
|
72
|
+
[`${bin} mcp install`, "Print MCP client registration commands (does not modify client config files)"],
|
|
73
|
+
]).map((l) => ` ${l}`),
|
|
74
|
+
"",
|
|
75
|
+
].join("\n");
|
|
76
|
+
if (sub !== undefined && (isHelp(sub) || rest.some(isHelp))) {
|
|
77
|
+
io.stdout.write(usage);
|
|
78
|
+
return EXIT.ok;
|
|
79
|
+
}
|
|
80
|
+
if (sub === "serve" && rest.length === 0) {
|
|
81
|
+
return startFromBuild(dir, { argv: ["--stdio"], stderr: io.stderr, ...(io.signal ? { signal: io.signal } : {}) });
|
|
82
|
+
}
|
|
83
|
+
if (sub === "install" && rest.length === 0) {
|
|
84
|
+
io.stdout.write(`${mcpInstallText({ name: bin, url: false, stdioCommand: `${bin} mcp serve` })}\n`);
|
|
85
|
+
return EXIT.ok;
|
|
86
|
+
}
|
|
87
|
+
io.stderr.write(`error: ${sub === undefined ? "missing subcommand" : `unknown argument "${argv.join(" ")}"`}\n\n${usage}`);
|
|
88
|
+
return EXIT.usage;
|
|
89
|
+
}
|
|
90
|
+
/** 사람용 루트 help 뒤의 내장 명령 */
|
|
91
|
+
function builtinHelp(bin) {
|
|
92
|
+
return [
|
|
93
|
+
"CLI commands:",
|
|
94
|
+
...table([
|
|
95
|
+
["mcp serve", `MCP server over stdio (${bin} mcp install for registration)`],
|
|
96
|
+
["mcp install", "Print MCP client registration commands"],
|
|
97
|
+
["--version", "Print the version"],
|
|
98
|
+
]).map((l) => ` ${l}`),
|
|
99
|
+
"",
|
|
100
|
+
].join("\n");
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=local-bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-bin.js","sourceRoot":"","sources":["../src/local-bin.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACpE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,SAAS,EAAc,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,IAAI,EAA0B,MAAM,iBAAiB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAuB,MAAM,cAAc,CAAA;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAmBtD,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAiB,EACjB,OAAwB,EACxB,IAAuB,EACvB,SAAS,GAAmB,EAAE;IAE9B,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAA;IAC/B,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAC7B,IAAI,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC5C,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAA;QACvC,OAAO,IAAI,CAAC,EAAE,CAAA;IAChB,CAAC;IACD,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;IACvD,OAAO,eAAe,CAAC,IAAI,EAAE,EAAE,EAAE,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAA;AAC7D,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAiB,EAAE,OAAwB;IAC5E,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;IACxC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAChD,UAAU,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC,CAAC,CAAA;IACF,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;IAClG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACpF,CAAC;AAED,oFAAoF;AACpF,SAAS,WAAW,CAAC,GAAiB,EAAE,OAAwB;IAC9D,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,GAAG;QACjB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,YAAY;YACrB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAA;YAClC,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;gBAAE,YAAY,CAAC,MAAM,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;YACxF,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrD,aAAa,CAAC,KAAK,EAAE,qBAAqB,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAA;YAC1F,CAAC;YACD,OAAO,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAA;QACnG,CAAC;KACF,CAAA;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,GAAiB,EAAE,IAAY;IAC1D,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAA;IACjJ,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,kCAAC,IAAI,EAAC,CAA0B,CAAA;IACzD,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,UAAU;QAAE,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,yDAAyD,CAAC,CAAA;IAC5H,OAAO,GAAG,CAAC,OAA4B,CAAA;AACzC,CAAC;AAED,KAAK,UAAU,GAAG,CAAC,GAAiB,EAAE,OAAwB,EAAE,IAAuB,EAAE,EAAS;IAChG,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAA;IACvB,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAC3B,MAAM,MAAM,GAAG,CAAC,CAAS,EAAW,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAA;IACnE,MAAM,KAAK,GAAG;QACZ,QAAQ;QACR,GAAG,KAAK,CAAC;YACP,CAAC,GAAG,GAAG,YAAY,EAAE,8DAA8D,CAAC;YACpF,CAAC,GAAG,GAAG,cAAc,EAAE,8EAA8E,CAAC;SACvG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACZ,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAC5D,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACtB,OAAO,IAAI,CAAC,EAAE,CAAA;IAChB,CAAC;IACD,IAAI,GAAG,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO,cAAc,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IACnH,CAAC;IACD,IAAI,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3C,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,GAAG,YAAY,EAAE,CAAC,IAAI,CAAC,CAAA;QACnG,OAAO,IAAI,CAAC,EAAE,CAAA;IAChB,CAAC;IACD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,qBAAqB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,KAAK,EAAE,CAAC,CAAA;IAC1H,OAAO,IAAI,CAAC,KAAK,CAAA;AACnB,CAAC;AAED,2BAA2B;AAC3B,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO;QACL,eAAe;QACf,GAAG,KAAK,CAAC;YACP,CAAC,WAAW,EAAE,0BAA0B,GAAG,gCAAgC,CAAC;YAC5E,CAAC,aAAa,EAAE,wCAAwC,CAAC;YACzD,CAAC,WAAW,EAAE,mBAAmB,CAAC;SACnC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC","sourcesContent":["import { resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport { cliSpecFromJsonSchema, defineCliSpec } from \"./cli/args.ts\"\nimport { table } from \"./cli/help.ts\"\nimport { resolveIo, type CliIo } from \"./cli/io.ts\"\nimport { EXIT, type CliErrorFormatter } from \"./cli/output.ts\"\nimport { runLocalCommand, type LocalRunSource } from \"./cli/run.ts\"\nimport { mcpInstallText } from \"./mcp/install.ts\"\nimport { loadBuild, startFromBuild } from \"./start.ts\"\n\n/**\n * 로컬 bin (cli.local, §5). .mext/bin.js 가 호출하는 런타임 (@obov/mext/start).\n * 생성 파일 계약 (mext build 가 쓰는 bin.js, 바꾸면 기존 빌드가 깨진다):\n * await mainLocalBin(new URL(\".\", import.meta.url), { bin, version, errors? })\n * 명령: <bin> help · <bin> <ns> <cmd> [flags] · <bin> mcp serve · <bin> mcp install · <bin> --version.\n * 명령어 실행 = mext run (로컬) 과 같은 코어 (cli/run.ts runLocalCommand), Registry = .mext/manifest.json (소스 · TypeScript 없음)\n */\n\nexport interface LocalBinOptions {\n /** 실행 파일 이름 (cli.bin) */\n bin: string\n /** --version (cli.version > 도입 프로젝트 package.json version) */\n version: string\n /** .mext/ 기준 cli.errors 번들 모듈 (예: \"cli-errors.js\") */\n errors?: string\n}\n\n/** 로컬 bin 실행. argv = 실행 파일 뒤 인자. 반환 = exit code */\nexport async function runLocalBin(\n dir: string | URL,\n options: LocalBinOptions,\n argv: readonly string[],\n partialIo: Partial<CliIo> = {},\n): Promise<number> {\n const io = resolveIo(partialIo)\n const [first, ...rest] = argv\n if (first === \"--version\" || first === \"-v\") {\n io.stdout.write(`${options.version}\\n`)\n return EXIT.ok\n }\n if (first === \"mcp\") return mcp(dir, options, rest, io)\n return runLocalCommand(argv, io, buildSource(dir, options))\n}\n\n/** 프로세스 진입점 (bin.js). 첫 SIGINT = ctx.signal abort (exit 130), 두 번째 = 즉시 종료 */\nexport async function mainLocalBin(dir: string | URL, options: LocalBinOptions): Promise<void> {\n const controller = new AbortController()\n process.on(\"SIGINT\", () => {\n if (controller.signal.aborted) process.exit(130)\n controller.abort()\n })\n const code = await runLocalBin(dir, options, process.argv.slice(2), { signal: controller.signal })\n process.stdout.write(\"\", () => process.stderr.write(\"\", () => process.exit(code)))\n}\n\n/** .mext/ → 로컬 실행 코어 입력. CLI 필드 = manifest 입력 스키마 (JSON Schema) 분석 (고객 CLI 와 같음) */\nfunction buildSource(dir: string | URL, options: LocalBinOptions): LocalRunSource {\n return {\n prog: options.bin,\n footer: builtinHelp(options.bin),\n async load(setFormatter) {\n const build = await loadBuild(dir)\n if (options.errors !== undefined) setFormatter(await loadFormatter(dir, options.errors))\n for (const entry of build.registry.commands.values()) {\n defineCliSpec(entry, cliSpecFromJsonSchema(entry.inputSchema, entry.command.positional))\n }\n return { instrumentation: build.instrumentation, config: build.config, registry: build.registry }\n },\n }\n}\n\nasync function loadFormatter(dir: string | URL, file: string): Promise<CliErrorFormatter> {\n const href = typeof dir === \"string\" ? pathToFileURL(resolve(dir, file)).href : new URL(file, dir.href.endsWith(\"/\") ? dir : `${dir.href}/`).href\n const mod = (await import(href)) as { default?: unknown }\n if (typeof mod.default !== \"function\") throw new TypeError(`${file}: default export must be a function (CliErrorFormatter)`)\n return mod.default as CliErrorFormatter\n}\n\nasync function mcp(dir: string | URL, options: LocalBinOptions, argv: readonly string[], io: CliIo): Promise<number> {\n const { bin } = options\n const [sub, ...rest] = argv\n const isHelp = (t: string): boolean => t === \"--help\" || t === \"-h\"\n const usage = [\n \"Usage:\",\n ...table([\n [`${bin} mcp serve`, \"Run the MCP server over stdio (handlers run on this machine)\"],\n [`${bin} mcp install`, \"Print MCP client registration commands (does not modify client config files)\"],\n ]).map((l) => ` ${l}`),\n \"\",\n ].join(\"\\n\")\n if (sub !== undefined && (isHelp(sub) || rest.some(isHelp))) {\n io.stdout.write(usage)\n return EXIT.ok\n }\n if (sub === \"serve\" && rest.length === 0) {\n return startFromBuild(dir, { argv: [\"--stdio\"], stderr: io.stderr, ...(io.signal ? { signal: io.signal } : {}) })\n }\n if (sub === \"install\" && rest.length === 0) {\n io.stdout.write(`${mcpInstallText({ name: bin, url: false, stdioCommand: `${bin} mcp serve` })}\\n`)\n return EXIT.ok\n }\n io.stderr.write(`error: ${sub === undefined ? \"missing subcommand\" : `unknown argument \"${argv.join(\" \")}\"`}\\n\\n${usage}`)\n return EXIT.usage\n}\n\n/** 사람용 루트 help 뒤의 내장 명령 */\nfunction builtinHelp(bin: string): string {\n return [\n \"CLI commands:\",\n ...table([\n [\"mcp serve\", `MCP server over stdio (${bin} mcp install for registration)`],\n [\"mcp install\", \"Print MCP client registration commands\"],\n [\"--version\", \"Print the version\"],\n ]).map((l) => ` ${l}`),\n \"\",\n ].join(\"\\n\")\n}\n"]}
|
package/dist/mcp/dispatch.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export type DispatchResult = ToolCallResult | InputRequiredResult;
|
|
|
60
60
|
* options.input 이 있으면 ctx.ask 가 InputRequiredResult 를 돌려준다 (mrtr.ts).
|
|
61
61
|
*/
|
|
62
62
|
export declare function callDispatcher(registry: Registry, tool: DispatcherTool, rawArguments: unknown, options: DispatchOptions): Promise<DispatchResult>;
|
|
63
|
-
/** 오류 → isError 결과. MextError = toJSON, 그 외 = EXECUTION_ERROR */
|
|
63
|
+
/** 오류 → isError 결과. MextError · CommandError = toJSON, 그 외 = EXECUTION_ERROR (message 만) */
|
|
64
64
|
export declare function errorResult(error: unknown): ToolCallResult;
|
|
65
65
|
/** dispatcher 도구 inputSchema. command 를 Mcp-Param-Command 헤더로 복사 (SEP-2243) */
|
|
66
66
|
export declare function dispatcherInputSchema(): JsonSchema;
|
package/dist/mcp/dispatch.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isDeclaredError, MextError } from "../errors.js";
|
|
2
2
|
import { invoke } from "../invoke.js";
|
|
3
3
|
import { formatHelp, help, HELP_COMMAND } from "./help.js";
|
|
4
4
|
import { createAskSession, hasPending, inputRequiredResult, } from "./mrtr.js";
|
|
@@ -129,9 +129,9 @@ function invalidRequestState(tool, command) {
|
|
|
129
129
|
examples: [],
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
|
-
/** 오류 → isError 결과. MextError = toJSON, 그 외 = EXECUTION_ERROR */
|
|
132
|
+
/** 오류 → isError 결과. MextError · CommandError = toJSON, 그 외 = EXECUTION_ERROR (message 만) */
|
|
133
133
|
export function errorResult(error) {
|
|
134
|
-
const body =
|
|
134
|
+
const body = isDeclaredError(error)
|
|
135
135
|
? error.toJSON()
|
|
136
136
|
: { code: EXECUTION_ERROR, message: error instanceof Error ? error.message : String(error) };
|
|
137
137
|
return {
|
package/dist/mcp/dispatch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/mcp/dispatch.ts"],"names":[],"mappings":"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","sourcesContent":["import { isMextError, MextError } from \"../errors.ts\"\nimport { invoke, type InvokeOptions } from \"../invoke.ts\"\nimport type { JsonSchema, RegisteredCommand, Registry } from \"../registry.ts\"\nimport { formatHelp, help, HELP_COMMAND } from \"./help.ts\"\nimport {\n createAskSession,\n hasPending,\n inputRequiredResult,\n type InputRequiredResult,\n type InputRound,\n type RequestStateBinding,\n type RequestStateSigner,\n} from \"./mrtr.ts\"\n\n/**\n * MCP 어댑터의 transport 무관 부분: dispatcher 도구 정의 · tools/call 실행 · help · 오류 → 결과 변환.\n * SDK · HTTP 에 의존하지 않는다 (HTTP · stdio 가 공유).\n */\n\n/** execute = 도구 1개 (기본), split = query (readOnly · help) + mutate (그 외) */\nexport type ToolExposure = \"execute\" | \"split\"\n\nexport type DispatcherToolName = \"execute\" | \"query\" | \"mutate\"\n\n/** MCP ToolAnnotations 중 mext 가 쓰는 항목 */\nexport interface DispatcherAnnotations {\n title?: string\n readOnlyHint: boolean\n destructiveHint?: boolean\n idempotentHint?: boolean\n openWorldHint?: boolean\n}\n\nexport interface DispatcherTool {\n name: DispatcherToolName\n description: string\n /** JSON Schema 2020-12. command 에 x-mcp-header: \"Command\" */\n inputSchema: JsonSchema\n annotations: DispatcherAnnotations\n /** readOnly 명령어만 실행 (split 의 query). 그 외 = PERMISSION_DENIED */\n readOnly: boolean\n}\n\nexport interface TextContent {\n type: \"text\"\n text: string\n}\n\n/** MCP CallToolResult 와 같은 형태 (SDK 타입 비의존) */\nexport interface ToolCallResult {\n content: TextContent[]\n /** 성공 = 핸들러 반환값 (undefined 는 null), 오류 = { error: MextError.toJSON() } */\n structuredContent: unknown\n isError?: true\n}\n\n/** 핸들러 예외 (MextError 외) 의 결과 code. CLI --json 과 같음 */\nexport const EXECUTION_ERROR = \"EXECUTION_ERROR\"\n\n/** 도구 설명에 나열할 명령어 수 상한. 넘으면 help 안내만 */\nconst DESCRIPTION_COMMAND_LIMIT = 50\n\n/** 노출 방식별 dispatcher 도구 (정렬 순서 고정: execute · query, mutate) */\nexport function dispatcherTools(registry: Registry, exposure: ToolExposure = \"execute\"): DispatcherTool[] {\n const all = [...registry.commands.values()]\n if (exposure === \"split\") {\n const reads = all.filter((e) => e.command.readOnly)\n const writes = all.filter((e) => !e.command.readOnly)\n return [\n {\n name: \"query\",\n description: describeTool(\n \"query\",\n \"Run a read-only command.\",\n reads,\n 'Commands that are not read-only are rejected here; call them with the \"mutate\" tool.',\n ),\n inputSchema: dispatcherInputSchema(),\n annotations: { title: \"Query\", readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n readOnly: true,\n },\n {\n name: \"mutate\",\n description: describeTool(\"mutate\", \"Run a command that changes state.\", writes),\n inputSchema: dispatcherInputSchema(),\n annotations: { title: \"Mutate\", readOnlyHint: false, destructiveHint: true },\n readOnly: false,\n },\n ]\n }\n const readOnly = all.every((e) => e.command.readOnly)\n return [\n {\n name: \"execute\",\n description: describeTool(\"execute\", \"Run a command.\", all),\n inputSchema: dispatcherInputSchema(),\n // 단일 dispatcher 는 최악값 (researches/others.md 9)\n annotations: readOnly\n ? { title: \"Execute\", readOnlyHint: true, destructiveHint: false }\n : { title: \"Execute\", readOnlyHint: false, destructiveHint: all.some((e) => e.command.destructive) },\n readOnly: false,\n },\n ]\n}\n\nexport function findDispatcherTool(tools: readonly DispatcherTool[], name: string): DispatcherTool | undefined {\n return tools.find((t) => t.name === name)\n}\n\nexport interface DispatchOptions extends Omit<InvokeOptions, \"readOnly\"> {\n /** help 의 tool 표시용. dispatcherTools 결과 */\n tools?: readonly DispatcherTool[]\n /**\n * MRTR (MCP 2026-07-28). 지정하면 ctx.ask = InputRequiredResult 반환 · 재시도의 inputResponses 로 resolve\n * (ask 옵션 무시). requiresConfirmation 확인도 이 경로\n */\n input?: InputRound & { signer: RequestStateSigner }\n}\n\n/** tools/call 결과: 완료 (CallToolResult 형태) 또는 입력 요청 (InputRequiredResult) */\nexport type DispatchResult = ToolCallResult | InputRequiredResult\n\n/**\n * dispatcher 도구 호출: { command, args } → help 또는 invoke.\n * MextError · 핸들러 예외는 isError 결과로 (throw 하지 않음). 인증 (UNAUTHENTICATED → 401) 은 transport 몫.\n * options.input 이 있으면 ctx.ask 가 InputRequiredResult 를 돌려준다 (mrtr.ts).\n */\nexport async function callDispatcher(\n registry: Registry,\n tool: DispatcherTool,\n rawArguments: unknown,\n options: DispatchOptions,\n): Promise<DispatchResult> {\n try {\n const { command, args } = parseDispatcherArguments(tool, rawArguments)\n if (command === HELP_COMMAND) {\n const target = (args as { target?: unknown } | undefined)?.target\n if (target !== undefined && typeof target !== \"string\") {\n throw dispatcherArgumentError(tool, \"help\", \"args.target must be a string\", [], {\n path: \"args.target\",\n code: \"invalid_type\",\n message: \"expected string\",\n })\n }\n const toolFor = splitToolFor(options.tools)\n const value = help(registry, target, toolFor ? { toolFor } : {})\n return { content: [{ type: \"text\", text: formatHelp(value, tool.name) }], structuredContent: value }\n }\n const { input, tools: _tools, ...invokeOptions } = options\n const result = input\n ? await invokeRound(registry, tool, command, args, invokeOptions, input)\n : await invoke(registry, command, args, { ...invokeOptions, readOnly: tool.readOnly })\n if (\"resultType\" in result) return result\n const value = result.value === undefined ? null : result.value\n return { content: [{ type: \"text\", text: stringify(value) }], structuredContent: value }\n } catch (error) {\n return errorResult(error)\n }\n}\n\n/**\n * MRTR 한 라운드: requestState 검증 → ask 세션으로 invoke. 답 없는 ask 가 있으면 (핸들러가 오류를 삼켜도)\n * 결과를 버리고 InputRequiredResult. elicitation 미선언 클라이언트 = ask 미주입 (INPUT_UNAVAILABLE)\n */\nasync function invokeRound(\n registry: Registry,\n tool: DispatcherTool,\n command: string,\n args: unknown,\n options: Omit<InvokeOptions, \"readOnly\">,\n input: NonNullable<DispatchOptions[\"input\"]>,\n): Promise<{ command: string; value: unknown } | InputRequiredResult> {\n const { ask: _ask, ...rest } = options\n if (!input.elicitation) return invoke(registry, command, args, { ...rest, readOnly: tool.readOnly })\n const binding: RequestStateBinding = {\n principal: `${options.principal.kind}:${options.principal.id}`,\n tool: tool.name,\n command,\n args: args ?? {},\n }\n let answers: Record<string, unknown> = { ...input.inputResponses }\n if (input.requestState !== undefined) {\n const prior = input.signer.verify(input.requestState, binding)\n if (!prior) throw invalidRequestState(tool, command)\n answers = { ...answers, ...prior }\n }\n const session = createAskSession(answers)\n const signal = options.signal ? AbortSignal.any([options.signal, session.signal]) : session.signal\n try {\n const result = await invoke(registry, command, args, { ...rest, signal, ask: session.ask, readOnly: tool.readOnly })\n return hasPending(session) ? inputRequiredResult(session, input.signer, binding) : result\n } catch (error) {\n if (hasPending(session)) return inputRequiredResult(session, input.signer, binding)\n throw error\n }\n}\n\n/** 서명 · 만료 · 바인딩 검증 실패한 requestState. 처음부터 다시 호출하도록 안내 */\nfunction invalidRequestState(tool: DispatcherTool, command: string): MextError<\"INVALID_ARGUMENT\"> {\n return new MextError(\n \"INVALID_ARGUMENT\",\n `Invalid arguments for ${command}: requestState is invalid or expired. Call ${tool.name} again without requestState and inputResponses.`,\n {\n command,\n missing_fields: [],\n issues: [\n {\n path: \"requestState\",\n code: \"invalid_request_state\",\n message: \"requestState failed verification (tampered, expired, or for a different call or server key)\",\n },\n ],\n expected_schema: tool.inputSchema,\n examples: [],\n },\n )\n}\n\n/** 오류 → isError 결과. MextError = toJSON, 그 외 = EXECUTION_ERROR */\nexport function errorResult(error: unknown): ToolCallResult {\n const body = isMextError(error)\n ? error.toJSON()\n : { code: EXECUTION_ERROR, message: error instanceof Error ? error.message : String(error) }\n return {\n content: [{ type: \"text\", text: `${body.code}: ${body.message}\\n${stringify(body)}` }],\n structuredContent: { error: body },\n isError: true,\n }\n}\n\n/** dispatcher 도구 inputSchema. command 를 Mcp-Param-Command 헤더로 복사 (SEP-2243) */\nexport function dispatcherInputSchema(): JsonSchema {\n return {\n type: \"object\",\n properties: {\n command: {\n type: \"string\",\n description: 'Command ID (e.g. \"users.get\"), or \"help\" to list namespaces and commands.',\n \"x-mcp-header\": \"Command\",\n },\n args: {\n type: \"object\",\n description: 'Command input. For \"help\": { \"target\": \"<namespace or command ID>\" }.',\n additionalProperties: true,\n },\n },\n required: [\"command\"],\n additionalProperties: false,\n }\n}\n\nfunction parseDispatcherArguments(tool: DispatcherTool, raw: unknown): { command: string; args: unknown } {\n const input = raw === undefined ? {} : raw\n if (input === null || typeof input !== \"object\" || Array.isArray(input)) {\n throw dispatcherArgumentError(tool, tool.name, \"arguments must be an object\", [], {\n path: \"\",\n code: \"invalid_type\",\n message: \"expected object\",\n })\n }\n const { command, args, ...rest } = input as Record<string, unknown>\n if (command === undefined) {\n throw dispatcherArgumentError(tool, tool.name, \"missing required: command\", [\"command\"], {\n path: \"command\",\n code: \"invalid_type\",\n message: \"expected string, received undefined\",\n })\n }\n if (typeof command !== \"string\") {\n throw dispatcherArgumentError(tool, tool.name, \"command must be a string\", [], {\n path: \"command\",\n code: \"invalid_type\",\n message: \"expected string\",\n })\n }\n const unknownKeys = Object.keys(rest)\n if (unknownKeys.length > 0) {\n throw dispatcherArgumentError(tool, tool.name, `unrecognized keys: ${unknownKeys.join(\", \")}`, [], {\n path: \"\",\n code: \"unrecognized_keys\",\n message: `Unrecognized keys: ${unknownKeys.join(\", \")}. Put command input under \"args\".`,\n })\n }\n if (args !== undefined && (args === null || typeof args !== \"object\" || Array.isArray(args))) {\n throw dispatcherArgumentError(tool, command, \"args must be an object\", [], {\n path: \"args\",\n code: \"invalid_type\",\n message: \"expected object\",\n })\n }\n return { command, args }\n}\n\nfunction dispatcherArgumentError(\n tool: DispatcherTool,\n command: string,\n summary: string,\n missing: string[],\n issue: { path: string; code: string; message: string },\n): MextError<\"INVALID_ARGUMENT\"> {\n return new MextError(\"INVALID_ARGUMENT\", `Invalid arguments for ${command}: ${summary}`, {\n command,\n missing_fields: missing,\n issues: [issue],\n expected_schema: tool.inputSchema,\n examples: [{ command: HELP_COMMAND }],\n })\n}\n\nfunction splitToolFor(tools: readonly DispatcherTool[] | undefined): ((e: RegisteredCommand) => string) | undefined {\n if (!tools || tools.length < 2) return undefined\n const query = tools.find((t) => t.readOnly)?.name\n const mutate = tools.find((t) => !t.readOnly)?.name\n if (query === undefined || mutate === undefined) return undefined\n return (e) => (e.command.readOnly ? query : mutate)\n}\n\nfunction describeTool(name: string, lead: string, commands: readonly RegisteredCommand[], note?: string): string {\n const lines = [\n lead,\n `Arguments: { \"command\": \"<command ID>\", \"args\": { ...input } }. ` +\n `Call ${name}({ \"command\": \"help\" }) to list namespaces and commands, ` +\n `${name}({ \"command\": \"help\", \"args\": { \"target\": \"<namespace or command ID>\" } }) for input schemas and examples.`,\n ]\n if (note) lines.push(note)\n if (commands.length > 0 && commands.length <= DESCRIPTION_COMMAND_LIMIT) {\n lines.push(\"\", \"Commands:\")\n for (const e of commands) lines.push(`- ${e.id}: ${firstLine(e.command.description)}`)\n }\n return lines.join(\"\\n\")\n}\n\nfunction firstLine(text: string): string {\n return text.split(\"\\n\", 1)[0]!.trim()\n}\n\nfunction stringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2) ?? \"null\"\n } catch {\n return String(value)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/mcp/dispatch.ts"],"names":[],"mappings":"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","sourcesContent":["import { isDeclaredError, MextError } from \"../errors.ts\"\nimport { invoke, type InvokeOptions } from \"../invoke.ts\"\nimport type { JsonSchema, RegisteredCommand, Registry } from \"../registry.ts\"\nimport { formatHelp, help, HELP_COMMAND } from \"./help.ts\"\nimport {\n createAskSession,\n hasPending,\n inputRequiredResult,\n type InputRequiredResult,\n type InputRound,\n type RequestStateBinding,\n type RequestStateSigner,\n} from \"./mrtr.ts\"\n\n/**\n * MCP 어댑터의 transport 무관 부분: dispatcher 도구 정의 · tools/call 실행 · help · 오류 → 결과 변환.\n * SDK · HTTP 에 의존하지 않는다 (HTTP · stdio 가 공유).\n */\n\n/** execute = 도구 1개 (기본), split = query (readOnly · help) + mutate (그 외) */\nexport type ToolExposure = \"execute\" | \"split\"\n\nexport type DispatcherToolName = \"execute\" | \"query\" | \"mutate\"\n\n/** MCP ToolAnnotations 중 mext 가 쓰는 항목 */\nexport interface DispatcherAnnotations {\n title?: string\n readOnlyHint: boolean\n destructiveHint?: boolean\n idempotentHint?: boolean\n openWorldHint?: boolean\n}\n\nexport interface DispatcherTool {\n name: DispatcherToolName\n description: string\n /** JSON Schema 2020-12. command 에 x-mcp-header: \"Command\" */\n inputSchema: JsonSchema\n annotations: DispatcherAnnotations\n /** readOnly 명령어만 실행 (split 의 query). 그 외 = PERMISSION_DENIED */\n readOnly: boolean\n}\n\nexport interface TextContent {\n type: \"text\"\n text: string\n}\n\n/** MCP CallToolResult 와 같은 형태 (SDK 타입 비의존) */\nexport interface ToolCallResult {\n content: TextContent[]\n /** 성공 = 핸들러 반환값 (undefined 는 null), 오류 = { error: MextError.toJSON() } */\n structuredContent: unknown\n isError?: true\n}\n\n/** 핸들러 예외 (MextError 외) 의 결과 code. CLI --json 과 같음 */\nexport const EXECUTION_ERROR = \"EXECUTION_ERROR\"\n\n/** 도구 설명에 나열할 명령어 수 상한. 넘으면 help 안내만 */\nconst DESCRIPTION_COMMAND_LIMIT = 50\n\n/** 노출 방식별 dispatcher 도구 (정렬 순서 고정: execute · query, mutate) */\nexport function dispatcherTools(registry: Registry, exposure: ToolExposure = \"execute\"): DispatcherTool[] {\n const all = [...registry.commands.values()]\n if (exposure === \"split\") {\n const reads = all.filter((e) => e.command.readOnly)\n const writes = all.filter((e) => !e.command.readOnly)\n return [\n {\n name: \"query\",\n description: describeTool(\n \"query\",\n \"Run a read-only command.\",\n reads,\n 'Commands that are not read-only are rejected here; call them with the \"mutate\" tool.',\n ),\n inputSchema: dispatcherInputSchema(),\n annotations: { title: \"Query\", readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n readOnly: true,\n },\n {\n name: \"mutate\",\n description: describeTool(\"mutate\", \"Run a command that changes state.\", writes),\n inputSchema: dispatcherInputSchema(),\n annotations: { title: \"Mutate\", readOnlyHint: false, destructiveHint: true },\n readOnly: false,\n },\n ]\n }\n const readOnly = all.every((e) => e.command.readOnly)\n return [\n {\n name: \"execute\",\n description: describeTool(\"execute\", \"Run a command.\", all),\n inputSchema: dispatcherInputSchema(),\n // 단일 dispatcher 는 최악값 (researches/others.md 9)\n annotations: readOnly\n ? { title: \"Execute\", readOnlyHint: true, destructiveHint: false }\n : { title: \"Execute\", readOnlyHint: false, destructiveHint: all.some((e) => e.command.destructive) },\n readOnly: false,\n },\n ]\n}\n\nexport function findDispatcherTool(tools: readonly DispatcherTool[], name: string): DispatcherTool | undefined {\n return tools.find((t) => t.name === name)\n}\n\nexport interface DispatchOptions extends Omit<InvokeOptions, \"readOnly\"> {\n /** help 의 tool 표시용. dispatcherTools 결과 */\n tools?: readonly DispatcherTool[]\n /**\n * MRTR (MCP 2026-07-28). 지정하면 ctx.ask = InputRequiredResult 반환 · 재시도의 inputResponses 로 resolve\n * (ask 옵션 무시). requiresConfirmation 확인도 이 경로\n */\n input?: InputRound & { signer: RequestStateSigner }\n}\n\n/** tools/call 결과: 완료 (CallToolResult 형태) 또는 입력 요청 (InputRequiredResult) */\nexport type DispatchResult = ToolCallResult | InputRequiredResult\n\n/**\n * dispatcher 도구 호출: { command, args } → help 또는 invoke.\n * MextError · 핸들러 예외는 isError 결과로 (throw 하지 않음). 인증 (UNAUTHENTICATED → 401) 은 transport 몫.\n * options.input 이 있으면 ctx.ask 가 InputRequiredResult 를 돌려준다 (mrtr.ts).\n */\nexport async function callDispatcher(\n registry: Registry,\n tool: DispatcherTool,\n rawArguments: unknown,\n options: DispatchOptions,\n): Promise<DispatchResult> {\n try {\n const { command, args } = parseDispatcherArguments(tool, rawArguments)\n if (command === HELP_COMMAND) {\n const target = (args as { target?: unknown } | undefined)?.target\n if (target !== undefined && typeof target !== \"string\") {\n throw dispatcherArgumentError(tool, \"help\", \"args.target must be a string\", [], {\n path: \"args.target\",\n code: \"invalid_type\",\n message: \"expected string\",\n })\n }\n const toolFor = splitToolFor(options.tools)\n const value = help(registry, target, toolFor ? { toolFor } : {})\n return { content: [{ type: \"text\", text: formatHelp(value, tool.name) }], structuredContent: value }\n }\n const { input, tools: _tools, ...invokeOptions } = options\n const result = input\n ? await invokeRound(registry, tool, command, args, invokeOptions, input)\n : await invoke(registry, command, args, { ...invokeOptions, readOnly: tool.readOnly })\n if (\"resultType\" in result) return result\n const value = result.value === undefined ? null : result.value\n return { content: [{ type: \"text\", text: stringify(value) }], structuredContent: value }\n } catch (error) {\n return errorResult(error)\n }\n}\n\n/**\n * MRTR 한 라운드: requestState 검증 → ask 세션으로 invoke. 답 없는 ask 가 있으면 (핸들러가 오류를 삼켜도)\n * 결과를 버리고 InputRequiredResult. elicitation 미선언 클라이언트 = ask 미주입 (INPUT_UNAVAILABLE)\n */\nasync function invokeRound(\n registry: Registry,\n tool: DispatcherTool,\n command: string,\n args: unknown,\n options: Omit<InvokeOptions, \"readOnly\">,\n input: NonNullable<DispatchOptions[\"input\"]>,\n): Promise<{ command: string; value: unknown } | InputRequiredResult> {\n const { ask: _ask, ...rest } = options\n if (!input.elicitation) return invoke(registry, command, args, { ...rest, readOnly: tool.readOnly })\n const binding: RequestStateBinding = {\n principal: `${options.principal.kind}:${options.principal.id}`,\n tool: tool.name,\n command,\n args: args ?? {},\n }\n let answers: Record<string, unknown> = { ...input.inputResponses }\n if (input.requestState !== undefined) {\n const prior = input.signer.verify(input.requestState, binding)\n if (!prior) throw invalidRequestState(tool, command)\n answers = { ...answers, ...prior }\n }\n const session = createAskSession(answers)\n const signal = options.signal ? AbortSignal.any([options.signal, session.signal]) : session.signal\n try {\n const result = await invoke(registry, command, args, { ...rest, signal, ask: session.ask, readOnly: tool.readOnly })\n return hasPending(session) ? inputRequiredResult(session, input.signer, binding) : result\n } catch (error) {\n if (hasPending(session)) return inputRequiredResult(session, input.signer, binding)\n throw error\n }\n}\n\n/** 서명 · 만료 · 바인딩 검증 실패한 requestState. 처음부터 다시 호출하도록 안내 */\nfunction invalidRequestState(tool: DispatcherTool, command: string): MextError<\"INVALID_ARGUMENT\"> {\n return new MextError(\n \"INVALID_ARGUMENT\",\n `Invalid arguments for ${command}: requestState is invalid or expired. Call ${tool.name} again without requestState and inputResponses.`,\n {\n command,\n missing_fields: [],\n issues: [\n {\n path: \"requestState\",\n code: \"invalid_request_state\",\n message: \"requestState failed verification (tampered, expired, or for a different call or server key)\",\n },\n ],\n expected_schema: tool.inputSchema,\n examples: [],\n },\n )\n}\n\n/** 오류 → isError 결과. MextError · CommandError = toJSON, 그 외 = EXECUTION_ERROR (message 만) */\nexport function errorResult(error: unknown): ToolCallResult {\n const body: Record<string, unknown> & { code: string; message: string } = isDeclaredError(error)\n ? error.toJSON()\n : { code: EXECUTION_ERROR, message: error instanceof Error ? error.message : String(error) }\n return {\n content: [{ type: \"text\", text: `${body.code}: ${body.message}\\n${stringify(body)}` }],\n structuredContent: { error: body },\n isError: true,\n }\n}\n\n/** dispatcher 도구 inputSchema. command 를 Mcp-Param-Command 헤더로 복사 (SEP-2243) */\nexport function dispatcherInputSchema(): JsonSchema {\n return {\n type: \"object\",\n properties: {\n command: {\n type: \"string\",\n description: 'Command ID (e.g. \"users.get\"), or \"help\" to list namespaces and commands.',\n \"x-mcp-header\": \"Command\",\n },\n args: {\n type: \"object\",\n description: 'Command input. For \"help\": { \"target\": \"<namespace or command ID>\" }.',\n additionalProperties: true,\n },\n },\n required: [\"command\"],\n additionalProperties: false,\n }\n}\n\nfunction parseDispatcherArguments(tool: DispatcherTool, raw: unknown): { command: string; args: unknown } {\n const input = raw === undefined ? {} : raw\n if (input === null || typeof input !== \"object\" || Array.isArray(input)) {\n throw dispatcherArgumentError(tool, tool.name, \"arguments must be an object\", [], {\n path: \"\",\n code: \"invalid_type\",\n message: \"expected object\",\n })\n }\n const { command, args, ...rest } = input as Record<string, unknown>\n if (command === undefined) {\n throw dispatcherArgumentError(tool, tool.name, \"missing required: command\", [\"command\"], {\n path: \"command\",\n code: \"invalid_type\",\n message: \"expected string, received undefined\",\n })\n }\n if (typeof command !== \"string\") {\n throw dispatcherArgumentError(tool, tool.name, \"command must be a string\", [], {\n path: \"command\",\n code: \"invalid_type\",\n message: \"expected string\",\n })\n }\n const unknownKeys = Object.keys(rest)\n if (unknownKeys.length > 0) {\n throw dispatcherArgumentError(tool, tool.name, `unrecognized keys: ${unknownKeys.join(\", \")}`, [], {\n path: \"\",\n code: \"unrecognized_keys\",\n message: `Unrecognized keys: ${unknownKeys.join(\", \")}. Put command input under \"args\".`,\n })\n }\n if (args !== undefined && (args === null || typeof args !== \"object\" || Array.isArray(args))) {\n throw dispatcherArgumentError(tool, command, \"args must be an object\", [], {\n path: \"args\",\n code: \"invalid_type\",\n message: \"expected object\",\n })\n }\n return { command, args }\n}\n\nfunction dispatcherArgumentError(\n tool: DispatcherTool,\n command: string,\n summary: string,\n missing: string[],\n issue: { path: string; code: string; message: string },\n): MextError<\"INVALID_ARGUMENT\"> {\n return new MextError(\"INVALID_ARGUMENT\", `Invalid arguments for ${command}: ${summary}`, {\n command,\n missing_fields: missing,\n issues: [issue],\n expected_schema: tool.inputSchema,\n examples: [{ command: HELP_COMMAND }],\n })\n}\n\nfunction splitToolFor(tools: readonly DispatcherTool[] | undefined): ((e: RegisteredCommand) => string) | undefined {\n if (!tools || tools.length < 2) return undefined\n const query = tools.find((t) => t.readOnly)?.name\n const mutate = tools.find((t) => !t.readOnly)?.name\n if (query === undefined || mutate === undefined) return undefined\n return (e) => (e.command.readOnly ? query : mutate)\n}\n\nfunction describeTool(name: string, lead: string, commands: readonly RegisteredCommand[], note?: string): string {\n const lines = [\n lead,\n `Arguments: { \"command\": \"<command ID>\", \"args\": { ...input } }. ` +\n `Call ${name}({ \"command\": \"help\" }) to list namespaces and commands, ` +\n `${name}({ \"command\": \"help\", \"args\": { \"target\": \"<namespace or command ID>\" } }) for input schemas and examples.`,\n ]\n if (note) lines.push(note)\n if (commands.length > 0 && commands.length <= DESCRIPTION_COMMAND_LIMIT) {\n lines.push(\"\", \"Commands:\")\n for (const e of commands) lines.push(`- ${e.id}: ${firstLine(e.command.description)}`)\n }\n return lines.join(\"\\n\")\n}\n\nfunction firstLine(text: string): string {\n return text.split(\"\\n\", 1)[0]!.trim()\n}\n\nfunction stringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2) ?? \"null\"\n } catch {\n return String(value)\n }\n}\n"]}
|
package/dist/mcp/http.d.ts
CHANGED
|
@@ -33,6 +33,10 @@ export interface McpHttpOptions {
|
|
|
33
33
|
};
|
|
34
34
|
/** serverInfo.name · 안내 문구. 기본 "mext" */
|
|
35
35
|
name?: string;
|
|
36
|
+
/** initialize · server/discover 결과 instructions */
|
|
37
|
+
instructions?: string;
|
|
38
|
+
/** 서버 capabilities 에 병합 (experimental) */
|
|
39
|
+
capabilities?: McpCoreOptions["capabilities"];
|
|
36
40
|
/** 응답에 영향 없는 오류 보고 (auth 예외 · SDK 내부 오류) */
|
|
37
41
|
onerror?: (error: Error) => void;
|
|
38
42
|
/** MRTR requestState 서명 키. McpCoreOptions.requestStateKey */
|
package/dist/mcp/http.js
CHANGED
|
@@ -21,6 +21,8 @@ export function createMcpFetchHandler(options) {
|
|
|
21
21
|
...(options.app ? { app: options.app } : {}),
|
|
22
22
|
...(options.tools ? { tools: options.tools } : {}),
|
|
23
23
|
...(options.name ? { name: options.name } : {}),
|
|
24
|
+
...(options.instructions !== undefined ? { instructions: options.instructions } : {}),
|
|
25
|
+
...(options.capabilities ? { capabilities: options.capabilities } : {}),
|
|
24
26
|
...(options.requestStateKey !== undefined ? { requestStateKey: options.requestStateKey } : {}),
|
|
25
27
|
...(options.progressInterval !== undefined ? { progressInterval: options.progressInterval } : {}),
|
|
26
28
|
...(options.instrumentation ? { instrumentation: options.instrumentation } : {}),
|
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, 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 { 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\"\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 /** 응답에 영향 없는 오류 보고 (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\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 /** 진행 중인 요청 abort · SDK handler 정리 */\n close(): 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 */\n fetch(request: Request): Promise<Response>\n /** SDK handler 정리 */\n close(): Promise<void>\n}\n\n/**\n * Streamable HTTP (2026-07-28) 의 transport 무관 처리 (Web Request → Response).\n * 순서: 경로 (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 const factory = createMcpServerFactory({\n registry: options.registry,\n ...(options.app ? { app: options.app } : {}),\n ...(options.tools ? { tools: options.tools } : {}),\n ...(options.name ? { name: options.name } : {}),\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 transport: \"http\",\n })\n const report = reporter(options.onerror)\n const sdkOptions = options.onerror ? { onerror: report } : {}\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): 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 (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 handler: McpHttpHandler = !legacy && hasProgressToken(parsedBody) ? sseHandler : jsonHandler\n return handler.fetch(sdkRequest, {\n authInfo: principalAuthInfo(principal),\n ...(parsedBody !== undefined ? { parsedBody } : {}),\n })\n }\n\n return {\n async fetch(request) {\n try {\n return await handle(request)\n } catch (error) {\n report(error)\n return jsonResponse(500, rpcError(-32_603, \"Internal server error\"))\n }\n },\n async close() {\n await Promise.all([jsonHandler.close(), sseHandler.close()])\n },\n }\n}\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.close = async () => {\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":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAA;AAEnF,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAuB,MAAM,8BAA8B,CAAA;AAErG,OAAO,EAAE,WAAW,EAAkB,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAE,SAAS,EAAkB,MAAM,iBAAiB,CAAA;AAE3D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAGrE,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAuB,MAAM,aAAa,CAAA;AAE5F,4BAA4B;AAC5B,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAA;AA2D7C,6BAA6B;AAC7B,MAAM,CAAC,MAAM,gCAAgC,GAAG,uCAAuC,CAAA;AAevF;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAuB;IAC3D,MAAM,OAAO,GAAG,sBAAsB,CAAC;QACrC,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,OAAO,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9F,GAAG,CAAC,OAAO,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,SAAS,EAAE,MAAM;KAClB,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IACxC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC7D,gEAAgE;IAChE,MAAM,WAAW,GAAG,gBAAgB,CAAC,OAAO,EAAE,EAAE,GAAG,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAA;IACtF,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,EAAE,EAAE,GAAG,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAA;IACpF,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,cAAc,CAAA;IAErD,MAAM,MAAM,GAAG,KAAK,EAAE,OAAgB,EAAqB,EAAE;QAC3D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAChC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;QAC3B,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,gCAAgC,IAAI,GAAG,CAAC,QAAQ,KAAK,6BAA6B,EAAE,CAAC,EAAE,CAAC;YACrH,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;gBAAE,OAAO,YAAY,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;YACzG,OAAO,YAAY,CAAC,GAAG,EAAE,yBAAyB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;QACjE,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,uCAAuC,QAAQ,GAAG,CAAC,CAAC,CAAA;QAC9H,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAA;QACzD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,CAAC;YACpF,OAAO,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,qBAAqB,MAAM,kBAAkB,CAAC,CAAC,CAAA;QAC5F,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC9B,OAAO,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,qBAAqB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACvF,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;QACzD,IAAI,IAAI,KAAK,WAAW;YAAE,OAAO,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAA;QAChG,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;QAC9B,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;QAE5B,IAAI,SAAS,GAAc,SAAS,CAAA;QACpC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC;gBACH,SAAS,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,SAAS,EAAE,CAAC,CAAA;YACtG,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,WAAW,CAAC,KAAK,EAAE,iBAAiB,CAAC,EAAE,CAAC;oBAC1C,OAAO,uBAAuB,CAAC,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,mBAAmB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;gBAChG,CAAC;gBACD,MAAM,CAAC,KAAK,CAAC,CAAA;gBACb,OAAO,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,uBAAuB,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,CAAA;YACrF,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;YAClC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;YAC1C,IAAI;YACJ,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAA;QACF,MAAM,UAAU,GAAG,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAA;QAC3D,oFAAoF;QACpF,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,EAAE,kBAAkB,EAAE,cAAc,EAAE,CAAC,CAAA;QACpG,MAAM,OAAO,GAAmB,CAAC,MAAM,IAAI,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAA;QAClG,OAAO,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE;YAC/B,QAAQ,EAAE,iBAAiB,CAAC,SAAS,CAAC;YACtC,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpD,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,OAAO;YACjB,IAAI,CAAC;gBACH,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,CAAA;YAC9B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAA;gBACb,OAAO,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC,CAAA;YACtE,CAAC;QACH,CAAC;QACD,KAAK,CAAC,KAAK;YACT,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QAC9D,CAAC;KACF,CAAA;AACH,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,oBAAoB,CAAC,OAAuB;IAC1D,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC3C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IACxC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmB,CAAA;IAE3C,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAoB,EAAE,GAAmB,EAAE,EAAE;QAC9D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QACxB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,IAAI,CAAC,GAAG,CAAC,gBAAgB;gBAAE,UAAU,CAAC,KAAK,EAAE,CAAA;YAC7C,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;QAC7B,CAAC,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,CAAA;QAC7D,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;YAC3C,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,KAAK;YAC3B,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC;YACzB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAA+B,EAAE,MAAM,EAAE,MAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxG,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAA;QACF,IAAI;aACD,KAAK,CAAC,OAAO,CAAC;aACd,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;aAC/C,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACxB,MAAM,CAAC,KAAK,CAAC,CAAA;YACb,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,SAAS;gBAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC,CAAA;;gBACjG,GAAG,CAAC,OAAO,EAAE,CAAA;QACpB,CAAC,CAAC,CAAA;IACN,CAAC,CAAoB,CAAA;IACrB,QAAQ,CAAC,KAAK,GAAG,KAAK,IAAI,EAAE;QAC1B,KAAK,MAAM,CAAC,IAAI,QAAQ;YAAE,CAAC,CAAC,KAAK,EAAE,CAAA;QACnC,QAAQ,CAAC,KAAK,EAAE,CAAA;QAChB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;IACpB,CAAC,CAAA;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,uCAAuC;AACvC,SAAS,QAAQ,CAAC,OAA6C;IAC7D,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,IAAI,CAAC;YACH,OAAO,EAAE,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,kBAAkB;QACpB,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAUD,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAuB;IAC9D,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,IAAI,YAAY,CAAA;IACjD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,IAAI,YAAY,CAAA;IACjD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC5B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;YAC7B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC3B,OAAO,EAAE,CAAA;QACX,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAiB,CAAA;IAC/C,OAAO;QACL,GAAG,EAAE,UAAU,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,GAAG,QAAQ,EAAE;QAC5D,IAAI;QACJ,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,CAAC,KAAK;YACT,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAA;YACtB,MAAM,CAAC,mBAAmB,EAAE,CAAA;YAC5B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QACrE,CAAC;KACF,CAAA;AACH,CAAC;AAED,YAAY;AAEZ,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAA;AAEvE,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,OAAsC;IAClF,IAAI,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACvC,IAAI,GAAQ,CAAA;IACZ,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IACvE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACtE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,CAAA;AACvE,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,uBAAuB;AAEvB,uCAAuC;AACvC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC,CAAA;AAEpE,SAAS,gBAAgB,CAAC,MAAe;IACvC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACnC,KAAK,MAAM,IAAI,IAAI,eAAe;QAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACxD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,WAAW,CAAC,GAAoB;IACvC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;IAC7B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACxD,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QACzD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,KAAK,MAAM,CAAC,IAAI,KAAK;gBAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;;YACnE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC/B,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,GAAoB;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC,CAAA;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAA;IACpD,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,KAAK,UAAU,QAAQ,CAAC,IAAuC,EAAE,KAAa;IAC5E,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAA;IAC3C,MAAM,MAAM,GAAiB,EAAE,CAAA;IAC/B,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAA;IAC/B,SAAS,CAAC;QACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;QAC3C,IAAI,IAAI;YAAE,MAAK;QACf,IAAI,IAAI,KAAK,CAAC,UAAU,CAAA;QACxB,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;YACjB,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACrC,OAAO,WAAW,CAAA;QACpB,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACpB,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAA;IAChC,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;QAClB,MAAM,IAAI,CAAC,CAAC,UAAU,CAAA;IACxB,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,GAAmB,EAAE,QAAkB;IACjE,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QAClB,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC7C,OAAM;IACR,CAAC;IACD,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAA;IAChC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;IACrE,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC3B,GAAG,CAAC,GAAG,EAAE,CAAA;QACT,OAAM;IACR,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;IACxC,iFAAiF;IACjF,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,IAAI,CAAC,GAAG,CAAC,gBAAgB;YAAE,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACjE,CAAC,CAAA;IACD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACxB,GAAG,CAAC,YAAY,EAAE,CAAA;IAClB,IAAI,CAAC;QACH,SAAS,CAAC;YACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;YAC3C,IAAI,IAAI,IAAI,GAAG,CAAC,SAAS;gBAAE,MAAK;YAChC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAClB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;YAAS,CAAC;QACT,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAC3B,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,SAAS;QAAE,GAAG,CAAC,GAAG,EAAE,CAAA;AAC/B,CAAC;AAED,SAAS,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa,EAAE,OAAO,GAA2B,EAAE;IACxG,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACjC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAA;IACpH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED,SAAS,YAAY,CAAC,MAAc,EAAE,IAAa,EAAE,OAAO,GAA2B,EAAE;IACvF,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,CAAA;AACpH,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAmC,EACnC,EAA0B,EAC1B,gBAAoC;IAEpC,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,eAAe;QAAE,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;IAClF,IAAI,gBAAgB,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,CAAC,sBAAsB,gBAAgB,GAAG,CAAC,CAAA;IAC1F,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAA;IAC9E,OAAO,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC,CAAA;AACnH,CAAC;AAED,kCAAkC;AAElC,kFAAkF;AAClF,SAAS,6BAA6B;IACpC,OAAO,GAAG,gCAAgC,GAAG,QAAQ,EAAE,CAAA;AACzD,CAAC;AAED,SAAS,UAAU,CAAC,KAA2B,EAAE,GAAQ;IACvD,OAAO,KAAK,CAAC,QAAQ,IAAI,GAAG,GAAG,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAA;AACrD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAA2B,EAAE,GAAQ;IAChE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACjD,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,gCAAgC,GAAG,IAAI,EAAE,CAAA;AACvE,CAAC;AAED,SAAS,yBAAyB,CAAC,KAA2B,EAAE,GAAQ;IACtE,MAAM,GAAG,GAA4B;QACnC,QAAQ,EAAE,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC;QAChC,qBAAqB,EAAE,CAAC,GAAG,KAAK,CAAC,oBAAoB,CAAC;QACtD,wBAAwB,EAAE,CAAC,QAAQ,CAAC;KACrC,CAAA;IACD,IAAI,KAAK,CAAC,eAAe;QAAE,GAAG,CAAC,gBAAgB,GAAG,CAAC,GAAG,KAAK,CAAC,eAAe,CAAC,CAAA;IAC5E,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY,EAAE,OAAe,EAAE,IAAc,EAAE,EAAE,GAA2B,IAAI;IAChG,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAA;AACxG,CAAC;AAED,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAA;AAEnC,SAAS,SAAS,CAAC,IAAgB;IACjC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAA;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAA;IACjB,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAa;IAC9B,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACjF,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,IAA0C,CAAA;IACjE,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAC3C,OAAO,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACrE,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAa;IACrC,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAClF,MAAM,IAAI,GAAI,IAA6D,CAAC,MAAM,EAAE,KAAK,CAAA;IACzF,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,CAAA;AACtF,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;AACzE,CAAC","sourcesContent":["import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport type { AddressInfo } from \"node:net\"\nimport { Readable } from \"node:stream\"\nimport { createMcpHandler, 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 { 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\"\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}\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 /** 진행 중인 요청 abort · SDK handler 정리 */\n close(): 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 */\n fetch(request: Request): Promise<Response>\n /** SDK handler 정리 */\n close(): Promise<void>\n}\n\n/**\n * Streamable HTTP (2026-07-28) 의 transport 무관 처리 (Web Request → Response).\n * 순서: 경로 (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 const factory = createMcpServerFactory({\n registry: options.registry,\n ...(options.app ? { app: options.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 transport: \"http\",\n })\n const report = reporter(options.onerror)\n const sdkOptions = options.onerror ? { onerror: report } : {}\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): 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 (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 handler: McpHttpHandler = !legacy && hasProgressToken(parsedBody) ? sseHandler : jsonHandler\n return handler.fetch(sdkRequest, {\n authInfo: principalAuthInfo(principal),\n ...(parsedBody !== undefined ? { parsedBody } : {}),\n })\n }\n\n return {\n async fetch(request) {\n try {\n return await handle(request)\n } catch (error) {\n report(error)\n return jsonResponse(500, rpcError(-32_603, \"Internal server error\"))\n }\n },\n async close() {\n await Promise.all([jsonHandler.close(), sseHandler.close()])\n },\n }\n}\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.close = async () => {\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"]}
|
package/dist/mcp/install.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export interface McpInstallOptions {
|
|
2
2
|
/** MCP 클라이언트에 등록할 서버 이름. 기본 "mext" */
|
|
3
3
|
name?: string;
|
|
4
|
-
/** Streamable HTTP 엔드포인트. 기본 http://127.0.0.1:3100/mcp */
|
|
5
|
-
url?: string;
|
|
4
|
+
/** Streamable HTTP 엔드포인트. 기본 http://127.0.0.1:3100/mcp. false = HTTP 안내 생략 (로컬 bin 은 stdio 만) */
|
|
5
|
+
url?: string | false;
|
|
6
6
|
/**
|
|
7
7
|
* stdio 실행 명령. 기본 "npx mext dev --stdio" (운영 = "npx mext start --stdio"). false = stdio 안내 생략 (고객 CLI 는 원격만)
|
|
8
8
|
*/
|
package/dist/mcp/install.js
CHANGED
|
@@ -8,6 +8,24 @@ export function mcpInstallText(options = {}) {
|
|
|
8
8
|
const url = options.url ?? `http://${DEFAULT_HOST}:${DEFAULT_PORT}${MCP_PATH}`;
|
|
9
9
|
const stdio = options.stdioCommand === undefined ? "npx mext dev --stdio" : options.stdioCommand;
|
|
10
10
|
const n = shellQuote(name);
|
|
11
|
+
if (url === false) {
|
|
12
|
+
if (stdio === false)
|
|
13
|
+
throw new TypeError("mcpInstallText: url and stdioCommand cannot both be false");
|
|
14
|
+
const [command, ...args] = stdio.split(" ");
|
|
15
|
+
return [
|
|
16
|
+
`Register the "${name}" MCP server with your MCP client.`,
|
|
17
|
+
"",
|
|
18
|
+
"Claude Code (stdio, runs commands locally):",
|
|
19
|
+
` claude mcp add ${n} -- ${stdio}`,
|
|
20
|
+
"",
|
|
21
|
+
"Other MCP clients (JSON config):",
|
|
22
|
+
...JSON.stringify({ mcpServers: { [name]: { command, args } } }, null, 2)
|
|
23
|
+
.split("\n")
|
|
24
|
+
.map((l) => ` ${l}`),
|
|
25
|
+
"",
|
|
26
|
+
"This command only prints instructions; it does not modify client configuration files.",
|
|
27
|
+
].join("\n");
|
|
28
|
+
}
|
|
11
29
|
const lines = [
|
|
12
30
|
`Register the "${name}" MCP server with your MCP client.`,
|
|
13
31
|
"",
|