@unson/brainbase-mcp 0.6.0 → 0.8.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 (148) hide show
  1. package/contracts/foundation/graph-history.sql +634 -0
  2. package/contracts/judgment-value-proof/schema.json +43 -1
  3. package/dist/canonical-task-contract.d.ts +9 -0
  4. package/dist/canonical-task-contract.js +39 -0
  5. package/dist/canonical-task-principal.d.ts +16 -0
  6. package/dist/canonical-task-principal.js +36 -0
  7. package/dist/canonical-task-service.d.ts +251 -0
  8. package/dist/canonical-task-service.js +820 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +107 -0
  11. package/dist/company-os-evaluation.d.ts +193 -0
  12. package/dist/company-os-evaluation.js +1150 -0
  13. package/dist/company-os-impact-review.d.ts +248 -0
  14. package/dist/company-os-impact-review.js +663 -0
  15. package/dist/company-os-learning-adoption.d.ts +288 -0
  16. package/dist/company-os-learning-adoption.js +944 -0
  17. package/dist/company-os-objectives.d.ts +63 -0
  18. package/dist/company-os-objectives.js +234 -0
  19. package/dist/company-os-receipt-adapter.d.ts +109 -0
  20. package/dist/company-os-receipt-adapter.js +636 -0
  21. package/dist/constraint-exception-store.d.ts +23 -0
  22. package/dist/constraint-exception-store.js +108 -0
  23. package/dist/constraint-resolution.d.ts +175 -0
  24. package/dist/constraint-resolution.js +922 -0
  25. package/dist/decision-adapter.d.ts +145 -0
  26. package/dist/decision-adapter.js +586 -0
  27. package/dist/durable-wait-http.d.ts +51 -0
  28. package/dist/durable-wait-http.js +497 -0
  29. package/dist/durable-waits.d.ts +234 -0
  30. package/dist/durable-waits.js +944 -0
  31. package/dist/execution-authority-http.d.ts +28 -0
  32. package/dist/execution-authority-http.js +359 -0
  33. package/dist/execution-authority.d.ts +201 -0
  34. package/dist/execution-authority.js +634 -0
  35. package/dist/foundation-authenticated-tools.d.ts +56 -0
  36. package/dist/foundation-authenticated-tools.js +347 -0
  37. package/dist/foundation-catalog.d.ts +26 -0
  38. package/dist/foundation-catalog.js +206 -0
  39. package/dist/foundation-constraint-store.d.ts +50 -0
  40. package/dist/foundation-constraint-store.js +215 -0
  41. package/dist/foundation-graph-http.d.ts +43 -0
  42. package/dist/foundation-graph-http.js +243 -0
  43. package/dist/foundation-graph-write.d.ts +90 -0
  44. package/dist/foundation-graph-write.js +447 -0
  45. package/dist/foundation-http.d.ts +90 -0
  46. package/dist/foundation-http.js +439 -0
  47. package/dist/foundation-public-provider.d.ts +140 -0
  48. package/dist/foundation-public-provider.js +192 -0
  49. package/dist/foundation-store.d.ts +132 -0
  50. package/dist/foundation-store.js +654 -0
  51. package/dist/graph-corrections.d.ts +157 -0
  52. package/dist/graph-corrections.js +620 -0
  53. package/dist/graph-foundation-reader.d.ts +60 -0
  54. package/dist/graph-foundation-reader.js +494 -0
  55. package/dist/graph-retrieval.d.ts +6 -1
  56. package/dist/graph-revision-reader.d.ts +80 -0
  57. package/dist/graph-revision-reader.js +246 -0
  58. package/dist/graph-web-http.d.ts +26 -0
  59. package/dist/graph-web-http.js +215 -0
  60. package/dist/graph-web.d.ts +364 -0
  61. package/dist/graph-web.js +639 -0
  62. package/dist/judgment-dag-composition.d.ts +224 -0
  63. package/dist/judgment-dag-composition.js +731 -0
  64. package/dist/judgment-dag.d.ts +2 -0
  65. package/dist/judgment-dag.js +1 -0
  66. package/dist/judgment-problem-snapshot.d.ts +213 -0
  67. package/dist/judgment-problem-snapshot.js +1073 -0
  68. package/dist/judgment-value-proof-review.d.ts +166 -0
  69. package/dist/judgment-value-proof-review.js +437 -0
  70. package/dist/judgment-value-proof.d.ts +28 -1
  71. package/dist/judgment-value-proof.js +53 -8
  72. package/dist/judgment-view-http.d.ts +22 -0
  73. package/dist/judgment-view-http.js +128 -0
  74. package/dist/judgment-view.d.ts +222 -0
  75. package/dist/judgment-view.js +627 -0
  76. package/dist/knowledge-adapter.d.ts +112 -0
  77. package/dist/knowledge-adapter.js +691 -0
  78. package/dist/knowledge-continuation.d.ts +127 -0
  79. package/dist/knowledge-continuation.js +446 -0
  80. package/dist/knowledge-lookup.d.ts +178 -0
  81. package/dist/knowledge-lookup.js +758 -0
  82. package/dist/local-web-fetch-bridge.d.ts +5 -0
  83. package/dist/local-web-fetch-bridge.js +37 -0
  84. package/dist/local-web-host.d.ts +109 -0
  85. package/dist/local-web-host.js +688 -0
  86. package/dist/local-web-security.d.ts +25 -0
  87. package/dist/local-web-security.js +95 -0
  88. package/dist/ontology-foundation.d.ts +209 -0
  89. package/dist/ontology-foundation.js +1000 -0
  90. package/dist/ontology.d.ts +13 -0
  91. package/dist/ontology.js +14 -0
  92. package/dist/organization-connection.d.ts +164 -0
  93. package/dist/organization-connection.js +428 -0
  94. package/dist/organization-graph.d.ts +15 -0
  95. package/dist/organization-graph.js +24 -4
  96. package/dist/personal-knowledge.d.ts +132 -0
  97. package/dist/personal-knowledge.js +779 -0
  98. package/dist/personal-memory-handover.d.ts +108 -0
  99. package/dist/personal-memory-handover.js +369 -0
  100. package/dist/philosophy-revision-reader.d.ts +85 -0
  101. package/dist/philosophy-revision-reader.js +241 -0
  102. package/dist/portable-graph.d.ts +24 -0
  103. package/dist/portable-graph.js +77 -0
  104. package/dist/problem-candidates.d.ts +149 -0
  105. package/dist/problem-candidates.js +898 -0
  106. package/dist/problem-selection.d.ts +238 -0
  107. package/dist/problem-selection.js +995 -0
  108. package/dist/resource-reservation-http.d.ts +31 -0
  109. package/dist/resource-reservation-http.js +371 -0
  110. package/dist/resource-reservations.d.ts +221 -0
  111. package/dist/resource-reservations.js +577 -0
  112. package/dist/server.d.ts +104 -2
  113. package/dist/server.js +186 -4
  114. package/dist/ssot.d.ts +6 -1
  115. package/dist/ssot.js +63 -5
  116. package/dist/streamable-http.d.ts +42 -0
  117. package/dist/streamable-http.js +288 -0
  118. package/dist/types.d.ts +20 -0
  119. package/dist/value-proof-review-http.d.ts +25 -0
  120. package/dist/value-proof-review-http.js +185 -0
  121. package/dist/world-model.d.ts +199 -0
  122. package/dist/world-model.js +955 -0
  123. package/package.json +230 -3
  124. package/ui/brainbase-tokens.css +56 -0
  125. package/ui/graph-own-share.js +367 -0
  126. package/ui/graph-projects-view.css +23 -0
  127. package/ui/graph-projects-view.js +730 -0
  128. package/ui/graph-registry-view.css +101 -0
  129. package/ui/graph-registry-view.js +804 -0
  130. package/ui/graph-view-shared.css +522 -0
  131. package/ui/graph-view-shared.js +1227 -0
  132. package/ui/judgment-view.css +312 -0
  133. package/ui/judgment-view.js +508 -0
  134. package/ui/local-web-shell.css +396 -0
  135. package/ui/local-web-shell.js +378 -0
  136. package/ui/objective-editor-http-port.js +154 -0
  137. package/ui/objective-editor.css +286 -0
  138. package/ui/objective-editor.js +1586 -0
  139. package/ui/outcome-knowledge.css +50 -14
  140. package/ui/outcome-knowledge.js +15 -1
  141. package/ui/outcome-mana.css +91 -14
  142. package/ui/outcome-mana.js +958 -61
  143. package/ui/value-proof-review.css +504 -0
  144. package/ui/value-proof-review.js +1104 -0
  145. package/ui/workspace-kit.css +485 -0
  146. package/ui/workspace-kit.js +229 -0
  147. package/ui/world-model-view.css +188 -0
  148. package/ui/world-model-view.js +486 -0
package/dist/server.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type FoundationPublicConnection } from './foundation-public-provider.js';
1
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
3
  export declare const toolDefinitions: readonly [{
3
4
  readonly name: "get_context";
@@ -117,6 +118,103 @@ export declare const toolDefinitions: readonly [{
117
118
  };
118
119
  };
119
120
  };
121
+ }, {
122
+ readonly name: "personal_knowledge_context";
123
+ readonly description: "Return the authenticated v1 personal knowledge context. Identity and storage selection come from trusted configuration, not tool arguments.";
124
+ readonly inputSchema: {
125
+ readonly type: "object";
126
+ readonly additionalProperties: false;
127
+ readonly properties: {};
128
+ };
129
+ }, {
130
+ readonly name: "personal_knowledge_register";
131
+ readonly description: "Register one v1 personal knowledge event in the explicitly configured local or managed context. Caller identity, organization, source, and path are never accepted as event fields.";
132
+ readonly inputSchema: {
133
+ readonly type: "object";
134
+ readonly required: readonly ["event"];
135
+ readonly additionalProperties: false;
136
+ readonly properties: {
137
+ readonly event: {
138
+ readonly type: "object";
139
+ readonly required: readonly ["event_id"];
140
+ readonly additionalProperties: false;
141
+ readonly properties: {
142
+ readonly event_id: {
143
+ readonly type: "string";
144
+ readonly minLength: 1;
145
+ };
146
+ readonly body: {
147
+ readonly type: "string";
148
+ };
149
+ readonly content: {
150
+ readonly type: "string";
151
+ };
152
+ readonly body_hash: {
153
+ readonly type: "string";
154
+ readonly minLength: 1;
155
+ };
156
+ readonly occurred_at: {
157
+ readonly type: "string";
158
+ readonly minLength: 1;
159
+ };
160
+ readonly captured_at: {
161
+ readonly type: "string";
162
+ readonly minLength: 1;
163
+ };
164
+ readonly source: {};
165
+ readonly source_pointer: {};
166
+ readonly parent_episode_id: {
167
+ readonly type: readonly ["string", "null"];
168
+ };
169
+ readonly permission_snapshot: {
170
+ readonly type: "object";
171
+ };
172
+ readonly sensitivity: {
173
+ readonly type: "string";
174
+ readonly minLength: 1;
175
+ };
176
+ readonly kind: {
177
+ readonly type: "string";
178
+ readonly minLength: 1;
179
+ };
180
+ readonly type: {
181
+ readonly type: "string";
182
+ readonly minLength: 1;
183
+ };
184
+ readonly tags: {
185
+ readonly type: "array";
186
+ readonly items: {
187
+ readonly type: "string";
188
+ readonly minLength: 1;
189
+ };
190
+ };
191
+ readonly metadata: {
192
+ readonly type: "object";
193
+ };
194
+ };
195
+ };
196
+ };
197
+ };
198
+ }, {
199
+ readonly name: "personal_knowledge_search";
200
+ readonly description: "Search the explicitly configured v1 personal knowledge context. The result includes the verified context and never falls back to another store.";
201
+ readonly inputSchema: {
202
+ readonly type: "object";
203
+ readonly required: readonly ["query"];
204
+ readonly additionalProperties: false;
205
+ readonly properties: {
206
+ readonly query: {
207
+ readonly type: "string";
208
+ readonly minLength: 1;
209
+ readonly maxLength: 4000;
210
+ };
211
+ readonly limit: {
212
+ readonly type: "integer";
213
+ readonly minimum: 1;
214
+ readonly maximum: 50;
215
+ };
216
+ };
217
+ };
120
218
  }, {
121
219
  readonly name: "onboarding_status";
122
220
  readonly description: "Report seeded areas, first value demo readiness, missing setup, and local connection status.";
@@ -537,6 +635,10 @@ export declare const toolDefinitions: readonly [{
537
635
  };
538
636
  };
539
637
  }];
540
- export declare function callBrainbaseTool(name: string, rawArgs?: unknown): Promise<unknown>;
541
- export declare function createServer(): Server;
638
+ export declare function callBrainbaseTool(name: string, rawArgs?: unknown, options?: {
639
+ foundation?: FoundationPublicConnection;
640
+ }): Promise<unknown>;
641
+ export declare function createServer(options?: {
642
+ foundation?: FoundationPublicConnection;
643
+ }): Server;
542
644
  export declare function runMcpServer(): Promise<void>;
package/dist/server.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { callFoundationPublicTool, foundationPublicToolDefinitions } from './foundation-public-provider.js';
1
2
  import { createOrganizationGraphConfig, createOrganizationGraphClient } from './organization-graph.js';
2
3
  import { createHash } from 'node:crypto';
3
4
  import { retrieveGraph } from './graph-retrieval.js';
@@ -16,6 +17,7 @@ import { auditPersonalOsDirectory } from './ontology-ssot.js';
16
17
  import { getOntologyImpact, inferPersonalOs, portableOntology, resolveOntologyVersion } from './ontology.js';
17
18
  import { loadPersonalOs } from './ssot.js';
18
19
  import { getContext, listEntities, onboardingStatus, searchAll, searchPersonalKg } from './tools.js';
20
+ import { createLocalPersonalKnowledgeStore, createPersonalKnowledgeClient, decodePersonalKnowledgeContextHeader, PERSONAL_KNOWLEDGE_CONTRACT_VERSION, validatePersonalKnowledgeContext } from './personal-knowledge.js';
19
21
  const argsSchema = z.object({
20
22
  dataDir: z.string().optional(),
21
23
  query: z.string().optional(),
@@ -35,6 +37,29 @@ const argsSchema = z.object({
35
37
  mode: z.never().optional()
36
38
  });
37
39
  const searchArgsSchema = argsSchema.pick({ dataDir: true, query: true, limit: true, project: true, as_of: true, asOf: true, seedIds: true, steps: true, mode: true }).strict();
40
+ const personalKnowledgeEventSchema = z.object({
41
+ event_id: z.string().min(1),
42
+ body: z.string().optional(),
43
+ content: z.string().optional(),
44
+ body_hash: z.string().min(1).optional(),
45
+ occurred_at: z.string().min(1).optional(),
46
+ captured_at: z.string().min(1).optional(),
47
+ source: z.unknown().optional(),
48
+ source_pointer: z.unknown().optional(),
49
+ parent_episode_id: z.string().min(1).nullable().optional(),
50
+ permission_snapshot: z.record(z.unknown()).optional(),
51
+ sensitivity: z.string().min(1).optional(),
52
+ kind: z.string().min(1).optional(),
53
+ type: z.string().min(1).optional(),
54
+ tags: z.array(z.string().min(1)).optional(),
55
+ metadata: z.record(z.unknown()).optional()
56
+ }).strict();
57
+ const personalKnowledgeContextSchema = z.object({}).strict();
58
+ const personalKnowledgeRegisterSchema = z.object({ event: personalKnowledgeEventSchema }).strict();
59
+ const personalKnowledgeSearchSchema = z.object({
60
+ query: z.string(),
61
+ limit: z.number().int().min(1).max(50).optional()
62
+ }).strict();
38
63
  const mentionSpanSchema = z.object({
39
64
  start: z.number().int().nonnegative(),
40
65
  end: z.number().int().positive()
@@ -187,6 +212,61 @@ export const toolDefinitions = [
187
212
  }
188
213
  }
189
214
  },
215
+ {
216
+ name: 'personal_knowledge_context',
217
+ description: 'Return the authenticated v1 personal knowledge context. Identity and storage selection come from trusted configuration, not tool arguments.',
218
+ inputSchema: {
219
+ type: 'object',
220
+ additionalProperties: false,
221
+ properties: {}
222
+ }
223
+ },
224
+ {
225
+ name: 'personal_knowledge_register',
226
+ description: 'Register one v1 personal knowledge event in the explicitly configured local or managed context. Caller identity, organization, source, and path are never accepted as event fields.',
227
+ inputSchema: {
228
+ type: 'object',
229
+ required: ['event'],
230
+ additionalProperties: false,
231
+ properties: {
232
+ event: {
233
+ type: 'object',
234
+ required: ['event_id'],
235
+ additionalProperties: false,
236
+ properties: {
237
+ event_id: { type: 'string', minLength: 1 },
238
+ body: { type: 'string' },
239
+ content: { type: 'string' },
240
+ body_hash: { type: 'string', minLength: 1 },
241
+ occurred_at: { type: 'string', minLength: 1 },
242
+ captured_at: { type: 'string', minLength: 1 },
243
+ source: {},
244
+ source_pointer: {},
245
+ parent_episode_id: { type: ['string', 'null'] },
246
+ permission_snapshot: { type: 'object' },
247
+ sensitivity: { type: 'string', minLength: 1 },
248
+ kind: { type: 'string', minLength: 1 },
249
+ type: { type: 'string', minLength: 1 },
250
+ tags: { type: 'array', items: { type: 'string', minLength: 1 } },
251
+ metadata: { type: 'object' }
252
+ }
253
+ }
254
+ }
255
+ }
256
+ },
257
+ {
258
+ name: 'personal_knowledge_search',
259
+ description: 'Search the explicitly configured v1 personal knowledge context. The result includes the verified context and never falls back to another store.',
260
+ inputSchema: {
261
+ type: 'object',
262
+ required: ['query'],
263
+ additionalProperties: false,
264
+ properties: {
265
+ query: { type: 'string', minLength: 1, maxLength: 4000 },
266
+ limit: { type: 'integer', minimum: 1, maximum: 50 }
267
+ }
268
+ }
269
+ },
190
270
  {
191
271
  name: 'onboarding_status',
192
272
  description: 'Report seeded areas, first value demo readiness, missing setup, and local connection status.',
@@ -351,6 +431,29 @@ export const toolDefinitions = [
351
431
  }
352
432
  }
353
433
  ];
434
+ const managedPersonalKnowledgeToolNames = new Set([
435
+ 'personal_knowledge_context',
436
+ 'personal_knowledge_register',
437
+ 'personal_knowledge_search'
438
+ ]);
439
+ function isPersonalKnowledgeTool(name) {
440
+ return managedPersonalKnowledgeToolNames.has(name);
441
+ }
442
+ function configuredPersonalKnowledgeMode() {
443
+ const configuredMode = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_MODE?.trim()
444
+ || process.env.BRAINBASE_PERSONAL_KG_STORAGE_MODE?.trim()
445
+ || 'local';
446
+ if (configuredMode === 'local' || configuredMode === 'managed_cloud') {
447
+ return configuredMode;
448
+ }
449
+ throw new Error(`Unsupported Personal Knowledge mode: ${configuredMode}.`);
450
+ }
451
+ function configuredToolDefinitions(foundation) {
452
+ if (configuredPersonalKnowledgeMode() === 'managed_cloud') {
453
+ return toolDefinitions.filter((tool) => isPersonalKnowledgeTool(tool.name));
454
+ }
455
+ return [...toolDefinitions, ...(foundation ? foundationPublicToolDefinitions : [])];
456
+ }
354
457
  let embeddingProvider;
355
458
  let embeddingProviderInitialized = false;
356
459
  function configuredEmbeddingProvider() {
@@ -360,7 +463,86 @@ function configuredEmbeddingProvider() {
360
463
  }
361
464
  return embeddingProvider;
362
465
  }
363
- export async function callBrainbaseTool(name, rawArgs = {}) {
466
+ function configuredPersonalKnowledgeContext() {
467
+ const encoded = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_CONTEXT?.trim()
468
+ || process.env.BRAINBASE_PERSONAL_CONTEXT?.trim();
469
+ if (encoded)
470
+ return decodePersonalKnowledgeContextHeader(encoded);
471
+ const scope = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_SCOPE?.trim()
472
+ || process.env.BRAINBASE_PERSONAL_SCOPE?.trim()
473
+ || 'organization_private';
474
+ const owner = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_OWNER_PERSON_ID?.trim()
475
+ || process.env.BRAINBASE_PERSON_ID?.trim();
476
+ const source = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_SOURCE_ID?.trim()
477
+ || process.env.BRAINBASE_PERSONAL_SOURCE_ID?.trim();
478
+ const organization = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_ORGANIZATION_ID?.trim()
479
+ || process.env.BRAINBASE_ORGANIZATION_ID?.trim();
480
+ if (!owner || !source) {
481
+ throw new Error('Managed Personal Knowledge requires owner person and source configuration.');
482
+ }
483
+ return validatePersonalKnowledgeContext({
484
+ contract_version: PERSONAL_KNOWLEDGE_CONTRACT_VERSION,
485
+ scope,
486
+ owner_person_id: owner,
487
+ organization_id: scope === 'personal_owned' ? null : organization,
488
+ source_id: source
489
+ });
490
+ }
491
+ function configuredPersonalKnowledgeRuntime() {
492
+ const configuredMode = configuredPersonalKnowledgeMode();
493
+ if (configuredMode === 'local') {
494
+ const encodedContext = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_CONTEXT?.trim()
495
+ || process.env.BRAINBASE_PERSONAL_CONTEXT?.trim();
496
+ if (encodedContext) {
497
+ const context = decodePersonalKnowledgeContextHeader(encodedContext);
498
+ if (context.scope !== 'personal_owned' || context.organization_id !== null) {
499
+ throw new Error('OSS local Personal Knowledge requires a personal_owned context.');
500
+ }
501
+ return createLocalPersonalKnowledgeStore({ context });
502
+ }
503
+ return createLocalPersonalKnowledgeStore();
504
+ }
505
+ const apiUrl = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_API_URL?.trim()
506
+ || process.env.BRAINBASE_PERSONAL_KG_MANAGED_CLOUD_API_URL?.trim();
507
+ if (!apiUrl)
508
+ throw new Error('Managed Personal Knowledge requires an explicit API URL.');
509
+ const token = process.env.BRAINBASE_PERSONAL_KNOWLEDGE_TOKEN
510
+ || process.env.BRAINBASE_PERSONAL_KG_TOKEN;
511
+ if (!token?.trim())
512
+ throw new Error('Managed Personal Knowledge requires an authenticated token.');
513
+ return createPersonalKnowledgeClient({
514
+ mode: 'managed_cloud',
515
+ apiUrl,
516
+ expectedContext: configuredPersonalKnowledgeContext(),
517
+ token
518
+ });
519
+ }
520
+ async function callPersonalKnowledgeTool(name, rawArgs) {
521
+ const runtime = configuredPersonalKnowledgeRuntime();
522
+ if (name === 'personal_knowledge_context') {
523
+ personalKnowledgeContextSchema.parse(rawArgs ?? {});
524
+ return runtime.getContext();
525
+ }
526
+ if (name === 'personal_knowledge_register') {
527
+ const args = personalKnowledgeRegisterSchema.parse(rawArgs ?? {});
528
+ return runtime.register(args.event);
529
+ }
530
+ if (name === 'personal_knowledge_search') {
531
+ const args = personalKnowledgeSearchSchema.parse(rawArgs ?? {});
532
+ return runtime.search(args.query, args.limit);
533
+ }
534
+ throw new Error(`Unknown Personal Knowledge tool: ${name}`);
535
+ }
536
+ export async function callBrainbaseTool(name, rawArgs = {}, options = {}) {
537
+ const mode = configuredPersonalKnowledgeMode();
538
+ if (mode === 'managed_cloud' && !isPersonalKnowledgeTool(name)) {
539
+ throw new Error('managed_cloud Personal Knowledge MCP only permits personal_knowledge_context, personal_knowledge_register, and personal_knowledge_search.');
540
+ }
541
+ if (name.startsWith('foundation_'))
542
+ return callFoundationPublicTool(name, rawArgs, options.foundation);
543
+ if (isPersonalKnowledgeTool(name)) {
544
+ return callPersonalKnowledgeTool(name, rawArgs);
545
+ }
364
546
  if (name in connectedSchemas) {
365
547
  return callConnectedOnboardingTool(name, rawArgs);
366
548
  }
@@ -678,7 +860,7 @@ function onboardingGuide(state) {
678
860
  };
679
861
  return guides[state];
680
862
  }
681
- export function createServer() {
863
+ export function createServer(options = {}) {
682
864
  const server = new Server({
683
865
  name: 'brainbase-mcp',
684
866
  version: '0.1.0'
@@ -688,10 +870,10 @@ export function createServer() {
688
870
  }
689
871
  });
690
872
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
691
- tools: [...toolDefinitions]
873
+ tools: configuredToolDefinitions(options.foundation)
692
874
  }));
693
875
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
694
- const result = await callBrainbaseTool(request.params.name, request.params.arguments);
876
+ const result = await callBrainbaseTool(request.params.name, request.params.arguments, options);
695
877
  return {
696
878
  content: [
697
879
  {
package/dist/ssot.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { PersonalOs } from './types.js';
3
3
  export declare function initializePersonalOs(dataDir: string): Promise<void>;
4
4
  export declare function loadPersonalOs(dataDir: string): Promise<PersonalOs>;
5
5
  export declare function mutatePersonalOs(dataDir: string, mutator: (current: PersonalOs) => PersonalOs | Promise<PersonalOs>): Promise<PersonalOs>;
6
- export declare function mutatePersonalOsWithSidecar<T>(dataDir: string, sidecarPath: string, mutator: (current: PersonalOs) => {
6
+ export declare function mutatePersonalOsWithSidecar<T>(dataDir: string, sidecarPath: string, mutator: (current: PersonalOs, sidecarContent?: string) => {
7
7
  next: PersonalOs;
8
8
  sidecarContent: string;
9
9
  result: T;
@@ -12,6 +12,11 @@ export declare function mutatePersonalOsWithSidecar<T>(dataDir: string, sidecarP
12
12
  sidecarContent: string;
13
13
  result: T;
14
14
  }>): Promise<T>;
15
+ /**
16
+ * Reads a sidecar while holding the canonical SSOT lock. A missing sidecar is
17
+ * returned as undefined so a first mutation can create it transactionally.
18
+ */
19
+ export declare function readPersonalOsSidecar(dataDir: string, sidecarPath: string): Promise<string | undefined>;
15
20
  export type CanonicalGraphMigrationExecution = CanonicalGraphMigrationPlan & {
16
21
  expectedInputDigest: string;
17
22
  written: boolean;
package/dist/ssot.js CHANGED
@@ -5,6 +5,7 @@ import { hostname } from 'node:os';
5
5
  import { dirname, isAbsolute, join, relative, resolve, win32 } from 'node:path';
6
6
  import { z } from 'zod';
7
7
  import { validateCanonicalGraph } from './canonical-graph.js';
8
+ import { assertFoundationCatalog } from './foundation-catalog.js';
8
9
  import { assertOntologyValid } from './ontology.js';
9
10
  import { planCanonicalGraphMigration } from './ontology-migration.js';
10
11
  import { emptyGraph, emptyRelationships, schemaTemplates } from './templates.js';
@@ -91,13 +92,25 @@ export async function mutatePersonalOsWithSidecar(dataDir, sidecarPath, mutator)
91
92
  await recoverTransactions(dataDir);
92
93
  assertCompleteCanonicalSet(dataDir, await canonicalPresence(dataDir));
93
94
  const current = await loadPersonalOsUnlocked(dataDir);
94
- const mutation = await mutator(current);
95
+ const mutation = await mutator(current, await readOptionalSidecar(dataDir, sidecarPath));
95
96
  const normalized = { ...mutation.next, dataDir, sourceCount: current.sourceCount };
96
97
  validateAggregate(normalized);
97
98
  await commitAggregate(dataDir, normalized, 'mutation', [{ relativePath: sidecarPath, content: mutation.sidecarContent }]);
98
99
  return mutation.result;
99
100
  });
100
101
  }
102
+ /**
103
+ * Reads a sidecar while holding the canonical SSOT lock. A missing sidecar is
104
+ * returned as undefined so a first mutation can create it transactionally.
105
+ */
106
+ export async function readPersonalOsSidecar(dataDir, sidecarPath) {
107
+ assertSafeSidecarPath(sidecarPath);
108
+ return withSsotLock(dataDir, async () => {
109
+ await recoverTransactions(dataDir);
110
+ assertCompleteCanonicalSet(dataDir, await canonicalPresence(dataDir));
111
+ return readOptionalSidecar(dataDir, sidecarPath);
112
+ });
113
+ }
101
114
  /**
102
115
  * Plans or atomically applies the canonical Graph migration.
103
116
  *
@@ -172,11 +185,22 @@ async function commitAggregate(dataDir, next, mode, sidecars = []) {
172
185
  await mkdir(previousDir, { recursive: true });
173
186
  await copyCanonicalSet(dataDir, previousDir);
174
187
  for (const sidecar of sidecars) {
175
- await mkdir(dirname(join(previousDir, sidecar.relativePath)), { recursive: true });
176
- await copyFile(join(dataDir, sidecar.relativePath), join(previousDir, sidecar.relativePath));
188
+ if (await exists(join(dataDir, sidecar.relativePath))) {
189
+ await mkdir(dirname(join(previousDir, sidecar.relativePath)), { recursive: true });
190
+ await copyFile(join(dataDir, sidecar.relativePath), join(previousDir, sidecar.relativePath));
191
+ }
177
192
  }
178
193
  }
179
- const metadata = { version: 1, mode, ...(sidecars.length > 0 ? { sidecarFiles: sidecars.map((item) => item.relativePath) } : {}) };
194
+ const sidecarFiles = sidecars.map((item) => item.relativePath);
195
+ const previousSidecarFiles = mode === 'mutation'
196
+ ? (await Promise.all(sidecars.map(async (item) => (await exists(join(dataDir, item.relativePath))) ? item.relativePath : undefined))).filter((item) => item !== undefined)
197
+ : [];
198
+ const metadata = {
199
+ version: 1,
200
+ mode,
201
+ ...(sidecarFiles.length > 0 ? { sidecarFiles } : {}),
202
+ ...(mode === 'mutation' && sidecarFiles.length > 0 ? { previousSidecarFiles } : {})
203
+ };
180
204
  await writeFile(join(stagingDir, 'transaction.json'), `${JSON.stringify(metadata, null, 2)}\n`);
181
205
  await writeFile(join(stagingDir, 'PREPARED'), '');
182
206
  await rename(stagingDir, transactionDir);
@@ -224,7 +248,13 @@ async function recoverTransaction(dataDir, transactionDir) {
224
248
  if (process.env.BRAINBASE_SSOT_FAIL_RECOVERY === '1') {
225
249
  throw new Error(`Injected SSOT transaction recovery failure for ${transactionDir}`);
226
250
  }
227
- await publishCanonicalSet(dataDir, retainedDir, `recovery-${randomUUID()}`, false, metadata.sidecarFiles ?? []);
251
+ const previousSidecarFiles = metadata.mode === 'initialization'
252
+ ? metadata.sidecarFiles ?? []
253
+ : metadata.previousSidecarFiles ?? metadata.sidecarFiles ?? [];
254
+ await publishCanonicalSet(dataDir, retainedDir, `recovery-${randomUUID()}`, false, previousSidecarFiles);
255
+ if (metadata.mode === 'mutation') {
256
+ await removeSidecars(dataDir, (metadata.sidecarFiles ?? []).filter((path) => !previousSidecarFiles.includes(path)));
257
+ }
228
258
  await rm(transactionDir, { recursive: true, force: true });
229
259
  }
230
260
  async function publishCanonicalSet(dataDir, retainedDir, token, allowInjectedFailure, sidecarFiles = []) {
@@ -256,6 +286,12 @@ async function publishCanonicalSet(dataDir, retainedDir, token, allowInjectedFai
256
286
  }
257
287
  }
258
288
  }
289
+ async function removeSidecars(dataDir, relativePaths) {
290
+ for (const relativePath of relativePaths) {
291
+ assertSafeSidecarPath(relativePath);
292
+ await rm(join(dataDir, relativePath), { force: true });
293
+ }
294
+ }
259
295
  async function writeAggregate(targetDir, os) {
260
296
  await writeFile(join(targetDir, 'graph.json'), `${JSON.stringify(os.graph, null, 2)}\n`);
261
297
  await writeFile(join(targetDir, 'relationships.json'), `${JSON.stringify(os.relationships, null, 2)}\n`);
@@ -268,6 +304,8 @@ function validateAggregate(os) {
268
304
  os.decisions.forEach((decision) => decisionSchema.parse(decision));
269
305
  assertOntologyValid(os);
270
306
  validateCanonicalGraph(os.graph);
307
+ if (os.graph.version === 2)
308
+ assertFoundationCatalog(os.graph.foundation);
271
309
  }
272
310
  function parseGraph(value) {
273
311
  try {
@@ -283,8 +321,13 @@ function parseGraph(value) {
283
321
  }
284
322
  validateCanonicalGraph(value, { allowDuplicateEntityIds: true });
285
323
  }
324
+ if (isGraphV2(value))
325
+ assertFoundationCatalog(value.foundation);
286
326
  return value;
287
327
  }
328
+ function isGraphV2(value) {
329
+ return typeof value === 'object' && value !== null && value.version === 2;
330
+ }
288
331
  function serializeJsonl(values) {
289
332
  return values.length === 0 ? '' : `${values.map((value) => JSON.stringify(value)).join('\n')}\n`;
290
333
  }
@@ -405,8 +448,13 @@ async function readTransactionMetadata(transactionDir) {
405
448
  if (value.sidecarFiles !== undefined && (!Array.isArray(value.sidecarFiles) || value.sidecarFiles.some((path) => typeof path !== 'string'))) {
406
449
  throw new Error(`Invalid registered SSOT transaction sidecars in ${transactionDir}`);
407
450
  }
451
+ if (value.previousSidecarFiles !== undefined && (!Array.isArray(value.previousSidecarFiles) || value.previousSidecarFiles.some((path) => typeof path !== 'string'))) {
452
+ throw new Error(`Invalid registered SSOT transaction previous sidecars in ${transactionDir}`);
453
+ }
408
454
  for (const path of value.sidecarFiles ?? [])
409
455
  assertSafeSidecarPath(path);
456
+ for (const path of value.previousSidecarFiles ?? [])
457
+ assertSafeSidecarPath(path);
410
458
  return value;
411
459
  }
412
460
  function assertSafeSidecarPath(relativePath) {
@@ -439,6 +487,16 @@ async function exists(path) {
439
487
  return false;
440
488
  }
441
489
  }
490
+ async function readOptionalSidecar(dataDir, sidecarPath) {
491
+ try {
492
+ return await readFile(join(dataDir, sidecarPath), 'utf8');
493
+ }
494
+ catch (error) {
495
+ if (error.code === 'ENOENT')
496
+ return undefined;
497
+ throw error;
498
+ }
499
+ }
442
500
  async function readJson(filePath) {
443
501
  try {
444
502
  return JSON.parse(await readFile(filePath, 'utf8'));
@@ -0,0 +1,42 @@
1
+ import { type IncomingMessage, type Server as HttpServer, type ServerResponse } from 'node:http';
2
+ import type { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';
3
+ import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
4
+ type MaybePromise<T> = T | Promise<T>;
5
+ export interface StreamableHttpRequestScope<Auth = AuthInfo> {
6
+ requestId: string;
7
+ method: string;
8
+ path: string;
9
+ auth?: Auth;
10
+ sessionId?: string;
11
+ }
12
+ export interface StreamableHttpRequestScopeInput<Auth = AuthInfo> {
13
+ request: IncomingMessage;
14
+ requestId: string;
15
+ auth?: Auth;
16
+ sessionId?: string;
17
+ }
18
+ export interface StreamableHttpHealthScope {
19
+ request: IncomingMessage;
20
+ requestId: string;
21
+ }
22
+ export interface StreamableHttpDependencies<Auth = AuthInfo> {
23
+ /** Return null to reject the request. Undefined means anonymous access. */
24
+ authenticate?: (request: IncomingMessage) => MaybePromise<Auth | null>;
25
+ /** Build one MCP server for each initialized MCP session. */
26
+ createServer: (scope: StreamableHttpRequestScope<Auth>) => MaybePromise<Server>;
27
+ /** Add application request context without coupling the transport to an app. */
28
+ requestScope?: (input: StreamableHttpRequestScopeInput<Auth>) => MaybePromise<Partial<StreamableHttpRequestScope<Auth>>>;
29
+ /** Health is deliberately independent from MCP authentication and application routes. */
30
+ health?: (scope: StreamableHttpHealthScope) => MaybePromise<unknown>;
31
+ bodyLimitBytes?: number;
32
+ mcpPath?: string;
33
+ healthPath?: string;
34
+ }
35
+ export interface StreamableHttpHandler {
36
+ handle(request: IncomingMessage, response: ServerResponse): Promise<void>;
37
+ close(): Promise<void>;
38
+ readonly activeSessionCount: number;
39
+ }
40
+ export declare function createStreamableHttpHandler<Auth = AuthInfo>(dependencies: StreamableHttpDependencies<Auth>): StreamableHttpHandler;
41
+ export declare function createStreamableHttpServer<Auth = AuthInfo>(dependencies: StreamableHttpDependencies<Auth>): HttpServer;
42
+ export {};