@novorb/mcp-core 2.1.2 → 3.0.1

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.
Files changed (240) hide show
  1. package/README.md +77 -163
  2. package/bin/mcp-core-jest.mjs +112 -0
  3. package/dist/auth.d.ts +57 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +74 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/bootstrap.d.ts +129 -0
  8. package/dist/bootstrap.d.ts.map +1 -0
  9. package/dist/bootstrap.js +206 -0
  10. package/dist/bootstrap.js.map +1 -0
  11. package/dist/client-input.d.ts +72 -0
  12. package/dist/client-input.d.ts.map +1 -0
  13. package/dist/client-input.js +109 -0
  14. package/dist/client-input.js.map +1 -0
  15. package/dist/credential-checks.d.ts +80 -0
  16. package/dist/credential-checks.d.ts.map +1 -0
  17. package/dist/credential-checks.js +189 -0
  18. package/dist/credential-checks.js.map +1 -0
  19. package/dist/credential-health.d.ts +12 -0
  20. package/dist/credential-health.d.ts.map +1 -0
  21. package/dist/credential-health.js +12 -0
  22. package/dist/credential-health.js.map +1 -0
  23. package/dist/credential-report.d.ts +46 -0
  24. package/dist/credential-report.d.ts.map +1 -0
  25. package/dist/credential-report.js +135 -0
  26. package/dist/credential-report.js.map +1 -0
  27. package/dist/credential-status-tool.d.ts +20 -0
  28. package/dist/credential-status-tool.d.ts.map +1 -0
  29. package/dist/credential-status-tool.js +33 -0
  30. package/dist/credential-status-tool.js.map +1 -0
  31. package/dist/credentials.d.ts +288 -0
  32. package/dist/credentials.d.ts.map +1 -0
  33. package/dist/credentials.js +652 -0
  34. package/dist/credentials.js.map +1 -0
  35. package/dist/express-peers.d.ts +29 -0
  36. package/dist/express-peers.d.ts.map +1 -0
  37. package/dist/express-peers.js +36 -0
  38. package/dist/express-peers.js.map +1 -0
  39. package/dist/express.d.ts +74 -0
  40. package/dist/express.d.ts.map +1 -0
  41. package/dist/express.js +164 -0
  42. package/dist/express.js.map +1 -0
  43. package/dist/http-client.d.ts +277 -42
  44. package/dist/http-client.d.ts.map +1 -1
  45. package/dist/http-client.js +620 -180
  46. package/dist/http-client.js.map +1 -1
  47. package/dist/index.d.ts +27 -6
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +47 -8
  50. package/dist/index.js.map +1 -1
  51. package/dist/limits.d.ts +28 -0
  52. package/dist/limits.d.ts.map +1 -0
  53. package/dist/limits.js +37 -0
  54. package/dist/limits.js.map +1 -0
  55. package/dist/list-pagination.d.ts +41 -0
  56. package/dist/list-pagination.d.ts.map +1 -0
  57. package/dist/list-pagination.js +104 -0
  58. package/dist/list-pagination.js.map +1 -0
  59. package/dist/net.d.ts +112 -0
  60. package/dist/net.d.ts.map +1 -0
  61. package/dist/net.js +490 -0
  62. package/dist/net.js.map +1 -0
  63. package/dist/notifications.d.ts +78 -0
  64. package/dist/notifications.d.ts.map +1 -0
  65. package/dist/notifications.js +173 -0
  66. package/dist/notifications.js.map +1 -0
  67. package/dist/pagination.d.ts +236 -5
  68. package/dist/pagination.d.ts.map +1 -1
  69. package/dist/pagination.js +393 -6
  70. package/dist/pagination.js.map +1 -1
  71. package/dist/prompts.d.ts +70 -0
  72. package/dist/prompts.d.ts.map +1 -0
  73. package/dist/prompts.js +109 -0
  74. package/dist/prompts.js.map +1 -0
  75. package/dist/protocol-errors.d.ts +15 -0
  76. package/dist/protocol-errors.d.ts.map +1 -0
  77. package/dist/protocol-errors.js +28 -0
  78. package/dist/protocol-errors.js.map +1 -0
  79. package/dist/protocol-logging.d.ts +37 -0
  80. package/dist/protocol-logging.d.ts.map +1 -0
  81. package/dist/protocol-logging.js +77 -0
  82. package/dist/protocol-logging.js.map +1 -0
  83. package/dist/rate-limiter.d.ts +36 -0
  84. package/dist/rate-limiter.d.ts.map +1 -0
  85. package/dist/rate-limiter.js +79 -0
  86. package/dist/rate-limiter.js.map +1 -0
  87. package/dist/request-state.d.ts +74 -0
  88. package/dist/request-state.d.ts.map +1 -0
  89. package/dist/request-state.js +190 -0
  90. package/dist/request-state.js.map +1 -0
  91. package/dist/resources.d.ts +181 -0
  92. package/dist/resources.d.ts.map +1 -0
  93. package/dist/resources.js +302 -0
  94. package/dist/resources.js.map +1 -0
  95. package/dist/result-limits.d.ts +80 -0
  96. package/dist/result-limits.d.ts.map +1 -0
  97. package/dist/result-limits.js +248 -0
  98. package/dist/result-limits.js.map +1 -0
  99. package/dist/retry.d.ts +79 -23
  100. package/dist/retry.d.ts.map +1 -1
  101. package/dist/retry.js +170 -57
  102. package/dist/retry.js.map +1 -1
  103. package/dist/sdk/client-stdio.d.ts +6 -0
  104. package/dist/sdk/client-stdio.d.ts.map +1 -0
  105. package/dist/sdk/client-stdio.js +6 -0
  106. package/dist/sdk/client-stdio.js.map +1 -0
  107. package/dist/sdk/client.d.ts +6 -0
  108. package/dist/sdk/client.d.ts.map +1 -0
  109. package/dist/sdk/client.js +6 -0
  110. package/dist/sdk/client.js.map +1 -0
  111. package/dist/sdk/express.d.ts +3 -0
  112. package/dist/sdk/express.d.ts.map +1 -0
  113. package/dist/sdk/express.js +11 -0
  114. package/dist/sdk/express.js.map +1 -0
  115. package/dist/sdk/node.d.ts +6 -0
  116. package/dist/sdk/node.d.ts.map +1 -0
  117. package/dist/sdk/node.js +6 -0
  118. package/dist/sdk/node.js.map +1 -0
  119. package/dist/sdk/server-stdio.d.ts +6 -0
  120. package/dist/sdk/server-stdio.d.ts.map +1 -0
  121. package/dist/sdk/server-stdio.js +6 -0
  122. package/dist/sdk/server-stdio.js.map +1 -0
  123. package/dist/sdk/server.d.ts +6 -0
  124. package/dist/sdk/server.d.ts.map +1 -0
  125. package/dist/sdk/server.js +6 -0
  126. package/dist/sdk/server.js.map +1 -0
  127. package/dist/server.d.ts +88 -35
  128. package/dist/server.d.ts.map +1 -1
  129. package/dist/server.js +98 -44
  130. package/dist/server.js.map +1 -1
  131. package/dist/task-request.d.ts +20 -0
  132. package/dist/task-request.d.ts.map +1 -0
  133. package/dist/task-request.js +43 -0
  134. package/dist/task-request.js.map +1 -0
  135. package/dist/task-store.d.ts +230 -0
  136. package/dist/task-store.d.ts.map +1 -0
  137. package/dist/task-store.js +459 -0
  138. package/dist/task-store.js.map +1 -0
  139. package/dist/task-tools.d.ts +115 -0
  140. package/dist/task-tools.d.ts.map +1 -0
  141. package/dist/task-tools.js +397 -0
  142. package/dist/task-tools.js.map +1 -0
  143. package/dist/testing/client.d.ts +25 -0
  144. package/dist/testing/client.d.ts.map +1 -0
  145. package/dist/testing/client.js +11 -0
  146. package/dist/testing/client.js.map +1 -0
  147. package/dist/testing/in-memory.d.ts +26 -0
  148. package/dist/testing/in-memory.d.ts.map +1 -0
  149. package/dist/testing/in-memory.js +41 -0
  150. package/dist/testing/in-memory.js.map +1 -0
  151. package/dist/testing/index.d.ts +20 -0
  152. package/dist/testing/index.d.ts.map +1 -0
  153. package/dist/testing/index.js +20 -0
  154. package/dist/testing/index.js.map +1 -0
  155. package/dist/testing/isolated-dirs.d.ts +27 -0
  156. package/dist/testing/isolated-dirs.d.ts.map +1 -0
  157. package/dist/testing/isolated-dirs.js +67 -0
  158. package/dist/testing/isolated-dirs.js.map +1 -0
  159. package/dist/testing/logs.d.ts +61 -0
  160. package/dist/testing/logs.d.ts.map +1 -0
  161. package/dist/testing/logs.js +113 -0
  162. package/dist/testing/logs.js.map +1 -0
  163. package/dist/testing/raw-http.d.ts +25 -0
  164. package/dist/testing/raw-http.d.ts.map +1 -0
  165. package/dist/testing/raw-http.js +41 -0
  166. package/dist/testing/raw-http.js.map +1 -0
  167. package/dist/testing/raw-peer.d.ts +43 -0
  168. package/dist/testing/raw-peer.d.ts.map +1 -0
  169. package/dist/testing/raw-peer.js +101 -0
  170. package/dist/testing/raw-peer.js.map +1 -0
  171. package/dist/testing/recording-server.d.ts +38 -0
  172. package/dist/testing/recording-server.d.ts.map +1 -0
  173. package/dist/testing/recording-server.js +38 -0
  174. package/dist/testing/recording-server.js.map +1 -0
  175. package/dist/testing/server-process.d.ts +76 -0
  176. package/dist/testing/server-process.d.ts.map +1 -0
  177. package/dist/testing/server-process.js +241 -0
  178. package/dist/testing/server-process.js.map +1 -0
  179. package/dist/testing/tools.d.ts +53 -0
  180. package/dist/testing/tools.d.ts.map +1 -0
  181. package/dist/testing/tools.js +98 -0
  182. package/dist/testing/tools.js.map +1 -0
  183. package/dist/testing/unit.d.ts +52 -0
  184. package/dist/testing/unit.d.ts.map +1 -0
  185. package/dist/testing/unit.js +95 -0
  186. package/dist/testing/unit.js.map +1 -0
  187. package/dist/tools.d.ts +205 -0
  188. package/dist/tools.d.ts.map +1 -0
  189. package/dist/tools.js +370 -0
  190. package/dist/tools.js.map +1 -0
  191. package/dist/transport.d.ts +143 -52
  192. package/dist/transport.d.ts.map +1 -1
  193. package/dist/transport.js +292 -123
  194. package/dist/transport.js.map +1 -1
  195. package/dist/url-path.d.ts +49 -0
  196. package/dist/url-path.d.ts.map +1 -0
  197. package/dist/url-path.js +165 -0
  198. package/dist/url-path.js.map +1 -0
  199. package/dist/utils/dataStore.d.ts +143 -0
  200. package/dist/utils/dataStore.d.ts.map +1 -0
  201. package/dist/utils/dataStore.js +429 -0
  202. package/dist/utils/dataStore.js.map +1 -0
  203. package/dist/utils/envLoader.d.ts +129 -0
  204. package/dist/utils/envLoader.d.ts.map +1 -0
  205. package/dist/utils/envLoader.js +399 -0
  206. package/dist/utils/envLoader.js.map +1 -0
  207. package/dist/utils/logger.d.ts +181 -0
  208. package/dist/utils/logger.d.ts.map +1 -0
  209. package/dist/utils/logger.js +664 -0
  210. package/dist/utils/logger.js.map +1 -0
  211. package/dist/utils/redact.d.ts +50 -0
  212. package/dist/utils/redact.d.ts.map +1 -0
  213. package/dist/utils/redact.js +318 -0
  214. package/dist/utils/redact.js.map +1 -0
  215. package/docs/api-reference.md +29 -0
  216. package/docs/building-a-server.md +63 -0
  217. package/docs/credentials.md +131 -0
  218. package/docs/data-store.md +37 -0
  219. package/docs/env.md +38 -0
  220. package/docs/features.md +28 -0
  221. package/docs/http-client.md +116 -0
  222. package/docs/logger.md +100 -0
  223. package/docs/migrating-to-v3.md +45 -0
  224. package/docs/outbound-urls.md +104 -0
  225. package/docs/pagination.md +45 -0
  226. package/docs/protocol-features.md +62 -0
  227. package/docs/resources-prompts-tasks.md +95 -0
  228. package/docs/sdk.md +33 -0
  229. package/docs/server.md +68 -0
  230. package/docs/testing-harness.md +139 -0
  231. package/docs/testing.md +151 -0
  232. package/docs/tools.md +88 -0
  233. package/docs/transport.md +85 -0
  234. package/examples/testing/tools.integration.test.example.ts +312 -0
  235. package/examples/testing/tools.unit.test.example.ts +149 -0
  236. package/package.json +130 -17
  237. package/dist/logger.d.ts +0 -80
  238. package/dist/logger.d.ts.map +0 -1
  239. package/dist/logger.js +0 -237
  240. package/dist/logger.js.map +0 -1
@@ -0,0 +1,129 @@
1
+ /**
2
+ * @novorb/mcp-core - Bootstrap
3
+ *
4
+ * `runMcpServer` is the one entry point shape for every MCP server:
5
+ *
6
+ * 1. logger init (name, rootDir)
7
+ * 2. env load (`loadEnv(schema)`, then the logger is reconfigured so LOG_* from the env file apply)
8
+ * 3. `setup` ONCE per process: clients, caches, DB handles, rate limiters (the shared state)
9
+ * 4. transport start: `create(shared, req)` builds a server per connection (stdio) / per request (HTTP)
10
+ * 2b. credentials: every declared credential registered, the env `check`s run once in parallel
11
+ * (bounded by MCP_CREDENTIAL_CHECK_TIMEOUT_MS, skipped with MCP_CREDENTIAL_CHECKS=false; never fatal)
12
+ * 5. ONE "started" line (transport, version, http url) after the listener is bound
13
+ *
14
+ * Signals are owned here: SIGINT/SIGTERM close the transport, then `dispose(shared)`, then exit 0.
15
+ * Consumers install no handlers of their own. Name and version come from `<rootDir>/package.json`.
16
+ *
17
+ * await runMcpServer({
18
+ * rootDir: packageRootFrom(import.meta.url),
19
+ * env: ENV_SCHEMA,
20
+ * setup: ({ env }) => ({ client: new ApiClient(env.get('API_URL')) }),
21
+ * create: (shared, req, { env, info }) => {
22
+ * const server = createMcpServer(info.name, info.version);
23
+ * registerTools(server, buildTools(shared), { env, serverName: info.name });
24
+ * return server;
25
+ * },
26
+ * });
27
+ */
28
+ import type { Implementation, ServerEventBus, ServerNotifier } from '@modelcontextprotocol/server';
29
+ import { type CredentialRegistry } from './credentials.js';
30
+ import { type CreateMcpServerOptions, type McpServer, type Server } from './server.js';
31
+ import { type RequestContext, type TransportMode, type TransportOptions } from './transport.js';
32
+ import { type EnvSchema, type LoadedEnv } from './utils/envLoader.js';
33
+ import { type Logger, type LoggerOptions } from './utils/logger.js';
34
+ export interface PackageInfo {
35
+ name: string;
36
+ version: string;
37
+ description?: string;
38
+ }
39
+ /** Read name, version and description from `<rootDir>/package.json`. Throws when it is missing or invalid. */
40
+ export declare function readPackageInfo(rootDir: string): PackageInfo;
41
+ /** What `setup` and `create` receive. */
42
+ export interface SetupContext {
43
+ env: LoadedEnv;
44
+ logger: Logger;
45
+ info: PackageInfo;
46
+ rootDir: string;
47
+ /** The change-event bus every transport connection is served from (`RunMcpServerOptions.bus`). */
48
+ bus: ServerEventBus;
49
+ /** Publish list-changed / resource-updated events to every connection (see `notifications.ts`). */
50
+ notify: ServerNotifier;
51
+ /**
52
+ * The credential registry (startup checks already run). It is the process registry unless
53
+ * `RunMcpServerOptions.credentials` is set; pass it to `registerTools({ credentials })` in that case.
54
+ */
55
+ credentials: CredentialRegistry;
56
+ /**
57
+ * A fresh `McpServer` for this server: `createMcpServer` with the package identity (`name`,
58
+ * `version`, `description`) plus `RunMcpServerOptions.server` (Implementation fields and
59
+ * `McpServerOptions`). Call it once per `create`.
60
+ */
61
+ createServer(): McpServer;
62
+ }
63
+ /** Server identity and options `runMcpServer` passes to every `createServer()`. */
64
+ export interface RunServerOptions extends CreateMcpServerOptions {
65
+ /** Implementation fields beyond name/version/description. */
66
+ title?: string;
67
+ websiteUrl?: string;
68
+ icons?: Implementation['icons'];
69
+ }
70
+ export interface RunMcpServerOptions<S> {
71
+ /** The server's package root: `packageRootFrom(import.meta.url)`. */
72
+ rootDir: string;
73
+ /** The server's own env schema (mcp-core's keys are merged in). */
74
+ env: EnvSchema;
75
+ /** Overrides package.json `name` (used for the logger and the started line). */
76
+ name?: string;
77
+ /** Overrides package.json `version`. */
78
+ version?: string;
79
+ /** Once per process: build the shared state (clients, caches, DB handles, rate limiters). */
80
+ setup?: (ctx: SetupContext) => Promise<S> | S;
81
+ /** Per connection (stdio) / per HTTP request: build a server over the shared state. */
82
+ create: (shared: S, req: RequestContext, ctx: SetupContext) => McpServer | Server;
83
+ /** On shutdown, after the transport is closed: release the shared state. */
84
+ dispose?: (shared: S) => Promise<void> | void;
85
+ /** Log uncaught exceptions / unhandled rejections, then exit 1 (default false). */
86
+ captureProcessErrors?: boolean;
87
+ /** Extra logger options (name and rootDir are set by runMcpServer). */
88
+ logger?: Omit<LoggerOptions, 'name' | 'rootDir' | 'captureProcessErrors'>;
89
+ /** Server identity and `McpServerOptions` for `ctx.createServer()`. */
90
+ server?: RunServerOptions;
91
+ /**
92
+ * Transport overrides; otherwise from the loaded env (MCP_TRANSPORT, PORT, MCP_HTTP_HOST,
93
+ * MCP_MAX_BODY_BYTES, MCP_ALLOWED_HOSTS, MCP_ALLOWED_ORIGINS, MCP_API_KEY). `auth.verifier` plugs a
94
+ * token verifier (for example JWTs) in place of the static key.
95
+ */
96
+ transport?: Omit<TransportOptions, 'handleSignals'>;
97
+ /** Throw on env validation errors instead of logging them (default false). */
98
+ strictEnv?: boolean;
99
+ /** Install SIGINT/SIGTERM handlers (default true). */
100
+ handleSignals?: boolean;
101
+ /** The environment to read and populate (default `process.env`). */
102
+ processEnv?: NodeJS.ProcessEnv;
103
+ /** The change-event bus (default the process bus; a shared pub/sub on multi-instance hosts). */
104
+ bus?: ServerEventBus;
105
+ /** The credential registry the startup checks fill (default the process registry). */
106
+ credentials?: CredentialRegistry;
107
+ }
108
+ export interface RunningServer<S> {
109
+ info: PackageInfo;
110
+ env: LoadedEnv;
111
+ shared: S;
112
+ /** The credential registry (startup check results, then live health). */
113
+ credentials: CredentialRegistry;
114
+ mode: TransportMode;
115
+ /** http only. */
116
+ host?: string;
117
+ port?: number;
118
+ url?: string;
119
+ /** Close the transport, then dispose the shared state. Idempotent; does not exit the process. */
120
+ close(): Promise<void>;
121
+ }
122
+ /**
123
+ * The transport options from the LOADED env (so `processEnv` and the env file reach the transport, and
124
+ * an invalid MCP_TRANSPORT throws), with explicit `overrides` winning.
125
+ */
126
+ export declare function transportFromEnv(env: LoadedEnv, overrides?: Omit<TransportOptions, 'handleSignals'>): Omit<TransportOptions, 'handleSignals'>;
127
+ /** Bootstrap an MCP server: logger, env, shared state, transport, started line, signals. */
128
+ export declare function runMcpServer<S = undefined>(opts: RunMcpServerOptions<S>): Promise<RunningServer<S>>;
129
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * @novorb/mcp-core - Bootstrap
3
+ *
4
+ * `runMcpServer` is the one entry point shape for every MCP server:
5
+ *
6
+ * 1. logger init (name, rootDir)
7
+ * 2. env load (`loadEnv(schema)`, then the logger is reconfigured so LOG_* from the env file apply)
8
+ * 3. `setup` ONCE per process: clients, caches, DB handles, rate limiters (the shared state)
9
+ * 4. transport start: `create(shared, req)` builds a server per connection (stdio) / per request (HTTP)
10
+ * 2b. credentials: every declared credential registered, the env `check`s run once in parallel
11
+ * (bounded by MCP_CREDENTIAL_CHECK_TIMEOUT_MS, skipped with MCP_CREDENTIAL_CHECKS=false; never fatal)
12
+ * 5. ONE "started" line (transport, version, http url) after the listener is bound
13
+ *
14
+ * Signals are owned here: SIGINT/SIGTERM close the transport, then `dispose(shared)`, then exit 0.
15
+ * Consumers install no handlers of their own. Name and version come from `<rootDir>/package.json`.
16
+ *
17
+ * await runMcpServer({
18
+ * rootDir: packageRootFrom(import.meta.url),
19
+ * env: ENV_SCHEMA,
20
+ * setup: ({ env }) => ({ client: new ApiClient(env.get('API_URL')) }),
21
+ * create: (shared, req, { env, info }) => {
22
+ * const server = createMcpServer(info.name, info.version);
23
+ * registerTools(server, buildTools(shared), { env, serverName: info.name });
24
+ * return server;
25
+ * },
26
+ * });
27
+ */
28
+ import { readFileSync } from 'node:fs';
29
+ import * as path from 'node:path';
30
+ import { runCredentialChecks } from './credential-checks.js';
31
+ import { processCredentials } from './credentials.js';
32
+ import { createNotifier, processBus } from './notifications.js';
33
+ import { createMcpServer } from './server.js';
34
+ import { parseList, resolveTransportMode, startMcpServer, } from './transport.js';
35
+ import { loadEnv } from './utils/envLoader.js';
36
+ import { getLogger, initLogger } from './utils/logger.js';
37
+ /** Read name, version and description from `<rootDir>/package.json`. Throws when it is missing or invalid. */
38
+ export function readPackageInfo(rootDir) {
39
+ const file = path.join(rootDir, 'package.json');
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(readFileSync(file, 'utf8'));
43
+ }
44
+ catch (e) {
45
+ throw new Error(`readPackageInfo: cannot read ${file}: ${e instanceof Error ? e.message : String(e)}`);
46
+ }
47
+ const pkg = (typeof parsed === 'object' && parsed !== null ? parsed : {});
48
+ if (typeof pkg.name !== 'string' || pkg.name === '' || typeof pkg.version !== 'string' || pkg.version === '') {
49
+ throw new Error(`readPackageInfo: ${file} has no name or version`);
50
+ }
51
+ const info = { name: pkg.name, version: pkg.version };
52
+ if (typeof pkg.description === 'string')
53
+ info.description = pkg.description;
54
+ return info;
55
+ }
56
+ /** The logger file name for a package name: the npm scope is dropped (`@scope/x-mcp` -> `x-mcp`). */
57
+ function loggerName(name) {
58
+ return name.replace(/^@[^/]+\//, '');
59
+ }
60
+ /**
61
+ * The transport options from the LOADED env (so `processEnv` and the env file reach the transport, and
62
+ * an invalid MCP_TRANSPORT throws), with explicit `overrides` winning.
63
+ */
64
+ export function transportFromEnv(env, overrides = {}) {
65
+ const mode = resolveTransportMode(overrides.mode ?? env.get('MCP_TRANSPORT'));
66
+ const out = { ...overrides, mode };
67
+ const port = env.int('PORT');
68
+ if (out.port === undefined && port !== undefined)
69
+ out.port = port;
70
+ const host = env.get('MCP_HTTP_HOST');
71
+ if (out.host === undefined && host !== undefined)
72
+ out.host = host;
73
+ const maxBody = env.int('MCP_MAX_BODY_BYTES');
74
+ if (out.maxBodyBytes === undefined && maxBody !== undefined)
75
+ out.maxBodyBytes = maxBody;
76
+ out.allowedHosts ??= parseList(env.get('MCP_ALLOWED_HOSTS'));
77
+ out.allowedOrigins ??= parseList(env.get('MCP_ALLOWED_ORIGINS'));
78
+ if (out.apiKey === undefined && !out.auth?.verifier) {
79
+ out.apiKey = env.bool('MCP_AUTH_DISABLED') === true ? null : (env.get('MCP_API_KEY') ?? '');
80
+ }
81
+ return out;
82
+ }
83
+ /** Bootstrap an MCP server: logger, env, shared state, transport, started line, signals. */
84
+ export async function runMcpServer(opts) {
85
+ const rootDir = path.resolve(opts.rootDir);
86
+ const pkg = opts.name !== undefined && opts.version !== undefined ? undefined : readPackageInfo(rootDir);
87
+ const info = {
88
+ ...(pkg ?? {}),
89
+ name: opts.name ?? pkg?.name ?? 'mcp-server',
90
+ version: opts.version ?? pkg?.version ?? '0.0.0',
91
+ };
92
+ const loggerOptions = {
93
+ ...opts.logger,
94
+ name: loggerName(info.name),
95
+ rootDir,
96
+ captureProcessErrors: opts.captureProcessErrors === true,
97
+ };
98
+ // 1. logger, so env-loading warnings are logged; 2. env; then reconfigure for LOG_* from the file.
99
+ initLogger(loggerOptions);
100
+ const env = loadEnv(opts.env, { rootDir, env: opts.processEnv ?? process.env, strict: opts.strictEnv === true });
101
+ const logger = initLogger(loggerOptions);
102
+ for (const e of env.errors)
103
+ logger.warn(`env ${e.key} ${e.message}`, 'Env');
104
+ // Credentials: registered from the env schema and checked ONCE (parallel, bounded); never fatal.
105
+ const credentials = opts.credentials ?? processCredentials();
106
+ try {
107
+ await runCredentialChecks(env, credentials, { logger });
108
+ }
109
+ catch (e) {
110
+ // Never fatal: the server starts with the credentials it could register.
111
+ logger.warn(`credential checks failed: ${e instanceof Error ? e.name : 'error'}`, 'Credentials');
112
+ }
113
+ const serverOptions = opts.server ?? {};
114
+ const bus = opts.bus ?? processBus();
115
+ const ctx = {
116
+ env,
117
+ logger,
118
+ info,
119
+ rootDir,
120
+ bus,
121
+ notify: createNotifier(bus),
122
+ credentials,
123
+ createServer: () => {
124
+ const { title, websiteUrl, icons, ...mcpOptions } = serverOptions;
125
+ return createMcpServer({
126
+ name: info.name,
127
+ version: info.version,
128
+ ...(info.description !== undefined ? { description: info.description } : {}),
129
+ ...(title !== undefined ? { title } : {}),
130
+ ...(websiteUrl !== undefined ? { websiteUrl } : {}),
131
+ ...(icons !== undefined ? { icons } : {}),
132
+ }, mcpOptions);
133
+ },
134
+ };
135
+ const transportOptions = transportFromEnv(env, opts.transport);
136
+ const shared = (opts.setup ? await opts.setup(ctx) : undefined);
137
+ let transport;
138
+ try {
139
+ transport = await startMcpServer((req) => opts.create(shared, req, ctx), {
140
+ ...transportOptions,
141
+ bus,
142
+ handleSignals: false,
143
+ });
144
+ }
145
+ catch (err) {
146
+ await Promise.resolve(opts.dispose?.(shared)).catch(() => undefined);
147
+ throw err;
148
+ }
149
+ let closing;
150
+ const shutdownAndExit = (reason) => {
151
+ getLogger().info(`${info.name} stopping (${reason})`, 'Server');
152
+ let code = 0;
153
+ close()
154
+ .catch((e) => {
155
+ code = 1;
156
+ getLogger().error(`shutdown failed: ${e instanceof Error ? e.message : String(e)}`, 'Server');
157
+ })
158
+ .finally(() => process.exit(code));
159
+ };
160
+ const onSignal = (signal) => shutdownAndExit(signal);
161
+ // The client closed the connection (stdio EOF): dispose the shared state and exit, so keep-alive
162
+ // handles created in `setup` (timers, pools, watchers) never orphan the process.
163
+ transport.closed.then(() => {
164
+ if (closing)
165
+ return;
166
+ if (opts.handleSignals === false) {
167
+ getLogger().info(`${info.name} stopping (transport closed)`, 'Server');
168
+ close().catch((e) => getLogger().error(`shutdown failed: ${e instanceof Error ? e.message : String(e)}`, 'Server'));
169
+ return;
170
+ }
171
+ shutdownAndExit('transport closed');
172
+ });
173
+ const close = () => {
174
+ closing ??= (async () => {
175
+ process.off('SIGINT', onSignal);
176
+ process.off('SIGTERM', onSignal);
177
+ try {
178
+ await transport.close();
179
+ }
180
+ finally {
181
+ await opts.dispose?.(shared);
182
+ }
183
+ })();
184
+ return closing;
185
+ };
186
+ if (opts.handleSignals !== false) {
187
+ process.on('SIGINT', onSignal);
188
+ process.on('SIGTERM', onSignal);
189
+ }
190
+ const meta = { version: info.version, transport: transport.mode };
191
+ if (transport.url)
192
+ Object.assign(meta, { host: transport.host, port: transport.port, url: transport.url });
193
+ logger.info(`${info.name} started`, 'Server', meta);
194
+ return {
195
+ info,
196
+ env,
197
+ shared,
198
+ credentials,
199
+ mode: transport.mode,
200
+ ...(transport.host !== undefined ? { host: transport.host } : {}),
201
+ ...(transport.port !== undefined ? { port: transport.port } : {}),
202
+ ...(transport.url !== undefined ? { url: transport.url } : {}),
203
+ close,
204
+ };
205
+ }
206
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAA2B,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAA+B,eAAe,EAA+B,MAAM,aAAa,CAAC;AACxG,OAAO,EACL,SAAS,EAET,oBAAoB,EACpB,cAAc,GAIf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAkC,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,UAAU,EAAmC,MAAM,mBAAmB,CAAC;AAQ3F,8GAA8G;AAC9G,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAChD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACzG,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAA4B,CAAC;IACrG,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,EAAE,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,KAAK,EAAE,EAAE,CAAC;QAC7G,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,yBAAyB,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,IAAI,GAAgB,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;IACnE,IAAI,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ;QAAE,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;IAC5E,OAAO,IAAI,CAAC;AACd,CAAC;AAuFD,qGAAqG;AACrG,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAc,EACd,YAAqD,EAAE;IAEvD,MAAM,IAAI,GAAkB,oBAAoB,CAC9C,SAAS,CAAC,IAAI,IAAK,GAAG,CAAC,GAAG,CAAC,eAAe,CAA+B,CAC1E,CAAC;IACF,MAAM,GAAG,GAA4C,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,CAAC;IAC5E,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS;QAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAClE,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACtC,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS;QAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;IAClE,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAC9C,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS;QAAE,GAAG,CAAC,YAAY,GAAG,OAAO,CAAC;IACxF,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC;IAC7D,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC;IACjE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC;QACpD,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,YAAY,CAAgB,IAA4B;IAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IACzG,MAAM,IAAI,GAAgB;QACxB,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;QACd,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,GAAG,EAAE,IAAI,IAAI,YAAY;QAC5C,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,GAAG,EAAE,OAAO,IAAI,OAAO;KACjD,CAAC;IACF,MAAM,aAAa,GAAkB;QACnC,GAAG,IAAI,CAAC,MAAM;QACd,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3B,OAAO;QACP,oBAAoB,EAAE,IAAI,CAAC,oBAAoB,KAAK,IAAI;KACzD,CAAC;IAEF,mGAAmG;IACnG,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC,CAAC;IACjH,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;IAE5E,iGAAiG;IACjG,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,kBAAkB,EAAE,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,yEAAyE;QACzE,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;IACnG,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,UAAU,EAAE,CAAC;IACrC,MAAM,GAAG,GAAiB;QACxB,GAAG;QACH,MAAM;QACN,IAAI;QACJ,OAAO;QACP,GAAG;QACH,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC;QAC3B,WAAW;QACX,YAAY,EAAE,GAAG,EAAE;YACjB,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,UAAU,EAAE,GAAG,aAAa,CAAC;YAClE,OAAO,eAAe,CACpB;gBACE,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5E,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnD,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC1C,EACD,UAAU,CACX,CAAC;QACJ,CAAC;KACF,CAAC;IACF,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAM,CAAC;IAErE,IAAI,SAA0B,CAAC;IAC/B,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,cAAc,CAAC,CAAC,GAAmB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE;YACvF,GAAG,gBAAgB;YACnB,GAAG;YACH,aAAa,EAAE,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACrE,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,OAAkC,CAAC;IACvC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAQ,EAAE;QAC/C,SAAS,EAAE,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,cAAc,MAAM,GAAG,EAAE,QAAQ,CAAC,CAAC;QAChE,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,EAAE;aACJ,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE;YACpB,IAAI,GAAG,CAAC,CAAC;YACT,SAAS,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAChG,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,CAAC,MAAsB,EAAQ,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3E,iGAAiG;IACjG,iFAAiF;IACjF,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;QACzB,IAAI,OAAO;YAAE,OAAO;QACpB,IAAI,IAAI,CAAC,aAAa,KAAK,KAAK,EAAE,CAAC;YACjC,SAAS,EAAE,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,8BAA8B,EAAE,QAAQ,CAAC,CAAC;YACvE,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CAC3B,SAAS,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAC9F,CAAC;YACF,OAAO;QACT,CAAC;QACD,eAAe,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,GAAkB,EAAE;QAChC,OAAO,KAAK,CAAC,KAAK,IAAI,EAAE;YACtB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;YAC1B,CAAC;oBAAS,CAAC;gBACT,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IACF,IAAI,IAAI,CAAC,aAAa,KAAK,KAAK,EAAE,CAAC;QACjC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,IAAI,GAA4B,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;IAC3F,IAAI,SAAS,CAAC,GAAG;QAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3G,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAEpD,OAAO;QACL,IAAI;QACJ,GAAG;QACH,MAAM;QACN,WAAW;QACX,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,GAAG,CAAC,SAAS,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,KAAK;KACN,CAAC;AACJ,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @novorb/mcp-core - Client input (elicitation, sampling, roots)
3
+ *
4
+ * Era-blind helpers over the SDK's multi-round-trip mechanism (MRTR, `inputRequired(...)`): a handler
5
+ * asks for input by RETURNING an input-required result, and is re-entered with the client's answer in
6
+ * `ctx.mcpReq.inputResponses`. This is how the SDK serves both eras from one handler:
7
+ *
8
+ * - 2026-07-28: the client fulfils the embedded requests and retries the call;
9
+ * - 2025-era connections: the SDK's legacy shim (on by default) sends real server-to-client requests
10
+ * and re-enters the handler itself.
11
+ *
12
+ * Each helper first reads the answer for its `key`; when there is none it checks the client's declared
13
+ * capability and answers either `{ status: 'pending', result }` (return `result` from the handler) or
14
+ * `{ status: 'unsupported', reason }` (never a throw). Stateless HTTP serves every 2025-era request on
15
+ * a fresh instance that never saw `initialize`, so no client capability is known there and every
16
+ * helper answers `unsupported`; stdio and 2026-07-28 clients declare theirs.
17
+ *
18
+ * Sampling and roots are deprecated by the 2026-07-28 revision (SEP-2577) but remain functional for at
19
+ * least twelve months; elicitation is not deprecated.
20
+ */
21
+ import { type ClientCapabilities, type CreateMessageRequestParams, type CreateMessageResult, type CreateMessageResultWithTools, type ElicitInputParams, type ElicitRequestURLParams, type InputRequiredResult, type Root, type ServerContext, type StandardSchemaWithJSON } from '@modelcontextprotocol/server';
22
+ /** The protocol era of the request being handled. */
23
+ export type RequestEra = 'modern' | 'legacy';
24
+ /** The outcome of asking the client for input. */
25
+ export type InputOutcome<T> =
26
+ /** The client answered (an accepted elicitation, a sampling result, the roots). */
27
+ {
28
+ status: 'accepted';
29
+ value: T;
30
+ }
31
+ /** The user declined the elicitation. */
32
+ | {
33
+ status: 'declined';
34
+ }
35
+ /** The user cancelled the elicitation. */
36
+ | {
37
+ status: 'cancelled';
38
+ }
39
+ /** An accepted elicitation whose content failed the requested schema. */
40
+ | {
41
+ status: 'invalid';
42
+ }
43
+ /** No answer yet: return `result` from the handler; the handler is re-entered with the answer. */
44
+ | {
45
+ status: 'pending';
46
+ result: InputRequiredResult;
47
+ }
48
+ /** The client cannot answer (capability not declared, or no capability information at all). */
49
+ | {
50
+ status: 'unsupported';
51
+ reason: string;
52
+ };
53
+ /** Elicitation parameters whose `requestedSchema` is a Standard Schema (the content is validated). */
54
+ export type TypedElicitParams<S extends StandardSchemaWithJSON> = Omit<ElicitInputParams, 'requestedSchema'> & {
55
+ requestedSchema: S;
56
+ };
57
+ export type ClientFeature = 'elicitation' | 'elicitation.url' | 'sampling' | 'roots';
58
+ /** The era of a request: modern when it carries the 2026-07-28 per-request envelope. */
59
+ export declare function requestEra(sdk: ServerContext): RequestEra;
60
+ /** Whether `caps` declares `feature`. A bare `elicitation: {}` means form mode only (2025-11-25). */
61
+ export declare function supportsClientFeature(caps: ClientCapabilities | undefined, feature: ClientFeature): boolean;
62
+ /** The per-request client input helpers; `caps` is the client's declared capabilities. */
63
+ export interface ClientInput {
64
+ elicit<S extends StandardSchemaWithJSON>(key: string, params: TypedElicitParams<S>): InputOutcome<StandardSchemaWithJSON.InferOutput<S>>;
65
+ elicit(key: string, params: ElicitInputParams): InputOutcome<Record<string, unknown>>;
66
+ elicitUrl(key: string, params: Omit<ElicitRequestURLParams, 'mode' | 'elicitationId'>): InputOutcome<true>;
67
+ sample(key: string, params: CreateMessageRequestParams): InputOutcome<CreateMessageResult | CreateMessageResultWithTools>;
68
+ listRoots(key?: string): InputOutcome<Root[]>;
69
+ }
70
+ /** Build the helpers for one request. Without an SDK context every helper answers `unsupported`. */
71
+ export declare function createClientInput(sdk: ServerContext | undefined, caps: ClientCapabilities | undefined): ClientInput;
72
+ //# sourceMappingURL=client-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-input.d.ts","sourceRoot":"","sources":["../src/client-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAE3B,KAAK,mBAAmB,EAIxB,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC5B,MAAM,8BAA8B,CAAC;AAEtC,qDAAqD;AACrD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7C,kDAAkD;AAClD,MAAM,MAAM,YAAY,CAAC,CAAC;AACxB,mFAAmF;AACjF;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE;AAClC,yCAAyC;GACvC;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE;AACxB,0CAA0C;GACxC;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE;AACzB,yEAAyE;GACvE;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE;AACvB,kGAAkG;GAChG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE;AACpD,+FAA+F;GAC7F;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,sGAAsG;AACtG,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,sBAAsB,IAAI,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,GAAG;IAC7G,eAAe,EAAE,CAAC,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,iBAAiB,GAAG,UAAU,GAAG,OAAO,CAAC;AAErF,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAGzD;AAED,qGAAqG;AACrG,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,kBAAkB,GAAG,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAa3G;AAkBD,0FAA0F;AAC1F,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,CAAC,SAAS,sBAAsB,EACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAC3B,YAAY,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtF,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,GAAG,eAAe,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC3G,MAAM,CACJ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,0BAA0B,GACjC,YAAY,CAAC,mBAAmB,GAAG,4BAA4B,CAAC,CAAC;IACpE,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;CAC/C;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,EAAE,IAAI,EAAE,kBAAkB,GAAG,SAAS,GAAG,WAAW,CA4CnH"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @novorb/mcp-core - Client input (elicitation, sampling, roots)
3
+ *
4
+ * Era-blind helpers over the SDK's multi-round-trip mechanism (MRTR, `inputRequired(...)`): a handler
5
+ * asks for input by RETURNING an input-required result, and is re-entered with the client's answer in
6
+ * `ctx.mcpReq.inputResponses`. This is how the SDK serves both eras from one handler:
7
+ *
8
+ * - 2026-07-28: the client fulfils the embedded requests and retries the call;
9
+ * - 2025-era connections: the SDK's legacy shim (on by default) sends real server-to-client requests
10
+ * and re-enters the handler itself.
11
+ *
12
+ * Each helper first reads the answer for its `key`; when there is none it checks the client's declared
13
+ * capability and answers either `{ status: 'pending', result }` (return `result` from the handler) or
14
+ * `{ status: 'unsupported', reason }` (never a throw). Stateless HTTP serves every 2025-era request on
15
+ * a fresh instance that never saw `initialize`, so no client capability is known there and every
16
+ * helper answers `unsupported`; stdio and 2026-07-28 clients declare theirs.
17
+ *
18
+ * Sampling and roots are deprecated by the 2026-07-28 revision (SEP-2577) but remain functional for at
19
+ * least twelve months; elicitation is not deprecated.
20
+ */
21
+ import { acceptedContent, inputRequired, inputResponse, PROTOCOL_VERSION_META_KEY, } from '@modelcontextprotocol/server';
22
+ /** The era of a request: modern when it carries the 2026-07-28 per-request envelope. */
23
+ export function requestEra(sdk) {
24
+ const envelope = sdk.mcpReq.envelope;
25
+ return envelope?.[PROTOCOL_VERSION_META_KEY] !== undefined ? 'modern' : 'legacy';
26
+ }
27
+ /** Whether `caps` declares `feature`. A bare `elicitation: {}` means form mode only (2025-11-25). */
28
+ export function supportsClientFeature(caps, feature) {
29
+ if (!caps)
30
+ return false;
31
+ const elicitation = caps.elicitation;
32
+ switch (feature) {
33
+ case 'elicitation':
34
+ return elicitation !== undefined && (elicitation.form !== undefined || elicitation.url === undefined);
35
+ case 'elicitation.url':
36
+ return elicitation?.url !== undefined;
37
+ case 'sampling':
38
+ return caps.sampling !== undefined;
39
+ case 'roots':
40
+ return caps.roots !== undefined;
41
+ }
42
+ }
43
+ function unsupported(feature, caps) {
44
+ const reason = caps === undefined
45
+ ? `${feature} is not supported by this client: no client capabilities are known for this request (stateless HTTP 2025-era requests carry none)`
46
+ : `${feature} is not supported by this client: it did not declare the ${feature} capability`;
47
+ return { status: 'unsupported', reason };
48
+ }
49
+ function pending(key, request) {
50
+ return { status: 'pending', result: inputRequired({ inputRequests: { [key]: request } }) };
51
+ }
52
+ function isStandardSchema(value) {
53
+ return typeof value === 'object' && value !== null && '~standard' in value;
54
+ }
55
+ /** Build the helpers for one request. Without an SDK context every helper answers `unsupported`. */
56
+ export function createClientInput(sdk, caps) {
57
+ const responses = sdk?.mcpReq.inputResponses;
58
+ const known = sdk ? caps : undefined;
59
+ function elicit(key, params) {
60
+ const view = inputResponse(responses, key);
61
+ if (view.kind === 'elicit') {
62
+ if (view.action === 'decline')
63
+ return { status: 'declined' };
64
+ if (view.action === 'cancel')
65
+ return { status: 'cancelled' };
66
+ if (isStandardSchema(params.requestedSchema)) {
67
+ const value = acceptedContent(responses, key, params.requestedSchema);
68
+ return value === undefined ? { status: 'invalid' } : { status: 'accepted', value };
69
+ }
70
+ return { status: 'accepted', value: view.content ?? {} };
71
+ }
72
+ if (!supportsClientFeature(known, 'elicitation'))
73
+ return unsupported('elicitation', known);
74
+ return pending(key, inputRequired.elicit(params));
75
+ }
76
+ return {
77
+ elicit: elicit,
78
+ elicitUrl(key, params) {
79
+ const view = inputResponse(responses, key);
80
+ if (view.kind === 'elicit') {
81
+ if (view.action === 'decline')
82
+ return { status: 'declined' };
83
+ if (view.action === 'cancel')
84
+ return { status: 'cancelled' };
85
+ return { status: 'accepted', value: true };
86
+ }
87
+ if (!supportsClientFeature(known, 'elicitation.url'))
88
+ return unsupported('elicitation.url', known);
89
+ return pending(key, inputRequired.elicitUrl(params));
90
+ },
91
+ sample(key, params) {
92
+ const view = inputResponse(responses, key);
93
+ if (view.kind === 'sampling')
94
+ return { status: 'accepted', value: view.result };
95
+ if (!supportsClientFeature(known, 'sampling'))
96
+ return unsupported('sampling', known);
97
+ return pending(key, inputRequired.createMessage(params));
98
+ },
99
+ listRoots(key = 'roots') {
100
+ const view = inputResponse(responses, key);
101
+ if (view.kind === 'roots')
102
+ return { status: 'accepted', value: view.roots };
103
+ if (!supportsClientFeature(known, 'roots'))
104
+ return unsupported('roots', known);
105
+ return pending(key, inputRequired.listRoots());
106
+ },
107
+ };
108
+ }
109
+ //# sourceMappingURL=client-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-input.js","sourceRoot":"","sources":["../src/client-input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @novorb/mcp-core - Startup credential checks
3
+ *
4
+ * `runMcpServer` registers every credential the env schema declares (a server's own `secret` keys and
5
+ * every key with a `check`; each member of a `multi` family on its own, pooled under the family's base
6
+ * key) and then runs the declared checks ONCE, in parallel, each bounded by
7
+ * `MCP_CREDENTIAL_CHECK_TIMEOUT_MS` (default 5000). `MCP_CREDENTIAL_CHECKS=false` skips them. A check
8
+ * never stops the server: a throw, a timeout or a network error reads `unknown`, and the results are
9
+ * logged by key name and status only.
10
+ *
11
+ * {
12
+ * key: 'SEARCH_API_KEY', multi: true, secret: true,
13
+ * check: async (value, { http, signal }) => {
14
+ * await http({ baseURL: 'https://api.example.com', auth: { type: 'bearer', token: value } })
15
+ * .get('/account', { signal });
16
+ * return 'valid';
17
+ * },
18
+ * }
19
+ *
20
+ * A check may return a status, `{ status, reason?, retryAfterMs? }`, or throw: a thrown `HttpError`
21
+ * is classified like any HTTP outcome (401/403 invalid, 402/429 degraded, ...).
22
+ */
23
+ import { type CredentialOutcomeInfo, type CredentialRegistry, type CredentialStatus } from './credentials.js';
24
+ import { type HttpClientConfig, type McpHttpClient } from './http-client.js';
25
+ import { type LoadedEnv } from './utils/envLoader.js';
26
+ import { type Logger } from './utils/logger.js';
27
+ export interface CredentialCheckContext {
28
+ /** The credential's key name (`KEY` or a family member `KEY_2`). */
29
+ key: string;
30
+ /** Aborted when the check times out. */
31
+ signal: AbortSignal;
32
+ /** A hardened http-client for the probe (retries off by default, the check timeout as its timeout). */
33
+ http(config: HttpClientConfig): McpHttpClient;
34
+ /**
35
+ * The loaded value of a sibling DECLARED env key (a multi-part credential: client id + secret, key +
36
+ * secret, user + password), or undefined when unset. Throws `UnknownCredentialError` for a key the
37
+ * schema does not declare. Values are never logged; declare the siblings `secret: true` so the logger
38
+ * masks them too.
39
+ */
40
+ get(key: string): string | undefined;
41
+ }
42
+ export interface CredentialCheckResult extends CredentialOutcomeInfo {
43
+ status: CredentialStatus;
44
+ }
45
+ /** A server-supplied probe for one credential value. */
46
+ export type CredentialCheck = (value: string, ctx: CredentialCheckContext) => Promise<CredentialStatus | CredentialCheckResult>;
47
+ export declare const DEFAULT_CREDENTIAL_CHECK_TIMEOUT_MS = 5000;
48
+ /**
49
+ * Register the env's credentials in `registry`: every set value of a spec with a `check`, and of every
50
+ * `secret` spec that is not one of mcp-core's own keys. A multi family's members are pooled under the
51
+ * base key. Returns the registered key names with their checks.
52
+ */
53
+ export declare function registerEnvCredentials(env: LoadedEnv, registry: CredentialRegistry): Array<{
54
+ key: string;
55
+ check?: CredentialCheck;
56
+ }>;
57
+ export interface RunCredentialChecksOptions {
58
+ /** Per-check timeout (default MCP_CREDENTIAL_CHECK_TIMEOUT_MS, else 5000 ms). */
59
+ timeoutMs?: number;
60
+ /** Run the checks (default MCP_CREDENTIAL_CHECKS, else true). */
61
+ enabled?: boolean;
62
+ /** How many checks run at once (default 4), so a large pool does not trip its provider's rate limit. */
63
+ concurrency?: number;
64
+ /** Re-check cool-down for invalid/expired keys (default MCP_CREDENTIAL_RECHECK_MS, else 300000 ms). */
65
+ recheckMs?: number;
66
+ logger?: Logger;
67
+ }
68
+ export declare const DEFAULT_CREDENTIAL_CHECK_CONCURRENCY = 4;
69
+ /**
70
+ * Register the env's credentials and run their checks once (at most `concurrency` at a time, each with
71
+ * a timeout), then attach each check as the key's re-check probe (run again after the
72
+ * MCP_CREDENTIAL_RECHECK_MS cool-down while the key is invalid or expired). Never throws; logs one
73
+ * summary line (key names and statuses only). Resolves with the checked keys' results.
74
+ */
75
+ export declare function runCredentialChecks(env: LoadedEnv, registry: CredentialRegistry, options?: RunCredentialChecksOptions): Promise<Array<{
76
+ key: string;
77
+ status: CredentialStatus;
78
+ reason?: string;
79
+ }>>;
80
+ //# sourceMappingURL=credential-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-checks.d.ts","sourceRoot":"","sources":["../src/credential-checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAGtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAoB,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAa,KAAK,MAAM,EAAoB,MAAM,mBAAmB,CAAC;AAE7E,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB,uGAAuG;IACvG,IAAI,CAAC,MAAM,EAAE,gBAAgB,GAAG,aAAa,CAAC;IAC9C;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAClE,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,CAC5B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,sBAAsB,KACxB,OAAO,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,CAAC;AAEvD,eAAO,MAAM,mCAAmC,OAAO,CAAC;AAIxD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,kBAAkB,GAC3B,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAqBjD;AAED,MAAM,WAAW,0BAA0B;IACzC,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wGAAwG;IACxG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsED,eAAO,MAAM,oCAAoC,IAAI,CAAC;AAoBtD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CA+C5E"}