frinus-mcp 3.2.1 → 3.3.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 CHANGED
@@ -1,13 +1,32 @@
1
1
  # Frinus MCP Server
2
2
 
3
- > **φρήν + νοῦς** — The cognitive memory bridge between Claude agents and the [Frinus](https://github.com/frinus-ai) platform.
3
+ > **φρήν + νοῦς** — Gives your Claude agent long-term, cognitive memory backed by the [Frinus](https://frinus.rdxsec.com.br) platform.
4
4
 
5
- MCP (Model Context Protocol) server that exposes **70 tools** spanning cognitive memory, working memory, sessions, agents, the L0–L3 knowledge hierarchy, orchestration tasks, and training pipelines. The server speaks stdio and is consumed by Claude Desktop, Claude Code, and any MCP-aware client.
5
+ `frinus-mcp` is an MCP (Model Context Protocol) server. It is the **bridge** between your MCP client — Claude Code, Cursor, or Claude Desktop — and the **Frinus platform hosted at https://frinus.rdxsec.com.br**.
6
6
 
7
- - **Version:** 3.1.0
7
+ It does **not** run on its own. It stores nothing locally: every tool call is forwarded over HTTPS to your Frinus account. So before it does anything useful you need two things:
8
+
9
+ 1. a **Frinus account** (free, no card), and
10
+ 2. a **Frinus API key** (`sk-frinus-...`).
11
+
12
+ With those in place, the server exposes **70 tools** spanning cognitive memory, working memory, sessions, agents, the L0–L3 knowledge hierarchy, orchestration tasks, and training pipelines. It speaks stdio and works with any MCP-aware client.
13
+
14
+ - **Version:** 3.3.0
8
15
  - **Tools:** 70 (see [Tools Reference](#tools-reference))
9
- - **Backends:** Memory Engine (`:8001`) + Control Plane (`:8000`) + Agent Service (`:8002`)
10
- - **Public mirror:** https://github.com/frinus-ai/frinus-mcp
16
+ - **Platform:** https://frinus.rdxsec.com.br (hosted SaaS — the backend this server talks to)
17
+ - **npm package:** [`frinus-mcp`](https://www.npmjs.com/package/frinus-mcp)
18
+
19
+ ## How it fits together
20
+
21
+ ```
22
+ +-------------------+ +--------------+ +----------------------------+
23
+ | Your MCP client | stdio | frinus-mcp | HTTPS | Frinus platform |
24
+ | (Claude Code, | <----> | (this server,| <----> | frinus.rdxsec.com.br |
25
+ | Cursor, Desktop) | | via npx) | | (your memories live here) |
26
+ +-------------------+ +--------------+ +----------------------------+
27
+ ```
28
+
29
+ The server validates your API key against the platform at startup, resolves your account + organisation, and routes every tool call there. No API key → it refuses to start.
11
30
 
12
31
  ## Rule Zero — MCP is mandatory
13
32
 
@@ -20,70 +39,51 @@ The Frinus MCP **is** the agent's long-term memory, identity, and intelligence.
20
39
 
21
40
  The complete protocol set lives in the global `CLAUDE.md` (Frinus organisation), summarised below in [The 7 Protocols](#the-7-protocols).
22
41
 
23
- ## Requirements
42
+ ## Before you start — account + API key
24
43
 
25
- - Node.js 18+
26
- - Frinus stack reachable (Memory Engine, Control Plane, Agent Service)
27
- - Personal API key (`sk-frinus-...`) tied to your tenant
44
+ You need a Frinus account and an API key. Both are free to get.
28
45
 
29
- ## Installation
46
+ ### 1. Create a free account
30
47
 
31
- **End users — no install needed.** Use the published package via `npx` (see config below), or the one-click `.mcpb` extension for Claude Desktop.
48
+ Sign up at **https://frinus.rdxsec.com.br**. The **Free plan (R$0)** is enough to get started:
32
49
 
33
- **Developers / from source:**
50
+ - 100 memories
51
+ - 20 queries/day
52
+ - no credit card required
53
+
54
+ ### 2. Generate an API key
55
+
56
+ Once logged in, open your account **Settings → API Keys** and create a new key. You'll get a value shaped like:
34
57
 
35
- ```bash
36
- npm install
37
- npm run build
58
+ ```
59
+ sk-frinus-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
38
60
  ```
39
61
 
40
- The build emits `dist/index.js`, ready to be wired into Claude Desktop / Claude Code.
62
+ Copy it now — for security it's shown **only once**. This value goes into the `FRINUS_API_KEY` environment variable below. Treat it like a password; never commit it to a repo.
41
63
 
42
- ## Distribution
64
+ ## Getting started (zero to first memory)
43
65
 
44
- | Channel | Client | User effort |
45
- |---------|--------|-------------|
46
- | **npm** (`npx -y frinus-mcp`) | Claude Code, Cursor, Codex, opencode | Paste config + API key |
47
- | **`.mcpb` bundle** | Claude Desktop | Double-click + paste API key |
48
- | **From source** | any | Clone + build + absolute path |
66
+ Five minutes, four steps.
49
67
 
50
- URL defaults point at the Frinus SaaS, so only `FRINUS_API_KEY` is required. Override `MEMORY_SERVICE_URL` / `FRINUS_CP_URL` / `AGENT_SERVICE_URL` for self-hosted instances or local dev.
68
+ ### Step 1 — Create your account
51
69
 
52
- ### Publishing (maintainers)
70
+ Sign up at https://frinus.rdxsec.com.br (Free plan, no card). See [above](#1-create-a-free-account).
53
71
 
54
- ```bash
55
- # 1) npm package — powers `npx -y frinus-mcp` everywhere
56
- npm version <patch|minor|major>
57
- npm publish # prepublishOnly runs the build
72
+ ### Step 2 — Generate your API key
58
73
 
59
- # 2) .mcpb bundle — powers the Claude Desktop one-click install
60
- npm run pack:mcpb # -> frinus.mcpb
61
- gh release upload v<version> frinus.mcpb --repo frinus-ai/frinus-mcp --clobber
62
- # Frontend points at: releases/latest/download/frinus.mcpb
63
- ```
74
+ Settings → API Keys → create. Copy the `sk-frinus-...` value. See [above](#2-generate-an-api-key).
64
75
 
65
- ## Environment Variables
76
+ ### Step 3 — Add the server to your client
66
77
 
67
- | Variable | Default | Description |
68
- |----------|---------|-------------|
69
- | `FRINUS_API_KEY` | **required** | Personal API key (`sk-frinus-...`). Resolves tenant + user identity at boot. |
70
- | `MEMORY_SERVICE_URL` | `http://localhost:8001` | Memory Engine base URL |
71
- | `FRINUS_CP_URL` | `http://localhost:8000` | Control Plane base URL (universes, orgs, billing) |
72
- | `AGENT_SERVICE_URL` | `http://localhost:8002` | Agent Service base URL (agents, invocation, skills) |
73
- | `FRINUS_MEMORY_API_KEY` | — | Legacy fallback for `FRINUS_API_KEY` |
78
+ You don't install anything — `npx` fetches and runs the package on demand. The only value you must provide is your API key; the platform URLs already default to production.
74
79
 
75
- Production endpoints (Frinus SaaS):
80
+ **Claude Code (one-liner):**
76
81
 
77
82
  ```bash
78
- MEMORY_SERVICE_URL=https://frinus-memory.rdxsec.com.br
79
- FRINUS_CP_URL=https://frinus-api.rdxsec.com.br
80
- AGENT_SERVICE_URL=https://frinus-agents.rdxsec.com.br
81
- FRINUS_API_KEY=sk-frinus-...
83
+ claude mcp add frinus --env FRINUS_API_KEY=sk-frinus-... -- npx -y frinus-mcp@latest
82
84
  ```
83
85
 
84
- ## Claude Desktop / Claude Code Configuration
85
-
86
- Add the server to your MCP client configuration. **Recommended (npx, no install):**
86
+ **Cursor / Claude Desktop / any client (config JSON):**
87
87
 
88
88
  ```json
89
89
  {
@@ -99,35 +99,45 @@ Add the server to your MCP client configuration. **Recommended (npx, no install)
99
99
  }
100
100
  ```
101
101
 
102
- Claude Code one-liner:
102
+ Config file locations:
103
103
 
104
- ```bash
105
- claude mcp add frinus --env FRINUS_API_KEY=sk-frinus-... -- npx -y frinus-mcp@latest
104
+ - **Claude Code:** `~/.claude.json`, under `mcpServers`.
105
+ - **Claude Desktop:** `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) / `~/.config/claude/claude_desktop_config.json` (Linux). Or use the one-click `.mcpb` extension and just paste your API key.
106
+ - **Cursor:** `~/.cursor/mcp.json`, under `mcpServers`.
107
+
108
+ Restart the client so it picks up the new server.
109
+
110
+ > Replace `sk-frinus-...` with the real key from Step 2. You normally set **only** `FRINUS_API_KEY` — every backend URL already defaults to the hosted platform. See [Environment Variables](#environment-variables) for the full list and the self-host override.
111
+
112
+ ### Step 4 — Validate with your first memory
113
+
114
+ In your client, ask the agent to store and recall something:
115
+
116
+ ```
117
+ Store this in Frinus memory: "Our staging DB is reset every night at 02:00 UTC."
106
118
  ```
107
119
 
108
- From source (developers), point at the built entry and override URLs as needed:
120
+ then in the same or a later session:
109
121
 
110
- ```json
111
- {
112
- "mcpServers": {
113
- "frinus": {
114
- "command": "node",
115
- "args": ["/absolute/path/to/mcp/dist/index.js"],
116
- "env": {
117
- "FRINUS_API_KEY": "sk-frinus-...",
118
- "MEMORY_SERVICE_URL": "http://localhost:8001",
119
- "FRINUS_CP_URL": "http://localhost:8000",
120
- "AGENT_SERVICE_URL": "http://localhost:8002"
121
- }
122
- }
123
- }
124
- }
125
122
  ```
123
+ What time does our staging DB reset?
124
+ ```
125
+
126
+ Behind the scenes the agent calls `memory_store` then `memory_search` / `search_with_attention`. If the recall comes back, the bridge is live. You can confirm the same memory appears in the web app at https://frinus.rdxsec.com.br.
126
127
 
127
- Claude Desktop config path: `~/.config/claude/claude_desktop_config.json` (Linux) / `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS).
128
- Claude Code config path: `~/.claude.json` under `mcpServers`.
128
+ ## Environment Variables
129
+
130
+ In normal use you set **only** `FRINUS_API_KEY`. The service URLs already point at the hosted platform — leave them alone unless you self-host (see [Advanced — self-host](#advanced--self-host--local-dev)).
131
+
132
+ | Variable | Default (hosted platform) | Description |
133
+ |----------|---------------------------|-------------|
134
+ | `FRINUS_API_KEY` | **required** | Your personal API key (`sk-frinus-...`). Resolves account + organisation at boot. |
135
+ | `MEMORY_SERVICE_URL` | `https://frinus-memory.rdxsec.com.br` | Memory Engine base URL |
136
+ | `FRINUS_CP_URL` | `https://frinus-api.rdxsec.com.br` | Control Plane base URL (account, orgs, API keys, billing) |
137
+ | `AGENT_SERVICE_URL` | `https://frinus-agents.rdxsec.com.br` | Agent Service base URL (agents, invocation, skills) |
138
+ | `FRINUS_MEMORY_API_KEY` | — | Legacy fallback for `FRINUS_API_KEY` |
129
139
 
130
- On startup the server validates the API key via `/auth/me` and resolves the tenant org ID + logged-in user. Failures abort the process with `[FATAL]` so the client surfaces the error.
140
+ On startup the server validates the API key against the platform and resolves your organisation + logged-in user. If validation fails it aborts with `[FATAL]` so the client surfaces the error — re-check the key from Settings → API Keys.
131
141
 
132
142
  ## The 7 Protocols
133
143
 
@@ -409,6 +419,46 @@ Operational guidelines:
409
419
 
410
420
  Tenant isolation is database-per-tenant. The MCP resolves your tenant org ID from the API key at boot — you never pass `org_id` manually.
411
421
 
422
+ ## Advanced — self-host / local dev
423
+
424
+ Everything above targets the hosted platform at https://frinus.rdxsec.com.br, which is what almost everyone wants. If you run your own Frinus stack (or develop the MCP against a local backend), build from source and override the three URLs:
425
+
426
+ ```bash
427
+ git clone https://github.com/frinus-ai/frinus-mcp && cd frinus-mcp
428
+ npm install
429
+ npm run build # emits dist/index.js
430
+ ```
431
+
432
+ ```json
433
+ {
434
+ "mcpServers": {
435
+ "frinus": {
436
+ "command": "node",
437
+ "args": ["/absolute/path/to/mcp/dist/index.js"],
438
+ "env": {
439
+ "FRINUS_API_KEY": "sk-frinus-...",
440
+ "MEMORY_SERVICE_URL": "http://localhost:8001",
441
+ "FRINUS_CP_URL": "http://localhost:8000",
442
+ "AGENT_SERVICE_URL": "http://localhost:8002"
443
+ }
444
+ }
445
+ }
446
+ }
447
+ ```
448
+
449
+ ### Publishing (maintainers)
450
+
451
+ ```bash
452
+ # 1) npm package — powers `npx -y frinus-mcp` everywhere
453
+ npm version <patch|minor|major>
454
+ npm publish # prepublishOnly runs the build
455
+
456
+ # 2) .mcpb bundle — powers the Claude Desktop one-click install
457
+ npm run pack:mcpb # -> frinus.mcpb
458
+ gh release upload v<version> frinus.mcpb --repo frinus-ai/frinus-mcp --clobber
459
+ # Frontend points at: releases/latest/download/frinus.mcpb
460
+ ```
461
+
412
462
  ## Development
413
463
 
414
464
  ```
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Resolved MCP client identity.
3
+ *
4
+ * The MCP client sends its `clientInfo: { name, version }` during the
5
+ * `initialize` handshake. We normalize the raw `name` into a small, stable
6
+ * set of buckets and expose it as the `X-Client` header so the Control Plane
7
+ * can attribute the `mcp_connected` PostHog event to the right client
8
+ * ("claude_code", "cursor", "desktop", "codex", "unknown").
9
+ *
10
+ * Module-level singleton (getter/setter), mirroring `resolvedTenantOrgId` in
11
+ * memory-client.ts: it is captured by an Axios request interceptor at
12
+ * construction time and read lazily on each request, so a single mutable
13
+ * module value is the least-surprising shape here.
14
+ */
15
+ export type ResolvedClient = "claude_code" | "cursor" | "desktop" | "codex" | "unknown";
16
+ /**
17
+ * Normalize a raw `clientInfo.name` into a stable bucket.
18
+ *
19
+ * Order matters: the more specific "claude-code" check must run before the
20
+ * generic "claude" → desktop fallback, so Claude Code is never misclassified
21
+ * as the desktop app.
22
+ */
23
+ export declare function normalizeClient(rawName?: string | null): ResolvedClient;
24
+ export declare function setResolvedClient(rawName?: string | null): void;
25
+ export declare function getResolvedClient(): ResolvedClient;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Resolved MCP client identity.
3
+ *
4
+ * The MCP client sends its `clientInfo: { name, version }` during the
5
+ * `initialize` handshake. We normalize the raw `name` into a small, stable
6
+ * set of buckets and expose it as the `X-Client` header so the Control Plane
7
+ * can attribute the `mcp_connected` PostHog event to the right client
8
+ * ("claude_code", "cursor", "desktop", "codex", "unknown").
9
+ *
10
+ * Module-level singleton (getter/setter), mirroring `resolvedTenantOrgId` in
11
+ * memory-client.ts: it is captured by an Axios request interceptor at
12
+ * construction time and read lazily on each request, so a single mutable
13
+ * module value is the least-surprising shape here.
14
+ */
15
+ let resolvedClient = "unknown";
16
+ /**
17
+ * Normalize a raw `clientInfo.name` into a stable bucket.
18
+ *
19
+ * Order matters: the more specific "claude-code" check must run before the
20
+ * generic "claude" → desktop fallback, so Claude Code is never misclassified
21
+ * as the desktop app.
22
+ */
23
+ export function normalizeClient(rawName) {
24
+ if (!rawName)
25
+ return "unknown";
26
+ const name = rawName.toLowerCase();
27
+ if (name.includes("claude-code") || name.includes("claudecode")) {
28
+ return "claude_code";
29
+ }
30
+ if (name.includes("cursor")) {
31
+ return "cursor";
32
+ }
33
+ if (name.includes("codex")) {
34
+ return "codex";
35
+ }
36
+ // Generic Claude clients (Claude Desktop, claude-ai, etc.) — must come after
37
+ // the claude-code check above.
38
+ if (name.includes("claude") || name.includes("claude-ai") || name.includes("desktop")) {
39
+ return "desktop";
40
+ }
41
+ return "unknown";
42
+ }
43
+ export function setResolvedClient(rawName) {
44
+ resolvedClient = normalizeClient(rawName);
45
+ }
46
+ export function getResolvedClient() {
47
+ return resolvedClient;
48
+ }
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import axios from "axios";
5
5
  import { getResolvedTenantOrgId } from "./memory-client.js";
6
+ import { getResolvedClient } from "./client-info.js";
6
7
  export class CpClient {
7
8
  client;
8
9
  constructor(baseURL, apiKey) {
@@ -16,6 +17,7 @@ export class CpClient {
16
17
  const orgId = getResolvedTenantOrgId();
17
18
  if (orgId)
18
19
  config.headers['X-Tenant-ID'] = orgId;
20
+ config.headers['X-Client'] = getResolvedClient();
19
21
  return config;
20
22
  });
21
23
  }
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextpro
17
17
  import { MemoryClient, getResolvedUserEmail, getResolvedUserId, setResolvedTenantOrgId, setResolvedUserEmail, setResolvedUserId, getResolvedTenantOrgId, } from "./client/memory-client.js";
18
18
  import { AgentClient } from "./client/agent-client.js";
19
19
  import { CpClient } from "./client/cp-client.js";
20
+ import { getResolvedClient, setResolvedClient } from "./client/client-info.js";
20
21
  import { InteractionCapture } from "./capture/interaction-capture.js";
21
22
  import { TOOLS } from "./tools/definitions.js";
22
23
  import { dispatchTool } from "./tools/handlers.js";
@@ -95,6 +96,17 @@ async function main() {
95
96
  }
96
97
  return toolResult;
97
98
  });
99
+ // Resolve the connecting MCP client's identity for the X-Client header.
100
+ // `getClientVersion()` is only populated after the `initialize` handshake,
101
+ // so we read it from the `oninitialized` callback (fired on the client's
102
+ // `notifications/initialized`), not right after `connect()`.
103
+ server.oninitialized = () => {
104
+ const rawName = server.getClientVersion()?.name;
105
+ setResolvedClient(rawName);
106
+ // Logged once for calibration against real clients (stderr, not stdout —
107
+ // stdout is the MCP transport).
108
+ console.error(`[Client] clientInfo.name=${JSON.stringify(rawName ?? null)} normalized=${getResolvedClient()}`);
109
+ };
98
110
  // Start server
99
111
  const transport = new StdioServerTransport();
100
112
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frinus-mcp",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "Frinus - MCP Server for Cognitive Memory (φρήν + νοῦς). Long-term memory, sessions, agents and knowledge for Claude and any MCP client.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",