@frontmcp/plugin-remember 1.8.2 → 1.8.3
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 +42 -15
- package/esm/package.json +4 -4
- package/index.js +41 -15
- package/package.json +4 -4
- package/providers/remember-accessor.provider.d.ts +28 -7
- package/providers/remember-accessor.provider.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
|
|
32
32
|
// plugins/plugin-remember/src/providers/remember-accessor.provider.ts
|
|
33
33
|
import {
|
|
34
|
+
getRunningTool,
|
|
34
35
|
Provider,
|
|
35
36
|
ProviderScope,
|
|
36
37
|
STATELESS_SESSION_ID
|
|
@@ -535,6 +536,9 @@ var RememberAccessor = class {
|
|
|
535
536
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
536
537
|
/**
|
|
537
538
|
* Get the session ID from context.
|
|
539
|
+
*
|
|
540
|
+
* This is the id the request carries, which under MCP 2026-07-28 the client chooses; it is not
|
|
541
|
+
* proof of identity. Session and tool memory are namespaced by the verified session instead.
|
|
538
542
|
*/
|
|
539
543
|
get sessionId() {
|
|
540
544
|
return this.ctx.sessionId;
|
|
@@ -556,18 +560,34 @@ var RememberAccessor = class {
|
|
|
556
560
|
return this.buildScopePrefix(scope) + key;
|
|
557
561
|
}
|
|
558
562
|
/**
|
|
559
|
-
* The
|
|
560
|
-
* (GHSA-225p-f8jh-f3rh).
|
|
563
|
+
* The session id the server verified for this request, or undefined when there is none.
|
|
561
564
|
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
565
|
+
* Read from the verified auth info (`authInfo.sessionId` from the transport, `extra.sessionId`
|
|
566
|
+
* from session verification), the same rule CONTEXT providers are cached by. Never
|
|
567
|
+
* `FrontMcpContext.sessionId` alone: under MCP 2026-07-28 that is whatever `mcp-session-id` the
|
|
568
|
+
* caller sent, including another caller's. The stateless transport's shared `__stateless__` id
|
|
569
|
+
* identifies no one.
|
|
570
|
+
*/
|
|
571
|
+
get verifiedSessionId() {
|
|
572
|
+
const authInfo = this.ctx.authInfo;
|
|
573
|
+
return [authInfo?.sessionId, authInfo?.extra?.["sessionId"]].find(
|
|
574
|
+
(candidate) => typeof candidate === "string" && candidate.length > 0 && candidate !== STATELESS_SESSION_ID
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* The identity that namespaces session- and tool-scoped storage.
|
|
579
|
+
*
|
|
580
|
+
* Only a session the server verified identifies one client across requests. Keying on the
|
|
581
|
+
* session id a request merely carries let a caller read or overwrite another caller's memory by
|
|
582
|
+
* sending that caller's `mcp-session-id` (MCP 2026-07-28), and put every stateless client under
|
|
583
|
+
* the shared `__stateless__` id (GHSA-225p-f8jh-f3rh). A request without a verified session
|
|
584
|
+
* (stateless transport, MCP 2026-07-28, or a session id the server did not verify) falls back to
|
|
585
|
+
* the authenticated principal, the only per-client identity it has; with neither, it has no
|
|
586
|
+
* business reading or writing per-client memory at all.
|
|
567
587
|
*/
|
|
568
588
|
resolveSessionIdentity() {
|
|
569
|
-
const sessionId = this.
|
|
570
|
-
if (sessionId
|
|
589
|
+
const sessionId = this.verifiedSessionId;
|
|
590
|
+
if (sessionId) {
|
|
571
591
|
return sessionId;
|
|
572
592
|
}
|
|
573
593
|
const userId = this.userId;
|
|
@@ -575,9 +595,18 @@ var RememberAccessor = class {
|
|
|
575
595
|
return `stateless-user:${userId}`;
|
|
576
596
|
}
|
|
577
597
|
throw new RememberIdentityError(
|
|
578
|
-
`Remember cannot use session or tool scope for an unauthenticated
|
|
598
|
+
`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
599
|
);
|
|
580
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* The tool that tool-scoped memory belongs to: the tool whose `execute()` is running (its
|
|
603
|
+
* owner-qualified name). Read when the memory is used, not when this accessor was built (it can
|
|
604
|
+
* serve several calls), so a tool that calls other tools still gets its own. Outside a tool,
|
|
605
|
+
* `'unknown'`.
|
|
606
|
+
*/
|
|
607
|
+
get toolName() {
|
|
608
|
+
return getRunningTool()?.fullName ?? this.ctx.flow?.name ?? "unknown";
|
|
609
|
+
}
|
|
581
610
|
/**
|
|
582
611
|
* Build the scope-specific prefix.
|
|
583
612
|
*
|
|
@@ -599,10 +628,8 @@ var RememberAccessor = class {
|
|
|
599
628
|
}
|
|
600
629
|
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:user:${encodeKeyPart(userId)}:`;
|
|
601
630
|
}
|
|
602
|
-
case "tool":
|
|
603
|
-
|
|
604
|
-
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:tool:${encodeKeyPart(toolName)}:${encodeKeyPart(this.resolveSessionIdentity())}:`;
|
|
605
|
-
}
|
|
631
|
+
case "tool":
|
|
632
|
+
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:tool:${encodeKeyPart(this.toolName)}:${encodeKeyPart(this.resolveSessionIdentity())}:`;
|
|
606
633
|
case "global":
|
|
607
634
|
return `${this.keyPrefix}global:`;
|
|
608
635
|
}
|
|
@@ -615,7 +642,7 @@ var RememberAccessor = class {
|
|
|
615
642
|
return getKeySourceForScope(scope, {
|
|
616
643
|
sessionId: needsSessionIdentity ? this.resolveSessionIdentity() : this.ctx.sessionId,
|
|
617
644
|
userId: this.userId,
|
|
618
|
-
toolName: this.
|
|
645
|
+
toolName: scope === "tool" ? this.toolName : void 0
|
|
619
646
|
});
|
|
620
647
|
}
|
|
621
648
|
/**
|
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.3",
|
|
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.3",
|
|
53
|
+
"@frontmcp/utils": "1.8.3",
|
|
54
54
|
"ioredis": "^5.8.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.8.3",
|
|
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,18 +582,34 @@ 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), the same rule CONTEXT providers are cached by. Never
|
|
589
|
+
* `FrontMcpContext.sessionId` alone: under MCP 2026-07-28 that is whatever `mcp-session-id` the
|
|
590
|
+
* caller sent, including another caller's. The stateless transport's shared `__stateless__` id
|
|
591
|
+
* 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.
|
|
590
609
|
*/
|
|
591
610
|
resolveSessionIdentity() {
|
|
592
|
-
const sessionId = this.
|
|
593
|
-
if (sessionId
|
|
611
|
+
const sessionId = this.verifiedSessionId;
|
|
612
|
+
if (sessionId) {
|
|
594
613
|
return sessionId;
|
|
595
614
|
}
|
|
596
615
|
const userId = this.userId;
|
|
@@ -598,9 +617,18 @@ var RememberAccessor = class {
|
|
|
598
617
|
return `stateless-user:${userId}`;
|
|
599
618
|
}
|
|
600
619
|
throw new RememberIdentityError(
|
|
601
|
-
`Remember cannot use session or tool scope for an unauthenticated
|
|
620
|
+
`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
621
|
);
|
|
603
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* The tool that tool-scoped memory belongs to: the tool whose `execute()` is running (its
|
|
625
|
+
* owner-qualified name). Read when the memory is used, not when this accessor was built (it can
|
|
626
|
+
* serve several calls), so a tool that calls other tools still gets its own. Outside a tool,
|
|
627
|
+
* `'unknown'`.
|
|
628
|
+
*/
|
|
629
|
+
get toolName() {
|
|
630
|
+
return (0, import_sdk.getRunningTool)()?.fullName ?? this.ctx.flow?.name ?? "unknown";
|
|
631
|
+
}
|
|
604
632
|
/**
|
|
605
633
|
* Build the scope-specific prefix.
|
|
606
634
|
*
|
|
@@ -622,10 +650,8 @@ var RememberAccessor = class {
|
|
|
622
650
|
}
|
|
623
651
|
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:user:${encodeKeyPart(userId)}:`;
|
|
624
652
|
}
|
|
625
|
-
case "tool":
|
|
626
|
-
|
|
627
|
-
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:tool:${encodeKeyPart(toolName)}:${encodeKeyPart(this.resolveSessionIdentity())}:`;
|
|
628
|
-
}
|
|
653
|
+
case "tool":
|
|
654
|
+
return `${this.keyPrefix}${STORAGE_LAYOUT_VERSION}:tool:${encodeKeyPart(this.toolName)}:${encodeKeyPart(this.resolveSessionIdentity())}:`;
|
|
629
655
|
case "global":
|
|
630
656
|
return `${this.keyPrefix}global:`;
|
|
631
657
|
}
|
|
@@ -638,7 +664,7 @@ var RememberAccessor = class {
|
|
|
638
664
|
return getKeySourceForScope(scope, {
|
|
639
665
|
sessionId: needsSessionIdentity ? this.resolveSessionIdentity() : this.ctx.sessionId,
|
|
640
666
|
userId: this.userId,
|
|
641
|
-
toolName: this.
|
|
667
|
+
toolName: scope === "tool" ? this.toolName : void 0
|
|
642
668
|
});
|
|
643
669
|
}
|
|
644
670
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/plugin-remember",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
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.3",
|
|
53
|
+
"@frontmcp/utils": "1.8.3",
|
|
54
54
|
"ioredis": "^5.8.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@frontmcp/lazy-zod": "1.8.
|
|
57
|
+
"@frontmcp/lazy-zod": "1.8.3",
|
|
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,34 @@ 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), the same rule CONTEXT providers are cached by. Never
|
|
114
|
+
* `FrontMcpContext.sessionId` alone: under MCP 2026-07-28 that is whatever `mcp-session-id` the
|
|
115
|
+
* caller sent, including another caller's. The stateless transport's shared `__stateless__` id
|
|
116
|
+
* 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.
|
|
115
129
|
*/
|
|
116
130
|
private resolveSessionIdentity;
|
|
131
|
+
/**
|
|
132
|
+
* The tool that tool-scoped memory belongs to: the tool whose `execute()` is running (its
|
|
133
|
+
* owner-qualified name). Read when the memory is used, not when this accessor was built (it can
|
|
134
|
+
* serve several calls), so a tool that calls other tools still gets its own. Outside a tool,
|
|
135
|
+
* `'unknown'`.
|
|
136
|
+
*/
|
|
137
|
+
private get toolName();
|
|
117
138
|
/**
|
|
118
139
|
* Build the scope-specific prefix.
|
|
119
140
|
*
|
|
@@ -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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"}
|