@lifesi/genesis-mcp 0.1.5 → 0.1.8

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.
@@ -8,7 +8,7 @@ export function hivesResourceInputSchema(id, fallback) {
8
8
  const upload = id.startsWith('hives_upload_object');
9
9
  return { type: 'object', properties: { ...keyProperties, ...(upload ? { body_base64: { type: 'string', maxLength: Math.ceil(OBJECT_BYTES / 3) * 4 }, content_type: { type: 'string', maxLength: 512 } } : {}) }, required: ['project_id', 'bucket_id', 'key', ...(upload ? ['body_base64'] : [])], additionalProperties: false };
10
10
  }
11
- export const isHivesResourceTool = (id) => /^(?:hives_marketplace_(?:categories|featured|installed|get_installation|uninstall|reconcile|list_packages|publish|get_package|install|update|list_versions)|hives_.*_native_queue|hives_(?:(?:list_volumes|create_volume|get_volume|delete_volume|mount_volume|unmount_volume)|list_buckets|create_bucket|get_bucket|delete_bucket|list_objects|upload_object(?:_by_key)?|delete_object(?:_by_key)?|download_object_by_key|get_cors_config|set_cors_config|generate_presigned_url|reconcile|list_runtimes|get_runtime|select_runtime|list_project_runtimes))$/.test(id);
11
+ export const isHivesResourceTool = (id) => /^(?:hives_marketplace_(?:categories|featured|installed|get_installation|uninstall|reconcile|list_packages|publish|get_package|install|update|list_versions)|hives_(?:get|configure|remove)_native_queue_consumer|hives_.*_native_queue|hives_.*_native_topic|hives_(?:(?:list_volumes|create_volume|get_volume|delete_volume|mount_volume|unmount_volume)|list_buckets|create_bucket|get_bucket|delete_bucket|list_objects|upload_object(?:_by_key)?|delete_object(?:_by_key)?|download_object_by_key|get_cors_config|set_cors_config|generate_presigned_url|reconcile|list_runtimes|get_runtime|select_runtime|list_project_runtimes))$/.test(id);
12
12
  function text(value) { if (typeof value !== 'string')
13
13
  throw new Error('Invalid Hives resource input.'); return value; }
14
14
  function decode(value) { const s = text(value); if (s.length > Math.ceil(OBJECT_BYTES / 3) * 4 || s.length % 4 || !/^[A-Za-z0-9+/]*={0,2}$/.test(s))
@@ -26,6 +26,14 @@ export async function callHivesResourceTool(g, id, a, signal) {
26
26
  const cells = g.hives.cells;
27
27
  const buzz = g.hives.queues;
28
28
  switch (id) {
29
+ case 'hives_list_native_topic': return g.hives.topics.list(project(), options);
30
+ case 'hives_inspect_native_topic': return g.hives.topics.get(project(), text(a.topic_id), options);
31
+ case 'hives_create_native_topic': return g.hives.topics.create(project(), body(), options);
32
+ case 'hives_delete_native_topic': return g.hives.topics.remove(project(), text(a.topic_id), options);
33
+ case 'hives_subscriptions_native_topic': return g.hives.topics.subscriptions.list(project(), text(a.topic_id), options);
34
+ case 'hives_subscribe_native_topic': return g.hives.topics.subscriptions.add(project(), text(a.topic_id), text(body()?.queueId), options);
35
+ case 'hives_unsubscribe_native_topic': return g.hives.topics.subscriptions.remove(project(), text(a.topic_id), text(a.subscription_id), options);
36
+ case 'hives_publish_native_topic': return g.hives.topics.publish(project(), text(a.topic_id), body(), options);
29
37
  case 'hives_list_volumes': return g.hives.volumes.list(project(), { page: a.page, per_page: a.per_page }, options);
30
38
  case 'hives_get_volume': return g.hives.volumes.get(project(), text(a.volume_id), options);
31
39
  case 'hives_create_volume': return g.hives.volumes.create(project(), body(), options);
@@ -57,6 +65,9 @@ export async function callHivesResourceTool(g, id, a, signal) {
57
65
  case 'hives_list_project_runtimes': return g.hives.runtimes.project(project(), options);
58
66
  case 'hives_get_runtime': return g.hives.runtimes.get(text(a.name), options);
59
67
  case 'hives_select_runtime': return g.hives.runtimes.select({ wasi: text(a.wasi), runner: text(a.runner), artifact: text(a.artifact) }, options);
68
+ case 'hives_get_native_queue_consumer': return buzz.consumer.get(project(), queue(), options);
69
+ case 'hives_configure_native_queue_consumer': return buzz.consumer.configure(project(), queue(), body(), options);
70
+ case 'hives_remove_native_queue_consumer': return buzz.consumer.remove(project(), queue(), options);
60
71
  case 'hives_list_native_queue': return buzz.list(project(), options);
61
72
  case 'hives_inspect_native_queue': return buzz.get(project(), queue(), options);
62
73
  case 'hives_create_native_queue': return buzz.create(project(), body(), options);
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { createServer, createHttpServer, serveStdio } from './server.js';
2
2
  export { tools, specTools, metaTools, searchTools, callTool } from './tools.js';
3
3
  export declare function cli(args: string[]): Promise<void>;
4
+ export { nativeLoginCredentials } from './native-credentials.js';
package/dist/index.js CHANGED
@@ -9,3 +9,4 @@ export async function cli(args) {
9
9
  }
10
10
  await serveStdio();
11
11
  }
12
+ export { nativeLoginCredentials } from './native-credentials.js';
@@ -0,0 +1,46 @@
1
+ import { type Genesis } from '@lifesi/genesis';
2
+ export declare function mindsInputSchema(id: string, schema: Record<string, unknown>): Record<string, unknown>;
3
+ export declare function callMindsTool(genesis: Genesis, id: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<{
4
+ schema_version: "minds.controller.v1";
5
+ items: import("@lifesi/genesis").components["schemas"]["Minds.Mind"][];
6
+ next_cursor: string | null;
7
+ context_sha256: string;
8
+ } | ({
9
+ schema_version: "minds.controller.v1";
10
+ mind_id: string;
11
+ organization_id: string;
12
+ project_id: string;
13
+ name: string;
14
+ region: string;
15
+ plan: "free" | "pro";
16
+ capacity: import("@lifesi/genesis").components["schemas"]["Minds.Capacity"];
17
+ observed_capacity: import("@lifesi/genesis").components["schemas"]["Minds.Capacity"] | null;
18
+ services: string[];
19
+ volume_id: string;
20
+ base_url: string;
21
+ desired_state: "running" | "stopped" | "deleted";
22
+ observed_state: "pending" | "running" | "stopped" | "deleted" | "failed" | "uncertain";
23
+ desired_generation: number;
24
+ observed_generation: number;
25
+ status: "ready" | "provisioning" | "stopped" | "deleted" | "failed" | "uncertain";
26
+ capacity_applied: boolean;
27
+ operation_id: string | null;
28
+ error_code: string | null;
29
+ created_at: string;
30
+ updated_at: string;
31
+ } & {
32
+ [key: string]: unknown;
33
+ }) | {
34
+ item: import("@lifesi/genesis").components["schemas"]["Minds.EpisodicEvent"] | null;
35
+ } | {
36
+ id: string;
37
+ } | ({
38
+ id: string;
39
+ content: string;
40
+ timestamp: string;
41
+ event_type: "Conversation" | "Command" | "Query" | "Document" | "Error" | "Success" | "Learning" | "Decision" | "Action" | "Context" | "Knowledge";
42
+ summary?: string | null;
43
+ tags: string[];
44
+ } & {
45
+ [key: string]: unknown;
46
+ })[]>;
package/dist/minds.js ADDED
@@ -0,0 +1,27 @@
1
+ import { GenesisError } from '@lifesi/genesis';
2
+ export function mindsInputSchema(id, schema) {
3
+ if (id !== 'minds_createMind')
4
+ return schema;
5
+ return { ...schema, properties: { ...schema.properties,
6
+ idempotency_key: { type: 'string', format: 'uuid', description: 'Persisted UUID4 for this creation intent. Keep it after an uncertain outcome.' },
7
+ context_sha256: { type: 'string', pattern: '^[a-f0-9]{64}$', description: 'context_sha256 from the current Minds list; an assertion, not authority.' }, }, required: [...schema.required, 'idempotency_key', 'context_sha256'], additionalProperties: false };
8
+ }
9
+ export async function callMindsTool(genesis, id, args, signal) {
10
+ if (id === 'minds_listMinds')
11
+ return genesis.minds.list(args, { signal });
12
+ if (id === 'minds_getMind')
13
+ return genesis.request('minds_getMind', args, { signal });
14
+ if (id === 'minds_getEpisodicMemory')
15
+ return genesis.request('minds_getEpisodicMemory', args, { signal });
16
+ if (id === 'minds_insertEpisodicMemory')
17
+ return genesis.request('minds_insertEpisodicMemory', args, { signal });
18
+ if (id === 'minds_searchMemory')
19
+ return genesis.request('minds_searchMemory', args, { signal });
20
+ if (id === 'minds_createMind' && Object.keys(args).every(key => ['body', 'idempotency_key', 'context_sha256'].includes(key))
21
+ && typeof args.idempotency_key === 'string' && typeof args.context_sha256 === 'string'
22
+ && args.body && typeof args.body === 'object' && !Array.isArray(args.body)
23
+ && Object.keys(args.body).length === 1 && typeof args.body.name === 'string') {
24
+ return genesis.minds.create(args.body.name, { idempotencyKey: args.idempotency_key, contextSha256: args.context_sha256, signal });
25
+ }
26
+ throw new GenesisError({ status: 0, type: 'invalid_request', operationId: id, message: 'Minds requires its exact input schema and retained creation context/key.' });
27
+ }
@@ -0,0 +1,9 @@
1
+ import { type CredentialStore } from '@lifesi/genesis-cli/store';
2
+ import type { CredentialProvider } from '@lifesi/genesis';
3
+ /** Reuse the CLI's exact OS-keychain entry and rotation; never print or export it.
4
+ * GenesisClient gives explicit options/environment credentials precedence. */
5
+ export declare function nativeLoginCredentials(options?: {
6
+ store?: () => Promise<CredentialStore>;
7
+ fetch?: typeof fetch;
8
+ env?: Record<string, string | undefined>;
9
+ }): CredentialProvider;
@@ -0,0 +1,11 @@
1
+ import { authConfig, savedLoginProvider } from '@lifesi/genesis-cli/auth';
2
+ import { keychainStore } from '@lifesi/genesis-cli/store';
3
+ /** Reuse the CLI's exact OS-keychain entry and rotation; never print or export it.
4
+ * GenesisClient gives explicit options/environment credentials precedence. */
5
+ export function nativeLoginCredentials(options = {}) {
6
+ let provider;
7
+ return async () => {
8
+ provider ??= (async () => savedLoginProvider(authConfig(options.env ?? process.env, options.fetch ?? fetch), await (options.store ?? keychainStore)()))();
9
+ return await (await provider)();
10
+ };
11
+ }
package/dist/server.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { nativeLoginCredentials } from './native-credentials.js';
1
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
4
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
@@ -5,12 +6,13 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprot
5
6
  import http from 'node:http';
6
7
  import { callTool, tools } from './tools.js';
7
8
  export function createServer(opts = {}) {
8
- const server = new Server({ name: 'genesis', version: '0.1.5' }, {
9
+ const configured = { ...opts, credentials: opts.credentials ?? nativeLoginCredentials({ fetch: opts.fetch }) };
10
+ const server = new Server({ name: 'genesis', version: '0.1.8' }, {
9
11
  capabilities: { tools: {} },
10
12
  instructions: 'Genesis: one API for Foundry (inference), Hives (compute), Relays (DNS) and LifeID keys. Use the named tools for common tasks; use genesis_search_tools + genesis_call for anything else.',
11
13
  });
12
14
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: tools() }));
13
- server.setRequestHandler(CallToolRequestSchema, async (req, extra) => callTool(opts, req.params.name, (req.params.arguments ?? {}), extra.signal));
15
+ server.setRequestHandler(CallToolRequestSchema, async (req, extra) => callTool(configured, req.params.name, (req.params.arguments ?? {}), extra.signal));
14
16
  return server;
15
17
  }
16
18
  /** stdio: credential from GENESIS_API_KEY / GENESIS_TOKEN (or `credentials` provider). */
package/dist/tools.js CHANGED
@@ -1,15 +1,16 @@
1
+ import { mindsInputSchema, callMindsTool } from './minds.js';
1
2
  import { callHivesResourceTool, hivesResourceInputSchema, isHivesResourceTool } from './hives-resources.js';
2
3
  import { createHivesNodeTransport } from './hives-node-transport.js';
3
4
  import { BEACONS_PROVISION_OPERATION, beaconsInputSchema, callBeaconsProvision } from './beacons.js';
4
5
  import { fleetsInputSchema, isFleetsLifecycleTool, callFleetsLifecycleTool } from './fleets.js';
5
- import { Genesis, GenesisError, MAX_WASM_BYTES, hivesResponseBytes, operationTable } from '@lifesi/genesis';
6
+ import { isFoundryBillingOperation, Genesis, GenesisError, MAX_WASM_BYTES, hivesResponseBytes, operationTable } from '@lifesi/genesis';
6
7
  const uploadSchema = { type: 'object', properties: {
7
8
  project_id: { type: 'string', description: 'Project owned by the caller’s verified org' },
8
9
  wasm_base64: { type: 'string', maxLength: Math.ceil(MAX_WASM_BYTES / 3) * 4, description: 'Explicit standard-base64 content of a real WASM binary (decoded maximum 10 MiB)' },
9
10
  filename: { type: 'string', maxLength: 255 },
10
11
  git_sha: { type: 'string', minLength: 7, maxLength: 40 }, git_branch: { type: 'string', maxLength: 255 }, git_message: { type: 'string', maxLength: 1000 },
11
12
  }, required: ['project_id', 'wasm_base64'], additionalProperties: false };
12
- const inputSchema = (id, op) => id === 'hives_upload_deployment' ? uploadSchema : fleetsInputSchema(id, beaconsInputSchema(id, hivesResourceInputSchema(id, op.inputSchema)));
13
+ const inputSchema = (id, op) => id.startsWith('minds_') ? mindsInputSchema(id, op.inputSchema) : isFoundryBillingOperation(id) ? { type: 'object', properties: ['foundry_ensureBillingProfile', 'foundry_createNativeCreditCheckout'].includes(id) ? { operation_key: { type: 'string', minLength: 1, maxLength: 255, description: 'Persisted original operation key; reconcile unknown outcomes before retrying.' } } : {}, required: ['foundry_ensureBillingProfile', 'foundry_createNativeCreditCheckout'].includes(id) ? ['operation_key'] : [], additionalProperties: false } : id === 'hives_upload_deployment' ? uploadSchema : fleetsInputSchema(id, beaconsInputSchema(id, hivesResourceInputSchema(id, op.inputSchema)));
13
14
  const all = Object.entries(operationTable);
14
15
  /** Operations callable by agents (everything except gateway-internal ones like credential verify). */
15
16
  export const callable = all.filter(([, op]) => !op.internal);
@@ -18,7 +19,7 @@ function describe(id, op) {
18
19
  return `${op.summary} (${op.method} ${op.path})${status}`;
19
20
  }
20
21
  const annotate = (op, id) => ({
21
- readOnlyHint: op.method === 'GET', destructiveHint: id === 'hives_stop_deployment' || op.method === 'DELETE' || isHivesResourceTool(id) && /^hives_purge/.test(id),
22
+ readOnlyHint: op.method === 'GET' || id === 'minds_searchMemory', destructiveHint: id === 'hives_stop_deployment' || op.method === 'DELETE' || isHivesResourceTool(id) && /^hives_purge/.test(id),
22
23
  idempotentHint: isHivesResourceTool(id) && op.method !== 'GET' ? false : ['GET', 'PUT', 'DELETE'].includes(op.method) || id === BEACONS_PROVISION_OPERATION || op.path === '/v1/iam/runner/self-execution-grant', openWorldHint: true,
23
24
  });
24
25
  /** Curated tools: one per operation tagged x-mcp in the merged spec. */
@@ -68,7 +69,16 @@ async function invoke(genesis, id, args, signal) {
68
69
  return text(`Unknown operation "${id}". Use genesis_search_tools to find one.`, true);
69
70
  try {
70
71
  let r;
71
- if (isFleetsLifecycleTool(id)) {
72
+ if (op.service === 'minds') {
73
+ r = await callMindsTool(genesis, id, args, signal);
74
+ }
75
+ else if (isFoundryBillingOperation(id)) {
76
+ const mutation = ['foundry_ensureBillingProfile', 'foundry_createNativeCreditCheckout'].includes(id);
77
+ if (Object.keys(args).some(k => k !== 'operation_key') || (mutation ? typeof args.operation_key !== 'string' : Object.keys(args).length !== 0))
78
+ throw new Error('Native billing accepts only a persisted operation key for mutations.');
79
+ r = id === 'foundry_readBillingProfile' ? await genesis.foundry.billing.profile({ signal }) : id === 'foundry_readNativeCreditBalance' ? await genesis.foundry.billing.creditBalance({ signal }) : id === 'foundry_ensureBillingProfile' ? await genesis.foundry.billing.ensureProfile(args.operation_key, { signal }) : await genesis.foundry.billing.checkoutCredits(args.operation_key, { signal });
80
+ }
81
+ else if (isFleetsLifecycleTool(id)) {
72
82
  r = await callFleetsLifecycleTool(genesis, id, args, signal);
73
83
  }
74
84
  else if (id === BEACONS_PROVISION_OPERATION) {
@@ -109,7 +119,7 @@ async function invoke(genesis, id, args, signal) {
109
119
  }
110
120
  catch (e) {
111
121
  if (e instanceof GenesisError)
112
- return text({ error: { type: e.type, status: e.status, message: e.message, request_id: e.requestId } }, true);
122
+ return text({ error: { type: e.type, status: e.status, message: e.message, request_id: e.requestId, ...((isFoundryBillingOperation(id) || op.service === 'minds') && e.body && typeof e.body === 'object' && 'outcome' in e.body ? { outcome: e.body.outcome } : {}) } }, true);
113
123
  return text({ error: { type: 'network', message: e.message, hint: `The ${op.service} service may be unreachable (status: ${op.upstream.status}).` } }, true);
114
124
  }
115
125
  }
@@ -125,5 +135,5 @@ export async function callTool(opts, name, args = {}, signal) {
125
135
  return text(`Unknown operation "${id}". Use genesis_search_tools to find one.`, true);
126
136
  const hives = op.service === 'hives';
127
137
  const genesis = new Genesis(hives ? { ...opts, fetch: createHivesNodeTransport(opts, signal) } : opts);
128
- return invoke(genesis, id, input, hives || op.service === 'blinds' || id === 'relays_getEnrollment' || id === 'relays_enroll' || isFleetsLifecycleTool(id) ? signal : undefined);
138
+ return invoke(genesis, id, input, hives || op.service === 'minds' || isFoundryBillingOperation(id) || op.service === 'blinds' || id === 'relays_getEnrollment' || id === 'relays_enroll' || isFleetsLifecycleTool(id) ? signal : undefined);
129
139
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifesi/genesis-mcp",
3
- "version": "0.1.5",
3
+ "version": "0.1.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/l1felabs/genesis-api.git",
@@ -8,6 +8,14 @@
8
8
  },
9
9
  "description": "Genesis MCP server (stdio + streamable HTTP): tools generated from the Genesis OpenAPI",
10
10
  "type": "module",
11
+ "main": "dist/index.js",
12
+ "types": "dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
11
19
  "bin": {
12
20
  "genesis-mcp": "bin/genesis-mcp.js"
13
21
  },
@@ -18,7 +26,8 @@
18
26
  "dependencies": {
19
27
  "@modelcontextprotocol/sdk": "^1.32.1",
20
28
  "undici": "6.29.0",
21
- "@lifesi/genesis": "0.1.5"
29
+ "@lifesi/genesis": "0.1.8",
30
+ "@lifesi/genesis-cli": "0.1.8"
22
31
  },
23
32
  "scripts": {
24
33
  "build": "tsc -p tsconfig.json"