@ai-ecoverse/slicc-agent 3.27.0 → 3.28.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 (57) hide show
  1. package/README.md +46 -3
  2. package/dist/codemode/index.js +10 -4
  3. package/dist/codemode/index.js.map +2 -2
  4. package/dist/gelatiere/index.js +47 -9
  5. package/dist/gelatiere/index.js.map +2 -2
  6. package/dist/host.js +1 -0
  7. package/dist/host.js.map +2 -2
  8. package/dist/main.js +21 -2
  9. package/dist/main.js.map +2 -2
  10. package/dist/mcp/allow.js +39 -0
  11. package/dist/mcp/allow.js.map +7 -0
  12. package/dist/mcp/catalog.js +182 -0
  13. package/dist/mcp/catalog.js.map +7 -0
  14. package/dist/mcp/config.js +201 -0
  15. package/dist/mcp/config.js.map +7 -0
  16. package/dist/mcp/connection.js +296 -0
  17. package/dist/mcp/connection.js.map +7 -0
  18. package/dist/mcp/content.js +139 -0
  19. package/dist/mcp/content.js.map +7 -0
  20. package/dist/mcp/credentials.js +45 -0
  21. package/dist/mcp/credentials.js.map +7 -0
  22. package/dist/mcp/index.js +54 -0
  23. package/dist/mcp/index.js.map +7 -0
  24. package/dist/mcp/runtime.js +209 -0
  25. package/dist/mcp/runtime.js.map +7 -0
  26. package/dist/mcp/section.js +35 -0
  27. package/dist/mcp/section.js.map +7 -0
  28. package/dist/mcp/sse.js +112 -0
  29. package/dist/mcp/sse.js.map +7 -0
  30. package/dist/mcp/tools.js +413 -0
  31. package/dist/mcp/tools.js.map +7 -0
  32. package/dist/patches.js +2 -0
  33. package/dist/patches.js.map +2 -2
  34. package/dist/roles/roles.js +10 -1
  35. package/dist/roles/roles.js.map +2 -2
  36. package/dist/scoops/index.js +2 -1
  37. package/dist/scoops/index.js.map +2 -2
  38. package/dist/scoops/service.js +21 -6
  39. package/dist/scoops/service.js.map +2 -2
  40. package/dist/types/codemode/index.d.ts +8 -3
  41. package/dist/types/gelatiere/index.d.ts +3 -0
  42. package/dist/types/host.d.ts +2 -0
  43. package/dist/types/mcp/allow.d.ts +12 -0
  44. package/dist/types/mcp/catalog.d.ts +29 -0
  45. package/dist/types/mcp/config.d.ts +35 -0
  46. package/dist/types/mcp/connection.d.ts +57 -0
  47. package/dist/types/mcp/content.d.ts +27 -0
  48. package/dist/types/mcp/credentials.d.ts +15 -0
  49. package/dist/types/mcp/index.d.ts +16 -0
  50. package/dist/types/mcp/runtime.d.ts +42 -0
  51. package/dist/types/mcp/section.d.ts +7 -0
  52. package/dist/types/mcp/sse.d.ts +16 -0
  53. package/dist/types/mcp/tools.d.ts +44 -0
  54. package/dist/types/patches.d.ts +1 -0
  55. package/dist/types/scoops/index.d.ts +1 -0
  56. package/dist/types/scoops/service.d.ts +1 -0
  57. package/package.json +5 -4
package/dist/main.js CHANGED
@@ -23,6 +23,7 @@ import { createActivity } from "./kernel/activity.js";
23
23
  import { HOME, kernelEnvironment, SliccKernelEnv } from "./kernel/env.js";
24
24
  import { processGroups } from "./kernel/groups.js";
25
25
  import { setupLicks } from "./licks/index.js";
26
+ import { setupMcp } from "./mcp/index.js";
26
27
  import { setupMemory } from "./memory/index.js";
27
28
  import { transportFetch } from "./net.js";
28
29
  import { sliccPrompt } from "./prompt.js";
@@ -72,6 +73,7 @@ async function start(scope, port, options) {
72
73
  const memory = setupMemory(registry);
73
74
  const settings = await client.fs.readFile(`${HOME}/.pi/agent/settings.json`).catch(() => void 0);
74
75
  const coding = CodingTools.tools;
76
+ const mcp = setupMcp(registry);
75
77
  const codemode = disabledBySettings(
76
78
  settings === void 0 ? void 0 : new TextDecoder().decode(settings)
77
79
  ) ? [] : [
@@ -80,7 +82,8 @@ async function start(scope, port, options) {
80
82
  sandbox: sandboxFactory(
81
83
  options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),
82
84
  options.codemodeWorker
83
- )
85
+ ),
86
+ extra: mcp.codemode
84
87
  })
85
88
  ];
86
89
  registry.install(codemodeExtension(codemode));
@@ -115,6 +118,20 @@ async function start(scope, port, options) {
115
118
  { env: home, home: HOME, assets: options.assets ?? packageAssets(), reloadMs: RELOAD_MS },
116
119
  BACKGROUND_CONTEXT
117
120
  );
121
+ const mcpRuntime = await mcp.attach(
122
+ {
123
+ env: home,
124
+ home: HOME,
125
+ credentials,
126
+ licks: licks.licks,
127
+ fetch: scope.fetch,
128
+ version: facts.version,
129
+ reloadMs: RELOAD_MS,
130
+ codemode: codemode.length > 0,
131
+ cors: client.transport.traits?.crossOrigin === "cors"
132
+ },
133
+ BACKGROUND_CONTEXT
134
+ );
118
135
  const gelatiere = lateGelatiere();
119
136
  const sprinkles = await setupSprinkles().attach(
120
137
  {
@@ -161,6 +178,7 @@ async function start(scope, port, options) {
161
178
  memory: memoryRuntime.command,
162
179
  gelatiere: gelatiere.command,
163
180
  freezer: freezer.command,
181
+ mcp: mcp.direct,
164
182
  ...options.assets ? { assets: options.assets } : {}
165
183
  },
166
184
  BACKGROUND_CONTEXT
@@ -188,7 +206,8 @@ async function start(scope, port, options) {
188
206
  sprinkles,
189
207
  memory: memoryRuntime,
190
208
  freezer,
191
- changes
209
+ changes,
210
+ mcp: mcpRuntime
192
211
  });
193
212
  }
194
213
  function alive(client) {
package/dist/main.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts"],
4
- "sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport {\n createRegistry,\n type ModelRef,\n type Storage,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { type Agent, openAgent } from './agent.ts';\nimport { attachChanges, CHANGES_MS } from './changes/index.ts';\nimport {\n codemodeExtension,\n codemodeTool,\n disabledBySettings,\n locateWasm,\n sandboxFactory,\n} from './codemode/index.ts';\nimport { EncryptedCredentialStore } from './credentials.ts';\nimport { attachFreezer } from './freezer/index.ts';\nimport { settingsText, titler } from './freezer/title.ts';\nimport { lateGelatiere } from './gelatiere/index.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport { imageReads } from './images/index.ts';\nimport { createActivity } from './kernel/activity.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { HOME, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nimport { processGroups } from './kernel/groups.ts';\nimport { setupLicks } from './licks/index.ts';\nimport { setupMemory } from './memory/index.ts';\nimport { type Transport, transportFetch } from './net.ts';\nimport { sliccPrompt } from './prompt.ts';\nimport { identity } from './scoops/identity.ts';\nimport { type Assets, packageAssets, type ScoopsRuntime, setupScoops } from './scoops/index.ts';\nimport {\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n sliccProviders,\n} from './settings.ts';\nimport { RELOAD_MS, setupSkills } from './skills/index.ts';\nimport { setupSprinkles } from './sprinkles/index.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport {\n agentVersion,\n browserConnected,\n commandsOnPath,\n kernelBoot,\n transportName,\n} from './system.ts';\nimport { kernelPort, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n credentials?: () => Promise<CredentialStore>;\n storage?: () => Promise<Storage>;\n assets?: Assets;\n codemodeWasm?: () => Promise<WebAssembly.Module | undefined>;\n codemodeWorker?: string | URL;\n catalog?: string;\n}\n\nasync function start(\n scope: AgentWorkerScope,\n port: Promise<MessagePort>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const client = await attach(await port);\n const native = scope.fetch.bind(scope);\n scope.fetch = transportFetch(client.transport, scope.location.origin, native);\n const facts = {\n version: await agentVersion((url) => native(url)),\n commands: await commandsOnPath(client),\n transport: transportName(client.transport),\n browser: await browserConnected(client),\n };\n const credentials = await (options.credentials ?? (() => EncryptedCredentialStore.open()))();\n const providers = options.providers ?? sliccProviders();\n const models = createSliccModels(credentials, providers);\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(sliccPrompt(facts));\n registry.install(\n imageReads(\n (CodingTools.tools as readonly ToolRegistration[]).find(\n (tool) => tool.name === 'read'\n ) as ToolRegistration\n )\n );\n const memory = setupMemory(registry);\n const settings = await client.fs\n .readFile(`${HOME}/.pi/agent/settings.json`)\n .catch(() => undefined);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n const codemode = disabledBySettings(\n settings === undefined ? undefined : new TextDecoder().decode(settings)\n )\n ? []\n : [\n codemodeTool({\n declared: coding,\n sandbox: sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n ),\n }),\n ];\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\n const scoops = setupScoops(registry, licks.licks, [...coding, ...codemode, ...memory.tools]);\n const skills = setupSkills(registry, licks.licks);\n const activity = createActivity();\n const groups = processGroups(client);\n const model = options.model ?? DEFAULT_MODEL;\n let opened: Agent | undefined;\n const environment = kernelEnvironment(client, {\n activity,\n groups,\n identify: identity(() => opened?.agents, model),\n });\n const agent = await openAgent({\n models,\n model,\n storage: await (options.storage ?? (() => openOpfsSqliteStorage()))(),\n registry,\n env: environment,\n });\n opened = agent;\n const home = new SliccKernelEnv(client, { cwd: HOME });\n const sources = licks.attach(agent, { env: home, home: HOME, activity });\n await sources.start(BACKGROUND_CONTEXT);\n await sources.boot(\n { version: facts.version, boot: await kernelBoot(client) },\n BACKGROUND_CONTEXT\n );\n const skillsRuntime = await skills.attach(\n { env: home, home: HOME, assets: options.assets ?? packageAssets(), reloadMs: RELOAD_MS },\n BACKGROUND_CONTEXT\n );\n const gelatiere = lateGelatiere();\n const sprinkles = await setupSprinkles().attach(\n {\n intercept: gelatiere.intercept,\n harness: agent.harness,\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n },\n BACKGROUND_CONTEXT\n );\n let roles: ScoopsRuntime | undefined;\n const memoryRuntime = await memory.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n home: HOME,\n reloadMs: RELOAD_MS,\n roles: async (using) => roles?.roles(using),\n },\n BACKGROUND_CONTEXT\n );\n const freezer = attachFreezer({\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n extract: memory.extract,\n title: titler(models, settingsText(home, HOME)),\n });\n licks.licks.guard(freezer.frozenTarget);\n const runtime = await scoops.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n groups,\n env: home,\n home: HOME,\n alive: alive(client),\n reads: skillsRuntime.dirs,\n sprinkle: sprinkles.command,\n memory: memoryRuntime.command,\n gelatiere: gelatiere.command,\n freezer: freezer.command,\n ...(options.assets ? { assets: options.assets } : {}),\n },\n BACKGROUND_CONTEXT\n );\n roles = runtime;\n gelatiere.attach({\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n home: HOME,\n scoops: scoops.scoops,\n roles: runtime.roles,\n assets: options.assets ?? packageAssets(),\n fetch: scope.fetch,\n skills: skillsRuntime.skills,\n ...(options.catalog ? { catalog: options.catalog } : {}),\n });\n await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => undefined);\n const changes = attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS });\n return hostAgent(agent, {\n settings: await createAgentSettings(models, credentials, providers),\n licks: { licks: licks.licks, sources },\n scoops: { scoops: scoops.scoops, runtime },\n skills: skillsRuntime,\n sprinkles,\n memory: memoryRuntime,\n freezer,\n changes,\n });\n}\n\nexport function alive(client: KernelClient) {\n return async (pid: number): Promise<boolean> => {\n if (!client.ps) return true;\n return (await client.ps()).some((process) => process.pid === pid);\n };\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const host = start(scope, kernelPort(scope), options);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport {\n createRegistry,\n type ModelRef,\n type Storage,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { type Agent, openAgent } from './agent.ts';\nimport { attachChanges, CHANGES_MS } from './changes/index.ts';\nimport {\n codemodeExtension,\n codemodeTool,\n disabledBySettings,\n locateWasm,\n sandboxFactory,\n} from './codemode/index.ts';\nimport { EncryptedCredentialStore } from './credentials.ts';\nimport { attachFreezer } from './freezer/index.ts';\nimport { settingsText, titler } from './freezer/title.ts';\nimport { lateGelatiere } from './gelatiere/index.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport { imageReads } from './images/index.ts';\nimport { createActivity } from './kernel/activity.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { HOME, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nimport { processGroups } from './kernel/groups.ts';\nimport { setupLicks } from './licks/index.ts';\nimport { setupMcp } from './mcp/index.ts';\nimport { setupMemory } from './memory/index.ts';\nimport { type Transport, transportFetch } from './net.ts';\nimport { sliccPrompt } from './prompt.ts';\nimport { identity } from './scoops/identity.ts';\nimport { type Assets, packageAssets, type ScoopsRuntime, setupScoops } from './scoops/index.ts';\nimport {\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n sliccProviders,\n} from './settings.ts';\nimport { RELOAD_MS, setupSkills } from './skills/index.ts';\nimport { setupSprinkles } from './sprinkles/index.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport {\n agentVersion,\n browserConnected,\n commandsOnPath,\n kernelBoot,\n transportName,\n} from './system.ts';\nimport { kernelPort, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n credentials?: () => Promise<CredentialStore>;\n storage?: () => Promise<Storage>;\n assets?: Assets;\n codemodeWasm?: () => Promise<WebAssembly.Module | undefined>;\n codemodeWorker?: string | URL;\n catalog?: string;\n}\n\nasync function start(\n scope: AgentWorkerScope,\n port: Promise<MessagePort>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const client = await attach(await port);\n const native = scope.fetch.bind(scope);\n scope.fetch = transportFetch(client.transport, scope.location.origin, native);\n const facts = {\n version: await agentVersion((url) => native(url)),\n commands: await commandsOnPath(client),\n transport: transportName(client.transport),\n browser: await browserConnected(client),\n };\n const credentials = await (options.credentials ?? (() => EncryptedCredentialStore.open()))();\n const providers = options.providers ?? sliccProviders();\n const models = createSliccModels(credentials, providers);\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(sliccPrompt(facts));\n registry.install(\n imageReads(\n (CodingTools.tools as readonly ToolRegistration[]).find(\n (tool) => tool.name === 'read'\n ) as ToolRegistration\n )\n );\n const memory = setupMemory(registry);\n const settings = await client.fs\n .readFile(`${HOME}/.pi/agent/settings.json`)\n .catch(() => undefined);\n const coding = CodingTools.tools as readonly ToolRegistration[];\n const mcp = setupMcp(registry);\n const codemode = disabledBySettings(\n settings === undefined ? undefined : new TextDecoder().decode(settings)\n )\n ? []\n : [\n codemodeTool({\n declared: coding,\n sandbox: sandboxFactory(\n options.codemodeWasm ?? (() => locateWasm(native, new URL(import.meta.url))),\n options.codemodeWorker\n ),\n extra: mcp.codemode,\n }),\n ];\n registry.install(codemodeExtension(codemode));\n const licks = setupLicks(registry);\n const scoops = setupScoops(registry, licks.licks, [...coding, ...codemode, ...memory.tools]);\n const skills = setupSkills(registry, licks.licks);\n const activity = createActivity();\n const groups = processGroups(client);\n const model = options.model ?? DEFAULT_MODEL;\n let opened: Agent | undefined;\n const environment = kernelEnvironment(client, {\n activity,\n groups,\n identify: identity(() => opened?.agents, model),\n });\n const agent = await openAgent({\n models,\n model,\n storage: await (options.storage ?? (() => openOpfsSqliteStorage()))(),\n registry,\n env: environment,\n });\n opened = agent;\n const home = new SliccKernelEnv(client, { cwd: HOME });\n const sources = licks.attach(agent, { env: home, home: HOME, activity });\n await sources.start(BACKGROUND_CONTEXT);\n await sources.boot(\n { version: facts.version, boot: await kernelBoot(client) },\n BACKGROUND_CONTEXT\n );\n const skillsRuntime = await skills.attach(\n { env: home, home: HOME, assets: options.assets ?? packageAssets(), reloadMs: RELOAD_MS },\n BACKGROUND_CONTEXT\n );\n const mcpRuntime = await mcp.attach(\n {\n env: home,\n home: HOME,\n credentials,\n licks: licks.licks,\n fetch: scope.fetch,\n version: facts.version,\n reloadMs: RELOAD_MS,\n codemode: codemode.length > 0,\n cors: client.transport.traits?.crossOrigin === 'cors',\n },\n BACKGROUND_CONTEXT\n );\n const gelatiere = lateGelatiere();\n const sprinkles = await setupSprinkles().attach(\n {\n intercept: gelatiere.intercept,\n harness: agent.harness,\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n assets: options.assets ?? packageAssets(),\n reloadMs: RELOAD_MS,\n },\n BACKGROUND_CONTEXT\n );\n let roles: ScoopsRuntime | undefined;\n const memoryRuntime = await memory.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n home: HOME,\n reloadMs: RELOAD_MS,\n roles: async (using) => roles?.roles(using),\n },\n BACKGROUND_CONTEXT\n );\n const freezer = attachFreezer({\n harness: agent.harness,\n agents: agent.agents,\n env: home,\n extract: memory.extract,\n title: titler(models, settingsText(home, HOME)),\n });\n licks.licks.guard(freezer.frozenTarget);\n const runtime = await scoops.attach(\n {\n harness: agent.harness,\n agents: agent.agents,\n groups,\n env: home,\n home: HOME,\n alive: alive(client),\n reads: skillsRuntime.dirs,\n sprinkle: sprinkles.command,\n memory: memoryRuntime.command,\n gelatiere: gelatiere.command,\n freezer: freezer.command,\n mcp: mcp.direct,\n ...(options.assets ? { assets: options.assets } : {}),\n },\n BACKGROUND_CONTEXT\n );\n roles = runtime;\n gelatiere.attach({\n agents: agent.agents,\n licks: licks.licks,\n env: home,\n home: HOME,\n scoops: scoops.scoops,\n roles: runtime.roles,\n assets: options.assets ?? packageAssets(),\n fetch: scope.fetch,\n skills: skillsRuntime.skills,\n ...(options.catalog ? { catalog: options.catalog } : {}),\n });\n await memoryRuntime.reload(BACKGROUND_CONTEXT).catch(() => undefined);\n const changes = attachChanges({ agents: agent.agents, env: home, reloadMs: CHANGES_MS });\n return hostAgent(agent, {\n settings: await createAgentSettings(models, credentials, providers),\n licks: { licks: licks.licks, sources },\n scoops: { scoops: scoops.scoops, runtime },\n skills: skillsRuntime,\n sprinkles,\n memory: memoryRuntime,\n freezer,\n changes,\n mcp: mcpRuntime,\n });\n}\n\nexport function alive(client: KernelClient) {\n return async (pid: number): Promise<boolean> => {\n if (!client.ps) return true;\n return (await client.ps()).some((process) => process.pid === pid);\n };\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const host = start(scope, kernelPort(scope), options);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,39 @@
1
+ import { defineDoc } from "@earendil-works/pi-durable";
2
+ import { mcpNamespace, nameMatcher } from "./config.js";
3
+ const RESOURCE_NAMES = /* @__PURE__ */ new Set([
4
+ "list_mcp_resources",
5
+ "list_mcp_resource_templates",
6
+ "read_mcp_resource"
7
+ ]);
8
+ const McpAllowDoc = defineDoc({
9
+ kind: "slicc.mcp",
10
+ version: 1,
11
+ scope: "conversation",
12
+ history: "rewindable",
13
+ fork: "asOf",
14
+ initial: () => ({ allow: null })
15
+ });
16
+ function mcpEntries(names) {
17
+ if (!names) return null;
18
+ return names.filter((name) => name.startsWith("mcp__") || RESOURCE_NAMES.has(name));
19
+ }
20
+ function allows(allow, name) {
21
+ return allow === null || nameMatcher(allow)(name);
22
+ }
23
+ function serverAllowed(allow, server) {
24
+ if (allow === null) return true;
25
+ const prefix = `${mcpNamespace(server)}__`;
26
+ return allow.some((entry) => {
27
+ if (entry.startsWith(prefix)) return true;
28
+ if (!entry.includes("*")) return false;
29
+ return prefix.startsWith(entry.slice(0, entry.indexOf("*")));
30
+ });
31
+ }
32
+ export {
33
+ McpAllowDoc,
34
+ RESOURCE_NAMES,
35
+ allows,
36
+ mcpEntries,
37
+ serverAllowed
38
+ };
39
+ //# sourceMappingURL=allow.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/mcp/allow.ts"],
4
+ "sourcesContent": ["import type { CodemodeTool } from '@earendil-works/pi-codemode';\nimport { defineDoc } from '@earendil-works/pi-durable';\nimport { mcpNamespace, nameMatcher } from './config.ts';\n\nexport const RESOURCE_NAMES: ReadonlySet<string> = new Set([\n 'list_mcp_resources',\n 'list_mcp_resource_templates',\n 'read_mcp_resource',\n]);\n\nexport const McpAllowDoc = defineDoc<{ allow: string[] | null }>({\n kind: 'slicc.mcp',\n version: 1,\n scope: 'conversation',\n history: 'rewindable',\n fork: 'asOf',\n initial: () => ({ allow: null }),\n});\n\nexport interface CodemodeExtra {\n tools: CodemodeTool[];\n globals: CodemodeTool[];\n}\n\nexport function mcpEntries(names: readonly string[] | undefined): string[] | null {\n if (!names) return null;\n return names.filter((name) => name.startsWith('mcp__') || RESOURCE_NAMES.has(name));\n}\n\nexport function allows(allow: readonly string[] | null, name: string): boolean {\n return allow === null || nameMatcher(allow)(name);\n}\n\nexport function serverAllowed(allow: readonly string[] | null, server: string): boolean {\n if (allow === null) return true;\n const prefix = `${mcpNamespace(server)}__`;\n return allow.some((entry) => {\n if (entry.startsWith(prefix)) return true;\n if (!entry.includes('*')) return false;\n return prefix.startsWith(entry.slice(0, entry.indexOf('*')));\n });\n}\n"],
5
+ "mappings": "AACA,SAAS,iBAAiB;AAC1B,SAAS,cAAc,mBAAmB;AAEnC,MAAM,iBAAsC,oBAAI,IAAI;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,MAAM,cAAc,UAAsC;AAAA,EAC/D,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS,OAAO,EAAE,OAAO,KAAK;AAChC,CAAC;AAOM,SAAS,WAAW,OAAuD;AAChF,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,OAAO,CAAC,SAAS,KAAK,WAAW,OAAO,KAAK,eAAe,IAAI,IAAI,CAAC;AACpF;AAEO,SAAS,OAAO,OAAiC,MAAuB;AAC7E,SAAO,UAAU,QAAQ,YAAY,KAAK,EAAE,IAAI;AAClD;AAEO,SAAS,cAAc,OAAiC,QAAyB;AACtF,MAAI,UAAU,KAAM,QAAO;AAC3B,QAAM,SAAS,GAAG,aAAa,MAAM,CAAC;AACtC,SAAO,MAAM,KAAK,CAAC,UAAU;AAC3B,QAAI,MAAM,WAAW,MAAM,EAAG,QAAO;AACrC,QAAI,CAAC,MAAM,SAAS,GAAG,EAAG,QAAO;AACjC,WAAO,OAAO,WAAW,MAAM,MAAM,GAAG,MAAM,QAAQ,GAAG,CAAC,CAAC;AAAA,EAC7D,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -0,0 +1,182 @@
1
+ import {
2
+ defineExtension,
3
+ hook,
4
+ section,
5
+ ToolTask
6
+ } from "@earendil-works/pi-durable";
7
+ import { allows, McpAllowDoc, RESOURCE_NAMES, serverAllowed } from "./allow.js";
8
+ import {
9
+ mcpNamespace,
10
+ mcpToolName,
11
+ nameMatcher,
12
+ toolExposure
13
+ } from "./config.js";
14
+ import { renderSection } from "./section.js";
15
+ import {
16
+ apiSaver,
17
+ directTool,
18
+ discoveryGlobals,
19
+ resourceScriptTools,
20
+ resourceTools,
21
+ scriptTool
22
+ } from "./tools.js";
23
+ const MCP_EXTENSION = "slicc-mcp";
24
+ const MCP_SECTION = "mcp_servers";
25
+ const DIRECT_WAIT_MS = 1e4;
26
+ function effective(exposure, codemode) {
27
+ const indirect = exposure === "deferred" ? "codemode" : exposure;
28
+ return indirect === "codemode" && !codemode ? "direct" : indirect;
29
+ }
30
+ async function allowOf(read, conversationId, context) {
31
+ const doc = await read.snapshot(McpAllowDoc, conversationId, context).catch(() => void 0);
32
+ return doc?.allow ?? null;
33
+ }
34
+ class McpCatalog {
35
+ connections = /* @__PURE__ */ new Map();
36
+ entries = [];
37
+ codemodeOn = true;
38
+ current;
39
+ #registry;
40
+ #section = section(
41
+ MCP_SECTION,
42
+ async (input, context) => renderSection(this.listings(await allowOf(input.read, input.conversationId, context)))
43
+ );
44
+ #guard = hook(ToolTask, {
45
+ beforeTool: async (call, api, context) => {
46
+ const name = call.name;
47
+ if (!name.startsWith("mcp__") && !RESOURCE_NAMES.has(name)) return void 0;
48
+ const allow = await allowOf(api, api.conversationId, context);
49
+ if (allows(allow, name)) return void 0;
50
+ return { block: `${name} isn't among the MCP tools this scoop may use` };
51
+ }
52
+ });
53
+ constructor(registry) {
54
+ this.#registry = registry;
55
+ this.current = defineExtension({ name: MCP_EXTENSION });
56
+ }
57
+ connected() {
58
+ return [...this.connections.values()].filter((connection) => connection.live);
59
+ }
60
+ #resourceful() {
61
+ return this.connected().filter(
62
+ (connection) => connection.hasResources && effective(connection.entry.config.exposure ?? "codemode", this.codemodeOn) !== "hidden"
63
+ );
64
+ }
65
+ resourceServers(allow) {
66
+ return this.#resourceful().filter((connection) => serverAllowed(allow, connection.name)).map((connection) => ({ name: connection.name, connection }));
67
+ }
68
+ resourceExposure() {
69
+ const exposures = this.#resourceful().map(
70
+ (connection) => effective(connection.entry.config.exposure ?? "codemode", this.codemodeOn)
71
+ );
72
+ if (!exposures.length) return void 0;
73
+ return exposures.includes("direct") ? "direct" : "codemode";
74
+ }
75
+ listings(allow) {
76
+ return [...this.connections.values()].filter((connection) => {
77
+ if (!serverAllowed(allow, connection.name)) return false;
78
+ const { config } = connection.entry;
79
+ const exposures = [
80
+ config.exposure ?? "codemode",
81
+ ...Object.values(config.toolExposure ?? {})
82
+ ];
83
+ return exposures.some((exposure) => effective(exposure, this.codemodeOn) === "codemode");
84
+ }).map((connection) => ({
85
+ name: connection.name,
86
+ ...connection.entry.config.description ? { description: connection.entry.config.description } : {},
87
+ ...connection.instructions ? { instructions: connection.instructions } : {}
88
+ }));
89
+ }
90
+ install() {
91
+ const readable = this.resourceExposure() !== void 0;
92
+ const direct = this.entries.filter((entry) => entry.exposure === "direct").map((entry) => directTool(entry, () => readable && entry.connection.hasResources));
93
+ const resources = this.resourceExposure() === "direct" ? resourceTools(
94
+ async (api, context) => this.resourceServers(await allowOf(api, api.conversationId, context))
95
+ ) : [];
96
+ this.current = defineExtension({
97
+ name: MCP_EXTENSION,
98
+ tools: [...direct, ...resources],
99
+ sections: [this.#section],
100
+ hooks: [this.#guard]
101
+ });
102
+ this.#registry.install(this.current);
103
+ }
104
+ rebuild() {
105
+ const taken = /* @__PURE__ */ new Set();
106
+ const next = [];
107
+ for (const connection of this.connected()) {
108
+ for (const tool of connection.tools) {
109
+ const exposure = effective(
110
+ toolExposure(connection.entry.config, tool.name),
111
+ this.codemodeOn
112
+ );
113
+ if (exposure === "hidden") continue;
114
+ const name = mcpToolName(connection.name, tool.name, (candidate) => taken.has(candidate));
115
+ taken.add(name);
116
+ next.push({ server: connection.name, name, exposure, tool, connection });
117
+ }
118
+ }
119
+ this.entries = next;
120
+ this.install();
121
+ }
122
+ direct(names) {
123
+ const match = nameMatcher([...names]);
124
+ return (this.current.tools ?? []).filter((tool) => match(tool.name));
125
+ }
126
+ async waitFor(allow) {
127
+ const pending = [...this.connections.values()].filter(
128
+ (connection) => connection.state === "connecting" && serverAllowed(allow, connection.name)
129
+ );
130
+ if (!pending.length) return;
131
+ let timer;
132
+ await Promise.race([
133
+ Promise.allSettled(pending.map((connection) => connection.getClient())),
134
+ new Promise((resolve) => {
135
+ timer = setTimeout(resolve, DIRECT_WAIT_MS);
136
+ })
137
+ ]);
138
+ clearTimeout(timer);
139
+ }
140
+ #namespaces() {
141
+ const spaces = /* @__PURE__ */ new Map();
142
+ for (const entry of this.entries) {
143
+ const { config } = entry.connection.entry;
144
+ spaces.set(entry.name, {
145
+ name: mcpNamespace(entry.server),
146
+ ...config.description ? { description: config.description } : {},
147
+ ...entry.connection.instructions ? { instructions: entry.connection.instructions } : {}
148
+ });
149
+ }
150
+ return spaces;
151
+ }
152
+ async codemode(api, agent, context) {
153
+ if (!agent.extensions.some((extension) => extension.name === MCP_EXTENSION))
154
+ return { tools: [], globals: [] };
155
+ const allow = await allowOf(api, api.conversationId, context);
156
+ await this.waitFor(allow);
157
+ const signal = context.abortSignal;
158
+ const offered = new Set(agent.tools.map((tool) => tool.name));
159
+ const tools = this.entries.filter(
160
+ (entry) => allows(allow, entry.name) && (entry.exposure !== "direct" || offered.has(entry.name))
161
+ ).map((entry) => scriptTool(entry, signal));
162
+ const save = apiSaver(api, "r", context);
163
+ const resources = this.resourceExposure() === "codemode" && this.resourceServers(allow).length ? resourceScriptTools(() => this.resourceServers(allow), signal, save).filter(
164
+ (tool) => allows(allow, tool.name)
165
+ ) : [];
166
+ const all = [...tools, ...resources];
167
+ const spaces = this.#namespaces();
168
+ return {
169
+ tools: all,
170
+ globals: all.length ? discoveryGlobals(all, (name) => spaces.get(name)) : []
171
+ };
172
+ }
173
+ }
174
+ export {
175
+ DIRECT_WAIT_MS,
176
+ MCP_EXTENSION,
177
+ MCP_SECTION,
178
+ McpCatalog,
179
+ allowOf,
180
+ effective
181
+ };
182
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/mcp/catalog.ts"],
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n type Agent,\n type ConversationId,\n type DocumentReader,\n defineExtension,\n type Extension,\n hook,\n type Registry,\n section,\n type ToolExecutionApi,\n type ToolRegistration,\n ToolTask,\n} from '@earendil-works/pi-durable';\nimport { allows, type CodemodeExtra, McpAllowDoc, RESOURCE_NAMES, serverAllowed } from './allow.ts';\nimport {\n type McpExposure,\n mcpNamespace,\n mcpToolName,\n nameMatcher,\n toolExposure,\n} from './config.ts';\nimport type { McpServerConnection } from './connection.ts';\nimport { type Listing, renderSection } from './section.ts';\nimport {\n apiSaver,\n directTool,\n discoveryGlobals,\n type McpToolEntry,\n type Namespace,\n type ResourceServer,\n resourceScriptTools,\n resourceTools,\n scriptTool,\n} from './tools.ts';\n\nexport const MCP_EXTENSION = 'slicc-mcp';\nexport const MCP_SECTION = 'mcp_servers';\nexport const DIRECT_WAIT_MS = 10_000;\n\nexport function effective(exposure: McpExposure, codemode: boolean): McpExposure {\n const indirect = exposure === 'deferred' ? 'codemode' : exposure;\n return indirect === 'codemode' && !codemode ? 'direct' : indirect;\n}\n\nexport async function allowOf(\n read: DocumentReader,\n conversationId: ConversationId,\n context: Context\n): Promise<string[] | null> {\n const doc = await read.snapshot(McpAllowDoc, conversationId, context).catch(() => undefined);\n return doc?.allow ?? null;\n}\n\nexport class McpCatalog {\n readonly connections = new Map<string, McpServerConnection>();\n entries: McpToolEntry[] = [];\n codemodeOn = true;\n current: Extension;\n readonly #registry: Registry;\n readonly #section = section(MCP_SECTION, async (input, context) =>\n renderSection(this.listings(await allowOf(input.read, input.conversationId, context)))\n );\n\n readonly #guard = hook(ToolTask, {\n beforeTool: async (call, api, context) => {\n const name = call.name;\n if (!name.startsWith('mcp__') && !RESOURCE_NAMES.has(name)) return undefined;\n const allow = await allowOf(api, api.conversationId, context);\n if (allows(allow, name)) return undefined;\n return { block: `${name} isn't among the MCP tools this scoop may use` };\n },\n });\n\n constructor(registry: Registry) {\n this.#registry = registry;\n this.current = defineExtension({ name: MCP_EXTENSION });\n }\n\n connected(): McpServerConnection[] {\n return [...this.connections.values()].filter((connection) => connection.live);\n }\n\n #resourceful(): McpServerConnection[] {\n return this.connected().filter(\n (connection) =>\n connection.hasResources &&\n effective(connection.entry.config.exposure ?? 'codemode', this.codemodeOn) !== 'hidden'\n );\n }\n\n resourceServers(allow: readonly string[] | null): ResourceServer[] {\n return this.#resourceful()\n .filter((connection) => serverAllowed(allow, connection.name))\n .map((connection) => ({ name: connection.name, connection }));\n }\n\n resourceExposure(): McpExposure | undefined {\n const exposures = this.#resourceful().map((connection) =>\n effective(connection.entry.config.exposure ?? 'codemode', this.codemodeOn)\n );\n if (!exposures.length) return undefined;\n return exposures.includes('direct') ? 'direct' : 'codemode';\n }\n\n listings(allow: readonly string[] | null): Listing[] {\n return [...this.connections.values()]\n .filter((connection) => {\n if (!serverAllowed(allow, connection.name)) return false;\n const { config } = connection.entry;\n const exposures = [\n config.exposure ?? 'codemode',\n ...Object.values(config.toolExposure ?? {}),\n ];\n return exposures.some((exposure) => effective(exposure, this.codemodeOn) === 'codemode');\n })\n .map((connection) => ({\n name: connection.name,\n ...(connection.entry.config.description\n ? { description: connection.entry.config.description }\n : {}),\n ...(connection.instructions ? { instructions: connection.instructions } : {}),\n }));\n }\n\n install(): void {\n const readable = this.resourceExposure() !== undefined;\n const direct = this.entries\n .filter((entry) => entry.exposure === 'direct')\n .map((entry) => directTool(entry, () => readable && entry.connection.hasResources));\n const resources =\n this.resourceExposure() === 'direct'\n ? resourceTools(async (api, context) =>\n this.resourceServers(await allowOf(api, api.conversationId, context))\n )\n : [];\n this.current = defineExtension({\n name: MCP_EXTENSION,\n tools: [...direct, ...resources],\n sections: [this.#section],\n hooks: [this.#guard],\n });\n this.#registry.install(this.current);\n }\n\n rebuild(): void {\n const taken = new Set<string>();\n const next: McpToolEntry[] = [];\n for (const connection of this.connected()) {\n for (const tool of connection.tools) {\n const exposure = effective(\n toolExposure(connection.entry.config, tool.name),\n this.codemodeOn\n );\n if (exposure === 'hidden') continue;\n const name = mcpToolName(connection.name, tool.name, (candidate) => taken.has(candidate));\n taken.add(name);\n next.push({ server: connection.name, name, exposure, tool, connection });\n }\n }\n this.entries = next;\n this.install();\n }\n\n direct(names: readonly string[]): ToolRegistration[] {\n const match = nameMatcher([...names]);\n return ((this.current.tools ?? []) as ToolRegistration[]).filter((tool) => match(tool.name));\n }\n\n async waitFor(allow: readonly string[] | null): Promise<void> {\n const pending = [...this.connections.values()].filter(\n (connection) => connection.state === 'connecting' && serverAllowed(allow, connection.name)\n );\n if (!pending.length) return;\n let timer: ReturnType<typeof setTimeout> | undefined;\n await Promise.race([\n Promise.allSettled(pending.map((connection) => connection.getClient())),\n new Promise((resolve) => {\n timer = setTimeout(resolve, DIRECT_WAIT_MS);\n }),\n ]);\n clearTimeout(timer);\n }\n\n #namespaces(): Map<string, Namespace> {\n const spaces = new Map<string, Namespace>();\n for (const entry of this.entries) {\n const { config } = entry.connection.entry;\n spaces.set(entry.name, {\n name: mcpNamespace(entry.server),\n ...(config.description ? { description: config.description } : {}),\n ...(entry.connection.instructions ? { instructions: entry.connection.instructions } : {}),\n });\n }\n return spaces;\n }\n\n async codemode(api: ToolExecutionApi, agent: Agent, context: Context): Promise<CodemodeExtra> {\n if (!agent.extensions.some((extension) => extension.name === MCP_EXTENSION))\n return { tools: [], globals: [] };\n const allow = await allowOf(api, api.conversationId, context);\n await this.waitFor(allow);\n const signal = context.abortSignal as AbortSignal | undefined;\n const offered = new Set(agent.tools.map((tool) => tool.name));\n const tools = this.entries\n .filter(\n (entry) =>\n allows(allow, entry.name) && (entry.exposure !== 'direct' || offered.has(entry.name))\n )\n .map((entry) => scriptTool(entry, signal));\n const save = apiSaver(api, 'r', context);\n const resources =\n this.resourceExposure() === 'codemode' && this.resourceServers(allow).length\n ? resourceScriptTools(() => this.resourceServers(allow), signal, save).filter((tool) =>\n allows(allow, tool.name)\n )\n : [];\n const all = [...tools, ...resources];\n const spaces = this.#namespaces();\n return {\n tools: all,\n globals: all.length ? discoveryGlobals(all, (name) => spaces.get(name)) : [],\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,201 @@
1
+ import { hash } from "../licks/sources.js";
2
+ const SERVER_NAME = /^[A-Za-z0-9_-]+$/;
3
+ const EXPOSURES = ["codemode", "deferred", "direct", "hidden"];
4
+ const ALIASES = { "codemode-deferred": "codemode" };
5
+ const ACCEPTED = /* @__PURE__ */ new Set([
6
+ "type",
7
+ "url",
8
+ "headers",
9
+ "exposure",
10
+ "toolExposure",
11
+ "enabled",
12
+ "timeout",
13
+ "description"
14
+ ]);
15
+ const SECRET_HEADER = /authorization|cookie|token|key|secret|password|session/i;
16
+ const SECRET_PARAM = /token|key|secret|password|signature|sig|auth|code/i;
17
+ const PLACEHOLDER = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
18
+ const SCHEME = /^\s*(?:bearer|basic|token|apikey|api-key)\s+/i;
19
+ const MAX_TOOL_NAME = 64;
20
+ const DEFAULT_TIMEOUT_SECONDS = 60;
21
+ function isRecord(value) {
22
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23
+ }
24
+ function alias(value) {
25
+ return typeof value === "string" ? ALIASES[value] ?? value : value;
26
+ }
27
+ function isExposure(value) {
28
+ return typeof value === "string" && EXPOSURES.includes(value);
29
+ }
30
+ function placeholders(value) {
31
+ return [...value.matchAll(PLACEHOLDER)].map((match) => match[1]);
32
+ }
33
+ function literalSecret(header, value) {
34
+ if (!SECRET_HEADER.test(header)) return false;
35
+ return value.replace(PLACEHOLDER, "").replace(SCHEME, "").trim() !== "";
36
+ }
37
+ function urlSecret(url) {
38
+ if (url.username || url.password) return "url";
39
+ for (const name of url.searchParams.keys()) if (SECRET_PARAM.test(name)) return `url ?${name}`;
40
+ return void 0;
41
+ }
42
+ function fail(server, message, field) {
43
+ return { server, ...field ? { field } : {}, message };
44
+ }
45
+ function checkHeaders(name, headers) {
46
+ if (headers === void 0) return void 0;
47
+ if (!isRecord(headers) || !Object.values(headers).every((value) => typeof value === "string"))
48
+ return fail(name, "headers must map names to strings", "headers");
49
+ for (const [header, value] of Object.entries(headers)) {
50
+ if (value.trim().startsWith("!"))
51
+ return fail(
52
+ name,
53
+ `headers.${header} runs a command, which SLICC can't do`,
54
+ `headers.${header}`
55
+ );
56
+ if (literalSecret(header, value))
57
+ return fail(
58
+ name,
59
+ `headers.${header} holds a literal secret. mcp.json is readable by every agent: write \${NAME} instead, and add the value in Settings \u203A Accounts`,
60
+ `headers.${header}`
61
+ );
62
+ }
63
+ return void 0;
64
+ }
65
+ function checkExposures(name, value) {
66
+ const allowed = EXPOSURES.map((item) => `"${item}"`).join(", ");
67
+ if (value.exposure !== void 0 && !isExposure(value.exposure))
68
+ return fail(name, `exposure must be one of ${allowed}`, "exposure");
69
+ if (value.toolExposure === void 0) return void 0;
70
+ if (!isRecord(value.toolExposure))
71
+ return fail(name, "toolExposure must map tool names to exposures", "toolExposure");
72
+ for (const [tool, exposure] of Object.entries(value.toolExposure))
73
+ if (!isExposure(exposure))
74
+ return fail(name, `toolExposure "${tool}" must be one of ${allowed}`, `toolExposure.${tool}`);
75
+ return void 0;
76
+ }
77
+ function checkFields(name, value) {
78
+ if (value.enabled !== void 0 && typeof value.enabled !== "boolean")
79
+ return fail(name, "enabled must be a boolean", "enabled");
80
+ if (value.description !== void 0 && typeof value.description !== "string")
81
+ return fail(name, "description must be a string", "description");
82
+ if (value.timeout !== void 0 && (typeof value.timeout !== "number" || !(value.timeout > 0)))
83
+ return fail(name, "timeout must be a positive number of seconds", "timeout");
84
+ return void 0;
85
+ }
86
+ function checkTransport(name, value) {
87
+ if (value.command !== void 0 || value.type === "stdio")
88
+ return fail(name, "stdio servers need slicc-kernel#68, so this one is skipped", "command");
89
+ if (value.type === "sse")
90
+ return fail(
91
+ name,
92
+ "the legacy SSE transport is not supported; use the streamable HTTP URL",
93
+ "type"
94
+ );
95
+ if (value.type !== void 0 && value.type !== "http" && value.type !== "streamable-http")
96
+ return fail(name, 'type must be "http" or "streamable-http"', "type");
97
+ if (typeof value.url !== "string") return fail(name, 'needs a "url" (streamable HTTP)', "url");
98
+ if (!URL.canParse(value.url) || !/^https?:$/.test(new URL(value.url).protocol))
99
+ return fail(name, "url must be an http or https URL", "url");
100
+ const secret = urlSecret(new URL(value.url));
101
+ if (secret)
102
+ return fail(
103
+ name,
104
+ `${secret} holds a literal secret. Put it in a header as \${NAME} and add the value in Settings \u203A Accounts`,
105
+ "url"
106
+ );
107
+ return void 0;
108
+ }
109
+ function validateServer(name, raw) {
110
+ if (!SERVER_NAME.test(name))
111
+ return fail(name, `invalid server name "${name}" (use letters, digits, "_" and "-")`);
112
+ if (!isRecord(raw)) return fail(name, "must be an object");
113
+ const value = { ...raw, exposure: alias(raw.exposure) };
114
+ if (raw.exposure === void 0) delete value.exposure;
115
+ if (isRecord(raw.toolExposure))
116
+ value.toolExposure = Object.fromEntries(
117
+ Object.entries(raw.toolExposure).map(([tool, exposure]) => [tool, alias(exposure)])
118
+ );
119
+ for (const key of Object.keys(value))
120
+ if (key === "oauth" || key === "auth")
121
+ return fail(name, `${key} is not supported in SLICC yet`, key);
122
+ const problem = checkTransport(name, value) ?? checkHeaders(name, value.headers) ?? checkExposures(name, value) ?? checkFields(name, value);
123
+ if (problem) return problem;
124
+ const config = {};
125
+ for (const [key, entry] of Object.entries(value))
126
+ if (ACCEPTED.has(key) && key !== "type") config[key] = entry;
127
+ return config;
128
+ }
129
+ function canonical(name) {
130
+ return name.replace(/-/g, "_");
131
+ }
132
+ function parseMcpConfig(text) {
133
+ if (text === void 0 || text.trim() === "") return { servers: [], problems: [] };
134
+ let parsed;
135
+ try {
136
+ parsed = JSON.parse(text);
137
+ } catch (error) {
138
+ return { servers: [], problems: [{ message: `not valid JSON: ${error.message}` }] };
139
+ }
140
+ if (!isRecord(parsed) || parsed.mcpServers !== void 0 && !isRecord(parsed.mcpServers))
141
+ return { servers: [], problems: [{ message: "mcpServers must be an object" }] };
142
+ const servers = [];
143
+ const problems = [];
144
+ const seen = /* @__PURE__ */ new Set();
145
+ for (const [name, raw] of Object.entries(parsed.mcpServers ?? {})) {
146
+ const checked = validateServer(name, raw);
147
+ if ("message" in checked) {
148
+ problems.push(checked);
149
+ continue;
150
+ }
151
+ if (seen.has(canonical(name))) {
152
+ problems.push(fail(name, 'names that differ only in "-" and "_" count as the same server'));
153
+ continue;
154
+ }
155
+ seen.add(canonical(name));
156
+ servers.push({ name, config: checked });
157
+ }
158
+ return { servers, problems };
159
+ }
160
+ function patternRegExp(pattern) {
161
+ const source = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
162
+ return new RegExp(`^${source}$`);
163
+ }
164
+ function nameMatcher(entries) {
165
+ const names = new Set(entries.filter((entry) => !entry.includes("*")));
166
+ const patterns = entries.filter((entry) => entry.includes("*")).map(patternRegExp);
167
+ return (name) => names.has(name) || patterns.some((pattern) => pattern.test(name));
168
+ }
169
+ function toolExposure(config, tool) {
170
+ const overrides = config.toolExposure ?? {};
171
+ const exact = overrides[tool];
172
+ if (exact !== void 0) return exact;
173
+ for (const [pattern, exposure] of Object.entries(overrides))
174
+ if (pattern.includes("*") && patternRegExp(pattern).test(tool)) return exposure;
175
+ return config.exposure ?? "codemode";
176
+ }
177
+ function mcpNamespace(server) {
178
+ return `mcp__${canonical(server)}`;
179
+ }
180
+ function mcpToolName(server, tool, taken = () => false) {
181
+ const name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_]/g, "_");
182
+ if (name.length <= MAX_TOOL_NAME && !taken(name)) return name;
183
+ const suffix = hash(`${server}\0${tool}`).padStart(7, "0").slice(0, 7);
184
+ return `${name.slice(0, MAX_TOOL_NAME - suffix.length - 1)}_${suffix}`;
185
+ }
186
+ function sameConfig(a, b) {
187
+ return JSON.stringify(a) === JSON.stringify(b);
188
+ }
189
+ export {
190
+ DEFAULT_TIMEOUT_SECONDS,
191
+ literalSecret,
192
+ mcpNamespace,
193
+ mcpToolName,
194
+ nameMatcher,
195
+ parseMcpConfig,
196
+ placeholders,
197
+ sameConfig,
198
+ toolExposure,
199
+ validateServer
200
+ };
201
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/mcp/config.ts"],
4
+ "sourcesContent": ["import { hash } from '../licks/sources.ts';\n\nexport type McpExposure = 'codemode' | 'deferred' | 'direct' | 'hidden';\n\nexport interface McpServerConfig {\n url: string;\n headers?: Record<string, string>;\n exposure?: McpExposure;\n toolExposure?: Record<string, McpExposure>;\n enabled?: boolean;\n timeout?: number;\n description?: string;\n}\n\nexport interface McpServerEntry {\n name: string;\n config: McpServerConfig;\n}\n\nexport interface McpConfigProblem {\n server?: string;\n field?: string;\n message: string;\n}\n\nexport interface McpConfig {\n servers: McpServerEntry[];\n problems: McpConfigProblem[];\n}\n\nconst SERVER_NAME = /^[A-Za-z0-9_-]+$/;\nconst EXPOSURES: readonly string[] = ['codemode', 'deferred', 'direct', 'hidden'];\nconst ALIASES: Record<string, McpExposure> = { 'codemode-deferred': 'codemode' };\nconst ACCEPTED = new Set([\n 'type',\n 'url',\n 'headers',\n 'exposure',\n 'toolExposure',\n 'enabled',\n 'timeout',\n 'description',\n]);\nconst SECRET_HEADER = /authorization|cookie|token|key|secret|password|session/i;\nconst SECRET_PARAM = /token|key|secret|password|signature|sig|auth|code/i;\nconst PLACEHOLDER = /\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g;\nconst SCHEME = /^\\s*(?:bearer|basic|token|apikey|api-key)\\s+/i;\nconst MAX_TOOL_NAME = 64;\nexport const DEFAULT_TIMEOUT_SECONDS = 60;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction alias(value: unknown): unknown {\n return typeof value === 'string' ? (ALIASES[value] ?? value) : value;\n}\n\nfunction isExposure(value: unknown): value is McpExposure {\n return typeof value === 'string' && EXPOSURES.includes(value);\n}\n\nexport function placeholders(value: string): string[] {\n return [...value.matchAll(PLACEHOLDER)].map((match) => match[1] as string);\n}\n\nexport function literalSecret(header: string, value: string): boolean {\n if (!SECRET_HEADER.test(header)) return false;\n return value.replace(PLACEHOLDER, '').replace(SCHEME, '').trim() !== '';\n}\n\nfunction urlSecret(url: URL): string | undefined {\n if (url.username || url.password) return 'url';\n for (const name of url.searchParams.keys()) if (SECRET_PARAM.test(name)) return `url ?${name}`;\n return undefined;\n}\n\ntype Checked = McpServerConfig | McpConfigProblem;\n\nfunction fail(server: string, message: string, field?: string): McpConfigProblem {\n return { server, ...(field ? { field } : {}), message };\n}\n\nfunction checkHeaders(name: string, headers: unknown): McpConfigProblem | undefined {\n if (headers === undefined) return undefined;\n if (!isRecord(headers) || !Object.values(headers).every((value) => typeof value === 'string'))\n return fail(name, 'headers must map names to strings', 'headers');\n for (const [header, value] of Object.entries(headers as Record<string, string>)) {\n if (value.trim().startsWith('!'))\n return fail(\n name,\n `headers.${header} runs a command, which SLICC can't do`,\n `headers.${header}`\n );\n if (literalSecret(header, value))\n return fail(\n name,\n `headers.${header} holds a literal secret. mcp.json is readable by every agent: write \\${NAME} instead, and add the value in Settings \u203A Accounts`,\n `headers.${header}`\n );\n }\n return undefined;\n}\n\nfunction checkExposures(\n name: string,\n value: Record<string, unknown>\n): McpConfigProblem | undefined {\n const allowed = EXPOSURES.map((item) => `\"${item}\"`).join(', ');\n if (value.exposure !== undefined && !isExposure(value.exposure))\n return fail(name, `exposure must be one of ${allowed}`, 'exposure');\n if (value.toolExposure === undefined) return undefined;\n if (!isRecord(value.toolExposure))\n return fail(name, 'toolExposure must map tool names to exposures', 'toolExposure');\n for (const [tool, exposure] of Object.entries(value.toolExposure))\n if (!isExposure(exposure))\n return fail(name, `toolExposure \"${tool}\" must be one of ${allowed}`, `toolExposure.${tool}`);\n return undefined;\n}\n\nfunction checkFields(name: string, value: Record<string, unknown>): McpConfigProblem | undefined {\n if (value.enabled !== undefined && typeof value.enabled !== 'boolean')\n return fail(name, 'enabled must be a boolean', 'enabled');\n if (value.description !== undefined && typeof value.description !== 'string')\n return fail(name, 'description must be a string', 'description');\n if (value.timeout !== undefined && (typeof value.timeout !== 'number' || !(value.timeout > 0)))\n return fail(name, 'timeout must be a positive number of seconds', 'timeout');\n return undefined;\n}\n\nfunction checkTransport(\n name: string,\n value: Record<string, unknown>\n): McpConfigProblem | undefined {\n if (value.command !== undefined || value.type === 'stdio')\n return fail(name, 'stdio servers need slicc-kernel#68, so this one is skipped', 'command');\n if (value.type === 'sse')\n return fail(\n name,\n 'the legacy SSE transport is not supported; use the streamable HTTP URL',\n 'type'\n );\n if (value.type !== undefined && value.type !== 'http' && value.type !== 'streamable-http')\n return fail(name, 'type must be \"http\" or \"streamable-http\"', 'type');\n if (typeof value.url !== 'string') return fail(name, 'needs a \"url\" (streamable HTTP)', 'url');\n if (!URL.canParse(value.url) || !/^https?:$/.test(new URL(value.url).protocol))\n return fail(name, 'url must be an http or https URL', 'url');\n const secret = urlSecret(new URL(value.url));\n if (secret)\n return fail(\n name,\n `${secret} holds a literal secret. Put it in a header as \\${NAME} and add the value in Settings \u203A Accounts`,\n 'url'\n );\n return undefined;\n}\n\nexport function validateServer(name: string, raw: unknown): Checked {\n if (!SERVER_NAME.test(name))\n return fail(name, `invalid server name \"${name}\" (use letters, digits, \"_\" and \"-\")`);\n if (!isRecord(raw)) return fail(name, 'must be an object');\n const value: Record<string, unknown> = { ...raw, exposure: alias(raw.exposure) };\n if (raw.exposure === undefined) delete value.exposure;\n if (isRecord(raw.toolExposure))\n value.toolExposure = Object.fromEntries(\n Object.entries(raw.toolExposure).map(([tool, exposure]) => [tool, alias(exposure)])\n );\n for (const key of Object.keys(value))\n if (key === 'oauth' || key === 'auth')\n return fail(name, `${key} is not supported in SLICC yet`, key);\n const problem =\n checkTransport(name, value) ??\n checkHeaders(name, value.headers) ??\n checkExposures(name, value) ??\n checkFields(name, value);\n if (problem) return problem;\n const config: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value))\n if (ACCEPTED.has(key) && key !== 'type') config[key] = entry;\n return config as unknown as McpServerConfig;\n}\n\nfunction canonical(name: string): string {\n return name.replace(/-/g, '_');\n}\n\nexport function parseMcpConfig(text: string | undefined): McpConfig {\n if (text === undefined || text.trim() === '') return { servers: [], problems: [] };\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (error) {\n return { servers: [], problems: [{ message: `not valid JSON: ${(error as Error).message}` }] };\n }\n if (!isRecord(parsed) || (parsed.mcpServers !== undefined && !isRecord(parsed.mcpServers)))\n return { servers: [], problems: [{ message: 'mcpServers must be an object' }] };\n const servers: McpServerEntry[] = [];\n const problems: McpConfigProblem[] = [];\n const seen = new Set<string>();\n for (const [name, raw] of Object.entries((parsed.mcpServers ?? {}) as Record<string, unknown>)) {\n const checked = validateServer(name, raw);\n if ('message' in checked) {\n problems.push(checked);\n continue;\n }\n if (seen.has(canonical(name))) {\n problems.push(fail(name, 'names that differ only in \"-\" and \"_\" count as the same server'));\n continue;\n }\n seen.add(canonical(name));\n servers.push({ name, config: checked });\n }\n return { servers, problems };\n}\n\nfunction patternRegExp(pattern: string): RegExp {\n const source = pattern\n .split('*')\n .map((part) => part.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n .join('.*');\n return new RegExp(`^${source}$`);\n}\n\nexport function nameMatcher(entries: readonly string[]): (name: string) => boolean {\n const names = new Set(entries.filter((entry) => !entry.includes('*')));\n const patterns = entries.filter((entry) => entry.includes('*')).map(patternRegExp);\n return (name) => names.has(name) || patterns.some((pattern) => pattern.test(name));\n}\n\nexport function toolExposure(config: McpServerConfig, tool: string): McpExposure {\n const overrides = config.toolExposure ?? {};\n const exact = overrides[tool];\n if (exact !== undefined) return exact;\n for (const [pattern, exposure] of Object.entries(overrides))\n if (pattern.includes('*') && patternRegExp(pattern).test(tool)) return exposure;\n return config.exposure ?? 'codemode';\n}\n\nexport function mcpNamespace(server: string): string {\n return `mcp__${canonical(server)}`;\n}\n\nexport function mcpToolName(\n server: string,\n tool: string,\n taken: (name: string) => boolean = () => false\n): string {\n const name = `mcp__${server}__${tool}`.replace(/[^A-Za-z0-9_]/g, '_');\n if (name.length <= MAX_TOOL_NAME && !taken(name)) return name;\n const suffix = hash(`${server}\\0${tool}`).padStart(7, '0').slice(0, 7);\n return `${name.slice(0, MAX_TOOL_NAME - suffix.length - 1)}_${suffix}`;\n}\n\nexport function sameConfig(a: McpServerConfig, b: McpServerConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }