@jini-ai/mcp 0.1.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.
Files changed (86) hide show
  1. package/LICENSE +201 -0
  2. package/dist/agent-install/index.d.ts +9 -0
  3. package/dist/agent-install/index.d.ts.map +1 -0
  4. package/dist/agent-install/index.js +9 -0
  5. package/dist/agent-install/index.js.map +1 -0
  6. package/dist/agent-install/install.d.ts +97 -0
  7. package/dist/agent-install/install.d.ts.map +1 -0
  8. package/dist/agent-install/install.js +410 -0
  9. package/dist/agent-install/install.js.map +1 -0
  10. package/dist/bin/serve.d.ts +75 -0
  11. package/dist/bin/serve.d.ts.map +1 -0
  12. package/dist/bin/serve.js +79 -0
  13. package/dist/bin/serve.js.map +1 -0
  14. package/dist/client/client.d.ts +48 -0
  15. package/dist/client/client.d.ts.map +1 -0
  16. package/dist/client/client.js +242 -0
  17. package/dist/client/client.js.map +1 -0
  18. package/dist/client/index.d.ts +8 -0
  19. package/dist/client/index.d.ts.map +1 -0
  20. package/dist/client/index.js +8 -0
  21. package/dist/client/index.js.map +1 -0
  22. package/dist/core/config.d.ts +157 -0
  23. package/dist/core/config.d.ts.map +1 -0
  24. package/dist/core/config.js +475 -0
  25. package/dist/core/config.js.map +1 -0
  26. package/dist/core/index.d.ts +14 -0
  27. package/dist/core/index.d.ts.map +1 -0
  28. package/dist/core/index.js +14 -0
  29. package/dist/core/index.js.map +1 -0
  30. package/dist/core/install-info.d.ts +69 -0
  31. package/dist/core/install-info.d.ts.map +1 -0
  32. package/dist/core/install-info.js +79 -0
  33. package/dist/core/install-info.js.map +1 -0
  34. package/dist/core/oauth.d.ts +274 -0
  35. package/dist/core/oauth.d.ts.map +1 -0
  36. package/dist/core/oauth.js +667 -0
  37. package/dist/core/oauth.js.map +1 -0
  38. package/dist/core/secure-write.d.ts +17 -0
  39. package/dist/core/secure-write.d.ts.map +1 -0
  40. package/dist/core/secure-write.js +72 -0
  41. package/dist/core/secure-write.js.map +1 -0
  42. package/dist/core/tokens.d.ts +72 -0
  43. package/dist/core/tokens.d.ts.map +1 -0
  44. package/dist/core/tokens.js +197 -0
  45. package/dist/core/tokens.js.map +1 -0
  46. package/dist/index.d.ts +28 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +29 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/server/daemon-client.d.ts +21 -0
  51. package/dist/server/daemon-client.d.ts.map +1 -0
  52. package/dist/server/daemon-client.js +176 -0
  53. package/dist/server/daemon-client.js.map +1 -0
  54. package/dist/server/index.d.ts +18 -0
  55. package/dist/server/index.d.ts.map +1 -0
  56. package/dist/server/index.js +18 -0
  57. package/dist/server/index.js.map +1 -0
  58. package/dist/server/resource-protocol.d.ts +38 -0
  59. package/dist/server/resource-protocol.d.ts.map +1 -0
  60. package/dist/server/resource-protocol.js +68 -0
  61. package/dist/server/resource-protocol.js.map +1 -0
  62. package/dist/server/resources/active-resource.d.ts +12 -0
  63. package/dist/server/resources/active-resource.d.ts.map +1 -0
  64. package/dist/server/resources/active-resource.js +46 -0
  65. package/dist/server/resources/active-resource.js.map +1 -0
  66. package/dist/server/tool-protocol.d.ts +45 -0
  67. package/dist/server/tool-protocol.d.ts.map +1 -0
  68. package/dist/server/tool-protocol.js +74 -0
  69. package/dist/server/tool-protocol.js.map +1 -0
  70. package/dist/server/tool-server.d.ts +105 -0
  71. package/dist/server/tool-server.d.ts.map +1 -0
  72. package/dist/server/tool-server.js +96 -0
  73. package/dist/server/tool-server.js.map +1 -0
  74. package/dist/server/tools/delegated-tool.d.ts +15 -0
  75. package/dist/server/tools/delegated-tool.d.ts.map +1 -0
  76. package/dist/server/tools/delegated-tool.js +90 -0
  77. package/dist/server/tools/delegated-tool.js.map +1 -0
  78. package/dist/server/tools/run-tools.d.ts +14 -0
  79. package/dist/server/tools/run-tools.d.ts.map +1 -0
  80. package/dist/server/tools/run-tools.js +142 -0
  81. package/dist/server/tools/run-tools.js.map +1 -0
  82. package/dist/server/tools/tool-catalog-tools.d.ts +8 -0
  83. package/dist/server/tools/tool-catalog-tools.d.ts.map +1 -0
  84. package/dist/server/tools/tool-catalog-tools.js +66 -0
  85. package/dist/server/tools/tool-catalog-tools.js.map +1 -0
  86. package/package.json +50 -0
@@ -0,0 +1,242 @@
1
+ /**
2
+ * @module @jini-ai/mcp/client/client
3
+ * Product-neutral runtime primitives for a stdio MCP server: an idle-exit
4
+ * controller that auto-closes an idle server process, a relative-reference
5
+ * extractor that walks HTML/CSS/JS text to find sibling files to bundle, and a
6
+ * textual-MIME classifier. Dependency-free (node stdlib only); imports no
7
+ * sibling MCP subdirectory.
8
+ */
9
+ // These are the generic, product-agnostic building blocks that back a stdio
10
+ // MCP server's lifecycle and its "pull an entry file plus everything it
11
+ // references" bundling. They hold no state beyond the idle controller's own
12
+ // timer and never touch the network or filesystem, so they unit-test against
13
+ // plain values.
14
+ // SEC-RB-011: an unvalidated `idleMs` (negative, `NaN`, `Infinity`, or a
15
+ // non-integer) would either schedule an immediately/never-firing timer or
16
+ // hand `setTimeout` a value it silently coerces in surprising ways. Bound it
17
+ // to a sane, documented range instead: reject anything that isn't a finite
18
+ // positive integer (a caller bug, not something to silently paper over), and
19
+ // clamp anything absurdly large down to a one-day ceiling rather than
20
+ // scheduling an effectively-infinite timer.
21
+ const MIN_IDLE_MS = 1;
22
+ const MAX_IDLE_MS = 24 * 60 * 60 * 1000; // 24h
23
+ function normalizeIdleMs(idleMs) {
24
+ if (typeof idleMs !== 'number' || !Number.isFinite(idleMs) || !Number.isInteger(idleMs) || idleMs < MIN_IDLE_MS) {
25
+ throw new RangeError(`createMcpIdleExitController: idleMs must be a finite positive integer (>= ${MIN_IDLE_MS}ms), got ${String(idleMs)}`);
26
+ }
27
+ return Math.min(idleMs, MAX_IDLE_MS);
28
+ }
29
+ /**
30
+ * Create an idle-exit controller that calls `onIdle` after `idleMs` of
31
+ * inactivity. Activity is tracked via `noteActivity()` and `trackRequest()`;
32
+ * in-flight requests defer the idle timer. Used to auto-close a long-running
33
+ * stdio MCP server process after a period of no tool calls.
34
+ * @param options Idle duration in ms (finite positive integer, clamped to a
35
+ * 24h ceiling — throws `RangeError` otherwise) and the callback to invoke on idle.
36
+ * @returns An object with `noteActivity`, `trackRequest`, and `dispose` methods.
37
+ */
38
+ export function createMcpIdleExitController({ idleMs, onIdle, }) {
39
+ const effectiveIdleMs = normalizeIdleMs(idleMs);
40
+ let timer = null;
41
+ let inFlight = 0;
42
+ let disposed = false;
43
+ const clear = () => {
44
+ if (timer) {
45
+ clearTimeout(timer);
46
+ timer = null;
47
+ }
48
+ };
49
+ const schedule = () => {
50
+ if (disposed)
51
+ return;
52
+ clear();
53
+ timer = setTimeout(() => {
54
+ // `dispose()` always clears the pending timer and `schedule()` bails when
55
+ // already disposed, so this callback can only fire while live.
56
+ timer = null;
57
+ if (inFlight > 0) {
58
+ schedule();
59
+ return;
60
+ }
61
+ disposed = true;
62
+ onIdle();
63
+ }, effectiveIdleMs);
64
+ };
65
+ schedule();
66
+ return {
67
+ noteActivity() {
68
+ schedule();
69
+ },
70
+ async trackRequest(fn) {
71
+ if (disposed) {
72
+ return fn();
73
+ }
74
+ inFlight += 1;
75
+ // Deliberately does NOT call `schedule()` here (SEC-RB-011): a request
76
+ // starting while the timer is already running doesn't need to reset
77
+ // the deadline — the timer, if it fires mid-flight, already re-checks
78
+ // `inFlight` and reschedules itself (above), and completion below
79
+ // reschedules once the last in-flight request finishes. Rescheduling
80
+ // on every concurrent request start instead caused needless
81
+ // clearTimeout/setTimeout churn under load with no behavioral benefit.
82
+ try {
83
+ return await fn();
84
+ }
85
+ finally {
86
+ inFlight -= 1;
87
+ if (inFlight === 0) {
88
+ schedule();
89
+ }
90
+ }
91
+ },
92
+ dispose() {
93
+ disposed = true;
94
+ clear();
95
+ },
96
+ };
97
+ }
98
+ // Mimes whose body a stdio MCP server can surface as `text` content.
99
+ const TEXTUAL_MIME_PATTERNS = [
100
+ /^text\//i,
101
+ /^application\/json\b/i,
102
+ /^application\/javascript\b/i,
103
+ /^application\/typescript\b/i,
104
+ /^application\/xml\b/i,
105
+ /^application\/x-(yaml|toml|httpd-php|sh)\b/i,
106
+ /\+json\b/i,
107
+ /\+xml\b/i,
108
+ /^image\/svg\+xml\b/i,
109
+ ];
110
+ /**
111
+ * True when `mime` names a textual content type whose body can be surfaced
112
+ * as MCP `text` content (text/*, JSON, JS/TS, XML, YAML/TOML/PHP/sh, `+json`
113
+ * / `+xml` suffixes, and SVG). Returns false for an absent/unknown mime.
114
+ * @param mime The MIME type string to classify (undefined counts as non-textual).
115
+ * @returns Whether the content should be treated as text.
116
+ */
117
+ export function isTextualMime(mime) {
118
+ if (!mime)
119
+ return false;
120
+ return TEXTUAL_MIME_PATTERNS.some((re) => re.test(mime));
121
+ }
122
+ // Patterns common to HTML and CSS (also fine to run on plain markdown).
123
+ const HTML_REF_PATTERNS = [
124
+ /<script\b[^>]*\bsrc=["']([^"']+)["']/gi,
125
+ /<link\b[^>]*\bhref=["']([^"']+)["']/gi,
126
+ /<img\b[^>]*\bsrc=["']([^"']+)["']/gi,
127
+ /<source\b[^>]*\bsrc=["']([^"']+)["']/gi,
128
+ /<video\b[^>]*\bsrc=["']([^"']+)["']/gi,
129
+ /<audio\b[^>]*\bsrc=["']([^"']+)["']/gi,
130
+ /<iframe\b[^>]*\bsrc=["']([^"']+)["']/gi,
131
+ ];
132
+ const CSS_REF_PATTERNS = [
133
+ /\burl\(\s*["']?([^"')]+)["']?\s*\)/gi,
134
+ /@import\s+(?:url\()?\s*["']([^"')]+)["']/gi,
135
+ ];
136
+ // JS/TS only - running these on prose creates false positives on words
137
+ // like "imported from 'X'".
138
+ const JS_REF_PATTERNS = [
139
+ /\bimport\s+[^'"]*?['"]([^'"]+)['"]/g,
140
+ /\bfrom\s+['"]([^'"]+)['"]/g,
141
+ /\bimport\(\s*['"]([^'"]+)['"]\s*\)/g,
142
+ /\brequire\(\s*['"]([^'"]+)['"]\s*\)/g,
143
+ ];
144
+ // `srcset` can list multiple comma-separated candidates.
145
+ const SRCSET_PATTERN = /\bsrcset=["']([^"']+)["']/gi;
146
+ function isJsLike(mime, fromPath) {
147
+ if (mime && /javascript|typescript/i.test(mime))
148
+ return true;
149
+ return /\.(?:m?jsx?|tsx?|cjs)$/i.test(fromPath);
150
+ }
151
+ function isCssLike(mime, fromPath) {
152
+ if (mime && /^text\/css\b/i.test(mime))
153
+ return true;
154
+ return /\.css$/i.test(fromPath);
155
+ }
156
+ function isHtmlLike(mime, fromPath) {
157
+ if (mime && /^text\/html\b/i.test(mime))
158
+ return true;
159
+ return /\.html?$/i.test(fromPath);
160
+ }
161
+ /**
162
+ * Extract all relative (non-absolute, non-CDN, non-data-URI) file references from
163
+ * the text content of a file, normalized to root-relative paths.
164
+ * Runs HTML, CSS, and/or JS pattern sets based on the file's MIME type and extension.
165
+ * Skips `https?:`, `//`, `data:`, `mailto:`, `tel:`, and `#` prefixes; drops any
166
+ * reference that would escape the root via `..` traversal.
167
+ * @param text The textual content of the file.
168
+ * @param fromPath The root-relative path of the file (used for relative-path resolution).
169
+ * @param fromMime The MIME type of the file (used to select reference-extraction patterns).
170
+ * @returns Deduplicated root-relative paths of all referenced files found.
171
+ */
172
+ export function extractRelativeRefs(text, fromPath, fromMime) {
173
+ if (!text)
174
+ return [];
175
+ const refs = new Set();
176
+ const runPatterns = [];
177
+ if (isHtmlLike(fromMime, fromPath)) {
178
+ runPatterns.push(...HTML_REF_PATTERNS, ...CSS_REF_PATTERNS);
179
+ }
180
+ if (isCssLike(fromMime, fromPath)) {
181
+ runPatterns.push(...CSS_REF_PATTERNS);
182
+ }
183
+ if (isJsLike(fromMime, fromPath)) {
184
+ runPatterns.push(...JS_REF_PATTERNS);
185
+ }
186
+ // Fallback for unknown textual files: only the safest pattern,
187
+ // url() in case it's a CSS-in-something we don't recognize.
188
+ if (runPatterns.length === 0) {
189
+ runPatterns.push(...CSS_REF_PATTERNS);
190
+ }
191
+ const candidates = [];
192
+ for (const re of runPatterns) {
193
+ for (const m of text.matchAll(re)) {
194
+ // The capture group is required in every pattern, so `m[1]` is always a
195
+ // matched string here (the `!` only satisfies noUncheckedIndexedAccess).
196
+ const ref = m[1].trim();
197
+ if (ref)
198
+ candidates.push(ref);
199
+ }
200
+ }
201
+ // Pull every candidate URL out of any srcset attributes in HTML.
202
+ if (isHtmlLike(fromMime, fromPath)) {
203
+ for (const m of text.matchAll(SRCSET_PATTERN)) {
204
+ const list = m[1];
205
+ for (const part of list.split(',')) {
206
+ const url = part.trim().split(/\s+/)[0];
207
+ if (url)
208
+ candidates.push(url);
209
+ }
210
+ }
211
+ }
212
+ for (const raw of candidates) {
213
+ if (/^(?:https?:|\/\/|data:|mailto:|tel:|#)/i.test(raw))
214
+ continue;
215
+ const dir = fromPath.includes('/')
216
+ ? fromPath.slice(0, fromPath.lastIndexOf('/') + 1)
217
+ : '';
218
+ const resolved = raw.startsWith('/') ? raw.slice(1) : dir + raw;
219
+ const stripped = resolved.replace(/[?#].*$/, '');
220
+ const segs = stripped.split('/').filter(Boolean);
221
+ const out = [];
222
+ let escaped = false;
223
+ for (const s of segs) {
224
+ if (s === '.')
225
+ continue;
226
+ if (s === '..') {
227
+ if (out.length === 0) {
228
+ escaped = true;
229
+ break;
230
+ }
231
+ out.pop();
232
+ continue;
233
+ }
234
+ out.push(s);
235
+ }
236
+ if (escaped || out.length === 0)
237
+ continue;
238
+ refs.add(out.join('/'));
239
+ }
240
+ return [...refs];
241
+ }
242
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @module @jini-ai/mcp/client
3
+ * Product-neutral runtime primitives for a stdio MCP server: the idle-exit
4
+ * controller, the relative-reference extractor, and the textual-MIME
5
+ * classifier. Depends on node stdlib only; imports no sibling MCP subdirectory.
6
+ */
7
+ export * from './client.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,aAAa,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @module @jini-ai/mcp/client
3
+ * Product-neutral runtime primitives for a stdio MCP server: the idle-exit
4
+ * controller, the relative-reference extractor, and the textual-MIME
5
+ * classifier. Depends on node stdlib only; imports no sibling MCP subdirectory.
6
+ */
7
+ export * from './client.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,aAAa,CAAC"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * @module @jini-ai/mcp/core/config
3
+ * Config schema + on-disk store for the external MCP servers the daemon connects
4
+ * to as a client, plus the per-agent config builders (Claude `.mcp.json`, ACP
5
+ * `mcpServers`, OpenCode) that hand those servers to a launching agent. Part of
6
+ * the MCP `core` kernel; depends on no sibling subdirectory.
7
+ */
8
+ /** Wire-level transport discriminator for how the daemon connects to an external MCP server. */
9
+ export type McpTransport = 'stdio' | 'sse' | 'http';
10
+ /** Authentication mode for remote MCP servers: `'none'` for local/loopback targets, `'oauth'` for remote ones. */
11
+ export type McpAuthMode = 'none' | 'oauth';
12
+ /**
13
+ * Persisted configuration for a single external MCP server the user has added.
14
+ * Stored as an element of `McpConfig.servers` in `<dataDir>/mcp-config.json`.
15
+ */
16
+ export interface McpServerConfig {
17
+ id: string;
18
+ label?: string;
19
+ transport: McpTransport;
20
+ enabled: boolean;
21
+ authMode?: McpAuthMode;
22
+ command?: string;
23
+ args?: string[];
24
+ env?: Record<string, string>;
25
+ url?: string;
26
+ headers?: Record<string, string>;
27
+ }
28
+ /** Top-level on-disk shape of `<dataDir>/mcp-config.json`. */
29
+ export interface McpConfig {
30
+ servers: McpServerConfig[];
31
+ }
32
+ /**
33
+ * Infer the appropriate `McpAuthMode` for a given server URL.
34
+ * Returns `'none'` for loopback targets (localhost, 127.x.x.x, ::1)
35
+ * and `'oauth'` for everything else, including when `rawUrl` is absent or unparseable.
36
+ * @param rawUrl The server URL string to inspect, if any.
37
+ * @returns The inferred `McpAuthMode`.
38
+ */
39
+ export declare function inferMcpAuthModeForUrl(rawUrl: string | undefined): McpAuthMode;
40
+ /**
41
+ * Validate a single user-supplied entry. Drops invalid fields so a typo in
42
+ * one server doesn't tank the whole config. Returns null when the entry is
43
+ * unsalvageable (no id, or no transport-required fields).
44
+ */
45
+ export declare function sanitizeMcpServer(raw: unknown): McpServerConfig | null;
46
+ /**
47
+ * Coerce and de-duplicate a freeform JSON blob into a valid `McpConfig`.
48
+ * Entries that fail `sanitizeMcpServer` are silently dropped; duplicate ids
49
+ * are kept first-wins. Returns `{ servers: [] }` for any non-object input.
50
+ * @param raw The raw parsed JSON to sanitize.
51
+ * @returns A clean `McpConfig` guaranteed to have only valid, unique server entries.
52
+ */
53
+ export declare function sanitizeMcpConfig(raw: unknown): McpConfig;
54
+ /**
55
+ * Read and sanitize the MCP config from `<dataDir>/mcp-config.json`.
56
+ * Returns `{ servers: [] }` when the file does not exist or contains invalid JSON.
57
+ * @param dataDir The resolved runtime data directory.
58
+ * @returns The sanitized `McpConfig`, never rejects on missing-file or corrupt-JSON.
59
+ */
60
+ export declare function readMcpConfig(dataDir: string): Promise<McpConfig>;
61
+ /**
62
+ * Sanitize and atomically write the MCP config to `<dataDir>/mcp-config.json`.
63
+ * Uses a per-`dataDir` promise-chain mutex so concurrent writes serialize
64
+ * instead of racing. The body is sanitized through `sanitizeMcpConfig` before
65
+ * being written. This file may carry environment variables and
66
+ * `Authorization` header values (API keys, bearer tokens — see
67
+ * `McpServerConfig.env`/`.headers`), so it is written with owner-only
68
+ * (0600) permissions from the very first byte via `writeSecretFileAtomic`
69
+ * rather than a post-rename chmod (CR-006 / SEC-RB-002).
70
+ * @param dataDir The resolved runtime data directory.
71
+ * @param body The raw config body to sanitize and persist.
72
+ * @returns The sanitized `McpConfig` that was written to disk.
73
+ */
74
+ export declare function writeMcpConfig(dataDir: string, body: unknown): Promise<McpConfig>;
75
+ /**
76
+ * True when `cwd` is a daemon-managed project directory under `projectsDir`
77
+ * (= safe to write `.mcp.json` into without risk of clobbering a user-owned
78
+ * file). Git-linked projects whose cwd points at the user's own repo, and
79
+ * the no-project fallback that resolves to the project root, both return false
80
+ * — the daemon must NOT write external-MCP config into either of those.
81
+ *
82
+ * Both `cwd` and `projectsDir` are realpath-resolved before the containment
83
+ * check (falling back to lexical `path.resolve` normalization for a path
84
+ * that doesn't exist on disk yet), and containment is decided with
85
+ * `@jini-ai/platform`'s separator-aware `pathContains` rather than a raw
86
+ * string-prefix check — a `..`-containing path or a symlinked descendant
87
+ * can defeat a plain `startsWith` (CR-006 / SEC-RB-011).
88
+ */
89
+ export declare function isManagedProjectCwd(cwd: string | null | undefined, projectsDir: string): boolean;
90
+ /**
91
+ * Project-cwd `.mcp.json` shape that Claude Code auto-loads on spawn (the
92
+ * same format Claude Desktop and Cursor use). Returns null when the user
93
+ * has no enabled servers — in that case the caller should NOT write the
94
+ * file (and should clean up any stale one).
95
+ *
96
+ * `tokens` is an optional map of `serverId -> bearer access token`, used
97
+ * for HTTP/SSE servers that completed the daemon's web OAuth flow. When a
98
+ * token is present we inject `Authorization: Bearer <token>` into the
99
+ * server's headers — this is what bypasses the per-spawn `mcp-remote`
100
+ * dance and lets Claude Code talk directly to the upstream MCP using
101
+ * pre-authenticated credentials. User-supplied headers always win on
102
+ * conflict so they can pin a specific token if they really want to.
103
+ */
104
+ export declare function buildClaudeMcpJson(servers: McpServerConfig[], tokens?: Record<string, string>): unknown | null;
105
+ /**
106
+ * Convert user-configured external MCP servers into the ACP `mcpServers`
107
+ * shape that stdio-capable ACP agents accept.
108
+ * SSE/HTTP servers are dropped — ACP currently models stdio only.
109
+ */
110
+ export interface AcpMcpServer {
111
+ type: 'stdio';
112
+ name: string;
113
+ command: string;
114
+ args: string[];
115
+ env: Array<{
116
+ name: string;
117
+ value: string;
118
+ }>;
119
+ }
120
+ /**
121
+ * Convert user-configured external MCP servers into the ACP `mcpServers` array.
122
+ * Only stdio servers are included — SSE/HTTP are dropped because ACP currently
123
+ * models stdio only. Returns an empty array when no enabled stdio servers exist.
124
+ * @param servers The full server list from `McpConfig`.
125
+ * @returns ACP-shaped server entries for all enabled stdio servers.
126
+ */
127
+ export declare function buildAcpMcpServers(servers: McpServerConfig[]): AcpMcpServer[];
128
+ /**
129
+ * OpenCode merges its config from multiple sources at boot — global
130
+ * `~/.config/opencode/opencode.json`, the `OPENCODE_CONFIG` file path, the
131
+ * project `opencode.json`, and the `OPENCODE_CONFIG_CONTENT` env var (an
132
+ * inline JSON string). The env-var path is what lets a launcher hand servers
133
+ * to a single `opencode run` invocation without writing into the user's
134
+ * global config or leaving a temp file around on crash. We also use the same
135
+ * payload to grant `external_directory` access to launcher-selected absolute
136
+ * paths (project cwd, staged skill dirs, etc.) so headless OpenCode runs do
137
+ * not auto-reject them.
138
+ *
139
+ * Returns `null` when nothing would be emitted — the caller must NOT set
140
+ * `OPENCODE_CONFIG_CONTENT` to `null`/empty in that case, because doing so
141
+ * would override the user's saved global config with an empty object. A
142
+ * null return means "leave the env untouched and let OpenCode read the
143
+ * user's home-dir config as-is."
144
+ *
145
+ * The OAuth Bearer merge mirrors `buildClaudeMcpJson` so a remote MCP
146
+ * server the daemon already authenticated against works the same way for
147
+ * OpenCode users without forcing them to re-authenticate inside OpenCode.
148
+ */
149
+ /** Options for `buildOpenCodeMcpConfigContent`. */
150
+ export interface OpenCodeConfigBuildOptions {
151
+ /** Absolute filesystem paths OpenCode's `external_directory` permission should allow. */
152
+ allowedDirectories?: string[];
153
+ /** Additional top-level keys merged into the emitted config object (e.g. `provider`). */
154
+ extraConfig?: Record<string, unknown>;
155
+ }
156
+ export declare function buildOpenCodeMcpConfigContent(servers: McpServerConfig[], tokens?: Record<string, string>, options?: OpenCodeConfigBuildOptions): string | null;
157
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsBH,gGAAgG;AAChG,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AACpD,kHAAkH;AAClH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3C;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,8DAA8D;AAC9D,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AA+DD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAO9E;AAeD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAwCtE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAazD;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAcvE;AAID;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,SAAS,CAAC,CASpB;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,WAAW,EAAE,MAAM,GAClB,OAAO,CAOT;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,eAAe,EAAE,EAC1B,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAClC,OAAO,GAAG,IAAI,CAwBhB;AAiCD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,YAAY,EAAE,CAoB7E;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,mDAAmD;AACnD,MAAM,WAAW,0BAA0B;IACzC,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,yFAAyF;IACzF,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,eAAe,EAAE,EAC1B,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,OAAO,GAAE,0BAA+B,GACvC,MAAM,GAAG,IAAI,CAuDf"}