@cencori/mcp 0.2.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -199,6 +199,16 @@ var DocsClient = class {
199
199
  }
200
200
  return response.json();
201
201
  }
202
+ /** Fetch the raw `llm.txt` integration contract (public, no auth). */
203
+ async getIntegrationGuide() {
204
+ const url = new URL("/llm.txt", this.baseUrl);
205
+ const response = await fetch(url, { signal: fetchSignal() });
206
+ if (!response.ok) {
207
+ const message = await readHttpErrorMessage(response);
208
+ throw new Error(`Integration guide fetch failed (${response.status}): ${message}`);
209
+ }
210
+ return response.text();
211
+ }
202
212
  };
203
213
 
204
214
  // src/tools/docs.ts
@@ -217,6 +227,12 @@ var WRITE_ANNOTATIONS = {
217
227
  destructiveHint: false,
218
228
  openWorldHint: false
219
229
  };
230
+ var DESTRUCTIVE_ANNOTATIONS = {
231
+ title: "Destructive",
232
+ readOnlyHint: false,
233
+ destructiveHint: true,
234
+ openWorldHint: false
235
+ };
220
236
  function jsonResult(data) {
221
237
  return {
222
238
  content: [
@@ -281,6 +297,28 @@ function registerDocsTools(server, docs, docsBaseUrl) {
281
297
  return jsonResult(navigation);
282
298
  }
283
299
  );
300
+ server.registerTool(
301
+ "get_integration_guide",
302
+ {
303
+ title: "Get the Cencori integration guide (llm.txt)",
304
+ description: 'Fetch the full Cencori "Integration Contract for Code Agents" (llm.txt) \u2014 the authoritative, always-current guide for setting up Cencori in a codebase: package names, import paths, env vars, base URLs, SDK usage, request/response shapes, and step-by-step setup. Call this FIRST when asked to add, integrate, or set up Cencori in a project.',
305
+ inputSchema: {},
306
+ annotations: READ_ONLY_ANNOTATIONS
307
+ },
308
+ async () => {
309
+ const guide = await docs.getIntegrationGuide();
310
+ return {
311
+ content: [
312
+ {
313
+ type: "text",
314
+ text: `Source: ${docsBaseUrl}/llm.txt
315
+
316
+ ${guide}`
317
+ }
318
+ ]
319
+ };
320
+ }
321
+ );
284
322
  }
285
323
 
286
324
  // src/tools/gateway.ts
@@ -338,7 +376,13 @@ function registerGatewayTools(server, client) {
338
376
 
339
377
  // src/tools/agents.ts
340
378
  import { z as z3 } from "zod";
341
- function registerAgentsTools(server, client) {
379
+ var agentConfigShape = z3.object({
380
+ model: z3.string().optional(),
381
+ system_prompt: z3.string().optional(),
382
+ tools: z3.array(z3.string()).optional(),
383
+ temperature: z3.number().min(0).max(2).optional()
384
+ }).optional().describe("Agent runtime config: model, system_prompt, tools, temperature.");
385
+ function registerAgentsTools(server, client, caps) {
342
386
  server.registerTool(
343
387
  "list_agents",
344
388
  {
@@ -377,45 +421,110 @@ function registerAgentsTools(server, client) {
377
421
  },
378
422
  async () => jsonResult(await client.get("/v1/agent/actions/poll"))
379
423
  );
424
+ if (caps.write) {
425
+ server.registerTool(
426
+ "create_agent",
427
+ {
428
+ title: "Create an agent",
429
+ description: "Create a new agent in a project.",
430
+ inputSchema: {
431
+ project_id: z3.string().min(1).describe("The project id to create the agent in."),
432
+ name: z3.string().min(1).describe("Agent name."),
433
+ description: z3.string().optional(),
434
+ config: agentConfigShape
435
+ },
436
+ annotations: WRITE_ANNOTATIONS
437
+ },
438
+ async ({ project_id, name, description, config }) => jsonResult(await client.post("/v1/agents", { project_id, name, description, config }))
439
+ );
440
+ server.registerTool(
441
+ "update_agent",
442
+ {
443
+ title: "Update an agent",
444
+ description: "Update an agent\u2019s name, description, status, shadow mode, or config.",
445
+ inputSchema: {
446
+ agent_id: z3.string().min(1).describe("The agent id to update."),
447
+ name: z3.string().optional(),
448
+ description: z3.string().optional(),
449
+ is_active: z3.boolean().optional(),
450
+ shadow_mode: z3.boolean().optional(),
451
+ config: agentConfigShape
452
+ },
453
+ annotations: WRITE_ANNOTATIONS
454
+ },
455
+ async ({ agent_id, name, description, is_active, shadow_mode, config }) => jsonResult(
456
+ await client.patch(`/v1/agents/${agent_id}`, {
457
+ name,
458
+ description,
459
+ is_active,
460
+ shadow_mode,
461
+ config
462
+ })
463
+ )
464
+ );
465
+ }
466
+ if (caps.destructive) {
467
+ server.registerTool(
468
+ "delete_agent",
469
+ {
470
+ title: "Delete an agent",
471
+ description: "Permanently delete an agent by id. This cannot be undone.",
472
+ inputSchema: { agent_id: z3.string().min(1).describe("The agent id to delete.") },
473
+ annotations: DESTRUCTIVE_ANNOTATIONS
474
+ },
475
+ async ({ agent_id }) => jsonResult(await client.del(`/v1/agents/${agent_id}`))
476
+ );
477
+ }
380
478
  }
381
479
 
382
480
  // src/tools/memory.ts
383
481
  import { z as z4 } from "zod";
384
482
  var scopeShape = {
385
483
  namespace: z4.string().optional().describe("Memory namespace to scope to."),
386
- scope: z4.string().optional().describe("Memory scope (e.g. project, user, session)."),
387
- user_id: z4.string().optional().describe("Scope to a specific end-user id."),
388
- session_id: z4.string().optional().describe("Scope to a specific session id.")
484
+ scope: z4.enum(["user", "session"]).optional().describe('Memory scope. Defaults to "user".'),
485
+ user_id: z4.string().optional().describe("End-user id. REQUIRED for user scope (the default)."),
486
+ session_id: z4.string().optional().describe("Session id. REQUIRED for session scope.")
389
487
  };
390
- function registerMemoryTools(server, client) {
488
+ function missingScopeKey({ scope, user_id, session_id }) {
489
+ if ((scope ?? "user") === "session") {
490
+ return session_id || user_id ? null : "session_id (or user_id) is required for session scope.";
491
+ }
492
+ return user_id ? null : 'user_id is required for user scope (the default). Pass user_id, or use scope="session" with session_id.';
493
+ }
494
+ var scopeErr = (msg) => jsonResult({ error: "missing_scope", message: msg });
495
+ function registerMemoryTools(server, client, caps) {
391
496
  server.registerTool(
392
497
  "list_memories",
393
498
  {
394
499
  title: "List memories",
395
- description: "List stored memories for the project, optionally scoped by namespace/user/session.",
500
+ description: "List stored memories for a user or session. Requires user_id (or session_id for session scope).",
396
501
  inputSchema: {
397
502
  ...scopeShape,
398
- limit: z4.number().int().positive().max(200).optional(),
503
+ limit: z4.number().int().positive().max(100).optional(),
399
504
  cursor: z4.string().optional().describe("Pagination cursor from a previous response.")
400
505
  },
401
506
  annotations: READ_ONLY_ANNOTATIONS
402
507
  },
403
- async ({ namespace, scope, user_id, session_id, limit, cursor }) => jsonResult(
404
- await client.get("/v1/memory/list", {
405
- namespace,
406
- scope,
407
- userId: user_id,
408
- sessionId: session_id,
409
- limit: limit?.toString(),
410
- cursor
411
- })
412
- )
508
+ async ({ namespace, scope, user_id, session_id, limit, cursor }) => {
509
+ const err = missingScopeKey({ scope, user_id, session_id });
510
+ if (err) return scopeErr(err);
511
+ return jsonResult(
512
+ await client.get("/v1/memory/list", {
513
+ namespace,
514
+ scope,
515
+ userId: user_id,
516
+ sessionId: session_id,
517
+ limit: limit?.toString(),
518
+ cursor
519
+ })
520
+ );
521
+ }
413
522
  );
414
523
  server.registerTool(
415
524
  "search_memory",
416
525
  {
417
526
  title: "Search memory (semantic)",
418
- description: "Semantically search stored memories by query.",
527
+ description: "Semantically search a user\u2019s or session\u2019s memories. Requires user_id (or session_id for session scope).",
419
528
  inputSchema: {
420
529
  query: z4.string().min(1).describe("Natural-language search query."),
421
530
  ...scopeShape,
@@ -424,17 +533,21 @@ function registerMemoryTools(server, client) {
424
533
  },
425
534
  annotations: READ_ONLY_ANNOTATIONS
426
535
  },
427
- async ({ query, namespace, scope, user_id, session_id, top_k, threshold }) => jsonResult(
428
- await client.post("/v1/memory/search", {
429
- query,
430
- namespace,
431
- scope,
432
- userId: user_id,
433
- sessionId: session_id,
434
- topK: top_k,
435
- threshold
436
- })
437
- )
536
+ async ({ query, namespace, scope, user_id, session_id, top_k, threshold }) => {
537
+ const err = missingScopeKey({ scope, user_id, session_id });
538
+ if (err) return scopeErr(err);
539
+ return jsonResult(
540
+ await client.post("/v1/memory/search", {
541
+ query,
542
+ namespace,
543
+ scope,
544
+ userId: user_id,
545
+ sessionId: session_id,
546
+ topK: top_k,
547
+ threshold
548
+ })
549
+ );
550
+ }
438
551
  );
439
552
  server.registerTool(
440
553
  "get_memory",
@@ -450,24 +563,23 @@ function registerMemoryTools(server, client) {
450
563
  "list_memory_entities",
451
564
  {
452
565
  title: "List memory entities",
453
- description: "List entities resolved from the memory graph.",
566
+ description: "List entities resolved from a user\u2019s or session\u2019s memory graph. Requires user_id (or session_id).",
454
567
  inputSchema: scopeShape,
455
568
  annotations: READ_ONLY_ANNOTATIONS
456
569
  },
457
- async ({ namespace, scope, user_id, session_id }) => jsonResult(
458
- await client.get("/v1/memory/entities", {
459
- namespace,
460
- scope,
461
- userId: user_id,
462
- sessionId: session_id
463
- })
464
- )
570
+ async ({ namespace, scope, user_id, session_id }) => {
571
+ const err = missingScopeKey({ scope, user_id, session_id });
572
+ if (err) return scopeErr(err);
573
+ return jsonResult(
574
+ await client.get("/v1/memory/entities", { namespace, scope, userId: user_id, sessionId: session_id })
575
+ );
576
+ }
465
577
  );
466
578
  server.registerTool(
467
579
  "get_memory_graph",
468
580
  {
469
581
  title: "Get memory entity graph",
470
- description: "Traverse the memory entity graph from an optional starting entity.",
582
+ description: "Traverse a user\u2019s or session\u2019s memory entity graph. Requires user_id (or session_id).",
471
583
  inputSchema: {
472
584
  ...scopeShape,
473
585
  entity: z4.string().optional().describe("Entity to start traversal from."),
@@ -475,39 +587,137 @@ function registerMemoryTools(server, client) {
475
587
  },
476
588
  annotations: READ_ONLY_ANNOTATIONS
477
589
  },
478
- async ({ namespace, scope, user_id, session_id, entity, hops }) => jsonResult(
479
- await client.get("/v1/memory/graph", {
480
- namespace,
481
- scope,
482
- userId: user_id,
483
- sessionId: session_id,
484
- entity,
485
- hops: hops?.toString()
486
- })
487
- )
590
+ async ({ namespace, scope, user_id, session_id, entity, hops }) => {
591
+ const err = missingScopeKey({ scope, user_id, session_id });
592
+ if (err) return scopeErr(err);
593
+ return jsonResult(
594
+ await client.get("/v1/memory/graph", {
595
+ namespace,
596
+ scope,
597
+ userId: user_id,
598
+ sessionId: session_id,
599
+ entity,
600
+ hops: hops?.toString()
601
+ })
602
+ );
603
+ }
488
604
  );
489
605
  server.registerTool(
490
606
  "get_forget_suggestions",
491
607
  {
492
608
  title: "Get forget suggestions",
493
- description: "List memories the system suggests forgetting (stale/superseded).",
609
+ description: "List memories the system suggests forgetting for a user or session. Requires user_id (or session_id).",
494
610
  inputSchema: scopeShape,
495
611
  annotations: READ_ONLY_ANNOTATIONS
496
612
  },
497
- async ({ namespace, scope, user_id, session_id }) => jsonResult(
498
- await client.get("/v1/memory/forget-suggestions", {
499
- namespace,
500
- scope,
501
- userId: user_id,
502
- sessionId: session_id
503
- })
504
- )
613
+ async ({ namespace, scope, user_id, session_id }) => {
614
+ const err = missingScopeKey({ scope, user_id, session_id });
615
+ if (err) return scopeErr(err);
616
+ return jsonResult(
617
+ await client.get("/v1/memory/forget-suggestions", {
618
+ namespace,
619
+ scope,
620
+ userId: user_id,
621
+ sessionId: session_id
622
+ })
623
+ );
624
+ }
505
625
  );
626
+ if (caps.write) {
627
+ server.registerTool(
628
+ "remember_memory",
629
+ {
630
+ title: "Remember a conversation turn",
631
+ description: "Store a user/assistant exchange as memory. Requires user_id (or session_id for session scope).",
632
+ inputSchema: {
633
+ user: z4.string().min(1).describe("The user message."),
634
+ assistant: z4.string().min(1).describe("The assistant response."),
635
+ ...scopeShape
636
+ },
637
+ annotations: WRITE_ANNOTATIONS
638
+ },
639
+ async ({ user, assistant, namespace, scope, user_id, session_id }) => {
640
+ const err = missingScopeKey({ scope, user_id, session_id });
641
+ if (err) return scopeErr(err);
642
+ return jsonResult(
643
+ await client.post("/v1/memory/remember", {
644
+ user,
645
+ assistant,
646
+ namespace,
647
+ scope,
648
+ userId: user_id,
649
+ sessionId: session_id
650
+ })
651
+ );
652
+ }
653
+ );
654
+ server.registerTool(
655
+ "write_memory",
656
+ {
657
+ title: "Write a memory",
658
+ description: "Store a single memory (a fact/note). Requires user_id (or session_id for session scope).",
659
+ inputSchema: {
660
+ content: z4.string().min(1).describe("The memory content to store."),
661
+ importance: z4.number().min(0).max(1).optional().describe("Importance weight 0\u20131."),
662
+ ...scopeShape
663
+ },
664
+ annotations: WRITE_ANNOTATIONS
665
+ },
666
+ async ({ content, importance, namespace, scope, user_id, session_id }) => {
667
+ const err = missingScopeKey({ scope, user_id, session_id });
668
+ if (err) return scopeErr(err);
669
+ return jsonResult(
670
+ await client.post("/v1/memory/write", {
671
+ content,
672
+ importance,
673
+ namespace,
674
+ scope,
675
+ userId: user_id,
676
+ sessionId: session_id
677
+ })
678
+ );
679
+ }
680
+ );
681
+ server.registerTool(
682
+ "create_namespace",
683
+ {
684
+ title: "Create a memory namespace",
685
+ description: "Create a new memory namespace.",
686
+ inputSchema: {
687
+ name: z4.string().min(1).describe("Namespace name."),
688
+ description: z4.string().optional(),
689
+ embedding_model: z4.string().optional().describe("Embedding model for this namespace."),
690
+ dimensions: z4.number().int().positive().optional()
691
+ },
692
+ annotations: WRITE_ANNOTATIONS
693
+ },
694
+ async ({ name, description, embedding_model, dimensions }) => jsonResult(
695
+ await client.post("/memory/namespaces", {
696
+ name,
697
+ description,
698
+ embeddingModel: embedding_model,
699
+ dimensions
700
+ })
701
+ )
702
+ );
703
+ }
704
+ if (caps.destructive) {
705
+ server.registerTool(
706
+ "delete_memory",
707
+ {
708
+ title: "Delete a memory",
709
+ description: "Permanently delete a memory by id. This cannot be undone.",
710
+ inputSchema: { memory_id: z4.string().min(1).describe("The memory id to delete.") },
711
+ annotations: DESTRUCTIVE_ANNOTATIONS
712
+ },
713
+ async ({ memory_id }) => jsonResult(await client.del(`/v1/memory/${memory_id}`))
714
+ );
715
+ }
506
716
  }
507
717
 
508
718
  // src/tools/sessions.ts
509
719
  import { z as z5 } from "zod";
510
- function registerSessionsTools(server, client) {
720
+ function registerSessionsTools(server, client, caps) {
511
721
  server.registerTool(
512
722
  "list_sessions",
513
723
  {
@@ -550,11 +760,87 @@ function registerSessionsTools(server, client) {
550
760
  },
551
761
  async ({ session_id }) => jsonResult(await client.get(`/v1/sessions/${session_id}/events`))
552
762
  );
763
+ if (caps.write) {
764
+ server.registerTool(
765
+ "create_session",
766
+ {
767
+ title: "Create an agent session",
768
+ description: "Start a new session for an agent.",
769
+ inputSchema: {
770
+ agent_id: z5.string().min(1).describe("The agent id to start a session for."),
771
+ metadata: z5.record(z5.string(), z5.unknown()).optional().describe("Optional session metadata.")
772
+ },
773
+ annotations: WRITE_ANNOTATIONS
774
+ },
775
+ async ({ agent_id, metadata }) => jsonResult(await client.post("/v1/sessions", { agent_id, metadata }))
776
+ );
777
+ server.registerTool(
778
+ "add_session_turn",
779
+ {
780
+ title: "Add a turn to a session",
781
+ description: "Run a turn in an agent session. Incurs usage/cost.",
782
+ inputSchema: {
783
+ session_id: z5.string().min(1).describe("The session id."),
784
+ model: z5.string().min(1).describe("Model id for the turn."),
785
+ input: z5.string().min(1).describe("The user input for this turn."),
786
+ instructions: z5.string().optional().describe("Optional system instructions."),
787
+ temperature: z5.number().min(0).max(2).optional()
788
+ },
789
+ annotations: WRITE_ANNOTATIONS
790
+ },
791
+ async ({ session_id, model, input, instructions, temperature }) => jsonResult(
792
+ await client.post(`/v1/sessions/${session_id}/turns`, {
793
+ model,
794
+ input,
795
+ instructions,
796
+ temperature
797
+ })
798
+ )
799
+ );
800
+ }
801
+ if (caps.destructive) {
802
+ server.registerTool(
803
+ "delete_session",
804
+ {
805
+ title: "Delete an agent session",
806
+ description: "Permanently delete an agent session by id. This cannot be undone.",
807
+ inputSchema: { session_id: z5.string().min(1).describe("The session id to delete.") },
808
+ annotations: DESTRUCTIVE_ANNOTATIONS
809
+ },
810
+ async ({ session_id }) => jsonResult(await client.del(`/v1/sessions/${session_id}`))
811
+ );
812
+ server.registerTool(
813
+ "approve_session",
814
+ {
815
+ title: "Approve a pending session action",
816
+ description: "Approve a pending action in an agent session (human-in-the-loop).",
817
+ inputSchema: {
818
+ session_id: z5.string().min(1).describe("The session id."),
819
+ action_id: z5.string().optional().describe("Specific pending action id, if any.")
820
+ },
821
+ annotations: DESTRUCTIVE_ANNOTATIONS
822
+ },
823
+ async ({ session_id, action_id }) => jsonResult(await client.post(`/v1/sessions/${session_id}/approve`, { action_id }))
824
+ );
825
+ server.registerTool(
826
+ "reject_session",
827
+ {
828
+ title: "Reject a pending session action",
829
+ description: "Reject a pending action in an agent session (human-in-the-loop).",
830
+ inputSchema: {
831
+ session_id: z5.string().min(1).describe("The session id."),
832
+ action_id: z5.string().optional().describe("Specific pending action id, if any.")
833
+ },
834
+ annotations: DESTRUCTIVE_ANNOTATIONS
835
+ },
836
+ async ({ session_id, action_id }) => jsonResult(await client.post(`/v1/sessions/${session_id}/reject`, { action_id }))
837
+ );
838
+ }
553
839
  }
554
840
 
555
841
  // src/tools/governance.ts
556
842
  import { z as z6 } from "zod";
557
- function registerGovernanceTools(server, client) {
843
+ function registerGovernanceTools(server, client, caps) {
558
844
  server.registerTool(
559
845
  "list_policies",
560
846
  {
@@ -617,6 +903,34 @@ function registerGovernanceTools(server, client) {
617
903
  },
618
904
  async () => jsonResult(await client.get("/v1/governance/templates"))
619
905
  );
906
+ if (caps.write) {
907
+ server.registerTool(
908
+ "create_policy",
909
+ {
910
+ title: "Draft a governance policy",
911
+ description: "Create a governance policy as a DRAFT. It is not enforced until a human activates it (see how_to_activate_policy).",
912
+ inputSchema: {
913
+ name: z6.string().min(1).describe("Policy name (unique per org)."),
914
+ spec: z6.record(z6.string(), z6.unknown()).describe("Policy spec object: match + rules + defaults + controls.")
915
+ },
916
+ annotations: WRITE_ANNOTATIONS
917
+ },
918
+ async ({ name, spec }) => jsonResult(await client.post("/v1/governance/policies", { name, spec }))
919
+ );
920
+ server.registerTool(
921
+ "install_template",
922
+ {
923
+ title: "Install a governance policy template",
924
+ description: "Install a policy template as a new DRAFT policy. Activation remains a manual human step (see how_to_activate_policy).",
925
+ inputSchema: {
926
+ template_id: z6.string().min(1).describe("The template id to install."),
927
+ name: z6.string().min(1).describe("Name for the new draft policy.")
928
+ },
929
+ annotations: WRITE_ANNOTATIONS
930
+ },
931
+ async ({ template_id, name }) => jsonResult(await client.post(`/v1/governance/templates/${template_id}/install`, { name }))
932
+ );
933
+ }
620
934
  }
621
935
 
622
936
  // src/tools/multimodal.ts
@@ -899,7 +1213,7 @@ function registerGuidanceTools(server, baseUrl) {
899
1213
 
900
1214
  // src/server.ts
901
1215
  var SERVER_NAME = "cencori";
902
- var SERVER_VERSION = "0.2.0";
1216
+ var SERVER_VERSION = "0.5.0";
903
1217
  function createServer(config) {
904
1218
  const server = new McpServer(
905
1219
  {
@@ -924,10 +1238,10 @@ function createServer(config) {
924
1238
  if (config.apiKey) {
925
1239
  const client = new PlatformClient(config.baseUrl, config.apiKey);
926
1240
  if (features.gateway) registerGatewayTools(server, client);
927
- if (features.agents) registerAgentsTools(server, client);
928
- if (features.memory) registerMemoryTools(server, client);
929
- if (features.sessions) registerSessionsTools(server, client);
930
- if (features.governance) registerGovernanceTools(server, client);
1241
+ if (features.agents) registerAgentsTools(server, client, capabilities);
1242
+ if (features.memory) registerMemoryTools(server, client, capabilities);
1243
+ if (features.sessions) registerSessionsTools(server, client, capabilities);
1244
+ if (features.governance) registerGovernanceTools(server, client, capabilities);
931
1245
  if (features.multimodal && capabilities.write) {
932
1246
  registerMultimodalTools(server, client);
933
1247
  }