@obov/mext 0.3.1 → 0.5.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.js +2 -1
- package/dist/build-cli.js.map +1 -1
- package/dist/build.js +67 -4
- package/dist/build.js.map +1 -1
- package/dist/cli/ask-url.d.ts +16 -0
- package/dist/cli/ask-url.js +27 -0
- package/dist/cli/ask-url.js.map +1 -0
- package/dist/cli/build.js +9 -2
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev-server.d.ts +7 -1
- package/dist/cli/dev-server.js +15 -2
- package/dist/cli/dev-server.js.map +1 -1
- package/dist/cli/dev.js +22 -7
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/login.d.ts +5 -0
- package/dist/cli/login.js +11 -7
- package/dist/cli/login.js.map +1 -1
- package/dist/cli/logout.js +4 -6
- package/dist/cli/logout.js.map +1 -1
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/run.js +7 -3
- package/dist/cli/run.js.map +1 -1
- package/dist/client/cache.d.ts +14 -4
- package/dist/client/cache.js +10 -3
- package/dist/client/cache.js.map +1 -1
- package/dist/client/main.js +11 -10
- package/dist/client/main.js.map +1 -1
- package/dist/client/manifest.d.ts +13 -1
- package/dist/client/manifest.js +43 -0
- package/dist/client/manifest.js.map +1 -1
- package/dist/client/runner.d.ts +3 -1
- package/dist/client/runner.js +80 -19
- package/dist/client/runner.js.map +1 -1
- package/dist/client/task.d.ts +47 -0
- package/dist/client/task.js +126 -0
- package/dist/client/task.js.map +1 -0
- package/dist/command.d.ts +30 -3
- package/dist/command.js +16 -0
- package/dist/command.js.map +1 -1
- package/dist/config.d.ts +40 -6
- package/dist/config.js +57 -8
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +3 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/instrumentation.d.ts +14 -2
- package/dist/instrumentation.js +12 -4
- package/dist/instrumentation.js.map +1 -1
- package/dist/invoke.d.ts +38 -0
- package/dist/invoke.js +72 -3
- package/dist/invoke.js.map +1 -1
- package/dist/local-bin.js +5 -3
- package/dist/local-bin.js.map +1 -1
- package/dist/manifest.d.ts +48 -3
- package/dist/manifest.js +14 -3
- package/dist/manifest.js.map +1 -1
- package/dist/mcp/constants.d.ts +4 -0
- package/dist/mcp/constants.js +4 -0
- package/dist/mcp/constants.js.map +1 -1
- package/dist/mcp/dispatch.d.ts +21 -7
- package/dist/mcp/dispatch.js +42 -7
- package/dist/mcp/dispatch.js.map +1 -1
- package/dist/mcp/http.d.ts +23 -5
- package/dist/mcp/http.js +64 -9
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/index.d.ts +14 -6
- package/dist/mcp/index.js +7 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/install.d.ts +1 -1
- package/dist/mcp/install.js +3 -2
- package/dist/mcp/install.js.map +1 -1
- package/dist/mcp/mrtr.d.ts +40 -8
- package/dist/mcp/mrtr.js +32 -11
- package/dist/mcp/mrtr.js.map +1 -1
- package/dist/mcp/prompts.d.ts +25 -0
- package/dist/mcp/prompts.js +164 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/resources.d.ts +48 -0
- package/dist/mcp/resources.js +142 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +30 -5
- package/dist/mcp/server.js +143 -16
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.d.ts +5 -0
- package/dist/mcp/stdio.js +41 -3
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/mcp/subscriptions.d.ts +61 -0
- package/dist/mcp/subscriptions.js +188 -0
- package/dist/mcp/subscriptions.js.map +1 -0
- package/dist/mcp/tasks.d.ts +127 -0
- package/dist/mcp/tasks.js +448 -0
- package/dist/mcp/tasks.js.map +1 -0
- package/dist/module-files.d.ts +24 -0
- package/dist/module-files.js +97 -0
- package/dist/module-files.js.map +1 -0
- package/dist/prompt.d.ts +133 -0
- package/dist/prompt.js +222 -0
- package/dist/prompt.js.map +1 -0
- package/dist/registry.d.ts +6 -0
- package/dist/registry.js.map +1 -1
- package/dist/remote/client.d.ts +17 -1
- package/dist/remote/client.js +18 -2
- package/dist/remote/client.js.map +1 -1
- package/dist/resource.d.ts +169 -0
- package/dist/resource.js +301 -0
- package/dist/resource.js.map +1 -0
- package/dist/route.d.ts +71 -0
- package/dist/route.js +280 -0
- package/dist/route.js.map +1 -0
- package/dist/runtime.d.ts +10 -0
- package/dist/runtime.js +11 -0
- package/dist/runtime.js.map +1 -0
- package/dist/start.d.ts +14 -3
- package/dist/start.js +76 -11
- package/dist/start.js.map +1 -1
- package/dist/state.d.ts +38 -0
- package/dist/state.js +98 -0
- package/dist/state.js.map +1 -0
- package/package.json +3 -2
package/dist/mcp/server.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { CLIENT_CAPABILITIES_META_KEY, McpServer, ProtocolError, ProtocolErrorCode, } from "@modelcontextprotocol/server";
|
|
2
3
|
import { ANONYMOUS } from "../principal.js";
|
|
3
4
|
import { VERSION } from "../index.js";
|
|
4
5
|
import { describeCommand, manifestHash } from "../manifest.js";
|
|
5
|
-
import {
|
|
6
|
+
import { resourceEntries } from "../resource.js";
|
|
7
|
+
import { MANIFEST_HASH_META_KEY, TOOLS_META_KEY } from "./constants.js";
|
|
6
8
|
import { callDispatcher, dispatcherTools } from "./dispatch.js";
|
|
7
9
|
import { createRequestStateSigner } from "./mrtr.js";
|
|
10
|
+
import { installCompletionHandler, installPromptHandlers } from "./prompts.js";
|
|
11
|
+
import { installResourceHandlers, RESOURCE_READ_CACHE } from "./resources.js";
|
|
12
|
+
import { installSubscriptions, resourceUpdatedFn } from "./subscriptions.js";
|
|
13
|
+
import { createTaskRuntime, declaresTasks, hasTaskCommands, installTaskHandlers } from "./tasks.js";
|
|
8
14
|
/** tools/list · server/discover 캐시 힌트. 도구 정의는 principal 과 무관하게 고정 → public */
|
|
9
15
|
export const TOOLS_LIST_CACHE = { ttlMs: 300_000, cacheScope: "public" };
|
|
16
|
+
/** resources/list · templates/list 캐시 힌트. ttlMs = tools/list, 결과가 scopes 로 주체별 필터 → private */
|
|
17
|
+
export const RESOURCE_LIST_CACHE = { ttlMs: TOOLS_LIST_CACHE.ttlMs, cacheScope: "private" };
|
|
10
18
|
/**
|
|
11
19
|
* progressToken 있는 요청의 주기 progress 간격 (ms). 마지막 알림 후 이 시간 동안 알림이 없으면 보낸다.
|
|
12
20
|
* TS SDK 클라이언트 기본 타임아웃 60초 · 프록시 유휴 타임아웃 (보통 60초) 보다 충분히 짧게
|
|
@@ -22,33 +30,116 @@ export function createMcpServerFactory(options) {
|
|
|
22
30
|
const serverInfo = { name: options.name ?? "mext", version: options.version ?? VERSION };
|
|
23
31
|
const signer = createRequestStateSigner(options.requestStateKey === undefined ? {} : { key: options.requestStateKey });
|
|
24
32
|
const meta = { [MANIFEST_HASH_META_KEY]: options.manifestHash ?? registryManifestHash(options.registry) };
|
|
33
|
+
const discoverMeta = { ...meta, [TOOLS_META_KEY]: options.tools ?? "execute" };
|
|
25
34
|
const experimental = options.capabilities?.experimental;
|
|
35
|
+
const resourceUpdated = resourceUpdatedFn(options.state);
|
|
26
36
|
const capabilities = {
|
|
27
37
|
...(experimental && Object.keys(experimental).length > 0 ? { experimental: { ...experimental } } : {}),
|
|
28
38
|
tools: { listChanged: false },
|
|
29
39
|
};
|
|
30
|
-
|
|
40
|
+
const tasks = options.state?.store && hasTaskCommands(options.registry)
|
|
41
|
+
? createTaskRuntime({ state: options.state, meta, ...(options.taskTiming ? { timing: options.taskTiming } : {}) })
|
|
42
|
+
: undefined;
|
|
43
|
+
const factory = (requestContext) => {
|
|
31
44
|
const principal = resolvePrincipal(options.principal, requestContext);
|
|
45
|
+
const waitUntil = waitUntilFromAuthInfo(requestContext.authInfo);
|
|
46
|
+
// 생성 가능 = runtime + (process 실행 또는 요청의 waitUntil)
|
|
47
|
+
const taskCreation = tasks && (options.taskExecution !== "waitUntil" || waitUntil) ? { runtime: tasks, waitUntil } : undefined;
|
|
32
48
|
const server = new McpServer(serverInfo, {
|
|
33
49
|
capabilities,
|
|
34
50
|
...(options.instructions !== undefined && options.instructions !== "" ? { instructions: options.instructions } : {}),
|
|
35
|
-
cacheHints: {
|
|
51
|
+
cacheHints: {
|
|
52
|
+
"tools/list": TOOLS_LIST_CACHE,
|
|
53
|
+
"server/discover": TOOLS_LIST_CACHE,
|
|
54
|
+
"resources/list": RESOURCE_LIST_CACHE,
|
|
55
|
+
"resources/templates/list": RESOURCE_LIST_CACHE,
|
|
56
|
+
"resources/read": RESOURCE_READ_CACHE,
|
|
57
|
+
"prompts/list": TOOLS_LIST_CACHE,
|
|
58
|
+
},
|
|
36
59
|
});
|
|
37
|
-
withDiscoverMeta(server,
|
|
60
|
+
withDiscoverMeta(server, discoverMeta);
|
|
61
|
+
if (tasks) {
|
|
62
|
+
rethrowStoreErrors(server);
|
|
63
|
+
skipTaskOutputValidation(server);
|
|
64
|
+
}
|
|
65
|
+
const handlerOptions = {
|
|
66
|
+
principal,
|
|
67
|
+
app: getApp,
|
|
68
|
+
...(options.instrumentation ? { instrumentation: options.instrumentation, traceContext: traceCarrier } : {}),
|
|
69
|
+
...(options.transport ? { transport: options.transport } : {}),
|
|
70
|
+
};
|
|
71
|
+
if (options.registry.resources)
|
|
72
|
+
installResourceHandlers(server, { ...handlerOptions, resources: options.registry.resources });
|
|
73
|
+
if (options.registry.prompts)
|
|
74
|
+
installPromptHandlers(server, { ...handlerOptions, prompts: options.registry.prompts });
|
|
75
|
+
installCompletionHandler(server, {
|
|
76
|
+
...handlerOptions,
|
|
77
|
+
...(options.registry.prompts ? { prompts: options.registry.prompts } : {}),
|
|
78
|
+
...(options.registry.resources ? { resources: options.registry.resources } : {}),
|
|
79
|
+
});
|
|
80
|
+
installSubscriptions(server, {
|
|
81
|
+
state: options.state,
|
|
82
|
+
resources: options.registry.resources,
|
|
83
|
+
era: requestContext.era,
|
|
84
|
+
// HTTP = 진입점이 SDK bus 로 전달 (createMcpFetchHandler), stdio = 연결 인스턴스가 전달
|
|
85
|
+
deliver: options.transport === "stdio",
|
|
86
|
+
...(options.onerror ? { onerror: options.onerror } : {}),
|
|
87
|
+
});
|
|
88
|
+
if (tasks)
|
|
89
|
+
installTaskHandlers(server, tasks, principal, taskCreation !== undefined);
|
|
38
90
|
for (const tool of tools) {
|
|
39
91
|
server.registerTool(tool.name, {
|
|
40
92
|
title: tool.annotations.title,
|
|
41
93
|
description: tool.description,
|
|
42
94
|
inputSchema: passthroughSchema(tool.inputSchema),
|
|
95
|
+
// 반환값 검증은 invoke (output safeParse, 실패 = EXECUTION_ERROR). SDK 검증은 통과시킨다
|
|
96
|
+
...(tool.outputSchema ? { outputSchema: passthroughSchema(tool.outputSchema) } : {}),
|
|
43
97
|
annotations: tool.annotations,
|
|
44
|
-
|
|
98
|
+
...(tool._meta ? { _meta: tool._meta } : {}),
|
|
99
|
+
}, async (args, ctx) => withMeta(await runTool(options, tools, tool, args, ctx, principal, getApp, signer, resourceUpdated, taskCreation), meta));
|
|
45
100
|
}
|
|
46
101
|
return server;
|
|
47
102
|
};
|
|
103
|
+
return Object.assign(factory, { close: async () => tasks?.close() });
|
|
48
104
|
}
|
|
49
|
-
/** registry 명령어
|
|
105
|
+
/** registry 명령어 메타데이터 · 자원 uri · 프롬프트 이름 · 스키마의 manifestHash (빌드 manifest 와 같은 계산) */
|
|
50
106
|
export function registryManifestHash(registry) {
|
|
51
|
-
|
|
107
|
+
const resources = registry.resources ? resourceEntries(registry.resources).map((r) => r.uri) : [];
|
|
108
|
+
const prompts = [...(registry.prompts?.values() ?? [])].map((p) => ({ name: p.name, argsSchema: p.argsSchema }));
|
|
109
|
+
return manifestHash([...registry.commands.values()].map(describeCommand), { resources, prompts });
|
|
110
|
+
}
|
|
111
|
+
/** runTool 이 store 예외를 알리는 오류 message (프로세스별 임의 값, 핸들러 오류와 겹치지 않는다) */
|
|
112
|
+
const STORE_ERROR_SENTINEL = `mext.state-store-error.${randomUUID()}`;
|
|
113
|
+
/**
|
|
114
|
+
* McpServer 는 도구 핸들러 예외를 isError 결과로 바꾼다 (createToolError). store 예외만 JSON-RPC -32603 으로 내보내도록
|
|
115
|
+
* 인스턴스의 createToolError 를 감싼다 (공개 API 에 도구 오류 → 프로토콜 오류 경로 없음)
|
|
116
|
+
*/
|
|
117
|
+
function rethrowStoreErrors(server) {
|
|
118
|
+
const target = server;
|
|
119
|
+
const original = target.createToolError;
|
|
120
|
+
if (typeof original !== "function")
|
|
121
|
+
return;
|
|
122
|
+
target.createToolError = function (message) {
|
|
123
|
+
if (message === STORE_ERROR_SENTINEL)
|
|
124
|
+
throw new ProtocolError(ProtocolErrorCode.InternalError, "State store error");
|
|
125
|
+
return original.call(server, message);
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* McpServer 는 outputSchema 가 있는 도구 (command 노출) 의 결과에 structuredContent 를 요구한다 (validateToolOutput).
|
|
130
|
+
* CreateTaskResult (resultType "task") 는 structuredContent 가 없으므로 검증을 건너뛴다. 완료 result 는 tasks/get 으로
|
|
131
|
+
* 전달되고 mext 가 output 을 이미 검증했다 (invoke). createToolError 와 같은 인스턴스 seam (공개 API 에 옵션 없음)
|
|
132
|
+
*/
|
|
133
|
+
function skipTaskOutputValidation(server) {
|
|
134
|
+
const target = server;
|
|
135
|
+
const original = target.validateToolOutput;
|
|
136
|
+
if (typeof original !== "function")
|
|
137
|
+
return;
|
|
138
|
+
target.validateToolOutput = function (tool, result, name) {
|
|
139
|
+
if (result?.resultType === "task")
|
|
140
|
+
return Promise.resolve();
|
|
141
|
+
return original.call(server, tool, result, name);
|
|
142
|
+
};
|
|
52
143
|
}
|
|
53
144
|
/** 결과 _meta 에 mext 키 추가 (SDK 의 serverInfo 등 기존 _meta 유지) */
|
|
54
145
|
function withMeta(result, meta) {
|
|
@@ -67,33 +158,52 @@ function withDiscoverMeta(server, meta) {
|
|
|
67
158
|
return withMeta(original.call(inner), meta);
|
|
68
159
|
};
|
|
69
160
|
}
|
|
70
|
-
async function runTool(options, tools, tool, args, ctx, principal, getApp, signer) {
|
|
161
|
+
async function runTool(options, tools, tool, args, ctx, principal, getApp, signer, resourceUpdated, taskCreation) {
|
|
71
162
|
const progress = progressReporter(ctx, options.progressInterval ?? PROGRESS_INTERVAL_MS);
|
|
72
163
|
try {
|
|
73
164
|
const app = await getApp();
|
|
165
|
+
const round = inputRound(ctx);
|
|
166
|
+
// tasks (§12.6): 확장을 선언한 요청만. 분리 실행 = 별도 signal (R2: 응답 종료 ≠ 취소)
|
|
167
|
+
const task = taskCreation && declaresTasks(clientCapabilities(ctx))
|
|
168
|
+
? taskCreation.runtime.request({
|
|
169
|
+
principal,
|
|
170
|
+
modes: { form: round.elicitation, url: round.urlElicitation === true },
|
|
171
|
+
...(taskCreation.waitUntil ? { waitUntil: taskCreation.waitUntil } : {}),
|
|
172
|
+
})
|
|
173
|
+
: undefined;
|
|
74
174
|
const result = await callDispatcher(options.registry, tool, args, {
|
|
75
175
|
principal,
|
|
76
176
|
signal: ctx.mcpReq.signal,
|
|
77
177
|
...(progress ? { progress: progress.report } : {}),
|
|
78
178
|
app,
|
|
79
179
|
tools,
|
|
80
|
-
input: { ...
|
|
180
|
+
input: { ...round, signer },
|
|
181
|
+
resourceUpdated,
|
|
81
182
|
...(options.instrumentation ? { instrumentation: options.instrumentation, traceContext: traceCarrier(ctx) } : {}),
|
|
82
183
|
...(options.transport ? { transport: options.transport } : {}),
|
|
184
|
+
...(task ? { detach: task.detach } : {}),
|
|
83
185
|
});
|
|
186
|
+
// task 생성 중 store 예외 = 요청 실패 (-32603, §12.1). McpServer 의 도구 오류 변환을 rethrowStoreErrors 가 건너뛴다
|
|
187
|
+
if (task?.failure !== undefined)
|
|
188
|
+
throw new Error(STORE_ERROR_SENTINEL);
|
|
84
189
|
return result;
|
|
85
190
|
}
|
|
86
191
|
finally {
|
|
87
192
|
progress?.stop();
|
|
88
193
|
}
|
|
89
194
|
}
|
|
90
|
-
/**
|
|
91
|
-
function
|
|
195
|
+
/** 요청 _meta 의 clientCapabilities (2025 레거시 = envelope 없음 → undefined) */
|
|
196
|
+
function clientCapabilities(ctx) {
|
|
92
197
|
const envelope = ctx.mcpReq.envelope;
|
|
93
|
-
|
|
198
|
+
return envelope?.[CLIENT_CAPABILITIES_META_KEY];
|
|
199
|
+
}
|
|
200
|
+
/** 요청의 MRTR 입력: elicitation (form · url) 선언 · inputResponses · requestState (SDK 가 params 에서 분리) */
|
|
201
|
+
function inputRound(ctx) {
|
|
202
|
+
const capabilities = clientCapabilities(ctx);
|
|
94
203
|
const state = ctx.mcpReq.requestState();
|
|
95
204
|
return {
|
|
96
205
|
elicitation: declaresFormElicitation(capabilities?.elicitation),
|
|
206
|
+
urlElicitation: declaresUrlElicitation(capabilities?.elicitation),
|
|
97
207
|
...(ctx.mcpReq.inputResponses ? { inputResponses: ctx.mcpReq.inputResponses } : {}),
|
|
98
208
|
...(typeof state === "string" ? { requestState: state } : {}),
|
|
99
209
|
};
|
|
@@ -116,6 +226,12 @@ function declaresFormElicitation(value) {
|
|
|
116
226
|
const modes = value;
|
|
117
227
|
return modes.form !== undefined || modes.url === undefined;
|
|
118
228
|
}
|
|
229
|
+
/** elicitation.url 선언 (URL 모드는 명시 선언만) */
|
|
230
|
+
function declaresUrlElicitation(value) {
|
|
231
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
232
|
+
return false;
|
|
233
|
+
return value.url !== undefined;
|
|
234
|
+
}
|
|
119
235
|
/**
|
|
120
236
|
* ctx.progress → notifications/progress. 요청에 progressToken 이 있을 때만 (없으면 undefined = 무시).
|
|
121
237
|
* HTTP 는 progressToken 이 있는 요청을 SSE 로 응답하므로 알림이 스트림으로 간다.
|
|
@@ -160,9 +276,20 @@ function increase(value) {
|
|
|
160
276
|
}
|
|
161
277
|
/* principal 은 SDK 의 pass-through authInfo 로 transport → factory 에 전달 */
|
|
162
278
|
const PRINCIPAL_KEY = "mext.principal";
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
279
|
+
const WAIT_UNTIL_KEY = "mext.waitUntil";
|
|
280
|
+
/**
|
|
281
|
+
* HTTP transport: 검증된 principal → SDK authInfo (토큰 원문은 담지 않는다).
|
|
282
|
+
* waitUntil = handler.js 요청의 응답 후 실행 유지 수단 (tasks, §10) 을 같은 경로로 factory 에 전달
|
|
283
|
+
*/
|
|
284
|
+
export function principalAuthInfo(principal, waitUntil) {
|
|
285
|
+
const extra = { [PRINCIPAL_KEY]: principal };
|
|
286
|
+
if (waitUntil)
|
|
287
|
+
extra[WAIT_UNTIL_KEY] = waitUntil;
|
|
288
|
+
return { token: "", clientId: principal.id, scopes: [...principal.scopes], extra };
|
|
289
|
+
}
|
|
290
|
+
function waitUntilFromAuthInfo(authInfo) {
|
|
291
|
+
const value = authInfo?.extra?.[WAIT_UNTIL_KEY];
|
|
292
|
+
return typeof value === "function" ? value : undefined;
|
|
166
293
|
}
|
|
167
294
|
export function principalFromAuthInfo(authInfo) {
|
|
168
295
|
const value = authInfo?.extra?.[PRINCIPAL_KEY];
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CLIENT_CAPABILITIES_META_KEY,\n McpServer,\n type AuthInfo,\n type CallToolResult,\n type InputRequiredResult,\n type McpRequestContext,\n type McpServerFactory,\n type ServerContext,\n type StandardSchemaWithJSON,\n} from \"@modelcontextprotocol/server\"\nimport type { MextApp, ProgressUpdate } from \"../command.ts\"\nimport type { McpCapabilities } from \"../config.ts\"\nimport type { Instrumentation, Transport } from \"../instrumentation.ts\"\nimport { ANONYMOUS, type Principal } from \"../principal.ts\"\nimport type { JsonSchema, Registry } from \"../registry.ts\"\nimport { VERSION } from \"../index.ts\"\nimport { describeCommand, manifestHash } from \"../manifest.ts\"\nimport { MANIFEST_HASH_META_KEY } from \"./constants.ts\"\nimport { callDispatcher, dispatcherTools, type DispatcherTool, type ToolExposure } from \"./dispatch.ts\"\nimport { createRequestStateSigner, type InputRound, type RequestStateSigner } from \"./mrtr.ts\"\n\ntype ServerCapabilities = NonNullable<NonNullable<ConstructorParameters<typeof McpServer>[1]>[\"capabilities\"]>\n\n/** tools/list · server/discover 캐시 힌트. 도구 정의는 principal 과 무관하게 고정 → public */\nexport const TOOLS_LIST_CACHE = { ttlMs: 300_000, cacheScope: \"public\" } as const\n\n/**\n * progressToken 있는 요청의 주기 progress 간격 (ms). 마지막 알림 후 이 시간 동안 알림이 없으면 보낸다.\n * TS SDK 클라이언트 기본 타임아웃 60초 · 프록시 유휴 타임아웃 (보통 60초) 보다 충분히 짧게\n */\nexport const PROGRESS_INTERVAL_MS = 15_000\n\n\nexport interface McpCoreOptions {\n registry: Registry\n /** ctx.app 생성. 처음 필요할 때 한 번 호출 (실패하면 다음 요청에서 재시도) */\n app?: () => MextApp | Promise<MextApp>\n /** 기본 execute */\n tools?: ToolExposure\n /** serverInfo.name. 기본 \"mext\" */\n name?: string\n /** initialize · server/discover 결과 instructions */\n instructions?: string\n /** 서버 capabilities 에 병합 (experimental). tools capability 는 mext 가 고정 */\n capabilities?: McpCapabilities\n /** serverInfo.version. 기본 mext 버전 */\n version?: string\n /**\n * 요청 주체. 기본 = HTTP transport 가 authInfo 로 넘긴 principal, 없으면 ANONYMOUS.\n * stdio = localPrincipal()\n */\n principal?: Principal | ((ctx: McpRequestContext) => Principal)\n /**\n * MRTR requestState 서명 키 (HMAC-SHA256, 32바이트 이상). requestState 는 2번째 이후 ctx.ask 에서만 쓴다.\n * 기본 = 프로세스별 임의 키. 여러 인스턴스 · 재시작을 넘는 재시도에는 공유 키를 지정한다\n */\n requestStateKey?: string | Uint8Array\n /** 주기 progress 간격 (ms). 기본 PROGRESS_INTERVAL_MS, 0 = 끔 */\n progressInterval?: number\n /** loadInstrumentation 결과 (onCommandError · span) */\n instrumentation?: Instrumentation\n /** onCommandError · span 의 transport. HTTP · stdio 어댑터가 지정 */\n transport?: Transport\n /**\n * _meta[\"dev.mext/manifestHash\"] 값. 기본 = registry 명령어로 계산 (mext dev = 스캔 결과).\n * mext start = manifest.json 의 manifestHash (같은 함수로 계산한 값)\n */\n manifestHash?: string\n}\n\n/**\n * Registry → MCP 서버 factory (SDK McpServerFactory). 요청 (HTTP) · 연결 (stdio) 마다 새 McpServer.\n * HTTP 의 createMcpHandler 와 stdio 의 serveStdio 가 같은 factory 를 쓴다.\n */\nexport function createMcpServerFactory(options: McpCoreOptions): McpServerFactory {\n const tools = dispatcherTools(options.registry, options.tools ?? \"execute\")\n const getApp = memoizeApp(options.app)\n const serverInfo = { name: options.name ?? \"mext\", version: options.version ?? VERSION }\n const signer = createRequestStateSigner(options.requestStateKey === undefined ? {} : { key: options.requestStateKey })\n const meta = { [MANIFEST_HASH_META_KEY]: options.manifestHash ?? registryManifestHash(options.registry) }\n const experimental = options.capabilities?.experimental\n const capabilities = {\n ...(experimental && Object.keys(experimental).length > 0 ? { experimental: { ...experimental } } : {}),\n tools: { listChanged: false },\n } as ServerCapabilities\n return (requestContext) => {\n const principal = resolvePrincipal(options.principal, requestContext)\n const server = new McpServer(serverInfo, {\n capabilities,\n ...(options.instructions !== undefined && options.instructions !== \"\" ? { instructions: options.instructions } : {}),\n cacheHints: { \"tools/list\": TOOLS_LIST_CACHE, \"server/discover\": TOOLS_LIST_CACHE },\n })\n withDiscoverMeta(server, meta)\n for (const tool of tools) {\n server.registerTool(\n tool.name,\n {\n title: tool.annotations.title,\n description: tool.description,\n inputSchema: passthroughSchema(tool.inputSchema),\n annotations: tool.annotations,\n },\n async (args, ctx) => withMeta(await runTool(options, tools, tool, args, ctx, principal, getApp, signer), meta),\n )\n }\n return server\n }\n}\n\n/** registry 명령어 메타데이터의 manifestHash (빌드 manifest 와 같은 계산) */\nexport function registryManifestHash(registry: Registry): string {\n return manifestHash([...registry.commands.values()].map(describeCommand))\n}\n\n/** 결과 _meta 에 mext 키 추가 (SDK 의 serverInfo 등 기존 _meta 유지) */\nfunction withMeta<T extends { _meta?: Record<string, unknown> }>(result: T, meta: Record<string, unknown>): T {\n return { ...result, _meta: { ...result._meta, ...meta } }\n}\n\n/**\n * server/discover 결과에 _meta 추가. SDK 의 discover handler 는 McpServer 생성 후 transport 진입점이\n * (재)설치하고 매번 server._ondiscover() 를 부르므로 인스턴스 메서드를 감싼다 (공개 API 에 discover _meta 옵션 없음)\n */\nfunction withDiscoverMeta(server: McpServer, meta: Record<string, unknown>): void {\n const inner = server.server as unknown as { _ondiscover?: () => Record<string, unknown> }\n const original = inner._ondiscover\n if (typeof original !== \"function\") return\n inner._ondiscover = function (this: unknown) {\n return withMeta(original.call(inner) as { _meta?: Record<string, unknown> }, meta)\n }\n}\n\nasync function runTool(\n options: McpCoreOptions,\n tools: readonly DispatcherTool[],\n tool: DispatcherTool,\n args: unknown,\n ctx: ServerContext,\n principal: Principal,\n getApp: () => Promise<MextApp>,\n signer: RequestStateSigner,\n): Promise<CallToolResult | InputRequiredResult> {\n const progress = progressReporter(ctx, options.progressInterval ?? PROGRESS_INTERVAL_MS)\n try {\n const app = await getApp()\n const result = await callDispatcher(options.registry, tool, args, {\n principal,\n signal: ctx.mcpReq.signal,\n ...(progress ? { progress: progress.report } : {}),\n app,\n tools,\n input: { ...inputRound(ctx), signer },\n ...(options.instrumentation ? { instrumentation: options.instrumentation, traceContext: traceCarrier(ctx) } : {}),\n ...(options.transport ? { transport: options.transport } : {}),\n })\n return result as CallToolResult | InputRequiredResult\n } finally {\n progress?.stop()\n }\n}\n\n/** 요청의 MRTR 입력: elicitation (form) 선언 · inputResponses · requestState (SDK 가 params 에서 분리) */\nfunction inputRound(ctx: ServerContext): InputRound {\n const envelope = ctx.mcpReq.envelope as Record<string, unknown> | undefined\n const capabilities = envelope?.[CLIENT_CAPABILITIES_META_KEY] as { elicitation?: unknown } | undefined\n const state = ctx.mcpReq.requestState()\n return {\n elicitation: declaresFormElicitation(capabilities?.elicitation),\n ...(ctx.mcpReq.inputResponses ? { inputResponses: ctx.mcpReq.inputResponses } : {}),\n ...(typeof state === \"string\" ? { requestState: state } : {}),\n }\n}\n\n/** D6: params._meta 의 W3C trace context (traceparent · tracestate · baggage). 등록된 propagator 가 해석 */\nfunction traceCarrier(ctx: ServerContext): Record<string, string> | undefined {\n const meta = ctx.mcpReq._meta as Record<string, unknown> | undefined\n let carrier: Record<string, string> | undefined\n for (const key of [\"traceparent\", \"tracestate\", \"baggage\"]) {\n const value = meta?.[key]\n if (typeof value === \"string\") (carrier ??= {})[key] = value\n }\n return carrier\n}\n\n/** elicitation.form 선언 또는 mode 없는 elicitation: {} (SDK 와 같은 해석). 2025 레거시 요청 = envelope 없음 → false */\nfunction declaresFormElicitation(value: unknown): boolean {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false\n const modes = value as { form?: unknown; url?: unknown }\n return modes.form !== undefined || modes.url === undefined\n}\n\n/**\n * ctx.progress → notifications/progress. 요청에 progressToken 이 있을 때만 (없으면 undefined = 무시).\n * HTTP 는 progressToken 이 있는 요청을 SSE 로 응답하므로 알림이 스트림으로 간다.\n * 주기 progress: 마지막 알림 후 intervalMs 동안 알림이 없으면 마지막 total · message 를 다시 보낸다 (keepalive).\n * progress 값은 항상 증가 (사양 MUST): 증가하지 않는 값 · keepalive 는 직전 값에 아주 작은 값을 더한다.\n */\nfunction progressReporter(\n ctx: ServerContext,\n intervalMs: number,\n): { report: (update: ProgressUpdate) => void; stop: () => void } | undefined {\n const token = ctx.mcpReq._meta?.progressToken\n if (token === undefined) return undefined\n let last: ProgressUpdate | undefined\n let timer: ReturnType<typeof setTimeout> | undefined\n let stopped = false\n const schedule = () => {\n if (timer !== undefined) clearTimeout(timer)\n if (intervalMs > 0 && !stopped) timer = setTimeout(() => report({ ...(last ?? { progress: 0 }) }), intervalMs)\n }\n const report = (update: ProgressUpdate) => {\n if (stopped || ctx.mcpReq.signal.aborted) return\n const progress = last === undefined || update.progress > last.progress ? update.progress : increase(last.progress)\n last = { progress, ...(update.total !== undefined ? { total: update.total } : {}), ...(update.message !== undefined ? { message: update.message } : {}) }\n const params: Record<string, unknown> = { progressToken: token, ...last }\n void ctx.mcpReq.notify({ method: \"notifications/progress\", params }).catch(() => {})\n schedule()\n }\n schedule()\n return {\n report,\n stop() {\n stopped = true\n if (timer !== undefined) clearTimeout(timer)\n },\n }\n}\n\n/** 직전 값보다 큰 가장 가까운 값 (표시에는 드러나지 않는 크기) */\nfunction increase(value: number): number {\n return value + Math.max(Math.abs(value), 1) * 1e-9\n}\n\n/* principal 은 SDK 의 pass-through authInfo 로 transport → factory 에 전달 */\n\nconst PRINCIPAL_KEY = \"mext.principal\"\n\n/** HTTP transport: 검증된 principal → SDK authInfo (토큰 원문은 담지 않는다) */\nexport function principalAuthInfo(principal: Principal): AuthInfo {\n return { token: \"\", clientId: principal.id, scopes: [...principal.scopes], extra: { [PRINCIPAL_KEY]: principal } }\n}\n\nexport function principalFromAuthInfo(authInfo: AuthInfo | undefined): Principal | undefined {\n const value = authInfo?.extra?.[PRINCIPAL_KEY]\n return isPrincipal(value) ? value : undefined\n}\n\nfunction resolvePrincipal(option: McpCoreOptions[\"principal\"], ctx: McpRequestContext): Principal {\n if (typeof option === \"function\") return option(ctx)\n if (option) return option\n return principalFromAuthInfo(ctx.authInfo) ?? ANONYMOUS\n}\n\nfunction isPrincipal(value: unknown): value is Principal {\n const p = value as Partial<Principal> | undefined\n return typeof p?.id === \"string\" && typeof p.kind === \"string\" && Array.isArray(p.scopes)\n}\n\nfunction memoizeApp(factory: McpCoreOptions[\"app\"]): () => Promise<MextApp> {\n if (!factory) return async () => ({}) as MextApp\n let pending: Promise<MextApp> | undefined\n return () => {\n pending ??= Promise.resolve()\n .then(factory)\n .catch((error: unknown) => {\n pending = undefined\n throw error\n })\n return pending\n }\n}\n\n/**\n * 고정 JSON Schema 를 그대로 광고하고 검증은 하지 않는 Standard Schema.\n * dispatcher 인자 검증은 callDispatcher 가 구조화 오류 (INVALID_ARGUMENT) 로 수행한다.\n */\nfunction passthroughSchema(schema: JsonSchema): StandardSchemaWithJSON<Record<string, unknown>> {\n return {\n \"~standard\": {\n version: 1,\n vendor: \"mext\",\n validate: (value: unknown) => ({ value: value as Record<string, unknown> }),\n jsonSchema: { input: () => schema, output: () => schema },\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\"\nimport {\n CLIENT_CAPABILITIES_META_KEY,\n McpServer,\n ProtocolError,\n ProtocolErrorCode,\n type AuthInfo,\n type CallToolResult,\n type InputRequiredResult,\n type McpRequestContext,\n type McpServerFactory,\n type ServerContext,\n type StandardSchemaWithJSON,\n} from \"@modelcontextprotocol/server\"\nimport type { MextApp, ProgressUpdate } from \"../command.ts\"\nimport type { McpCapabilities } from \"../config.ts\"\nimport type { Instrumentation, Transport } from \"../instrumentation.ts\"\nimport { ANONYMOUS, type Principal } from \"../principal.ts\"\nimport type { JsonSchema, Registry } from \"../registry.ts\"\nimport { VERSION } from \"../index.ts\"\nimport { describeCommand, manifestHash } from \"../manifest.ts\"\nimport { resourceEntries } from \"../resource.ts\"\nimport { MANIFEST_HASH_META_KEY, TOOLS_META_KEY } from \"./constants.ts\"\nimport { callDispatcher, dispatcherTools, type DispatcherTool, type ToolExposure } from \"./dispatch.ts\"\nimport { createRequestStateSigner, type InputRound, type RequestStateSigner } from \"./mrtr.ts\"\nimport { installCompletionHandler, installPromptHandlers } from \"./prompts.ts\"\nimport { installResourceHandlers, RESOURCE_READ_CACHE } from \"./resources.ts\"\nimport { installSubscriptions, resourceUpdatedFn } from \"./subscriptions.ts\"\nimport type { MextState } from \"../state.ts\"\nimport { createTaskRuntime, declaresTasks, hasTaskCommands, installTaskHandlers, type TaskRuntime, type TaskTiming } from \"./tasks.ts\"\n\ntype ServerCapabilities = NonNullable<NonNullable<ConstructorParameters<typeof McpServer>[1]>[\"capabilities\"]>\n\n/** tools/list · server/discover 캐시 힌트. 도구 정의는 principal 과 무관하게 고정 → public */\nexport const TOOLS_LIST_CACHE = { ttlMs: 300_000, cacheScope: \"public\" } as const\n\n/** resources/list · templates/list 캐시 힌트. ttlMs = tools/list, 결과가 scopes 로 주체별 필터 → private */\nexport const RESOURCE_LIST_CACHE = { ttlMs: TOOLS_LIST_CACHE.ttlMs, cacheScope: \"private\" } as const\n\n/**\n * progressToken 있는 요청의 주기 progress 간격 (ms). 마지막 알림 후 이 시간 동안 알림이 없으면 보낸다.\n * TS SDK 클라이언트 기본 타임아웃 60초 · 프록시 유휴 타임아웃 (보통 60초) 보다 충분히 짧게\n */\nexport const PROGRESS_INTERVAL_MS = 15_000\n\n\nexport interface McpCoreOptions {\n registry: Registry\n /** ctx.app 생성. 처음 필요할 때 한 번 호출 (실패하면 다음 요청에서 재시도) */\n app?: () => MextApp | Promise<MextApp>\n /** 기본 execute. command = 명령어별 도구 (§12.2) */\n tools?: ToolExposure\n /** serverInfo.name. 기본 \"mext\" */\n name?: string\n /** initialize · server/discover 결과 instructions */\n instructions?: string\n /** 서버 capabilities 에 병합 (experimental). tools capability 는 mext 가 고정 */\n capabilities?: McpCapabilities\n /** serverInfo.version. 기본 mext 버전 */\n version?: string\n /**\n * 요청 주체. 기본 = HTTP transport 가 authInfo 로 넘긴 principal, 없으면 ANONYMOUS.\n * stdio = localPrincipal()\n */\n principal?: Principal | ((ctx: McpRequestContext) => Principal)\n /**\n * MRTR requestState 서명 키 (HMAC-SHA256, 32바이트 이상). requestState 는 2번째 이후 ctx.ask 에서만 쓴다.\n * 기본 = 프로세스별 임의 키. 여러 인스턴스 · 재시작을 넘는 재시도에는 공유 키를 지정한다\n */\n requestStateKey?: string | Uint8Array\n /** 주기 progress 간격 (ms). 기본 PROGRESS_INTERVAL_MS, 0 = 끔 */\n progressInterval?: number\n /** loadInstrumentation 결과 (onCommandError · span) */\n instrumentation?: Instrumentation\n /** onCommandError · span 의 transport. HTTP · stdio 어댑터가 지정 */\n transport?: Transport\n /**\n * _meta[\"dev.mext/manifestHash\"] 값. 기본 = registry 명령어로 계산 (mext dev = 스캔 결과).\n * mext start = manifest.json 의 manifestHash (같은 함수로 계산한 값)\n */\n manifestHash?: string\n /** 주입 state (§12.1). 자원 구독 (resources.subscribe · ctx.resourceUpdated, §12.5). 없음 = stateless */\n state?: MextState\n /** 응답에 영향 없는 오류 보고 (state.bus 구독 실패) */\n onerror?: (error: Error) => void\n /** task 시간 간격 (테스트). 기본 TASK_TIMING */\n taskTiming?: Partial<TaskTiming>\n /**\n * task 실행 유지 수단. process (기본) = 이 프로세스가 응답 후 계속 실행 (node 서버 · stdio),\n * waitUntil = 요청이 waitUntil 을 넘긴 경우만 task (handler.js, §10). 없으면 확장 미선언 · 동기 실행\n */\n taskExecution?: \"process\" | \"waitUntil\"\n}\n\n/** createMcpServerFactory 결과. close = 실행 중 task 취소 · cancelled 기록 (상한 5초, §12.6) */\nexport type MextServerFactory = McpServerFactory & { close(): Promise<void> }\n\n/**\n * Registry → MCP 서버 factory (SDK McpServerFactory). 요청 (HTTP) · 연결 (stdio) 마다 새 McpServer.\n * HTTP 의 createMcpHandler 와 stdio 의 serveStdio 가 같은 factory 를 쓴다.\n */\nexport function createMcpServerFactory(options: McpCoreOptions): MextServerFactory {\n const tools = dispatcherTools(options.registry, options.tools ?? \"execute\")\n const getApp = memoizeApp(options.app)\n const serverInfo = { name: options.name ?? \"mext\", version: options.version ?? VERSION }\n const signer = createRequestStateSigner(options.requestStateKey === undefined ? {} : { key: options.requestStateKey })\n const meta = { [MANIFEST_HASH_META_KEY]: options.manifestHash ?? registryManifestHash(options.registry) }\n const discoverMeta = { ...meta, [TOOLS_META_KEY]: options.tools ?? \"execute\" }\n const experimental = options.capabilities?.experimental\n const resourceUpdated = resourceUpdatedFn(options.state)\n const capabilities = {\n ...(experimental && Object.keys(experimental).length > 0 ? { experimental: { ...experimental } } : {}),\n tools: { listChanged: false },\n } as ServerCapabilities\n const tasks =\n options.state?.store && hasTaskCommands(options.registry)\n ? createTaskRuntime({ state: options.state, meta, ...(options.taskTiming ? { timing: options.taskTiming } : {}) })\n : undefined\n const factory = (requestContext: McpRequestContext): McpServer => {\n const principal = resolvePrincipal(options.principal, requestContext)\n const waitUntil = waitUntilFromAuthInfo(requestContext.authInfo)\n // 생성 가능 = runtime + (process 실행 또는 요청의 waitUntil)\n const taskCreation = tasks && (options.taskExecution !== \"waitUntil\" || waitUntil) ? { runtime: tasks, waitUntil } : undefined\n const server = new McpServer(serverInfo, {\n capabilities,\n ...(options.instructions !== undefined && options.instructions !== \"\" ? { instructions: options.instructions } : {}),\n cacheHints: {\n \"tools/list\": TOOLS_LIST_CACHE,\n \"server/discover\": TOOLS_LIST_CACHE,\n \"resources/list\": RESOURCE_LIST_CACHE,\n \"resources/templates/list\": RESOURCE_LIST_CACHE,\n \"resources/read\": RESOURCE_READ_CACHE,\n \"prompts/list\": TOOLS_LIST_CACHE,\n },\n })\n withDiscoverMeta(server, discoverMeta)\n if (tasks) {\n rethrowStoreErrors(server)\n skipTaskOutputValidation(server)\n }\n const handlerOptions = {\n principal,\n app: getApp,\n ...(options.instrumentation ? { instrumentation: options.instrumentation, traceContext: traceCarrier } : {}),\n ...(options.transport ? { transport: options.transport } : {}),\n }\n if (options.registry.resources) installResourceHandlers(server, { ...handlerOptions, resources: options.registry.resources })\n if (options.registry.prompts) installPromptHandlers(server, { ...handlerOptions, prompts: options.registry.prompts })\n installCompletionHandler(server, {\n ...handlerOptions,\n ...(options.registry.prompts ? { prompts: options.registry.prompts } : {}),\n ...(options.registry.resources ? { resources: options.registry.resources } : {}),\n })\n installSubscriptions(server, {\n state: options.state,\n resources: options.registry.resources,\n era: requestContext.era,\n // HTTP = 진입점이 SDK bus 로 전달 (createMcpFetchHandler), stdio = 연결 인스턴스가 전달\n deliver: options.transport === \"stdio\",\n ...(options.onerror ? { onerror: options.onerror } : {}),\n })\n if (tasks) installTaskHandlers(server, tasks, principal, taskCreation !== undefined)\n for (const tool of tools) {\n server.registerTool(\n tool.name,\n {\n title: tool.annotations.title,\n description: tool.description,\n inputSchema: passthroughSchema(tool.inputSchema),\n // 반환값 검증은 invoke (output safeParse, 실패 = EXECUTION_ERROR). SDK 검증은 통과시킨다\n ...(tool.outputSchema ? { outputSchema: passthroughSchema(tool.outputSchema) } : {}),\n annotations: tool.annotations,\n ...(tool._meta ? { _meta: tool._meta } : {}),\n },\n async (args, ctx) => withMeta(await runTool(options, tools, tool, args, ctx, principal, getApp, signer, resourceUpdated, taskCreation), meta),\n )\n }\n return server\n }\n return Object.assign(factory, { close: async () => tasks?.close() })\n}\n\n/** registry 명령어 메타데이터 · 자원 uri · 프롬프트 이름 · 스키마의 manifestHash (빌드 manifest 와 같은 계산) */\nexport function registryManifestHash(registry: Registry): string {\n const resources = registry.resources ? resourceEntries(registry.resources).map((r) => r.uri) : []\n const prompts = [...(registry.prompts?.values() ?? [])].map((p) => ({ name: p.name, argsSchema: p.argsSchema }))\n return manifestHash([...registry.commands.values()].map(describeCommand), { resources, prompts })\n}\n\n/** runTool 이 store 예외를 알리는 오류 message (프로세스별 임의 값, 핸들러 오류와 겹치지 않는다) */\nconst STORE_ERROR_SENTINEL = `mext.state-store-error.${randomUUID()}`\n\n/**\n * McpServer 는 도구 핸들러 예외를 isError 결과로 바꾼다 (createToolError). store 예외만 JSON-RPC -32603 으로 내보내도록\n * 인스턴스의 createToolError 를 감싼다 (공개 API 에 도구 오류 → 프로토콜 오류 경로 없음)\n */\nfunction rethrowStoreErrors(server: McpServer): void {\n const target = server as unknown as { createToolError?: (message: string) => unknown }\n const original = target.createToolError\n if (typeof original !== \"function\") return\n target.createToolError = function (this: unknown, message: string) {\n if (message === STORE_ERROR_SENTINEL) throw new ProtocolError(ProtocolErrorCode.InternalError, \"State store error\")\n return original.call(server, message)\n }\n}\n\n/**\n * McpServer 는 outputSchema 가 있는 도구 (command 노출) 의 결과에 structuredContent 를 요구한다 (validateToolOutput).\n * CreateTaskResult (resultType \"task\") 는 structuredContent 가 없으므로 검증을 건너뛴다. 완료 result 는 tasks/get 으로\n * 전달되고 mext 가 output 을 이미 검증했다 (invoke). createToolError 와 같은 인스턴스 seam (공개 API 에 옵션 없음)\n */\nfunction skipTaskOutputValidation(server: McpServer): void {\n const target = server as unknown as { validateToolOutput?: (tool: unknown, result: unknown, name: string) => Promise<void> }\n const original = target.validateToolOutput\n if (typeof original !== \"function\") return\n target.validateToolOutput = function (this: unknown, tool: unknown, result: unknown, name: string) {\n if ((result as { resultType?: unknown } | undefined)?.resultType === \"task\") return Promise.resolve()\n return original.call(server, tool, result, name)\n }\n}\n\n/** 결과 _meta 에 mext 키 추가 (SDK 의 serverInfo 등 기존 _meta 유지) */\nfunction withMeta<T extends { _meta?: Record<string, unknown> }>(result: T, meta: Record<string, unknown>): T {\n return { ...result, _meta: { ...result._meta, ...meta } }\n}\n\n/**\n * server/discover 결과에 _meta 추가. SDK 의 discover handler 는 McpServer 생성 후 transport 진입점이\n * (재)설치하고 매번 server._ondiscover() 를 부르므로 인스턴스 메서드를 감싼다 (공개 API 에 discover _meta 옵션 없음)\n */\nfunction withDiscoverMeta(server: McpServer, meta: Record<string, unknown>): void {\n const inner = server.server as unknown as { _ondiscover?: () => Record<string, unknown> }\n const original = inner._ondiscover\n if (typeof original !== \"function\") return\n inner._ondiscover = function (this: unknown) {\n return withMeta(original.call(inner) as { _meta?: Record<string, unknown> }, meta)\n }\n}\n\nasync function runTool(\n options: McpCoreOptions,\n tools: readonly DispatcherTool[],\n tool: DispatcherTool,\n args: unknown,\n ctx: ServerContext,\n principal: Principal,\n getApp: () => Promise<MextApp>,\n signer: RequestStateSigner,\n resourceUpdated: (uri: string) => Promise<void>,\n taskCreation: { runtime: TaskRuntime; waitUntil: ((promise: Promise<unknown>) => void) | undefined } | undefined,\n): Promise<CallToolResult | InputRequiredResult> {\n const progress = progressReporter(ctx, options.progressInterval ?? PROGRESS_INTERVAL_MS)\n try {\n const app = await getApp()\n const round = inputRound(ctx)\n // tasks (§12.6): 확장을 선언한 요청만. 분리 실행 = 별도 signal (R2: 응답 종료 ≠ 취소)\n const task =\n taskCreation && declaresTasks(clientCapabilities(ctx))\n ? taskCreation.runtime.request({\n principal,\n modes: { form: round.elicitation, url: round.urlElicitation === true },\n ...(taskCreation.waitUntil ? { waitUntil: taskCreation.waitUntil } : {}),\n })\n : undefined\n const result = await callDispatcher(options.registry, tool, args, {\n principal,\n signal: ctx.mcpReq.signal,\n ...(progress ? { progress: progress.report } : {}),\n app,\n tools,\n input: { ...round, signer },\n resourceUpdated,\n ...(options.instrumentation ? { instrumentation: options.instrumentation, traceContext: traceCarrier(ctx) } : {}),\n ...(options.transport ? { transport: options.transport } : {}),\n ...(task ? { detach: task.detach } : {}),\n })\n // task 생성 중 store 예외 = 요청 실패 (-32603, §12.1). McpServer 의 도구 오류 변환을 rethrowStoreErrors 가 건너뛴다\n if (task?.failure !== undefined) throw new Error(STORE_ERROR_SENTINEL)\n return result as CallToolResult | InputRequiredResult\n } finally {\n progress?.stop()\n }\n}\n\n/** 요청 _meta 의 clientCapabilities (2025 레거시 = envelope 없음 → undefined) */\nfunction clientCapabilities(ctx: ServerContext): Record<string, unknown> | undefined {\n const envelope = ctx.mcpReq.envelope as Record<string, unknown> | undefined\n return envelope?.[CLIENT_CAPABILITIES_META_KEY] as Record<string, unknown> | undefined\n}\n\n/** 요청의 MRTR 입력: elicitation (form · url) 선언 · inputResponses · requestState (SDK 가 params 에서 분리) */\nfunction inputRound(ctx: ServerContext): InputRound {\n const capabilities = clientCapabilities(ctx) as { elicitation?: unknown } | undefined\n const state = ctx.mcpReq.requestState()\n return {\n elicitation: declaresFormElicitation(capabilities?.elicitation),\n urlElicitation: declaresUrlElicitation(capabilities?.elicitation),\n ...(ctx.mcpReq.inputResponses ? { inputResponses: ctx.mcpReq.inputResponses } : {}),\n ...(typeof state === \"string\" ? { requestState: state } : {}),\n }\n}\n\n/** D6: params._meta 의 W3C trace context (traceparent · tracestate · baggage). 등록된 propagator 가 해석 */\nfunction traceCarrier(ctx: ServerContext): Record<string, string> | undefined {\n const meta = ctx.mcpReq._meta as Record<string, unknown> | undefined\n let carrier: Record<string, string> | undefined\n for (const key of [\"traceparent\", \"tracestate\", \"baggage\"]) {\n const value = meta?.[key]\n if (typeof value === \"string\") (carrier ??= {})[key] = value\n }\n return carrier\n}\n\n/** elicitation.form 선언 또는 mode 없는 elicitation: {} (SDK 와 같은 해석). 2025 레거시 요청 = envelope 없음 → false */\nfunction declaresFormElicitation(value: unknown): boolean {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false\n const modes = value as { form?: unknown; url?: unknown }\n return modes.form !== undefined || modes.url === undefined\n}\n\n/** elicitation.url 선언 (URL 모드는 명시 선언만) */\nfunction declaresUrlElicitation(value: unknown): boolean {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false\n return (value as { url?: unknown }).url !== undefined\n}\n\n/**\n * ctx.progress → notifications/progress. 요청에 progressToken 이 있을 때만 (없으면 undefined = 무시).\n * HTTP 는 progressToken 이 있는 요청을 SSE 로 응답하므로 알림이 스트림으로 간다.\n * 주기 progress: 마지막 알림 후 intervalMs 동안 알림이 없으면 마지막 total · message 를 다시 보낸다 (keepalive).\n * progress 값은 항상 증가 (사양 MUST): 증가하지 않는 값 · keepalive 는 직전 값에 아주 작은 값을 더한다.\n */\nfunction progressReporter(\n ctx: ServerContext,\n intervalMs: number,\n): { report: (update: ProgressUpdate) => void; stop: () => void } | undefined {\n const token = ctx.mcpReq._meta?.progressToken\n if (token === undefined) return undefined\n let last: ProgressUpdate | undefined\n let timer: ReturnType<typeof setTimeout> | undefined\n let stopped = false\n const schedule = () => {\n if (timer !== undefined) clearTimeout(timer)\n if (intervalMs > 0 && !stopped) timer = setTimeout(() => report({ ...(last ?? { progress: 0 }) }), intervalMs)\n }\n const report = (update: ProgressUpdate) => {\n if (stopped || ctx.mcpReq.signal.aborted) return\n const progress = last === undefined || update.progress > last.progress ? update.progress : increase(last.progress)\n last = { progress, ...(update.total !== undefined ? { total: update.total } : {}), ...(update.message !== undefined ? { message: update.message } : {}) }\n const params: Record<string, unknown> = { progressToken: token, ...last }\n void ctx.mcpReq.notify({ method: \"notifications/progress\", params }).catch(() => {})\n schedule()\n }\n schedule()\n return {\n report,\n stop() {\n stopped = true\n if (timer !== undefined) clearTimeout(timer)\n },\n }\n}\n\n/** 직전 값보다 큰 가장 가까운 값 (표시에는 드러나지 않는 크기) */\nfunction increase(value: number): number {\n return value + Math.max(Math.abs(value), 1) * 1e-9\n}\n\n/* principal 은 SDK 의 pass-through authInfo 로 transport → factory 에 전달 */\n\nconst PRINCIPAL_KEY = \"mext.principal\"\nconst WAIT_UNTIL_KEY = \"mext.waitUntil\"\n\n/**\n * HTTP transport: 검증된 principal → SDK authInfo (토큰 원문은 담지 않는다).\n * waitUntil = handler.js 요청의 응답 후 실행 유지 수단 (tasks, §10) 을 같은 경로로 factory 에 전달\n */\nexport function principalAuthInfo(principal: Principal, waitUntil?: (promise: Promise<unknown>) => void): AuthInfo {\n const extra: Record<string, unknown> = { [PRINCIPAL_KEY]: principal }\n if (waitUntil) extra[WAIT_UNTIL_KEY] = waitUntil\n return { token: \"\", clientId: principal.id, scopes: [...principal.scopes], extra }\n}\n\nfunction waitUntilFromAuthInfo(authInfo: AuthInfo | undefined): ((promise: Promise<unknown>) => void) | undefined {\n const value = authInfo?.extra?.[WAIT_UNTIL_KEY]\n return typeof value === \"function\" ? (value as (promise: Promise<unknown>) => void) : undefined\n}\n\nexport function principalFromAuthInfo(authInfo: AuthInfo | undefined): Principal | undefined {\n const value = authInfo?.extra?.[PRINCIPAL_KEY]\n return isPrincipal(value) ? value : undefined\n}\n\nfunction resolvePrincipal(option: McpCoreOptions[\"principal\"], ctx: McpRequestContext): Principal {\n if (typeof option === \"function\") return option(ctx)\n if (option) return option\n return principalFromAuthInfo(ctx.authInfo) ?? ANONYMOUS\n}\n\nfunction isPrincipal(value: unknown): value is Principal {\n const p = value as Partial<Principal> | undefined\n return typeof p?.id === \"string\" && typeof p.kind === \"string\" && Array.isArray(p.scopes)\n}\n\nfunction memoizeApp(factory: McpCoreOptions[\"app\"]): () => Promise<MextApp> {\n if (!factory) return async () => ({}) as MextApp\n let pending: Promise<MextApp> | undefined\n return () => {\n pending ??= Promise.resolve()\n .then(factory)\n .catch((error: unknown) => {\n pending = undefined\n throw error\n })\n return pending\n }\n}\n\n/**\n * 고정 JSON Schema 를 그대로 광고하고 검증은 하지 않는 Standard Schema.\n * dispatcher 인자 검증은 callDispatcher 가 구조화 오류 (INVALID_ARGUMENT) 로 수행한다.\n */\nfunction passthroughSchema(schema: JsonSchema): StandardSchemaWithJSON<Record<string, unknown>> {\n return {\n \"~standard\": {\n version: 1,\n vendor: \"mext\",\n validate: (value: unknown) => ({ value: value as Record<string, unknown> }),\n jsonSchema: { input: () => schema, output: () => schema },\n },\n }\n}\n"]}
|
package/dist/mcp/stdio.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { Registry } from "../registry.ts";
|
|
|
7
7
|
import type { Instrumentation } from "../instrumentation.ts";
|
|
8
8
|
import type { ToolExposure } from "./dispatch.ts";
|
|
9
9
|
import { type McpCoreOptions } from "./server.ts";
|
|
10
|
+
import type { MextState } from "../state.ts";
|
|
10
11
|
export interface McpStdioOptions {
|
|
11
12
|
registry: Registry;
|
|
12
13
|
app?: () => MextApp | Promise<MextApp>;
|
|
@@ -47,6 +48,10 @@ export interface McpStdioOptions {
|
|
|
47
48
|
instrumentation?: Instrumentation;
|
|
48
49
|
/** _meta["dev.mext/manifestHash"]. McpCoreOptions.manifestHash (기본 = registry 로 계산) */
|
|
49
50
|
manifestHash?: string;
|
|
51
|
+
/** 주입 state (§12.1). 자원 구독 · ctx.resourceUpdated (§12.5) */
|
|
52
|
+
state?: MextState;
|
|
53
|
+
/** McpCoreOptions.taskTiming (테스트) */
|
|
54
|
+
taskTiming?: McpCoreOptions["taskTiming"];
|
|
50
55
|
}
|
|
51
56
|
export interface McpStdioServer {
|
|
52
57
|
/** stdin EOF · stdout 오류 · close() 로 연결이 끝나면 resolve */
|
package/dist/mcp/stdio.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
+
import { Console } from "node:console";
|
|
1
2
|
import { Writable } from "node:stream";
|
|
2
3
|
import { serveStdio, StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
4
|
+
import { isBun } from "../runtime.js";
|
|
3
5
|
import { localPrincipal } from "../principal.js";
|
|
4
6
|
import { createMcpServerFactory } from "./server.js";
|
|
7
|
+
import { narrowListenRequest } from "./subscriptions.js";
|
|
5
8
|
/**
|
|
6
9
|
* MCP stdio (2026-07-28 · 2025 레거시 모두 SDK serveStdio). 줄 단위 JSON-RPC, 연결 하나 = McpServer 하나.
|
|
7
10
|
* notifications/cancelled → ctx.signal abort (SDK). stdin EOF = 연결 종료, 진행 중 요청은 abort 되고 응답하지 않는다.
|
|
8
11
|
* 헤더 검증 · Origin · 바인딩 · Authorization 은 해당 없음. 주체 = 로컬 (kind local).
|
|
9
12
|
*/
|
|
10
13
|
export function serveMcpStdio(options) {
|
|
14
|
+
const principal = options.principal ?? localPrincipal();
|
|
11
15
|
const core = createMcpServerFactory({
|
|
12
16
|
registry: options.registry,
|
|
13
|
-
principal
|
|
17
|
+
principal,
|
|
14
18
|
...(options.app ? { app: options.app } : {}),
|
|
15
19
|
...(options.tools ? { tools: options.tools } : {}),
|
|
16
20
|
...(options.name ? { name: options.name } : {}),
|
|
@@ -20,6 +24,9 @@ export function serveMcpStdio(options) {
|
|
|
20
24
|
...(options.progressInterval !== undefined ? { progressInterval: options.progressInterval } : {}),
|
|
21
25
|
...(options.instrumentation ? { instrumentation: options.instrumentation } : {}),
|
|
22
26
|
...(options.manifestHash !== undefined ? { manifestHash: options.manifestHash } : {}),
|
|
27
|
+
...(options.state ? { state: options.state } : {}),
|
|
28
|
+
...(options.onerror ? { onerror: options.onerror } : {}),
|
|
29
|
+
...(options.taskTiming ? { taskTiming: options.taskTiming } : {}),
|
|
23
30
|
transport: "stdio",
|
|
24
31
|
});
|
|
25
32
|
const onConnect = options.onConnect;
|
|
@@ -43,7 +50,8 @@ export function serveMcpStdio(options) {
|
|
|
43
50
|
if (finishing)
|
|
44
51
|
return;
|
|
45
52
|
finishing = true;
|
|
46
|
-
|
|
53
|
+
// 실행 중 task = 취소 · cancelled 기록 (상한 5초, §12.6)
|
|
54
|
+
void Promise.all([waitCleanups(settled, report), core.close().catch(report)]).then(() => resolveClosed());
|
|
47
55
|
};
|
|
48
56
|
const wrapClose = () => {
|
|
49
57
|
const sdkOnClose = transport.onclose;
|
|
@@ -81,8 +89,15 @@ export function serveMcpStdio(options) {
|
|
|
81
89
|
}
|
|
82
90
|
else {
|
|
83
91
|
handle = serveStdio(factory, options.onerror ? { transport, onerror: options.onerror } : { transport });
|
|
84
|
-
// serveStdio 가 onclose 를 동기적으로 설정한 뒤 감싼다 (stdin 이벤트는 비동기)
|
|
92
|
+
// serveStdio 가 onclose · onmessage 를 동기적으로 설정한 뒤 감싼다 (stdin 이벤트는 비동기)
|
|
85
93
|
wrapClose();
|
|
94
|
+
// subscriptions/listen (§12.5): SDK StdioListenRouter 가 ack 하기 전에 notifications 를 허용 부분으로
|
|
95
|
+
const subscriptions = { state: options.state, resources: options.registry.resources };
|
|
96
|
+
const sdkOnMessage = transport.onmessage;
|
|
97
|
+
transport.onmessage = (message) => {
|
|
98
|
+
const listen = narrowListenRequest(message, subscriptions, principal);
|
|
99
|
+
sdkOnMessage?.((listen ?? message));
|
|
100
|
+
};
|
|
86
101
|
}
|
|
87
102
|
return {
|
|
88
103
|
closed,
|
|
@@ -197,6 +212,7 @@ export function redirectStdout() {
|
|
|
197
212
|
const original = stdout.write;
|
|
198
213
|
const toStderr = (...args) => process.stderr.write.apply(process.stderr, args);
|
|
199
214
|
stdout.write = toStderr;
|
|
215
|
+
const restoreConsole = !isBun ? () => { } : redirectBunConsole(toStderr);
|
|
200
216
|
// EPIPE 등은 wire 의 write 콜백으로 transport 에 전달된다. process.stdout 의 미처리 error 로 죽지 않게
|
|
201
217
|
const ignore = () => { };
|
|
202
218
|
stdout.on("error", ignore);
|
|
@@ -215,8 +231,30 @@ export function redirectStdout() {
|
|
|
215
231
|
restored = true;
|
|
216
232
|
if (stdout.write === toStderr)
|
|
217
233
|
stdout.write = original;
|
|
234
|
+
restoreConsole();
|
|
218
235
|
stdout.off("error", ignore);
|
|
219
236
|
},
|
|
220
237
|
};
|
|
221
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* Bun 의 console 은 process.stdout.write 를 거치지 않고 fd 1 에 직접 쓴다.
|
|
241
|
+
* console 메서드를 stderr 로 쓰는 Console 의 메서드로 바꾸고 (Bun 전용 console.write 포함), 원복 함수를 반환한다.
|
|
242
|
+
* Node 의 console 은 process.stdout.write 를 거치므로 바꾸지 않는다 (group 들여쓰기 등 기존 출력 유지)
|
|
243
|
+
*/
|
|
244
|
+
function redirectBunConsole(toStderr) {
|
|
245
|
+
const target = console;
|
|
246
|
+
const stderrConsole = new Console({ stdout: process.stderr, stderr: process.stderr });
|
|
247
|
+
const saved = new Map();
|
|
248
|
+
for (const key of Object.keys(target)) {
|
|
249
|
+
const replacement = key === "write" ? toStderr : typeof stderrConsole[key] === "function" ? stderrConsole[key].bind(stderrConsole) : undefined;
|
|
250
|
+
if (typeof target[key] !== "function" || key === "Console" || replacement === undefined)
|
|
251
|
+
continue;
|
|
252
|
+
saved.set(key, target[key]);
|
|
253
|
+
target[key] = replacement;
|
|
254
|
+
}
|
|
255
|
+
return () => {
|
|
256
|
+
for (const [key, value] of saved)
|
|
257
|
+
target[key] = value;
|
|
258
|
+
};
|
|
259
|
+
}
|
|
222
260
|
//# sourceMappingURL=stdio.js.map
|
package/dist/mcp/stdio.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Readable } from \"node:stream\"\nimport { Writable } from \"node:stream\"\nimport type { McpServer, McpServerFactory } from \"@modelcontextprotocol/server\"\nimport { serveStdio, StdioServerTransport } from \"@modelcontextprotocol/server/stdio\"\nimport type { MextApp } from \"../command.ts\"\nimport type { McpCapabilities, McpConnectHandler, McpConnection } from \"../config.ts\"\nimport { localPrincipal, type Principal } from \"../principal.ts\"\nimport type { Registry } from \"../registry.ts\"\nimport type { Instrumentation } from \"../instrumentation.ts\"\nimport type { ToolExposure } from \"./dispatch.ts\"\nimport { createMcpServerFactory, type McpCoreOptions } from \"./server.ts\"\n\nexport interface McpStdioOptions {\n registry: Registry\n app?: () => MextApp | Promise<MextApp>\n tools?: ToolExposure\n /** serverInfo.name. 기본 \"mext\" */\n name?: string\n /** initialize · server/discover 결과 instructions */\n instructions?: string\n /** 서버 capabilities 에 병합 (experimental) */\n capabilities?: McpCapabilities\n /**\n * 연결 하나에 1회 (2025 = notifications/initialized 후, 2026-07-28 = 연결 직후).\n * conn.notify = 요청과 무관한 서버 발신 알림. 반환 함수 = 연결 종료 시 cleanup. 예외 = onerror\n */\n onConnect?: McpConnectHandler\n /**\n * auto = 2026-07-28 · 2025 모두 (SDK serveStdio 가 판별). legacy = 2025 만:\n * server/discover = -32601 → 클라이언트가 initialize 로 재시도 (Claude Code channel 은 2025 연결에서만 전달).\n * 기본 = capabilities.experimental[\"claude/channel\"] 선언 시 legacy, 그 외 auto\n */\n era?: \"auto\" | \"legacy\"\n /** 연결 주체 (로컬 모드). 기본 localPrincipal() */\n principal?: Principal\n /** 기본 process.stdin */\n stdin?: Readable\n /**\n * MCP 메시지 출력. 기본 process.stdout.\n * D4: process.stdout 을 쓰는 경우 redirectStdout() 의 wire 를 넘겨 핸들러 출력이 메시지와 섞이지 않게 한다\n */\n stdout?: Writable\n /** 응답에 영향 없는 오류 보고 (SDK 내부 오류 · 깨진 메시지) */\n onerror?: (error: Error) => void\n /** MRTR requestState 서명 키 (createMcpServerFactory 와 같음) */\n requestStateKey?: McpCoreOptions[\"requestStateKey\"]\n /** 주기 progress 간격 (ms). 0 = 끔 */\n progressInterval?: number\n /** loadInstrumentation 결과 (onCommandError · span, transport = \"stdio\") */\n instrumentation?: Instrumentation\n /** _meta[\"dev.mext/manifestHash\"]. McpCoreOptions.manifestHash (기본 = registry 로 계산) */\n manifestHash?: string\n}\n\nexport interface McpStdioServer {\n /** stdin EOF · stdout 오류 · close() 로 연결이 끝나면 resolve */\n closed: Promise<void>\n close(): Promise<void>\n}\n\n/**\n * MCP stdio (2026-07-28 · 2025 레거시 모두 SDK serveStdio). 줄 단위 JSON-RPC, 연결 하나 = McpServer 하나.\n * notifications/cancelled → ctx.signal abort (SDK). stdin EOF = 연결 종료, 진행 중 요청은 abort 되고 응답하지 않는다.\n * 헤더 검증 · Origin · 바인딩 · Authorization 은 해당 없음. 주체 = 로컬 (kind local).\n */\nexport function serveMcpStdio(options: McpStdioOptions): McpStdioServer {\n const core = createMcpServerFactory({\n registry: options.registry,\n principal: options.principal ?? localPrincipal(),\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: \"stdio\",\n })\n const onConnect = options.onConnect\n const report = (error: unknown): void => options.onerror?.(error instanceof Error ? error : new Error(String(error)))\n /** 인스턴스별 정리 완료 (onConnect settle + cleanup). closed 는 이것들을 기다린다 */\n const settled = new Set<Promise<void>>()\n const factory: McpServerFactory = onConnect\n ? async (ctx) => {\n const server = (await core(ctx)) as McpServer\n settled.add(attachConnection(server, ctx.era, onConnect, report))\n return server\n }\n : core\n const transport = new StdioServerTransport(options.stdin, options.stdout)\n let resolveClosed!: () => void\n const closed = new Promise<void>((resolve) => {\n resolveClosed = resolve\n })\n let finishing = false\n const finish = (): void => {\n if (finishing) return\n finishing = true\n void waitCleanups(settled, report).then(resolveClosed)\n }\n const wrapClose = (): void => {\n const sdkOnClose = transport.onclose\n transport.onclose = () => {\n try {\n sdkOnClose?.()\n } finally {\n finish()\n }\n }\n }\n let handle: { close(): Promise<void> }\n const era = options.era ?? (options.capabilities?.experimental?.[CLAUDE_CHANNEL] !== undefined ? \"legacy\" : \"auto\")\n if (era === \"legacy\") {\n // serveStdio 는 server/discover 를 받으면 2026-07-28 로 고정한다 → 우회.\n // SDK 기본 supportedProtocolVersions = 2025 버전만 → McpServer 생성자가 server/discover 를 등록하지 않는다\n const ready = Promise.resolve(factory({ era: \"legacy\" } as Parameters<McpServerFactory>[0])).then(async (product) => {\n const server = product as McpServer\n server.server.onerror = report\n await server.connect(transport)\n wrapClose()\n return server\n })\n ready.catch((error: unknown) => {\n report(error)\n finish()\n })\n handle = {\n async close() {\n const server = await ready.catch(() => undefined)\n await server?.close()\n },\n }\n } else {\n handle = serveStdio(factory, options.onerror ? { transport, onerror: options.onerror } : { transport })\n // serveStdio 가 onclose 를 동기적으로 설정한 뒤 감싼다 (stdin 이벤트는 비동기)\n wrapClose()\n }\n return {\n closed,\n async close() {\n await handle.close()\n finish()\n await closed\n },\n }\n}\n\n/** Claude Code channel capability. 선언하면 stdio 기본 era = legacy */\nconst CLAUDE_CHANNEL = \"claude/channel\"\n\n/** 연결 종료 후 onConnect cleanup 대기 상한 (ms). 넘으면 오류 보고 후 종료 진행 */\nexport const CLEANUP_TIMEOUT_MS = 5_000\n\nasync function waitCleanups(settled: ReadonlySet<Promise<void>>, report: (error: unknown) => void): Promise<void> {\n if (settled.size === 0) return\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<\"timeout\">((resolve) => {\n timer = setTimeout(() => resolve(\"timeout\"), CLEANUP_TIMEOUT_MS)\n timer.unref?.()\n })\n const result = await Promise.race([Promise.all(settled), timeout])\n clearTimeout(timer)\n if (result === \"timeout\") report(new Error(`mcp.onConnect cleanup did not finish within ${CLEANUP_TIMEOUT_MS}ms`))\n}\n\n/**\n * McpServer 인스턴스 하나 = stdio 연결 하나. onConnect 시점: 2025 = notifications/initialized\n * (initialize 응답 전 알림은 클라이언트가 버릴 수 있음), 2026-07-28 = connect 직후 (handshake 없음).\n * SDK 가 era 판별용 probe 인스턴스를 버리면 그 인스턴스의 onclose 로 cleanup 된다.\n * 반환 = 인스턴스 종료 후 (onConnect settle · cleanup 완료) resolve. 시작 전 종료 = 바로 resolve\n */\nfunction attachConnection(\n server: McpServer,\n era: McpConnection[\"era\"],\n onConnect: McpConnectHandler,\n report: (error: unknown) => void,\n): Promise<void> {\n const inner = server.server\n let connected: Promise<unknown> | undefined\n let resolveDone!: () => void\n const done = new Promise<void>((resolve) => {\n resolveDone = resolve\n })\n let closed = false\n const handlers = new Map<string, (params: Record<string, unknown>) => void | Promise<void>>()\n // SDK 가 등록하지 않은 method 만 fallback 으로 온다 (사양 알림은 SDK handler · era 필터가 먼저)\n inner.fallbackNotificationHandler = async (notification) => {\n const handler = handlers.get(notification.method)\n if (!handler) return\n const params = (notification.params ?? {}) as Record<string, unknown>\n try {\n await handler(params)\n } catch (error) {\n report(error)\n }\n }\n const conn: McpConnection = {\n era,\n notify: (method, params) => inner.notification({ method, ...(params !== undefined ? { params } : {}) } as never),\n onNotification(method, handler) {\n handlers.set(method, handler)\n return () => {\n if (handlers.get(method) === handler) handlers.delete(method)\n }\n },\n }\n const start = (): void => {\n if (connected || closed) return\n connected = Promise.resolve().then(() => onConnect(conn))\n connected.catch(report)\n }\n const previousClose = inner.onclose\n inner.onclose = () => {\n previousClose?.()\n if (closed) return\n closed = true\n if (!connected) return resolveDone()\n connected\n .then(async (cleanup) => {\n if (typeof cleanup === \"function\") await cleanup()\n }, () => {})\n .catch(report)\n .finally(resolveDone)\n }\n if (era === \"legacy\") {\n const previousInit = inner.oninitialized\n inner.oninitialized = () => {\n previousInit?.()\n start()\n }\n } else {\n const connect = server.connect.bind(server)\n server.connect = async (transport) => {\n await connect(transport)\n start()\n }\n }\n return done\n}\n\nexport interface StdoutRedirect {\n /** 원래 process.stdout 으로 쓰는 스트림. MCP transport 전용 */\n wire: Writable\n /** process.stdout.write 원복 */\n restore(): void\n}\n\n/**\n * D4: stdio 모드에서 transport 외의 stdout 쓰기 (console.log · process.stdout.write) 를 stderr 로 돌린다.\n * 반환된 wire 만 실제 stdout 에 쓴다. 명령어 모듈 import 전에 호출해야 top-level 출력도 막는다.\n * 자식 프로세스 · fd 1 직접 쓰기 (fs.writeSync(1)) 는 막지 못한다.\n */\nexport function redirectStdout(): StdoutRedirect {\n const stdout = process.stdout\n const original = stdout.write\n const toStderr = (...args: unknown[]): boolean =>\n (process.stderr.write as (...a: unknown[]) => boolean).apply(process.stderr, args)\n stdout.write = toStderr as typeof stdout.write\n // EPIPE 등은 wire 의 write 콜백으로 transport 에 전달된다. process.stdout 의 미처리 error 로 죽지 않게\n const ignore = (): void => {}\n stdout.on(\"error\", ignore)\n const wire = new Writable({\n write(chunk: Buffer | string, _encoding, callback) {\n const write = original as (chunk: Buffer | string, done: (error?: Error | null) => void) => boolean\n write.call(stdout, chunk, (error) => callback(error ?? null))\n },\n })\n let restored = false\n return {\n wire,\n restore() {\n if (restored) return\n restored = true\n if (stdout.write === (toStderr as typeof stdout.write)) stdout.write = original\n stdout.off(\"error\", ignore)\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/mcp/stdio.ts"],"names":[],"mappings":"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","sourcesContent":["import { Console } from \"node:console\"\nimport type { Readable } from \"node:stream\"\nimport { Writable } from \"node:stream\"\nimport type { McpServer, McpServerFactory } from \"@modelcontextprotocol/server\"\nimport { serveStdio, StdioServerTransport } from \"@modelcontextprotocol/server/stdio\"\nimport type { MextApp } from \"../command.ts\"\nimport { isBun } from \"../runtime.ts\"\nimport type { McpCapabilities, McpConnectHandler, McpConnection } from \"../config.ts\"\nimport { localPrincipal, type Principal } from \"../principal.ts\"\nimport type { Registry } from \"../registry.ts\"\nimport type { Instrumentation } from \"../instrumentation.ts\"\nimport type { ToolExposure } from \"./dispatch.ts\"\nimport { createMcpServerFactory, type McpCoreOptions } from \"./server.ts\"\nimport type { MextState } from \"../state.ts\"\nimport { narrowListenRequest } from \"./subscriptions.ts\"\n\nexport interface McpStdioOptions {\n registry: Registry\n app?: () => MextApp | Promise<MextApp>\n tools?: ToolExposure\n /** serverInfo.name. 기본 \"mext\" */\n name?: string\n /** initialize · server/discover 결과 instructions */\n instructions?: string\n /** 서버 capabilities 에 병합 (experimental) */\n capabilities?: McpCapabilities\n /**\n * 연결 하나에 1회 (2025 = notifications/initialized 후, 2026-07-28 = 연결 직후).\n * conn.notify = 요청과 무관한 서버 발신 알림. 반환 함수 = 연결 종료 시 cleanup. 예외 = onerror\n */\n onConnect?: McpConnectHandler\n /**\n * auto = 2026-07-28 · 2025 모두 (SDK serveStdio 가 판별). legacy = 2025 만:\n * server/discover = -32601 → 클라이언트가 initialize 로 재시도 (Claude Code channel 은 2025 연결에서만 전달).\n * 기본 = capabilities.experimental[\"claude/channel\"] 선언 시 legacy, 그 외 auto\n */\n era?: \"auto\" | \"legacy\"\n /** 연결 주체 (로컬 모드). 기본 localPrincipal() */\n principal?: Principal\n /** 기본 process.stdin */\n stdin?: Readable\n /**\n * MCP 메시지 출력. 기본 process.stdout.\n * D4: process.stdout 을 쓰는 경우 redirectStdout() 의 wire 를 넘겨 핸들러 출력이 메시지와 섞이지 않게 한다\n */\n stdout?: Writable\n /** 응답에 영향 없는 오류 보고 (SDK 내부 오류 · 깨진 메시지) */\n onerror?: (error: Error) => void\n /** MRTR requestState 서명 키 (createMcpServerFactory 와 같음) */\n requestStateKey?: McpCoreOptions[\"requestStateKey\"]\n /** 주기 progress 간격 (ms). 0 = 끔 */\n progressInterval?: number\n /** loadInstrumentation 결과 (onCommandError · span, transport = \"stdio\") */\n instrumentation?: Instrumentation\n /** _meta[\"dev.mext/manifestHash\"]. McpCoreOptions.manifestHash (기본 = registry 로 계산) */\n manifestHash?: string\n /** 주입 state (§12.1). 자원 구독 · ctx.resourceUpdated (§12.5) */\n state?: MextState\n /** McpCoreOptions.taskTiming (테스트) */\n taskTiming?: McpCoreOptions[\"taskTiming\"]\n}\n\nexport interface McpStdioServer {\n /** stdin EOF · stdout 오류 · close() 로 연결이 끝나면 resolve */\n closed: Promise<void>\n close(): Promise<void>\n}\n\n/**\n * MCP stdio (2026-07-28 · 2025 레거시 모두 SDK serveStdio). 줄 단위 JSON-RPC, 연결 하나 = McpServer 하나.\n * notifications/cancelled → ctx.signal abort (SDK). stdin EOF = 연결 종료, 진행 중 요청은 abort 되고 응답하지 않는다.\n * 헤더 검증 · Origin · 바인딩 · Authorization 은 해당 없음. 주체 = 로컬 (kind local).\n */\nexport function serveMcpStdio(options: McpStdioOptions): McpStdioServer {\n const principal = options.principal ?? localPrincipal()\n const core = createMcpServerFactory({\n registry: options.registry,\n principal,\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 ...(options.state ? { state: options.state } : {}),\n ...(options.onerror ? { onerror: options.onerror } : {}),\n ...(options.taskTiming ? { taskTiming: options.taskTiming } : {}),\n transport: \"stdio\",\n })\n const onConnect = options.onConnect\n const report = (error: unknown): void => options.onerror?.(error instanceof Error ? error : new Error(String(error)))\n /** 인스턴스별 정리 완료 (onConnect settle + cleanup). closed 는 이것들을 기다린다 */\n const settled = new Set<Promise<void>>()\n const factory: McpServerFactory = onConnect\n ? async (ctx) => {\n const server = (await core(ctx)) as McpServer\n settled.add(attachConnection(server, ctx.era, onConnect, report))\n return server\n }\n : core\n const transport = new StdioServerTransport(options.stdin, options.stdout)\n let resolveClosed!: () => void\n const closed = new Promise<void>((resolve) => {\n resolveClosed = resolve\n })\n let finishing = false\n const finish = (): void => {\n if (finishing) return\n finishing = true\n // 실행 중 task = 취소 · cancelled 기록 (상한 5초, §12.6)\n void Promise.all([waitCleanups(settled, report), core.close().catch(report)]).then(() => resolveClosed())\n }\n const wrapClose = (): void => {\n const sdkOnClose = transport.onclose\n transport.onclose = () => {\n try {\n sdkOnClose?.()\n } finally {\n finish()\n }\n }\n }\n let handle: { close(): Promise<void> }\n const era = options.era ?? (options.capabilities?.experimental?.[CLAUDE_CHANNEL] !== undefined ? \"legacy\" : \"auto\")\n if (era === \"legacy\") {\n // serveStdio 는 server/discover 를 받으면 2026-07-28 로 고정한다 → 우회.\n // SDK 기본 supportedProtocolVersions = 2025 버전만 → McpServer 생성자가 server/discover 를 등록하지 않는다\n const ready = Promise.resolve(factory({ era: \"legacy\" } as Parameters<McpServerFactory>[0])).then(async (product) => {\n const server = product as McpServer\n server.server.onerror = report\n await server.connect(transport)\n wrapClose()\n return server\n })\n ready.catch((error: unknown) => {\n report(error)\n finish()\n })\n handle = {\n async close() {\n const server = await ready.catch(() => undefined)\n await server?.close()\n },\n }\n } else {\n handle = serveStdio(factory, options.onerror ? { transport, onerror: options.onerror } : { transport })\n // serveStdio 가 onclose · onmessage 를 동기적으로 설정한 뒤 감싼다 (stdin 이벤트는 비동기)\n wrapClose()\n // subscriptions/listen (§12.5): SDK StdioListenRouter 가 ack 하기 전에 notifications 를 허용 부분으로\n const subscriptions = { state: options.state, resources: options.registry.resources }\n const sdkOnMessage = transport.onmessage\n transport.onmessage = (message) => {\n const listen = narrowListenRequest(message, subscriptions, principal)\n sdkOnMessage?.((listen ?? message) as typeof message)\n }\n }\n return {\n closed,\n async close() {\n await handle.close()\n finish()\n await closed\n },\n }\n}\n\n/** Claude Code channel capability. 선언하면 stdio 기본 era = legacy */\nconst CLAUDE_CHANNEL = \"claude/channel\"\n\n/** 연결 종료 후 onConnect cleanup 대기 상한 (ms). 넘으면 오류 보고 후 종료 진행 */\nexport const CLEANUP_TIMEOUT_MS = 5_000\n\nasync function waitCleanups(settled: ReadonlySet<Promise<void>>, report: (error: unknown) => void): Promise<void> {\n if (settled.size === 0) return\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<\"timeout\">((resolve) => {\n timer = setTimeout(() => resolve(\"timeout\"), CLEANUP_TIMEOUT_MS)\n timer.unref?.()\n })\n const result = await Promise.race([Promise.all(settled), timeout])\n clearTimeout(timer)\n if (result === \"timeout\") report(new Error(`mcp.onConnect cleanup did not finish within ${CLEANUP_TIMEOUT_MS}ms`))\n}\n\n/**\n * McpServer 인스턴스 하나 = stdio 연결 하나. onConnect 시점: 2025 = notifications/initialized\n * (initialize 응답 전 알림은 클라이언트가 버릴 수 있음), 2026-07-28 = connect 직후 (handshake 없음).\n * SDK 가 era 판별용 probe 인스턴스를 버리면 그 인스턴스의 onclose 로 cleanup 된다.\n * 반환 = 인스턴스 종료 후 (onConnect settle · cleanup 완료) resolve. 시작 전 종료 = 바로 resolve\n */\nfunction attachConnection(\n server: McpServer,\n era: McpConnection[\"era\"],\n onConnect: McpConnectHandler,\n report: (error: unknown) => void,\n): Promise<void> {\n const inner = server.server\n let connected: Promise<unknown> | undefined\n let resolveDone!: () => void\n const done = new Promise<void>((resolve) => {\n resolveDone = resolve\n })\n let closed = false\n const handlers = new Map<string, (params: Record<string, unknown>) => void | Promise<void>>()\n // SDK 가 등록하지 않은 method 만 fallback 으로 온다 (사양 알림은 SDK handler · era 필터가 먼저)\n inner.fallbackNotificationHandler = async (notification) => {\n const handler = handlers.get(notification.method)\n if (!handler) return\n const params = (notification.params ?? {}) as Record<string, unknown>\n try {\n await handler(params)\n } catch (error) {\n report(error)\n }\n }\n const conn: McpConnection = {\n era,\n notify: (method, params) => inner.notification({ method, ...(params !== undefined ? { params } : {}) } as never),\n onNotification(method, handler) {\n handlers.set(method, handler)\n return () => {\n if (handlers.get(method) === handler) handlers.delete(method)\n }\n },\n }\n const start = (): void => {\n if (connected || closed) return\n connected = Promise.resolve().then(() => onConnect(conn))\n connected.catch(report)\n }\n const previousClose = inner.onclose\n inner.onclose = () => {\n previousClose?.()\n if (closed) return\n closed = true\n if (!connected) return resolveDone()\n connected\n .then(async (cleanup) => {\n if (typeof cleanup === \"function\") await cleanup()\n }, () => {})\n .catch(report)\n .finally(resolveDone)\n }\n if (era === \"legacy\") {\n const previousInit = inner.oninitialized\n inner.oninitialized = () => {\n previousInit?.()\n start()\n }\n } else {\n const connect = server.connect.bind(server)\n server.connect = async (transport) => {\n await connect(transport)\n start()\n }\n }\n return done\n}\n\nexport interface StdoutRedirect {\n /** 원래 process.stdout 으로 쓰는 스트림. MCP transport 전용 */\n wire: Writable\n /** process.stdout.write 원복 */\n restore(): void\n}\n\n/**\n * D4: stdio 모드에서 transport 외의 stdout 쓰기 (console.log · process.stdout.write) 를 stderr 로 돌린다.\n * 반환된 wire 만 실제 stdout 에 쓴다. 명령어 모듈 import 전에 호출해야 top-level 출력도 막는다.\n * 자식 프로세스 · fd 1 직접 쓰기 (fs.writeSync(1)) 는 막지 못한다.\n */\nexport function redirectStdout(): StdoutRedirect {\n const stdout = process.stdout\n const original = stdout.write\n const toStderr = (...args: unknown[]): boolean =>\n (process.stderr.write as (...a: unknown[]) => boolean).apply(process.stderr, args)\n stdout.write = toStderr as typeof stdout.write\n const restoreConsole = !isBun ? () => {} : redirectBunConsole(toStderr)\n // EPIPE 등은 wire 의 write 콜백으로 transport 에 전달된다. process.stdout 의 미처리 error 로 죽지 않게\n const ignore = (): void => {}\n stdout.on(\"error\", ignore)\n const wire = new Writable({\n write(chunk: Buffer | string, _encoding, callback) {\n const write = original as (chunk: Buffer | string, done: (error?: Error | null) => void) => boolean\n write.call(stdout, chunk, (error) => callback(error ?? null))\n },\n })\n let restored = false\n return {\n wire,\n restore() {\n if (restored) return\n restored = true\n if (stdout.write === (toStderr as typeof stdout.write)) stdout.write = original\n restoreConsole()\n stdout.off(\"error\", ignore)\n },\n }\n}\n\n/**\n * Bun 의 console 은 process.stdout.write 를 거치지 않고 fd 1 에 직접 쓴다.\n * console 메서드를 stderr 로 쓰는 Console 의 메서드로 바꾸고 (Bun 전용 console.write 포함), 원복 함수를 반환한다.\n * Node 의 console 은 process.stdout.write 를 거치므로 바꾸지 않는다 (group 들여쓰기 등 기존 출력 유지)\n */\nfunction redirectBunConsole(toStderr: (...args: unknown[]) => boolean): () => void {\n const target = console as unknown as Record<string, unknown>\n const stderrConsole = new Console({ stdout: process.stderr, stderr: process.stderr }) as unknown as Record<string, unknown>\n const saved = new Map<string, unknown>()\n for (const key of Object.keys(target)) {\n const replacement =\n key === \"write\" ? toStderr : typeof stderrConsole[key] === \"function\" ? (stderrConsole[key] as Function).bind(stderrConsole) : undefined\n if (typeof target[key] !== \"function\" || key === \"Console\" || replacement === undefined) continue\n saved.set(key, target[key])\n target[key] = replacement\n }\n return () => {\n for (const [key, value] of saved) target[key] = value\n }\n}\n"]}
|