@forwardreach/saas-mcp 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 +7 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +1 -0
- package/dist/client/management.d.ts +80 -0
- package/dist/client/management.js +78 -0
- package/dist/core/http.d.ts +27 -0
- package/dist/core/http.js +29 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +5 -0
- package/dist/core/redaction.d.ts +11 -0
- package/dist/core/redaction.js +43 -0
- package/dist/core/scopes.d.ts +13 -0
- package/dist/core/scopes.js +35 -0
- package/dist/core/types.d.ts +256 -0
- package/dist/core/types.js +1 -0
- package/dist/core/urls.d.ts +69 -0
- package/dist/core/urls.js +85 -0
- package/dist/hono/index.d.ts +1 -0
- package/dist/hono/index.js +1 -0
- package/dist/hono/routes.d.ts +212 -0
- package/dist/hono/routes.js +535 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/node/better-auth.d.ts +84 -0
- package/dist/node/better-auth.js +77 -0
- package/dist/node/index.d.ts +2 -0
- package/dist/node/index.js +2 -0
- package/dist/node/oauth.d.ts +18 -0
- package/dist/node/oauth.js +39 -0
- package/dist/react/McpActivity.d.ts +32 -0
- package/dist/react/McpActivity.js +182 -0
- package/dist/react/McpConnectedClients.d.ts +27 -0
- package/dist/react/McpConnectedClients.js +34 -0
- package/dist/react/McpConnectorOverview.d.ts +21 -0
- package/dist/react/McpConnectorOverview.js +12 -0
- package/dist/react/McpConsentPanel.d.ts +47 -0
- package/dist/react/McpConsentPanel.js +18 -0
- package/dist/react/McpDeveloperTokens.d.ts +27 -0
- package/dist/react/McpDeveloperTokens.js +46 -0
- package/dist/react/McpToolReference.d.ts +17 -0
- package/dist/react/McpToolReference.js +19 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +6 -0
- package/dist/react/mcp-settings-shared.d.ts +29 -0
- package/dist/react/mcp-settings-shared.js +37 -0
- package/package.json +98 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { McpPromptDescriptor, McpResourceDescriptor, McpScopeDefinition, McpScopeValue, McpToolDescriptor } from "../core/types.js";
|
|
2
|
+
/** Props for the full tools & capabilities reference. */
|
|
3
|
+
export interface McpToolReferenceProps<S extends McpScopeValue = McpScopeValue> {
|
|
4
|
+
/** Product-supported MCP scopes with descriptions. */
|
|
5
|
+
scopes: McpScopeDefinition<S>[];
|
|
6
|
+
/** Product-owned MCP tool descriptors; grouped by read/write, with anything else under "Other". */
|
|
7
|
+
tools: McpToolDescriptor<S>[];
|
|
8
|
+
/** MCP resources exposed by the product. */
|
|
9
|
+
resources?: McpResourceDescriptor<S>[];
|
|
10
|
+
/** MCP prompts exposed by the product. */
|
|
11
|
+
prompts?: McpPromptDescriptor<S>[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Full reference for the MCP surface: scopes, tools grouped by read/write, and
|
|
15
|
+
* any resources and prompts. Presentational — reflects the current registry.
|
|
16
|
+
*/
|
|
17
|
+
export declare function McpToolReference<S extends McpScopeValue = McpScopeValue>({ scopes, tools, resources, prompts, }: McpToolReferenceProps<S>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { SettingsSection } from "@forwardreach/saas-ui";
|
|
4
|
+
/**
|
|
5
|
+
* Full reference for the MCP surface: scopes, tools grouped by read/write, and
|
|
6
|
+
* any resources and prompts. Presentational — reflects the current registry.
|
|
7
|
+
*/
|
|
8
|
+
export function McpToolReference({ scopes, tools, resources = [], prompts = [], }) {
|
|
9
|
+
// Every tool must land in exactly one group so nothing is silently dropped:
|
|
10
|
+
// tools without a read/write activity kind (e.g. `management` or unset) fall
|
|
11
|
+
// into "Other", which only renders when it has members.
|
|
12
|
+
const otherTools = tools.filter((tool) => tool.activityKind !== "read" && tool.activityKind !== "write");
|
|
13
|
+
const toolGroups = [
|
|
14
|
+
{ label: "Read", group: tools.filter((tool) => tool.activityKind === "read") },
|
|
15
|
+
{ label: "Write", group: tools.filter((tool) => tool.activityKind === "write") },
|
|
16
|
+
...(otherTools.length > 0 ? [{ label: "Other", group: otherTools }] : []),
|
|
17
|
+
];
|
|
18
|
+
return (_jsxs("div", { className: "space-y-5", children: [_jsx(SettingsSection, { description: "Permissions an AI client requests and you approve during connection.", title: "Scopes", children: _jsx("div", { className: "space-y-2", children: scopes.map((scope) => (_jsxs("div", { className: "rounded-[var(--ssui-radius)] border border-[color:var(--ssui-border)] p-3", children: [_jsx("div", { className: "text-sm font-medium", children: scope.title }), _jsx("div", { className: "mt-1 text-xs text-[color:var(--ssui-text-muted)]", children: scope.description }), _jsx("div", { className: "mt-2 font-mono text-xs text-[color:var(--ssui-text-subtle)]", children: scope.scope })] }, scope.scope))) }) }), _jsx(SettingsSection, { description: "Every tool an AI client can call, grouped by read and write behavior (other tools listed under Other).", title: "Tools", children: _jsx("div", { className: "grid gap-2", children: toolGroups.map(({ label, group }) => (_jsxs("div", { className: "rounded-[var(--ssui-radius)] border border-[color:var(--ssui-border)]", children: [_jsx("div", { className: "border-b border-[color:var(--ssui-border)] px-3 py-2 text-xs font-medium uppercase text-[color:var(--ssui-text-muted)]", children: label }), _jsx("div", { className: "divide-y divide-[color:var(--ssui-border)]", children: group.length === 0 ? (_jsxs("div", { className: "px-3 py-2 text-xs text-[color:var(--ssui-text-muted)]", children: ["No ", label.toLowerCase(), " tools."] })) : (group.map((tool) => (_jsxs("div", { className: "px-3 py-2", children: [_jsx("div", { className: "text-sm font-medium", children: tool.title }), _jsx("div", { className: "mt-1 text-xs text-[color:var(--ssui-text-muted)]", children: tool.description }), _jsx("div", { className: "mt-1 font-mono text-xs text-[color:var(--ssui-text-subtle)]", children: tool.name })] }, tool.name)))) })] }, label))) }) }), (resources.length > 0 || prompts.length > 0) && (_jsxs("div", { className: "grid gap-5 md:grid-cols-2", children: [resources.length > 0 && (_jsx(SettingsSection, { description: "Cacheable context an AI client can read.", title: "Resources", children: _jsx("div", { className: "divide-y divide-[color:var(--ssui-border)] rounded-[var(--ssui-radius)] border border-[color:var(--ssui-border)]", children: resources.map((resource) => (_jsxs("div", { className: "px-3 py-2", children: [_jsx("div", { className: "text-sm font-medium", children: resource.title }), _jsx("div", { className: "mt-1 text-xs text-[color:var(--ssui-text-muted)]", children: resource.description }), _jsx("div", { className: "mt-1 font-mono text-xs text-[color:var(--ssui-text-subtle)]", children: resource.uri })] }, resource.uri))) }) })), prompts.length > 0 && (_jsx(SettingsSection, { description: "Guided workflows an AI client can invoke.", title: "Prompts", children: _jsx("div", { className: "divide-y divide-[color:var(--ssui-border)] rounded-[var(--ssui-radius)] border border-[color:var(--ssui-border)]", children: prompts.map((prompt) => (_jsxs("div", { className: "px-3 py-2", children: [_jsx("div", { className: "text-sm font-medium", children: prompt.title }), _jsx("div", { className: "mt-1 text-xs text-[color:var(--ssui-text-muted)]", children: prompt.description }), _jsx("div", { className: "mt-1 font-mono text-xs text-[color:var(--ssui-text-subtle)]", children: prompt.name })] }, prompt.name))) }) }))] }))] }));
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Check } from "lucide-react";
|
|
2
|
+
import { type McpManagementClient } from "../client/management.js";
|
|
3
|
+
import type { McpScopeValue } from "../core/types.js";
|
|
4
|
+
/** Join truthy class fragments. */
|
|
5
|
+
export declare function cx(...values: Array<string | false | null | undefined>): string;
|
|
6
|
+
/** Format an ISO timestamp for settings tables, or "Never" when absent. */
|
|
7
|
+
export declare function formatDate(value: string | null | undefined): string;
|
|
8
|
+
/** Derive a status pill (label, classes, icon) for a token or connection. */
|
|
9
|
+
export declare function statusLabel(item: {
|
|
10
|
+
revokedAt: string | null;
|
|
11
|
+
expired?: boolean;
|
|
12
|
+
}): {
|
|
13
|
+
label: string;
|
|
14
|
+
className: string;
|
|
15
|
+
Icon: typeof Check;
|
|
16
|
+
};
|
|
17
|
+
/** Compact list of scope strings rendered as monospace pills. */
|
|
18
|
+
export declare function ScopePills<S extends McpScopeValue>({ scopes }: {
|
|
19
|
+
scopes: readonly S[];
|
|
20
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
/** Pretty-printed JSON block used for audit metadata. */
|
|
22
|
+
export declare function JsonBlock({ value }: {
|
|
23
|
+
value: unknown;
|
|
24
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the management client for a section: prefer an explicitly provided
|
|
27
|
+
* client, otherwise create one bound to the workspace's default routes.
|
|
28
|
+
*/
|
|
29
|
+
export declare function useMcpManagementClient<S extends McpScopeValue = McpScopeValue>(workspaceId: string, managementClient?: McpManagementClient<S>): McpManagementClient<S>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Check, XCircle } from "lucide-react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { createMcpManagementClient } from "../client/management.js";
|
|
5
|
+
/** Join truthy class fragments. */
|
|
6
|
+
export function cx(...values) {
|
|
7
|
+
return values.filter(Boolean).join(" ");
|
|
8
|
+
}
|
|
9
|
+
/** Format an ISO timestamp for settings tables, or "Never" when absent. */
|
|
10
|
+
export function formatDate(value) {
|
|
11
|
+
if (!value)
|
|
12
|
+
return "Never";
|
|
13
|
+
return new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
|
|
14
|
+
}
|
|
15
|
+
/** Derive a status pill (label, classes, icon) for a token or connection. */
|
|
16
|
+
export function statusLabel(item) {
|
|
17
|
+
if (item.revokedAt)
|
|
18
|
+
return { label: "Revoked", className: "bg-red-100 text-red-700", Icon: XCircle };
|
|
19
|
+
if (item.expired)
|
|
20
|
+
return { label: "Expired", className: "bg-zinc-100 text-zinc-600", Icon: XCircle };
|
|
21
|
+
return { label: "Active", className: "bg-emerald-100 text-emerald-700", Icon: Check };
|
|
22
|
+
}
|
|
23
|
+
/** Compact list of scope strings rendered as monospace pills. */
|
|
24
|
+
export function ScopePills({ scopes }) {
|
|
25
|
+
return (_jsx("div", { className: "flex flex-wrap gap-1", children: scopes.map((scope) => (_jsx("span", { className: "rounded border border-[color:var(--ssui-border)] bg-[color:var(--ssui-surface-muted)] px-1.5 py-0.5 font-mono text-xs text-[color:var(--ssui-text-muted)]", children: scope }, scope))) }));
|
|
26
|
+
}
|
|
27
|
+
/** Pretty-printed JSON block used for audit metadata. */
|
|
28
|
+
export function JsonBlock({ value }) {
|
|
29
|
+
return (_jsx("pre", { className: "max-h-56 overflow-auto rounded-[var(--ssui-radius)] border border-[color:var(--ssui-border)] bg-[color:var(--ssui-surface-muted)] p-3 font-mono text-xs text-[color:var(--ssui-text-muted)]", children: JSON.stringify(value, null, 2) }));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the management client for a section: prefer an explicitly provided
|
|
33
|
+
* client, otherwise create one bound to the workspace's default routes.
|
|
34
|
+
*/
|
|
35
|
+
export function useMcpManagementClient(workspaceId, managementClient) {
|
|
36
|
+
return React.useMemo(() => managementClient ?? createMcpManagementClient({ workspaceId }), [managementClient, workspaceId]);
|
|
37
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forwardreach/saas-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared MCP contracts, OAuth helpers, Hono route plumbing, management client, and React UI for ForwardReach SaaS applications.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/forwardreach/saas-shared.git",
|
|
11
|
+
"directory": "packages/saas-mcp"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/forwardreach/saas-shared/tree/main/packages/saas-mcp#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/forwardreach/saas-shared/issues"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public",
|
|
19
|
+
"registry": "https://registry.npmjs.org/"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./core": {
|
|
32
|
+
"types": "./dist/core/index.d.ts",
|
|
33
|
+
"import": "./dist/core/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./client": {
|
|
36
|
+
"types": "./dist/client/index.d.ts",
|
|
37
|
+
"import": "./dist/client/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./react": {
|
|
40
|
+
"types": "./dist/react/index.d.ts",
|
|
41
|
+
"import": "./dist/react/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./node": {
|
|
44
|
+
"types": "./dist/node/index.d.ts",
|
|
45
|
+
"import": "./dist/node/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./hono": {
|
|
48
|
+
"types": "./dist/hono/index.d.ts",
|
|
49
|
+
"import": "./dist/hono/index.js"
|
|
50
|
+
},
|
|
51
|
+
"./package.json": "./package.json"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
55
|
+
"@forwardreach/saas-ui": "^0.4.0",
|
|
56
|
+
"better-auth": "^1.6.10",
|
|
57
|
+
"hono": "^4.10.3",
|
|
58
|
+
"react": "^19.0.0",
|
|
59
|
+
"react-dom": "^19.0.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"@modelcontextprotocol/sdk": {
|
|
63
|
+
"optional": true
|
|
64
|
+
},
|
|
65
|
+
"better-auth": {
|
|
66
|
+
"optional": true
|
|
67
|
+
},
|
|
68
|
+
"hono": {
|
|
69
|
+
"optional": true
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"lucide-react": "^0.468.0",
|
|
74
|
+
"zod": "^4.4.3"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
78
|
+
"@testing-library/react": "^16.3.0",
|
|
79
|
+
"@types/node": "^24.9.2",
|
|
80
|
+
"@types/react": "^19.0.0",
|
|
81
|
+
"@types/react-dom": "^19.0.0",
|
|
82
|
+
"better-auth": "^1.6.10",
|
|
83
|
+
"hono": "^4.12.29",
|
|
84
|
+
"jsdom": "^26.1.0",
|
|
85
|
+
"rimraf": "^6.0.1",
|
|
86
|
+
"typescript": "^5.8.3",
|
|
87
|
+
"vitest": "^3.2.4",
|
|
88
|
+
"@forwardreach/saas-ui": "0.4.0"
|
|
89
|
+
},
|
|
90
|
+
"scripts": {
|
|
91
|
+
"build": "pnpm clean && tsc -p tsconfig.build.json",
|
|
92
|
+
"dev": "tsc -p tsconfig.build.json --watch",
|
|
93
|
+
"clean": "rimraf dist coverage dist-pack *.tgz",
|
|
94
|
+
"pack:local": "pnpm build && mkdir -p dist-pack && pnpm pack --pack-destination dist-pack",
|
|
95
|
+
"test": "vitest run",
|
|
96
|
+
"typecheck": "tsc --noEmit"
|
|
97
|
+
}
|
|
98
|
+
}
|