mneva-connect 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # mneva-connect
2
+
3
+ Connect your coding agent to its hosted **Mneva** brain — persistent memory,
4
+ belief revision, and instinct, over MCP.
5
+
6
+ Every AI coding tool starts cold: it re-reads your codebase, re-asks what you
7
+ told it last week, repeats the mistake you already corrected. Mneva is the
8
+ mind underneath them — it remembers, it revises, and it carries across every
9
+ session and every tool you use.
10
+
11
+ ## Setup
12
+
13
+ 1. Get an API key at [mneva.dev/signup](https://mneva.dev/signup).
14
+ 2. Add this to your coding tool's `.mcp.json` (Claude Code, Cursor, or any
15
+ MCP client):
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "mneva": {
21
+ "command": "npx",
22
+ "args": ["-y", "mneva-connect"],
23
+ "env": { "MNEVA_KEY": "mnv_your_key_here" }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ 3. Restart your coding tool.
30
+
31
+ ## What your agent gets
32
+
33
+ | Tool | What it does |
34
+ |------|--------------|
35
+ | `remember` | Record a decision, a fix, a fact — kept across sessions |
36
+ | `recall` | Semantic recall of past memories — finds them by meaning |
37
+ | `believe` | Assert something held true about the project |
38
+ | `revise` | Correct a belief — the old one is superseded for good |
39
+ | `flag` | Mark code as fragile or dangerous |
40
+ | `assess` | Gut-check before working — clear, caution, or danger |
41
+
42
+ ## Environment
43
+
44
+ - `MNEVA_KEY` *(required)* — your tenant API key
45
+ - `MNEVA_API` *(optional)* — engine base URL, defaults to the hosted service
46
+
47
+ MIT licensed.
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "mneva-connect",
3
+ "version": "0.1.0",
4
+ "description": "Connect your coding agent to its hosted Mneva brain — persistent memory, belief revision, and instinct over MCP.",
5
+ "type": "module",
6
+ "bin": {
7
+ "mneva-connect": "./src/index.js"
8
+ },
9
+ "scripts": {
10
+ "prove": "node src/prove.js"
11
+ },
12
+ "files": ["src"],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "keywords": ["mcp", "ai", "memory", "agent", "mneva", "claude", "cursor"],
17
+ "license": "MIT",
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^1.0.4"
20
+ }
21
+ }
package/src/index.js ADDED
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * mneva-connect — connect a coding agent to its hosted Mneva brain.
4
+ *
5
+ * This is the package the Mneva signup page tells you to install. It is a
6
+ * thin MCP stdio server: every tool call is forwarded to your hosted Mneva
7
+ * brain over HTTPS, authenticated with your MNEVA_KEY. No local database,
8
+ * no embeddings here — the hosted engine does all of it. Your agent just
9
+ * sees six tools and a memory that persists everywhere you code.
10
+ *
11
+ * Add to your coding tool's .mcp.json:
12
+ *
13
+ * {
14
+ * "mcpServers": {
15
+ * "mneva": {
16
+ * "command": "npx",
17
+ * "args": ["-y", "mneva-connect"],
18
+ * "env": { "MNEVA_KEY": "mnv_your_key_here" }
19
+ * }
20
+ * }
21
+ * }
22
+ *
23
+ * Env:
24
+ * MNEVA_KEY (required) — your tenant API key from the Mneva dashboard
25
+ * MNEVA_API (optional) — engine base URL, defaults to the hosted service
26
+ */
27
+
28
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
29
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
30
+ import { z } from 'zod';
31
+
32
+ // Defaults to the hosted Mneva service. Override MNEVA_API only for
33
+ // self-hosting or local development against your own engine.
34
+ const API = (process.env.MNEVA_API || 'https://mneva.dev').replace(/\/$/, '');
35
+ const KEY = process.env.MNEVA_KEY;
36
+
37
+ if (!KEY) {
38
+ console.error(
39
+ '[mneva] MNEVA_KEY is not set. Add your API key to the mneva server\'s\n' +
40
+ ' env block in .mcp.json. Get a key at https://mneva.dev/signup',
41
+ );
42
+ process.exit(1);
43
+ }
44
+
45
+ const json = (data) => ({ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] });
46
+ const fail = (msg) => ({ content: [{ type: 'text', text: `error: ${msg}` }], isError: true });
47
+
48
+ /** Forward one tool call to the hosted brain. */
49
+ async function call(path, body) {
50
+ let res;
51
+ try {
52
+ res = await fetch(`${API}/v1/${path}`, {
53
+ method: 'POST',
54
+ headers: { 'content-type': 'application/json', 'x-mneva-key': KEY },
55
+ body: JSON.stringify(body),
56
+ signal: AbortSignal.timeout(20000),
57
+ });
58
+ } catch (err) {
59
+ return fail(`could not reach your Mneva brain (${err.message})`);
60
+ }
61
+ if (res.status === 401) return fail('your MNEVA_KEY is invalid — check it in the Mneva dashboard');
62
+ let data;
63
+ try {
64
+ data = await res.json();
65
+ } catch {
66
+ return fail(`unexpected response from the Mneva engine (HTTP ${res.status})`);
67
+ }
68
+ if (!res.ok) return fail(data.error || `Mneva engine error (HTTP ${res.status})`);
69
+ return json(data);
70
+ }
71
+
72
+ const server = new McpServer({ name: 'mneva', version: '0.1.0' });
73
+
74
+ server.registerTool(
75
+ 'remember',
76
+ {
77
+ description:
78
+ 'Record something that happened in this project — a decision, a fix, a fact. Your hosted Mneva brain keeps it across every session and every tool.',
79
+ inputSchema: { text: z.string().describe('What to remember.') },
80
+ },
81
+ ({ text }) => call('remember', { text }),
82
+ );
83
+
84
+ server.registerTool(
85
+ 'recall',
86
+ {
87
+ description:
88
+ 'Recall past memories related to a query — semantic, so it finds relevant memories even with no shared words. You do not start cold.',
89
+ inputSchema: { query: z.string().describe('What to recall about.') },
90
+ },
91
+ ({ query }) => call('recall', { query }),
92
+ );
93
+
94
+ server.registerTool(
95
+ 'believe',
96
+ {
97
+ description: 'Assert a belief — something held true about this project (a convention, a constraint).',
98
+ inputSchema: {
99
+ text: z.string().describe('The belief to hold.'),
100
+ confidence: z.number().min(0).max(1).optional(),
101
+ },
102
+ },
103
+ ({ text, confidence }) => call('believe', { text, confidence }),
104
+ );
105
+
106
+ server.registerTool(
107
+ 'revise',
108
+ {
109
+ description:
110
+ 'Revise a belief. The old one is superseded and will never resurface — this is how a corrected mistake stays corrected.',
111
+ inputSchema: {
112
+ belief_id: z.number().int().describe('Id of the belief to revise.'),
113
+ new_text: z.string().describe('The corrected belief.'),
114
+ confidence: z.number().min(0).max(1).optional(),
115
+ },
116
+ },
117
+ ({ belief_id, new_text, confidence }) => call('revise', { belief_id, new_text, confidence }),
118
+ );
119
+
120
+ server.registerTool(
121
+ 'flag',
122
+ {
123
+ description:
124
+ 'Flag something as dangerous or fragile. Mneva remembers the danger and will warn about it later.',
125
+ inputSchema: {
126
+ text: z.string().describe('What is dangerous, and why.'),
127
+ caution: z.number().min(0).max(1).optional(),
128
+ },
129
+ },
130
+ ({ text, caution }) => call('flag', { text, caution }),
131
+ );
132
+
133
+ server.registerTool(
134
+ 'assess',
135
+ {
136
+ description:
137
+ 'Gut-check a topic before working on it. Returns clear, caution, or danger with the reason — the partner\'s instinct.',
138
+ inputSchema: { topic: z.string().describe('What you are about to work on.') },
139
+ },
140
+ ({ topic }) => call('assess', { topic }),
141
+ );
142
+
143
+ const transport = new StdioServerTransport();
144
+ await server.connect(transport);
145
+ console.error(`[mneva] connected to your hosted brain at ${API}`);
package/src/prove.js ADDED
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Proof — mneva-connect against the live hosted engine.
3
+ *
4
+ * 1. Provision a fresh tenant via the engine admin endpoint.
5
+ * 2. Spawn mneva-connect as an MCP server with that tenant's key — exactly
6
+ * how Cursor / Claude Code would spawn it from .mcp.json.
7
+ * 3. Call tools through the connector and confirm they reach the hosted
8
+ * brain: remember -> recall, flag -> assess, and an invalid key fails loud.
9
+ *
10
+ * If this passes, the signup page's .mcp.json snippet is true: install
11
+ * mneva-connect with your key and your agent is talking to its brain.
12
+ */
13
+
14
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
15
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { dirname, join } from 'node:path';
18
+
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ const CONNECT = join(__dirname, 'index.js');
21
+ const ENGINE = process.env.MNEVA_API || 'http://localhost:8787';
22
+ const ADMIN = process.env.MNEVA_ADMIN_SECRET || 'dev-admin-secret';
23
+
24
+ let pass = 0;
25
+ let fail = 0;
26
+ const check = (label, cond, detail = '') => {
27
+ if (cond) { pass++; console.log(` PASS ${label}`); }
28
+ else { fail++; console.log(` FAIL ${label} ${detail}`); }
29
+ };
30
+
31
+ console.log('\nmneva-connect PROOF (against the live engine)');
32
+ console.log('==============================================\n');
33
+
34
+ // 1. Provision a fresh tenant.
35
+ let key;
36
+ try {
37
+ const res = await fetch(`${ENGINE}/admin/tenant`, {
38
+ method: 'POST',
39
+ headers: { 'content-type': 'application/json', 'x-mneva-admin': ADMIN },
40
+ body: JSON.stringify({ name: 'connect-proof' }),
41
+ });
42
+ const t = await res.json();
43
+ key = t.key;
44
+ check('provisioned a fresh tenant brain', !!key, JSON.stringify(t));
45
+ } catch (err) {
46
+ console.log(` FAIL engine unreachable at ${ENGINE} — start it first (${err.message})`);
47
+ process.exit(1);
48
+ }
49
+
50
+ /** Spawn mneva-connect as an MCP server with a given key. */
51
+ async function connector(apiKey) {
52
+ const transport = new StdioClientTransport({
53
+ command: process.execPath,
54
+ args: [CONNECT],
55
+ env: { ...process.env, MNEVA_KEY: apiKey, MNEVA_API: ENGINE },
56
+ });
57
+ const client = new Client({ name: 'connect-proof', version: '0.1.0' });
58
+ await client.connect(transport);
59
+ return {
60
+ client,
61
+ async call(tool, args) {
62
+ const r = await client.callTool({ name: tool, arguments: args });
63
+ const t = r.content?.[0]?.text ?? '';
64
+ try { return { data: JSON.parse(t), isError: !!r.isError }; }
65
+ catch { return { data: t, isError: !!r.isError }; }
66
+ },
67
+ end: () => client.close(),
68
+ };
69
+ }
70
+
71
+ // 2. A real session through the connector.
72
+ console.log('\nThrough mneva-connect, with a valid key:');
73
+ {
74
+ const c = await connector(key);
75
+
76
+ const tools = (await c.client.listTools()).tools.map((t) => t.name).sort();
77
+ check('connector exposes all six tools',
78
+ JSON.stringify(tools) === JSON.stringify(['assess', 'believe', 'flag', 'recall', 'remember', 'revise']),
79
+ `got ${JSON.stringify(tools)}`);
80
+
81
+ await c.call('remember', { text: 'the deploy script is scripts/ship.sh and needs the staging DB up first' });
82
+ const recalled = await c.call('recall', { query: 'how do we release' });
83
+ const hits = recalled.data?.results ?? [];
84
+ check('remember -> recall reaches the hosted brain (semantic)',
85
+ hits.some((m) => m.text.includes('ship.sh')),
86
+ JSON.stringify(recalled.data));
87
+
88
+ await c.call('flag', { text: 'the migration runner has dropped columns before — never run it without a backup' });
89
+ const verdict = await c.call('assess', { topic: 'about to run a database migration' });
90
+ check('flag -> assess works through the connector',
91
+ verdict.data?.verdict === 'danger',
92
+ JSON.stringify(verdict.data));
93
+ console.log(` > assess verdict: ${verdict.data?.verdict} — "${verdict.data?.why}"`);
94
+
95
+ await c.end();
96
+ }
97
+
98
+ // 3. An invalid key must fail loudly, not silently.
99
+ console.log('\nWith an invalid key:');
100
+ {
101
+ const c = await connector('mnv_not_a_real_key');
102
+ const res = await c.call('recall', { query: 'anything' });
103
+ check('invalid key produces a clear error', res.isError === true && /invalid/i.test(res.data),
104
+ JSON.stringify(res));
105
+ await c.end();
106
+ }
107
+
108
+ console.log(`\n${'='.repeat(46)}`);
109
+ console.log(`RESULT: ${pass} passed, ${fail} failed`);
110
+ console.log(fail === 0
111
+ ? 'mneva-connect works — the signup snippet is true.'
112
+ : 'mneva-connect NOT proven — see failures above.');
113
+ console.log('='.repeat(46) + '\n');
114
+
115
+ process.exit(fail === 0 ? 0 : 1);