@softure-ai/mcp-access 0.2.4 → 0.2.6
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/CHANGELOG.md +25 -0
- package/README.md +50 -1
- package/dist/index.js +1 -1
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +3 -2
- package/dist/next/index.js.map +1 -1
- package/dist/next/pages.d.ts.map +1 -1
- package/dist/next/pages.js +5 -56
- package/dist/next/pages.js.map +1 -1
- package/dist/next/token-manager-props.d.ts +18 -0
- package/dist/next/token-manager-props.d.ts.map +1 -0
- package/dist/next/token-manager-props.js +74 -0
- package/dist/next/token-manager-props.js.map +1 -0
- package/dist/server/action-tool.d.ts +6 -2
- package/dist/server/action-tool.d.ts.map +1 -1
- package/dist/server/action-tool.js +10 -3
- package/dist/server/action-tool.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/tokens.d.ts +5 -0
- package/dist/server/tokens.d.ts.map +1 -1
- package/dist/server/tokens.js +10 -0
- package/dist/server/tokens.js.map +1 -1
- package/dist/server/tools.d.ts +40 -1
- package/dist/server/tools.d.ts.map +1 -1
- package/dist/server/tools.js +41 -3
- package/dist/server/tools.js.map +1 -1
- package/dist/ui/token-manager.d.ts.map +1 -1
- package/dist/ui/token-manager.js +18 -3
- package/dist/ui/token-manager.js.map +1 -1
- package/module.json +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/next/index.ts +3 -2
- package/src/next/pages.tsx +7 -68
- package/src/next/token-manager-props.ts +92 -0
- package/src/server/action-tool.ts +15 -4
- package/src/server/index.ts +12 -1
- package/src/server/tokens.ts +10 -0
- package/src/server/tools.ts +78 -5
- package/src/ui/token-manager.tsx +21 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAA8C,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAElG,4IAA4I;AAC5I,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,+GAA+G;IAC/G,QAAQ,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC;IACnC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnD;AAED,mHAAmH;AACnH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACjE;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAA;CAAE,CAAC;AAErE,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC;AAQ/D,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAEzD;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAEzD;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,OAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAcjH;AA8BD,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,GAAE,cAAmB,GAAG,cAAc,CAItF;AAUD,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAExE"}
|
package/dist/server/tools.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Tool results for the app's MCP server and the boundary that keeps failures safe: the assistant gets
|
|
2
2
|
// a value, a `PublicError`'s message or a hint, never a thrown error's text (a failed query carries
|
|
3
|
-
// its SQL and parameters). The log gets the error's kind only (`errorLogLabel`).
|
|
3
|
+
// its SQL and parameters). The log gets the error's kind only (`errorLogLabel`). An optional hook sees
|
|
4
|
+
// each call as a whole: which tool, which client, the outcome with its code, and how long it took.
|
|
4
5
|
import { isCallToolResult } from "@modelcontextprotocol/server";
|
|
5
6
|
import { errorLogLabel, getPublicMessage, safeError } from "@softure-ai/core";
|
|
6
7
|
/** For failures the tool did not expect: what `safeError` makes of them, unless a hint replaces it. */
|
|
@@ -23,12 +24,49 @@ export function toolError(message) {
|
|
|
23
24
|
* anything else is logged by kind and answered with the hint for its `safeError` code, else a fixed text.
|
|
24
25
|
*/
|
|
25
26
|
export async function withToolErrors(work, options = {}) {
|
|
27
|
+
const startedAt = Date.now();
|
|
28
|
+
let answer;
|
|
29
|
+
let outcome;
|
|
26
30
|
try {
|
|
27
|
-
|
|
31
|
+
const value = await work();
|
|
32
|
+
answer = answerValue(value, options.hints);
|
|
33
|
+
outcome = describeValueOutcome(value);
|
|
28
34
|
}
|
|
29
35
|
catch (error) {
|
|
30
|
-
|
|
36
|
+
answer = answerFailure(error, options);
|
|
37
|
+
outcome = { kind: "thrown", code: getPublicMessage(error) === null ? safeError(error).error : null };
|
|
31
38
|
}
|
|
39
|
+
if (options.onToolCall !== undefined)
|
|
40
|
+
await reportToolCall(options, outcome, startedAt);
|
|
41
|
+
return answer;
|
|
42
|
+
}
|
|
43
|
+
async function reportToolCall(options, outcome, startedAt) {
|
|
44
|
+
const tool = options.label ?? "call";
|
|
45
|
+
const record = {
|
|
46
|
+
tool,
|
|
47
|
+
tokenId: options.caller?.tokenId ?? null,
|
|
48
|
+
clientName: options.caller?.clientName ?? null,
|
|
49
|
+
argumentNames: Object.keys(options.args ?? {}),
|
|
50
|
+
outcome,
|
|
51
|
+
startedAt: new Date(startedAt),
|
|
52
|
+
durationMs: Date.now() - startedAt,
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
await options.onToolCall?.(record);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
console.error(`@softure-ai/mcp-access: the onToolCall hook failed for tool ${tool}: ${errorLogLabel(error)}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function describeValueOutcome(value) {
|
|
62
|
+
if (isCallToolResult(value))
|
|
63
|
+
return value.isError === true ? { kind: "failed", code: null } : { kind: "succeeded", itemCount: null };
|
|
64
|
+
if (isResult(value))
|
|
65
|
+
return value.ok ? countItems(value.value) : { kind: "failed", code: value.error };
|
|
66
|
+
return countItems(value);
|
|
67
|
+
}
|
|
68
|
+
function countItems(value) {
|
|
69
|
+
return { kind: "succeeded", itemCount: Array.isArray(value) ? value.length : null };
|
|
32
70
|
}
|
|
33
71
|
/** The answer for a value a tool or an action returned. */
|
|
34
72
|
export function answerValue(value, hints = {}) {
|
package/dist/server/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,oGAAoG;AACpG,
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,oGAAoG;AACpG,uGAAuG;AACvG,mGAAmG;AACnG,OAAO,EAAE,gBAAgB,EAAuB,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,SAAS,EAAsB,MAAM,kBAAkB,CAAC;AAgDlG,uGAAuG;AACvG,MAAM,oBAAoB,GAAmB;IAC3C,sBAAsB,EAAE,iDAAiD;IACzE,iBAAiB,EAAE,mCAAmC;CACvD,CAAC;AAEF,8EAA8E;AAC9E,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,CAAC;AACpH,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAmB,EAAE,UAA4B,EAAE;IACtF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,MAAsB,CAAC;IAC3B,IAAI,OAAwB,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,IAAI,EAAE,CAAC;QAC3B,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAC3C,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACvC,OAAO,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,gBAAgB,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACvG,CAAC;IACD,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;QAAE,MAAM,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACxF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,OAAyB,EAAE,OAAwB,EAAE,SAAiB;IAClG,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC;IACrC,MAAM,MAAM,GAAmB;QAC7B,IAAI;QACJ,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;QACxC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,UAAU,IAAI,IAAI;QAC9C,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QAC9C,OAAO;QACP,SAAS,EAAE,IAAI,IAAI,CAAC,SAAS,CAAC;QAC9B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;KACnC,CAAC;IACF,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,+DAA+D,IAAI,KAAK,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChH,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,IAAI,gBAAgB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACrI,IAAI,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IACvG,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACtF,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,KAAc,EAAE,QAAwB,EAAE;IACpE,IAAI,gBAAgB,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7G,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,OAAyB;IAC9D,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC,aAAa,CAAC,CAAC;IAC5D,OAAO,CAAC,KAAK,CAAC,gCAAgC,OAAO,CAAC,KAAK,IAAI,MAAM,YAAY,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzG,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;IACpC,OAAO,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;AAChF,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,KAAqB;IAC9D,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACnE,CAAC;AAED,+FAA+F;AAC/F,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAClF,IAAI,KAAK,CAAC,EAAE,KAAK,IAAI;QAAE,OAAO,OAAO,IAAI,KAAK,CAAC;IAC/C,OAAO,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,OAAO,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC;AACnF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/ui/token-manager.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAgC,KAAK,UAAU,EAA+C,MAAM,gBAAgB,CAAC;AAE5H,OAAO,KAAK,EAAe,mBAAmB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACnH,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/ui/token-manager.tsx"],"names":[],"mappings":"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"}
|
package/dist/ui/token-manager.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { formatMessage } from "@softure-ai/core";
|
|
4
4
|
import { Button, ButtonLink, Checkbox, createSlotClassGetter, FormError, TextField } from "@softure-ai/ui";
|
|
5
|
-
import { useActionState, useState } from "react";
|
|
5
|
+
import { useActionState, useEffect, useRef, useState } from "react";
|
|
6
6
|
import { getTokenErrorMessage } from "../messages/index.js";
|
|
7
7
|
import { MAX_TOKEN_NAME_LENGTH } from "../options.js";
|
|
8
8
|
const DEFAULT_CLASSES = {
|
|
@@ -30,14 +30,29 @@ function Snippet({ title, value, messages, slot, unstyled }) {
|
|
|
30
30
|
}
|
|
31
31
|
function IssuedTokenPanel({ issued, onDone, messages, slot, unstyled, }) {
|
|
32
32
|
const snippet = (title, value) => _jsx(Snippet, { title: title, value: value, messages: messages, slot: slot, unstyled: unstyled });
|
|
33
|
-
|
|
33
|
+
const headingRef = useRef(null);
|
|
34
|
+
// Once per issued token, so a screen reader announces it; not on re-renders while the owner copies.
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
headingRef.current?.focus();
|
|
37
|
+
}, [issued.id]);
|
|
38
|
+
return (_jsxs("section", { className: slot("section"), children: [_jsx("h3", { ref: headingRef, tabIndex: -1, className: slot("heading"), children: formatMessage(messages.issued.title, { name: issued.name }) }), _jsx("p", { className: slot("text"), children: messages.issued.once }), _jsxs("p", { className: slot("text"), children: [issued.expiresText, " ", issued.canWrite ? messages.issued.readWrite : messages.issued.readOnly] }), snippet(messages.issued.promptTitle, issued.setup.assistantPrompt), _jsx("p", { className: slot("text"), children: messages.issued.promptHint }), _jsx(ButtonLink, { href: issued.setup.claudeCodeLink, variant: "secondary", size: "sm", unstyled: unstyled, children: messages.issued.openClaudeCode }), snippet(messages.issued.commandTitle, issued.setup.claudeCodeCommand), snippet(messages.issued.jsonTitle, issued.setup.jsonConfig), snippet(messages.issued.desktopTitle, issued.setup.desktopConfig), snippet(messages.issued.headerTitle, `${issued.setup.endpointUrl}\nAuthorization: ${issued.setup.authorizationHeader}`), _jsx(Button, { variant: "primary", onClick: onDone, unstyled: unstyled, children: messages.issued.done })] }));
|
|
34
39
|
}
|
|
35
40
|
function IssueForm({ action, allowWrites, maxTokens, messages, locale, slot, unstyled, }) {
|
|
36
41
|
const [state, formAction, isPending] = useActionState(action, { status: "idle" });
|
|
37
42
|
// The id of the issued token the owner dismissed; a new one shows again.
|
|
38
43
|
const [dismissedId, setDismissedId] = useState(null);
|
|
39
44
|
const issued = state.status === "ok" && state.issued.id !== dismissedId ? state.issued : null;
|
|
40
|
-
|
|
45
|
+
const formRef = useRef(null);
|
|
46
|
+
function dismiss(id) {
|
|
47
|
+
setDismissedId(id);
|
|
48
|
+
// The focused "Done" button unmounts with the panel; once it is gone, the name field is the next step.
|
|
49
|
+
requestAnimationFrame(() => {
|
|
50
|
+
const field = formRef.current?.elements.namedItem("name");
|
|
51
|
+
if (field instanceof HTMLInputElement)
|
|
52
|
+
field.focus();
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return (_jsxs(_Fragment, { children: [_jsxs("section", { className: slot("section"), children: [_jsx("h2", { className: slot("heading"), children: messages.issue.title }), _jsxs("form", { ref: formRef, action: formAction, className: slot("list"), children: [_jsx(TextField, { name: "name", label: messages.issue.name, hint: messages.issue.nameHint, maxLength: MAX_TOKEN_NAME_LENGTH, required: true, autoComplete: "off", locale: locale, unstyled: unstyled }), allowWrites ? _jsx(Checkbox, { name: "canWrite", label: messages.issue.canWrite, description: messages.issue.canWriteHint, unstyled: unstyled }) : null, _jsx("p", { className: slot("text"), children: formatMessage(messages.issue.limit, { max: maxTokens }) }), _jsx(FormError, { message: state.status === "error" ? (state.message ?? getTokenErrorMessage(messages, state.error)) : undefined, unstyled: unstyled }), _jsx(Button, { type: "submit", variant: "primary", pending: isPending, unstyled: unstyled, children: isPending ? messages.issue.pending : messages.issue.submit })] })] }), issued === null ? null : _jsx(IssuedTokenPanel, { issued: issued, onDone: () => dismiss(issued.id), messages: messages, slot: slot, unstyled: unstyled })] }));
|
|
41
56
|
}
|
|
42
57
|
function TokenItem({ row, action, messages, slot, unstyled, }) {
|
|
43
58
|
const [state, formAction, isPending] = useActionState(action, { status: "idle" });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/ui/token-manager.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,aAAa,EAAe,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAmB,qBAAqB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC5H,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/ui/token-manager.tsx"],"names":[],"mappings":"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"}
|
package/module.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "mcp-access",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"dependsOn": { "security": "^0.2.0", "auth": "^0.2.0", "jobs": "^0.1.1?", "ops": "^0.2.0?" },
|
|
5
5
|
"dbSchema": "mcp",
|
|
6
6
|
"tables": ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softure-ai/mcp-access",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "SOFTURE AI MCP access module: hashed, scoped, expiring access tokens, a rate-limited Bearer endpoint around the app's MCP server factory, and a token page with client setup instructions for Next.js; tool result helpers with a safe error boundary, a stdio entry, a catalog parity check and the softure-mcp prune command.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/index.ts
CHANGED
|
@@ -34,7 +34,7 @@ export const MCP_RATE_LIMIT_BUCKETS = {
|
|
|
34
34
|
export const mcpAccess = defineModule({
|
|
35
35
|
manifest: {
|
|
36
36
|
id: MODULE_ID,
|
|
37
|
-
version: "0.2.
|
|
37
|
+
version: "0.2.6",
|
|
38
38
|
dependsOn: { security: "^0.2.0", auth: "^0.2.0", jobs: "^0.1.1?", ops: "^0.2.0?" },
|
|
39
39
|
dbSchema: "mcp",
|
|
40
40
|
tables: ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window"],
|
package/src/next/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// The Next.js adapter of @softure-ai/mcp-access: the MCP route factory, the token page
|
|
2
|
-
// server actions, and the OAuth routes and consent page (docs/02-module-standard.md §8).
|
|
1
|
+
// The Next.js adapter of @softure-ai/mcp-access: the MCP route factory, the token page, its prop
|
|
2
|
+
// builder and its server actions, and the OAuth routes and consent page (docs/02-module-standard.md §8).
|
|
3
3
|
export { issueTokenAction, revokeGrantAction, revokeTokenAction } from "./actions.js";
|
|
4
4
|
export { OAuthConsentPage, type OAuthConsentPageProps } from "./oauth-page.js";
|
|
5
5
|
export {
|
|
@@ -14,3 +14,4 @@ export { getMcpAccessContext, getRequestOrigins } from "./context.js";
|
|
|
14
14
|
export { issueToken, refuseIssue, type BeforeIssueGate, type IssueGateInput, type IssueGateResult, type IssueTokenOptions } from "./issue-token.js";
|
|
15
15
|
export { McpAccessPage, type McpAccessPageProps } from "./pages.js";
|
|
16
16
|
export { createMcpRoute } from "./route.js";
|
|
17
|
+
export { getTokenManagerProps, type TokenManagerData, type TokenManagerPropsInput } from "./token-manager-props.js";
|
package/src/next/pages.tsx
CHANGED
|
@@ -1,69 +1,17 @@
|
|
|
1
1
|
// The token page, ready to mount with one line:
|
|
2
2
|
// `export { McpAccessPage as default } from "@softure-ai/mcp-access/next"`.
|
|
3
3
|
// A server component for the signed-in user; without a session it redirects to the login page and
|
|
4
|
-
// back.
|
|
5
|
-
// app's locale and time zone, and never differ between the server render and hydration.
|
|
4
|
+
// back. Its props come from `getTokenManagerProps`, the same builder an app's own page uses.
|
|
6
5
|
import { requireUser } from "@softure-ai/auth/next";
|
|
7
|
-
import { formatMessage, type SoftureConfig } from "@softure-ai/core";
|
|
8
6
|
import { getSoftureConfig } from "@softure-ai/core/next";
|
|
9
7
|
import { Card } from "@softure-ai/ui";
|
|
10
|
-
import
|
|
11
|
-
import type
|
|
12
|
-
import type { McpAccessOptions } from "../options.js";
|
|
13
|
-
import { getLocalizedText, getMcpAccessMessages, getMcpAccessOptions, getMcpAccessRoutes } from "../server/options.js";
|
|
14
|
-
import { listOAuthGrants } from "../server/oauth.js";
|
|
15
|
-
import { listAccessTokens } from "../server/tokens.js";
|
|
16
|
-
import { getAccessTokenStatus } from "../token-status.js";
|
|
17
|
-
import { TokenManager, type IssueTokenAction, type TokenManagerGrant, type TokenManagerRow, type TokenManagerTool } from "../ui/token-manager.js";
|
|
8
|
+
import { getMcpAccessMessages, getMcpAccessRoutes } from "../server/options.js";
|
|
9
|
+
import { TokenManager, type IssueTokenAction } from "../ui/token-manager.js";
|
|
18
10
|
import { issueTokenAction, revokeGrantAction, revokeTokenAction } from "./actions.js";
|
|
19
|
-
import {
|
|
20
|
-
import { formatDate, formatDateTime } from "./format.js";
|
|
11
|
+
import { getTokenManagerProps } from "./token-manager-props.js";
|
|
21
12
|
|
|
22
13
|
const LAYOUT_CLASS = "sft:mx-auto sft:box-border sft:w-full sft:sm:max-w-3xl sft:px-4 sft:py-4";
|
|
23
14
|
|
|
24
|
-
function describeStatus(status: AccessTokenStatus, messages: McpAccessMessages): string {
|
|
25
|
-
switch (status.kind) {
|
|
26
|
-
case "active":
|
|
27
|
-
return messages.list.active;
|
|
28
|
-
case "expired":
|
|
29
|
-
return messages.list.expired;
|
|
30
|
-
case "expiring":
|
|
31
|
-
if (status.daysLeft === 0) return messages.list.expiresToday;
|
|
32
|
-
if (status.daysLeft === 1) return messages.list.expiresTomorrow;
|
|
33
|
-
return formatMessage(messages.list.expiresInDays, { days: status.daysLeft });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function toRow(token: AccessTokenView, now: Date, config: SoftureConfig, options: McpAccessOptions, messages: McpAccessMessages): TokenManagerRow {
|
|
38
|
-
const status = getAccessTokenStatus(token.expiresAt, now, { timezone: config.timezone, warningDays: options.expiryWarningDays });
|
|
39
|
-
const isExpired = status.kind === "expired";
|
|
40
|
-
const expiry = formatMessage(isExpired ? messages.list.expiredOn : messages.list.expiresOn, { date: formatDate(config, token.expiresAt) });
|
|
41
|
-
const lastUse = token.lastUsedAt === null ? messages.list.neverUsed : formatMessage(messages.list.lastUsed, { date: formatDateTime(config, token.lastUsedAt) });
|
|
42
|
-
return {
|
|
43
|
-
id: token.id,
|
|
44
|
-
name: token.name,
|
|
45
|
-
scopeText: token.canWrite && options.allowWrites ? messages.list.readWrite : messages.list.readOnly,
|
|
46
|
-
statusText: describeStatus(status, messages),
|
|
47
|
-
isExpired,
|
|
48
|
-
details: [formatMessage(messages.list.createdOn, { date: formatDate(config, token.createdAt) }), expiry, lastUse],
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function toGrant(grant: OAuthGrantView, config: SoftureConfig, options: McpAccessOptions, messages: McpAccessMessages): TokenManagerGrant {
|
|
53
|
-
const lastUse = grant.lastUsedAt === null ? messages.list.neverUsed : formatMessage(messages.list.lastUsed, { date: formatDateTime(config, grant.lastUsedAt) });
|
|
54
|
-
return {
|
|
55
|
-
id: grant.id,
|
|
56
|
-
clientName: grant.clientName,
|
|
57
|
-
scopeText: grant.canWrite && options.allowWrites ? messages.list.readWrite : messages.list.readOnly,
|
|
58
|
-
details: [formatMessage(messages.grants.connectedOn, { date: formatDate(config, grant.createdAt) }), lastUse],
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function toTool(tool: McpAccessOptions["tools"][number], config: SoftureConfig, options: McpAccessOptions, messages: McpAccessMessages): TokenManagerTool {
|
|
63
|
-
const accessText = tool.access === "read" ? messages.tools.read : options.allowWrites ? messages.tools.write : messages.tools.writeUnavailable;
|
|
64
|
-
return { name: tool.name, description: getLocalizedText(tool.description, config.locale), accessText };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
15
|
export interface McpAccessPageProps {
|
|
68
16
|
/**
|
|
69
17
|
* The app's own issue action, e.g. one that calls `issueToken` with a `beforeIssue` gate. Default:
|
|
@@ -75,25 +23,16 @@ export interface McpAccessPageProps {
|
|
|
75
23
|
export async function McpAccessPage({ issueAction = issueTokenAction }: McpAccessPageProps = {}) {
|
|
76
24
|
const config = getSoftureConfig();
|
|
77
25
|
const user = await requireUser({ next: getMcpAccessRoutes(config).page });
|
|
78
|
-
const options = getMcpAccessOptions(config);
|
|
79
26
|
const messages = getMcpAccessMessages(config);
|
|
80
|
-
const
|
|
81
|
-
const now = ctx.clock.now();
|
|
82
|
-
const tokens = await listAccessTokens(ctx, user.id);
|
|
83
|
-
const grants = options.oauth.enabled ? await listOAuthGrants(ctx, user.id) : null;
|
|
27
|
+
const props = await getTokenManagerProps({ userId: user.id, config });
|
|
84
28
|
return (
|
|
85
29
|
<main className={LAYOUT_CLASS}>
|
|
86
30
|
<Card title={messages.page.title} subtitle={messages.page.lead}>
|
|
87
31
|
<TokenManager
|
|
88
|
-
|
|
89
|
-
tokens={tokens.map((token) => toRow(token, now, config, options, messages))}
|
|
90
|
-
allowWrites={options.allowWrites}
|
|
91
|
-
maxTokens={options.maxTokensPerUser}
|
|
32
|
+
{...props}
|
|
92
33
|
issueAction={issueAction}
|
|
93
34
|
revokeAction={revokeTokenAction}
|
|
94
|
-
{...(grants ===
|
|
95
|
-
messages={messages}
|
|
96
|
-
locale={config.locale}
|
|
35
|
+
{...(props.grants === undefined ? {} : { revokeGrantAction })}
|
|
97
36
|
/>
|
|
98
37
|
</Card>
|
|
99
38
|
</main>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// The data `TokenManager` shows, built on the server for one user: what `McpAccessPage` renders, for an
|
|
2
|
+
// app that composes its own page around `TokenManager`. Dates are formatted here, once, in the app's
|
|
3
|
+
// locale and time zone, so the server render and hydration never differ.
|
|
4
|
+
import { formatMessage, type SoftureConfig } from "@softure-ai/core";
|
|
5
|
+
import { getSoftureConfig } from "@softure-ai/core/next";
|
|
6
|
+
import type { AccessTokenStatus, AccessTokenView, OAuthGrantView } from "../contract.js";
|
|
7
|
+
import type { McpAccessMessages } from "../messages/index.js";
|
|
8
|
+
import type { McpAccessOptions } from "../options.js";
|
|
9
|
+
import { getLocalizedText, getMcpAccessMessages, getMcpAccessOptions } from "../server/options.js";
|
|
10
|
+
import { listOAuthGrants } from "../server/oauth.js";
|
|
11
|
+
import { listAccessTokens } from "../server/tokens.js";
|
|
12
|
+
import { getAccessTokenStatus } from "../token-status.js";
|
|
13
|
+
import type { TokenManagerGrant, TokenManagerProps, TokenManagerRow, TokenManagerTool } from "../ui/token-manager.js";
|
|
14
|
+
import { getMcpAccessContext } from "./context.js";
|
|
15
|
+
import { formatDate, formatDateTime } from "./format.js";
|
|
16
|
+
|
|
17
|
+
/** Every prop of `TokenManager` but the actions and the styling. */
|
|
18
|
+
export type TokenManagerData = Pick<TokenManagerProps, "tools" | "tokens" | "grants" | "allowWrites" | "maxTokens" | "messages" | "locale">;
|
|
19
|
+
|
|
20
|
+
export interface TokenManagerPropsInput {
|
|
21
|
+
/** The signed-in user's id, from the app's session check: only this user's tokens and apps are listed. */
|
|
22
|
+
readonly userId: string;
|
|
23
|
+
/** Default: the registered config (`getSoftureConfig()`). */
|
|
24
|
+
readonly config?: SoftureConfig;
|
|
25
|
+
/** The moment token statuses are computed for. Default: the module clock's now. */
|
|
26
|
+
readonly now?: Date;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function describeStatus(status: AccessTokenStatus, messages: McpAccessMessages): string {
|
|
30
|
+
switch (status.kind) {
|
|
31
|
+
case "active":
|
|
32
|
+
return messages.list.active;
|
|
33
|
+
case "expired":
|
|
34
|
+
return messages.list.expired;
|
|
35
|
+
case "expiring":
|
|
36
|
+
if (status.daysLeft === 0) return messages.list.expiresToday;
|
|
37
|
+
if (status.daysLeft === 1) return messages.list.expiresTomorrow;
|
|
38
|
+
return formatMessage(messages.list.expiresInDays, { days: status.daysLeft });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function toRow(token: AccessTokenView, now: Date, config: SoftureConfig, options: McpAccessOptions, messages: McpAccessMessages): TokenManagerRow {
|
|
43
|
+
const status = getAccessTokenStatus(token.expiresAt, now, { timezone: config.timezone, warningDays: options.expiryWarningDays });
|
|
44
|
+
const isExpired = status.kind === "expired";
|
|
45
|
+
const expiry = formatMessage(isExpired ? messages.list.expiredOn : messages.list.expiresOn, { date: formatDate(config, token.expiresAt) });
|
|
46
|
+
const lastUse = token.lastUsedAt === null ? messages.list.neverUsed : formatMessage(messages.list.lastUsed, { date: formatDateTime(config, token.lastUsedAt) });
|
|
47
|
+
return {
|
|
48
|
+
id: token.id,
|
|
49
|
+
name: token.name,
|
|
50
|
+
scopeText: token.canWrite && options.allowWrites ? messages.list.readWrite : messages.list.readOnly,
|
|
51
|
+
statusText: describeStatus(status, messages),
|
|
52
|
+
isExpired,
|
|
53
|
+
details: [formatMessage(messages.list.createdOn, { date: formatDate(config, token.createdAt) }), expiry, lastUse],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function toGrant(grant: OAuthGrantView, config: SoftureConfig, options: McpAccessOptions, messages: McpAccessMessages): TokenManagerGrant {
|
|
58
|
+
const lastUse = grant.lastUsedAt === null ? messages.list.neverUsed : formatMessage(messages.list.lastUsed, { date: formatDateTime(config, grant.lastUsedAt) });
|
|
59
|
+
return {
|
|
60
|
+
id: grant.id,
|
|
61
|
+
clientName: grant.clientName,
|
|
62
|
+
scopeText: grant.canWrite && options.allowWrites ? messages.list.readWrite : messages.list.readOnly,
|
|
63
|
+
details: [formatMessage(messages.grants.connectedOn, { date: formatDate(config, grant.createdAt) }), lastUse],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function toTool(tool: McpAccessOptions["tools"][number], config: SoftureConfig, options: McpAccessOptions, messages: McpAccessMessages): TokenManagerTool {
|
|
68
|
+
const accessText = tool.access === "read" ? messages.tools.read : options.allowWrites ? messages.tools.write : messages.tools.writeUnavailable;
|
|
69
|
+
return { name: tool.name, description: getLocalizedText(tool.description, config.locale), accessText };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The tools, the user's tokens and (while OAuth is on) connected apps, and the page settings, ready to
|
|
74
|
+
* spread into `TokenManager` next to the actions. Reads the database; it checks no session itself.
|
|
75
|
+
*/
|
|
76
|
+
export async function getTokenManagerProps({ userId, config = getSoftureConfig(), now }: TokenManagerPropsInput): Promise<TokenManagerData> {
|
|
77
|
+
const options = getMcpAccessOptions(config);
|
|
78
|
+
const messages = getMcpAccessMessages(config);
|
|
79
|
+
const ctx = await getMcpAccessContext(config);
|
|
80
|
+
const at = now ?? ctx.clock.now();
|
|
81
|
+
const tokens = await listAccessTokens(ctx, userId);
|
|
82
|
+
const grants = options.oauth.enabled ? await listOAuthGrants(ctx, userId) : null;
|
|
83
|
+
return {
|
|
84
|
+
tools: options.tools.map((tool) => toTool(tool, config, options, messages)),
|
|
85
|
+
tokens: tokens.map((token) => toRow(token, at, config, options, messages)),
|
|
86
|
+
...(grants === null ? {} : { grants: grants.map((grant) => toGrant(grant, config, options, messages)) }),
|
|
87
|
+
allowWrites: options.allowWrites,
|
|
88
|
+
maxTokens: options.maxTokensPerUser,
|
|
89
|
+
messages,
|
|
90
|
+
locale: config.locale,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// A server action as a write tool: the tool's arguments become the form the action reads, so the tool
|
|
2
2
|
// and the form share one validation path, and the action's error state becomes a tool error.
|
|
3
3
|
import type { CallToolResult } from "@modelcontextprotocol/server";
|
|
4
|
-
import {
|
|
4
|
+
import { toolResult, withToolErrors, type ToolCaller, type ToolCallHook, type ToolErrorHints } from "./tools.js";
|
|
5
5
|
|
|
6
6
|
/** The action, called with the form. A `useActionState` action is passed as `(form) => action(INITIAL, form)`. */
|
|
7
7
|
export type FormActionHandler = (formData: FormData) => unknown;
|
|
@@ -11,8 +11,12 @@ export interface ActionToolOptions {
|
|
|
11
11
|
readonly message?: string | ((state: unknown) => string);
|
|
12
12
|
/** Texts per error code, as in `withToolErrors`. */
|
|
13
13
|
readonly hints?: ToolErrorHints;
|
|
14
|
-
/** The tool's name in the log line. */
|
|
14
|
+
/** The tool's name in the log line and in the `onToolCall` record. */
|
|
15
15
|
readonly label?: string;
|
|
16
|
+
/** Called once after each call with its record, as in `withToolErrors`. */
|
|
17
|
+
readonly onToolCall?: ToolCallHook;
|
|
18
|
+
/** Who called, for the record, as in `withToolErrors`. */
|
|
19
|
+
readonly caller?: ToolCaller;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
/** The tool callback for `server.registerTool(name, { inputSchema }, actionTool(handler))`. */
|
|
@@ -23,11 +27,18 @@ export function actionTool(handler: FormActionHandler, options: ActionToolOption
|
|
|
23
27
|
async () => {
|
|
24
28
|
const state = await handler(toFormData(args));
|
|
25
29
|
const error = readErrorCode(state);
|
|
26
|
-
|
|
30
|
+
// As a core result, so withToolErrors answers it through the hints and records its code.
|
|
31
|
+
if (error !== null) return { ok: false, error };
|
|
27
32
|
if (options.message === undefined) return toolResult(state);
|
|
28
33
|
return toolResult(typeof options.message === "string" ? options.message : options.message(state));
|
|
29
34
|
},
|
|
30
|
-
{
|
|
35
|
+
{
|
|
36
|
+
hints,
|
|
37
|
+
args,
|
|
38
|
+
...(options.label === undefined ? {} : { label: options.label }),
|
|
39
|
+
...(options.onToolCall === undefined ? {} : { onToolCall: options.onToolCall }),
|
|
40
|
+
...(options.caller === undefined ? {} : { caller: options.caller }),
|
|
41
|
+
},
|
|
31
42
|
);
|
|
32
43
|
}
|
|
33
44
|
|
package/src/server/index.ts
CHANGED
|
@@ -92,6 +92,7 @@ export {
|
|
|
92
92
|
issueAccessToken,
|
|
93
93
|
listAccessTokens,
|
|
94
94
|
pruneAccessTokens,
|
|
95
|
+
findTokenClientName,
|
|
95
96
|
revokeAccessToken,
|
|
96
97
|
verifyAccessToken,
|
|
97
98
|
type IssueAccessTokenInput,
|
|
@@ -101,4 +102,14 @@ export {
|
|
|
101
102
|
type RevokeAccessTokenInput,
|
|
102
103
|
type VerifiedAccessToken,
|
|
103
104
|
} from "./tokens.js";
|
|
104
|
-
export {
|
|
105
|
+
export {
|
|
106
|
+
toolError,
|
|
107
|
+
toolResult,
|
|
108
|
+
withToolErrors,
|
|
109
|
+
type ToolCaller,
|
|
110
|
+
type ToolCallHook,
|
|
111
|
+
type ToolCallOutcome,
|
|
112
|
+
type ToolCallRecord,
|
|
113
|
+
type ToolErrorHints,
|
|
114
|
+
type ToolErrorOptions,
|
|
115
|
+
} from "./tools.js";
|
package/src/server/tokens.ts
CHANGED
|
@@ -159,6 +159,16 @@ export interface VerifiedAccessToken {
|
|
|
159
159
|
readonly grantId: string | null;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
/**
|
|
163
|
+
* A token's name, the client it was issued for ("Laptop", an OAuth client's name), for a record of tool calls:
|
|
164
|
+
* `null` for an id that is not a stored token's (the stdio id, a pruned or unknown token).
|
|
165
|
+
*/
|
|
166
|
+
export async function findTokenClientName(ctx: McpAccessContext, tokenId: string): Promise<string | null> {
|
|
167
|
+
if (!UUID_SHAPE.test(tokenId)) return null;
|
|
168
|
+
const [row] = await ctx.db.select({ name: accessTokens.name }).from(accessTokens).where(eq(accessTokens.id, tokenId));
|
|
169
|
+
return row?.name ?? null;
|
|
170
|
+
}
|
|
171
|
+
|
|
162
172
|
/**
|
|
163
173
|
* The identity behind a token, or null for anything unknown, revoked or expired: the caller cannot
|
|
164
174
|
* tell which, so a guess learns nothing. The expiry sits in the query, so no code path can forget
|