@frontmcp/plugin-remember 1.8.2 → 1.8.4
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/esm/index.mjs +45 -16
- package/esm/package.json +4 -4
- package/index.js +43 -16
- package/package.json +4 -4
- package/providers/remember-accessor.provider.d.ts +29 -7
- package/providers/remember-accessor.provider.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
|
|
32
32
|
// plugins/plugin-remember/src/providers/remember-accessor.provider.ts
|
|
33
33
|
import {
|
|
34
|
+
getRunningTool,
|
|
35
|
+
isAnonymousSubject,
|
|
34
36
|
Provider,
|
|
35
37
|
ProviderScope,
|
|
36
38
|
STATELESS_SESSION_ID
|
|
@@ -535,6 +537,9 @@ var RememberAccessor = class {
|
|
|
535
537
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
536
538
|
/**
|
|
537
539
|
* Get the session ID from context.
|
|
540
|
+
*
|
|
541
|
+
* This is the id the request carries, which under MCP 2026-07-28 the client chooses; it is not
|
|
542
|
+
* proof of identity. Session and tool memory are namespaced by the verified session instead.
|
|
538
543
|
*/
|
|
539
544
|
get sessionId() {
|
|
540
545
|
return this.ctx.sessionId;
|
|
@@ -556,28 +561,54 @@ var RememberAccessor = class {
|
|
|
556
561
|
return this.buildScopePrefix(scope) + key;
|
|
557
562
|
}
|
|
558
563
|
/**
|
|
559
|
-
* The
|
|
560
|
-
* (GHSA-225p-f8jh-f3rh).
|
|
564
|
+
* The session id the server verified for this request, or undefined when there is none.
|
|
561
565
|
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
566
|
+
* Read from the verified auth info (`authInfo.sessionId` from the transport, `extra.sessionId`
|
|
567
|
+
* from session verification, which records only a session the request presented), the same rule
|
|
568
|
+
* CONTEXT providers are cached by. Never `FrontMcpContext.sessionId` alone: under MCP 2026-07-28
|
|
569
|
+
* that is whatever `mcp-session-id` the caller sent, including another caller's. The stateless
|
|
570
|
+
* transport's shared `__stateless__` id identifies no one.
|
|
571
|
+
*/
|
|
572
|
+
get verifiedSessionId() {
|
|
573
|
+
const authInfo = this.ctx.authInfo;
|
|
574
|
+
return [authInfo?.sessionId, authInfo?.extra?.["sessionId"]].find(
|
|
575
|
+
(candidate) => typeof candidate === "string" && candidate.length > 0 && candidate !== STATELESS_SESSION_ID
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* The identity that namespaces session- and tool-scoped storage.
|
|
580
|
+
*
|
|
581
|
+
* Only a session the server verified identifies one client across requests. Keying on the
|
|
582
|
+
* session id a request merely carries let a caller read or overwrite another caller's memory by
|
|
583
|
+
* sending that caller's `mcp-session-id` (MCP 2026-07-28), and put every stateless client under
|
|
584
|
+
* the shared `__stateless__` id (GHSA-225p-f8jh-f3rh). A request without a verified session
|
|
585
|
+
* (stateless transport, MCP 2026-07-28, or a session id the server did not verify) falls back to
|
|
586
|
+
* the authenticated principal, the only per-client identity it has; with neither, it has no
|
|
587
|
+
* business reading or writing per-client memory at all. An anonymous subject (`anon:…`) is no
|
|
588
|
+
* principal: without a session, the server makes a new one up for each request.
|
|
567
589
|
*/
|
|
568
590
|
resolveSessionIdentity() {
|
|
569
|
-
const sessionId = this.
|
|
570
|
-
if (sessionId
|
|
591
|
+
const sessionId = this.verifiedSessionId;
|
|
592
|
+
if (sessionId) {
|
|
571
593
|
return sessionId;
|
|
572
594
|
}
|
|
573
595
|
const userId = this.userId;
|
|
574
|
-
if (userId) {
|
|
596
|
+
if (userId && !isAnonymousSubject(userId)) {
|
|
575
597
|
return `stateless-user:${userId}`;
|
|
576
598
|
}
|
|
577
599
|
throw new RememberIdentityError(
|
|
578
|
-
`Remember cannot use session or tool scope for an unauthenticated
|
|
600
|
+
`Remember cannot use session or tool scope for an unauthenticated request without a verified session: a stateless request shares the session id "${STATELESS_SESSION_ID}", and an mcp-session-id the server did not verify could belong to any caller, so the data would be shared across clients. Authenticate the request, use a stateful transport, or choose the 'global' scope if the data really is shared.`
|
|
579
601
|
);
|
|
580
602
|
}
|
|
603
|
+
/**
|
|
604
|
+
* The tool that tool-scoped memory belongs to: the tool whose `execute()` is running (its
|
|
605
|
+
* owner-qualified name). Read when the memory is used, not when this accessor was built (it can
|
|
606
|
+
* serve several calls), so a tool that calls other tools still gets its own. Outside a tool,
|
|
607
|
+
* `'unknown'`.
|
|
608
|
+
*/
|
|
609
|
+
get toolName() {
|
|
610
|
+
return getRunningTool()?.fullName ?? this.ctx.flow?.name ?? "unknown";
|
|
611
|
+
}
|
|
581
612
|
/**
|
|
582
613
|
* Build the scope-specific prefix.
|
|
583
614
|
*
|
|
@@ -599,10 +630,8 @@ var RememberAccessor = class {
|
|
|
599
630
|
}
|
|
600
631
|
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:user:${encodeKeyPart(userId)}:`;
|
|
601
632
|
}
|
|
602
|
-
case "tool":
|
|
603
|
-
|
|
604
|
-
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:tool:${encodeKeyPart(toolName)}:${encodeKeyPart(this.resolveSessionIdentity())}:`;
|
|
605
|
-
}
|
|
633
|
+
case "tool":
|
|
634
|
+
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:tool:${encodeKeyPart(this.toolName)}:${encodeKeyPart(this.resolveSessionIdentity())}:`;
|
|
606
635
|
case "global":
|
|
607
636
|
return `${this.keyPrefix}global:`;
|
|
608
637
|
}
|
|
@@ -615,7 +644,7 @@ var RememberAccessor = class {
|
|
|
615
644
|
return getKeySourceForScope(scope, {
|
|
616
645
|
sessionId: needsSessionIdentity ? this.resolveSessionIdentity() : this.ctx.sessionId,
|
|
617
646
|
userId: this.userId,
|
|
618
|
-
toolName: this.
|
|
647
|
+
toolName: scope === "tool" ? this.toolName : void 0
|
|
619
648
|
});
|
|
620
649
|
}
|
|
621
650
|
/**
|
package/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-remember",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.4",
|
|
4
4
|
"description": "Remember plugin for FrontMCP - encrypted session memory with approval system for secure tool authorization",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@frontmcp/sdk": "1.8.
|
|
53
|
-
"@frontmcp/utils": "1.8.
|
|
52
|
+
"@frontmcp/sdk": "1.8.4",
|
|
53
|
+
"@frontmcp/utils": "1.8.4",
|
|
54
54
|
"ioredis": "^5.8.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.8.4",
|
|
58
58
|
"@vercel/kv": "^2.0.0 || ^3.0.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
package/index.js
CHANGED
|
@@ -558,6 +558,9 @@ var RememberAccessor = class {
|
|
|
558
558
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
559
559
|
/**
|
|
560
560
|
* Get the session ID from context.
|
|
561
|
+
*
|
|
562
|
+
* This is the id the request carries, which under MCP 2026-07-28 the client chooses; it is not
|
|
563
|
+
* proof of identity. Session and tool memory are namespaced by the verified session instead.
|
|
561
564
|
*/
|
|
562
565
|
get sessionId() {
|
|
563
566
|
return this.ctx.sessionId;
|
|
@@ -579,28 +582,54 @@ var RememberAccessor = class {
|
|
|
579
582
|
return this.buildScopePrefix(scope) + key;
|
|
580
583
|
}
|
|
581
584
|
/**
|
|
582
|
-
* The
|
|
583
|
-
* (GHSA-225p-f8jh-f3rh).
|
|
585
|
+
* The session id the server verified for this request, or undefined when there is none.
|
|
584
586
|
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
587
|
+
* Read from the verified auth info (`authInfo.sessionId` from the transport, `extra.sessionId`
|
|
588
|
+
* from session verification, which records only a session the request presented), the same rule
|
|
589
|
+
* CONTEXT providers are cached by. Never `FrontMcpContext.sessionId` alone: under MCP 2026-07-28
|
|
590
|
+
* that is whatever `mcp-session-id` the caller sent, including another caller's. The stateless
|
|
591
|
+
* transport's shared `__stateless__` id identifies no one.
|
|
592
|
+
*/
|
|
593
|
+
get verifiedSessionId() {
|
|
594
|
+
const authInfo = this.ctx.authInfo;
|
|
595
|
+
return [authInfo?.sessionId, authInfo?.extra?.["sessionId"]].find(
|
|
596
|
+
(candidate) => typeof candidate === "string" && candidate.length > 0 && candidate !== import_sdk.STATELESS_SESSION_ID
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* The identity that namespaces session- and tool-scoped storage.
|
|
601
|
+
*
|
|
602
|
+
* Only a session the server verified identifies one client across requests. Keying on the
|
|
603
|
+
* session id a request merely carries let a caller read or overwrite another caller's memory by
|
|
604
|
+
* sending that caller's `mcp-session-id` (MCP 2026-07-28), and put every stateless client under
|
|
605
|
+
* the shared `__stateless__` id (GHSA-225p-f8jh-f3rh). A request without a verified session
|
|
606
|
+
* (stateless transport, MCP 2026-07-28, or a session id the server did not verify) falls back to
|
|
607
|
+
* the authenticated principal, the only per-client identity it has; with neither, it has no
|
|
608
|
+
* business reading or writing per-client memory at all. An anonymous subject (`anon:…`) is no
|
|
609
|
+
* principal: without a session, the server makes a new one up for each request.
|
|
590
610
|
*/
|
|
591
611
|
resolveSessionIdentity() {
|
|
592
|
-
const sessionId = this.
|
|
593
|
-
if (sessionId
|
|
612
|
+
const sessionId = this.verifiedSessionId;
|
|
613
|
+
if (sessionId) {
|
|
594
614
|
return sessionId;
|
|
595
615
|
}
|
|
596
616
|
const userId = this.userId;
|
|
597
|
-
if (userId) {
|
|
617
|
+
if (userId && !(0, import_sdk.isAnonymousSubject)(userId)) {
|
|
598
618
|
return `stateless-user:${userId}`;
|
|
599
619
|
}
|
|
600
620
|
throw new RememberIdentityError(
|
|
601
|
-
`Remember cannot use session or tool scope for an unauthenticated
|
|
621
|
+
`Remember cannot use session or tool scope for an unauthenticated request without a verified session: a stateless request shares the session id "${import_sdk.STATELESS_SESSION_ID}", and an mcp-session-id the server did not verify could belong to any caller, so the data would be shared across clients. Authenticate the request, use a stateful transport, or choose the 'global' scope if the data really is shared.`
|
|
602
622
|
);
|
|
603
623
|
}
|
|
624
|
+
/**
|
|
625
|
+
* The tool that tool-scoped memory belongs to: the tool whose `execute()` is running (its
|
|
626
|
+
* owner-qualified name). Read when the memory is used, not when this accessor was built (it can
|
|
627
|
+
* serve several calls), so a tool that calls other tools still gets its own. Outside a tool,
|
|
628
|
+
* `'unknown'`.
|
|
629
|
+
*/
|
|
630
|
+
get toolName() {
|
|
631
|
+
return (0, import_sdk.getRunningTool)()?.fullName ?? this.ctx.flow?.name ?? "unknown";
|
|
632
|
+
}
|
|
604
633
|
/**
|
|
605
634
|
* Build the scope-specific prefix.
|
|
606
635
|
*
|
|
@@ -622,10 +651,8 @@ var RememberAccessor = class {
|
|
|
622
651
|
}
|
|
623
652
|
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:user:${encodeKeyPart(userId)}:`;
|
|
624
653
|
}
|
|
625
|
-
case "tool":
|
|
626
|
-
|
|
627
|
-
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:tool:${encodeKeyPart(toolName)}:${encodeKeyPart(this.resolveSessionIdentity())}:`;
|
|
628
|
-
}
|
|
654
|
+
case "tool":
|
|
655
|
+
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:tool:${encodeKeyPart(this.toolName)}:${encodeKeyPart(this.resolveSessionIdentity())}:`;
|
|
629
656
|
case "global":
|
|
630
657
|
return `${this.keyPrefix}global:`;
|
|
631
658
|
}
|
|
@@ -638,7 +665,7 @@ var RememberAccessor = class {
|
|
|
638
665
|
return getKeySourceForScope(scope, {
|
|
639
666
|
sessionId: needsSessionIdentity ? this.resolveSessionIdentity() : this.ctx.sessionId,
|
|
640
667
|
userId: this.userId,
|
|
641
|
-
toolName: this.
|
|
668
|
+
toolName: scope === "tool" ? this.toolName : void 0
|
|
642
669
|
});
|
|
643
670
|
}
|
|
644
671
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-remember",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.4",
|
|
4
4
|
"description": "Remember plugin for FrontMCP - encrypted session memory with approval system for secure tool authorization",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@frontmcp/sdk": "1.8.
|
|
53
|
-
"@frontmcp/utils": "1.8.
|
|
52
|
+
"@frontmcp/sdk": "1.8.4",
|
|
53
|
+
"@frontmcp/utils": "1.8.4",
|
|
54
54
|
"ioredis": "^5.8.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.8.4",
|
|
58
58
|
"@vercel/kv": "^2.0.0 || ^3.0.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
|
@@ -93,6 +93,9 @@ export declare class RememberAccessor {
|
|
|
93
93
|
}): Promise<boolean>;
|
|
94
94
|
/**
|
|
95
95
|
* Get the session ID from context.
|
|
96
|
+
*
|
|
97
|
+
* This is the id the request carries, which under MCP 2026-07-28 the client chooses; it is not
|
|
98
|
+
* proof of identity. Session and tool memory are namespaced by the verified session instead.
|
|
96
99
|
*/
|
|
97
100
|
get sessionId(): string;
|
|
98
101
|
/**
|
|
@@ -104,16 +107,35 @@ export declare class RememberAccessor {
|
|
|
104
107
|
*/
|
|
105
108
|
private buildStorageKey;
|
|
106
109
|
/**
|
|
107
|
-
* The
|
|
108
|
-
*
|
|
110
|
+
* The session id the server verified for this request, or undefined when there is none.
|
|
111
|
+
*
|
|
112
|
+
* Read from the verified auth info (`authInfo.sessionId` from the transport, `extra.sessionId`
|
|
113
|
+
* from session verification, which records only a session the request presented), the same rule
|
|
114
|
+
* CONTEXT providers are cached by. Never `FrontMcpContext.sessionId` alone: under MCP 2026-07-28
|
|
115
|
+
* that is whatever `mcp-session-id` the caller sent, including another caller's. The stateless
|
|
116
|
+
* transport's shared `__stateless__` id identifies no one.
|
|
117
|
+
*/
|
|
118
|
+
private get verifiedSessionId();
|
|
119
|
+
/**
|
|
120
|
+
* The identity that namespaces session- and tool-scoped storage.
|
|
109
121
|
*
|
|
110
|
-
*
|
|
111
|
-
* request
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
122
|
+
* Only a session the server verified identifies one client across requests. Keying on the
|
|
123
|
+
* session id a request merely carries let a caller read or overwrite another caller's memory by
|
|
124
|
+
* sending that caller's `mcp-session-id` (MCP 2026-07-28), and put every stateless client under
|
|
125
|
+
* the shared `__stateless__` id (GHSA-225p-f8jh-f3rh). A request without a verified session
|
|
126
|
+
* (stateless transport, MCP 2026-07-28, or a session id the server did not verify) falls back to
|
|
127
|
+
* the authenticated principal, the only per-client identity it has; with neither, it has no
|
|
128
|
+
* business reading or writing per-client memory at all. An anonymous subject (`anon:…`) is no
|
|
129
|
+
* principal: without a session, the server makes a new one up for each request.
|
|
115
130
|
*/
|
|
116
131
|
private resolveSessionIdentity;
|
|
132
|
+
/**
|
|
133
|
+
* The tool that tool-scoped memory belongs to: the tool whose `execute()` is running (its
|
|
134
|
+
* owner-qualified name). Read when the memory is used, not when this accessor was built (it can
|
|
135
|
+
* serve several calls), so a tool that calls other tools still gets its own. Outside a tool,
|
|
136
|
+
* `'unknown'`.
|
|
137
|
+
*/
|
|
138
|
+
private get toolName();
|
|
117
139
|
/**
|
|
118
140
|
* Build the scope-specific prefix.
|
|
119
141
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remember-accessor.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-accessor.provider.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"remember-accessor.provider.d.ts","sourceRoot":"","sources":["../../src/providers/remember-accessor.provider.ts"],"names":[],"mappings":"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"}
|