@softure-ai/mcp-access 0.7.0 → 0.7.1
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 +12 -1
- package/README.md +4 -2
- package/dist/index.js +1 -1
- package/dist/server/server-info.d.ts +7 -1
- package/dist/server/server-info.d.ts.map +1 -1
- package/dist/server/server-info.js +9 -7
- package/dist/server/server-info.js.map +1 -1
- package/module.json +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -1
- package/src/server/server-info.ts +19 -9
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ Newest first. Each version lists what changed for an app that uses `@softure-ai/
|
|
|
4
4
|
production, the version gets a line `verified in: <app>@<commit>` ([docs/05](../../docs/05-adoption-playbook.md),
|
|
5
5
|
"Definition of done"). Versions before the first one below are described in their GitHub Releases (`mcp-access@x.y.z`).
|
|
6
6
|
|
|
7
|
+
## 0.7.1
|
|
8
|
+
|
|
9
|
+
- **`get_server_info` speaks the app's language (#1117):** `serverInfoTool` (and `registerServerInfoTool`) takes
|
|
10
|
+
`config`, the app's config; the tool description, the `name` input description and the `toolsHint` /
|
|
11
|
+
`unknownToolHint` answers then come from `serverInfoTool` of the app's messages in its locale, with the app's
|
|
12
|
+
overrides. Without `config` they stay English, as before. Migrate: to serve the translations, pass
|
|
13
|
+
`serverInfoTool: { ..., config }`; a translated description changes the tool list version once.
|
|
14
|
+
|
|
7
15
|
## 0.7.0
|
|
8
16
|
|
|
9
17
|
- The served tool contract in `get_server_info` (#1078): `serverInfoTool: { tools: true }` makes the tool answer each
|
|
@@ -11,7 +19,10 @@ production, the version gets a line `verified in: <app>@<commit>` ([docs/05](../
|
|
|
11
19
|
them (the measured list the version comes from), with a `toolsHint` that the server's copy is current. An optional
|
|
12
20
|
`name` input narrows it to one tool; an unknown name answers `toolNames`. A hosted client never caches a tool result,
|
|
13
21
|
so a model on a stale tool list reads the current one in-band. `registerServerInfoTool` takes `tools` with
|
|
14
|
-
`servedTools` for a hand-built server. Migrate:
|
|
22
|
+
`servedTools` for a hand-built server. Migrate: an app whose own dictionary is typed as `McpAccessMessages` adds
|
|
23
|
+
four keys to `serverInfoTool`: `descriptionWithTools`, `nameInputDescription`, `toolsHint` and `unknownToolHint`
|
|
24
|
+
(#1117; an app that passes partial overrides gets the English ones). The tool is off by default; turning it on
|
|
25
|
+
changes the version once.
|
|
15
26
|
|
|
16
27
|
## 0.6.0
|
|
17
28
|
|
package/README.md
CHANGED
|
@@ -327,8 +327,10 @@ export const createServer = createMcpServerFactory({
|
|
|
327
327
|
- The app passes the reader, so `/server` never loads `@softure-ai/ops`; `McpBuildInfo` is its `BuildInfo` by shape.
|
|
328
328
|
- `changelog` appears only with a provider; a provider that fails answers `changelog: null` and logs the error
|
|
329
329
|
class, as the route does. A failing `buildInfo` answers a tool error.
|
|
330
|
-
- The tool is part of the measured list, so turning it on changes the version once.
|
|
331
|
-
`
|
|
330
|
+
- The tool is part of the measured list, so turning it on changes the version once. Its texts (the description,
|
|
331
|
+
with `tools: true` also `descriptionWithTools`, `nameInputDescription`, `toolsHint` and `unknownToolHint`) come
|
|
332
|
+
from `serverInfoTool` of the messages: pass `config` (the app's config) to use its locale and overrides, otherwise
|
|
333
|
+
they are English. `description` in the options wins over the dictionary.
|
|
332
334
|
- A hand-built server registers it with `registerServerInfoTool(server, { buildInfo, server: { name, version } })`,
|
|
333
335
|
passing the name and version it serves.
|
|
334
336
|
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,7 @@ export const API_TOKEN_RATE_LIMIT_BUCKETS = {
|
|
|
45
45
|
export const mcpAccess = defineModule({
|
|
46
46
|
manifest: {
|
|
47
47
|
id: MODULE_ID,
|
|
48
|
-
version: "0.7.
|
|
48
|
+
version: "0.7.1",
|
|
49
49
|
dependsOn: { security: "^0.2.0", auth: "^0.2.0", jobs: "^0.1.1?", ops: "^0.2.0?" },
|
|
50
50
|
dbSchema: "mcp",
|
|
51
51
|
tables: ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window", "used_confirmations", "operation_tasks"],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/server";
|
|
2
|
+
import { type SoftureConfig } from "@softure-ai/core";
|
|
2
3
|
import type { ServedTool } from "./tool-list.js";
|
|
3
4
|
export declare const SERVER_INFO_TOOL_NAME = "get_server_info";
|
|
4
5
|
/** The build info of `@softure-ai/ops` (`readBuildInfo()`), typed by shape so mcp-access does not import ops. */
|
|
@@ -18,7 +19,12 @@ export interface ServerInfoToolOptions {
|
|
|
18
19
|
* it on changes the tool's input schema, so the version changes once. Default: off.
|
|
19
20
|
*/
|
|
20
21
|
readonly tools?: boolean;
|
|
21
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* The app's config: the tool's texts (`serverInfoTool` of the messages) follow its locale and overrides (#1117).
|
|
24
|
+
* Default: the built-in English dictionary.
|
|
25
|
+
*/
|
|
26
|
+
readonly config?: SoftureConfig;
|
|
27
|
+
/** Default: `serverInfoTool.description` (or `descriptionWithTools`) of the messages. */
|
|
22
28
|
readonly description?: string;
|
|
23
29
|
}
|
|
24
30
|
/** One served tool's contract, exactly as `tools/list` answers it. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-info.d.ts","sourceRoot":"","sources":["../../src/server/server-info.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"server-info.d.ts","sourceRoot":"","sources":["../../src/server/server-info.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AAEvD,iHAAiH;AACjH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,2GAA2G;IAC3G,QAAQ,CAAC,SAAS,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/D,sGAAsG;IACtG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,yFAAyF;IACzF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAID,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;IAC1E,wGAAwG;IACxG,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,SAAS,UAAU,EAAE,GAAG,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAAC;CACrF;AAED,wDAAwD;AACxD,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC9C,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,0GAA0G;AAC1G,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEnJ;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAqBtG"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { errorLogLabel } from "@softure-ai/core";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { en } from "../messages/en.js";
|
|
4
|
+
import { getMcpAccessMessages } from "./options.js";
|
|
4
5
|
import { toolResult } from "./tools.js";
|
|
5
6
|
export const SERVER_INFO_TOOL_NAME = "get_server_info";
|
|
6
7
|
/**
|
|
@@ -9,7 +10,8 @@ export const SERVER_INFO_TOOL_NAME = "get_server_info";
|
|
|
9
10
|
*/
|
|
10
11
|
export function registerServerInfoTool(server, options) {
|
|
11
12
|
const annotations = { readOnlyHint: true, idempotentHint: true, openWorldHint: false };
|
|
12
|
-
const
|
|
13
|
+
const messages = options.config === undefined ? en.serverInfoTool : getMcpAccessMessages(options.config).serverInfoTool;
|
|
14
|
+
const description = options.description ?? (options.tools === true ? messages.descriptionWithTools : messages.description);
|
|
13
15
|
if (options.tools !== true) {
|
|
14
16
|
// An empty object rather than no schema, so strict input refuses a field sent to it.
|
|
15
17
|
server.registerTool(SERVER_INFO_TOOL_NAME, { description, inputSchema: z.object({}), annotations }, async () => toolResult(await readServerInfo(options)));
|
|
@@ -19,9 +21,9 @@ export function registerServerInfoTool(server, options) {
|
|
|
19
21
|
if (readServedTools === undefined) {
|
|
20
22
|
throw new Error("@softure-ai/mcp-access: get_server_info with tools: true needs servedTools, e.g. () => listServedTools(createServer)");
|
|
21
23
|
}
|
|
22
|
-
server.registerTool(SERVER_INFO_TOOL_NAME, { description, inputSchema: z.object({ name: z.string().optional().describe(
|
|
24
|
+
server.registerTool(SERVER_INFO_TOOL_NAME, { description, inputSchema: z.object({ name: z.string().optional().describe(messages.nameInputDescription) }), annotations }, async ({ name }) => {
|
|
23
25
|
const answer = await readServerInfo(options);
|
|
24
|
-
return toolResult({ ...answer, ...describeToolContract(await readServedTools(), name) });
|
|
26
|
+
return toolResult({ ...answer, ...describeToolContract(await readServedTools(), name, messages) });
|
|
25
27
|
});
|
|
26
28
|
}
|
|
27
29
|
async function readServerInfo(options) {
|
|
@@ -30,14 +32,14 @@ async function readServerInfo(options) {
|
|
|
30
32
|
return options.changelog === undefined ? answer : { ...answer, changelog: await readChangelog(options.changelog) };
|
|
31
33
|
}
|
|
32
34
|
/** The contract of every served tool, or of the one named; an unknown name answers no tool and every name. */
|
|
33
|
-
function describeToolContract(served, name) {
|
|
35
|
+
function describeToolContract(served, name, messages) {
|
|
34
36
|
const tools = served.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema }));
|
|
35
37
|
if (name === undefined)
|
|
36
|
-
return { toolsHint:
|
|
38
|
+
return { toolsHint: messages.toolsHint, tools };
|
|
37
39
|
const named = tools.filter((tool) => tool.name === name);
|
|
38
40
|
if (named.length > 0)
|
|
39
|
-
return { toolsHint:
|
|
40
|
-
return { toolsHint:
|
|
41
|
+
return { toolsHint: messages.toolsHint, tools: named };
|
|
42
|
+
return { toolsHint: messages.unknownToolHint, tools: [], toolNames: tools.map((tool) => tool.name).sort() };
|
|
41
43
|
}
|
|
42
44
|
/** As the build info route: a failing provider answers `null` and logs the error class, so the build info still answers. */
|
|
43
45
|
async function readChangelog(provider) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-info.js","sourceRoot":"","sources":["../../src/server/server-info.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"server-info.js","sourceRoot":"","sources":["../../src/server/server-info.ts"],"names":[],"mappings":"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"}
|
package/module.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "mcp-access",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
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", "used_confirmations", "operation_tasks"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softure-ai/mcp-access",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
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",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"@softure-ai/core": "^0.2.0",
|
|
99
99
|
"@softure-ai/db": "^0.1.0",
|
|
100
100
|
"@softure-ai/security": "^0.2.0",
|
|
101
|
-
"zod": "^4.6.
|
|
101
|
+
"zod": "^4.6.7"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
104
|
"@modelcontextprotocol/server": "^2.0.0",
|
package/src/index.ts
CHANGED
|
@@ -51,7 +51,7 @@ export const API_TOKEN_RATE_LIMIT_BUCKETS = {
|
|
|
51
51
|
export const mcpAccess = defineModule({
|
|
52
52
|
manifest: {
|
|
53
53
|
id: MODULE_ID,
|
|
54
|
-
version: "0.7.
|
|
54
|
+
version: "0.7.1",
|
|
55
55
|
dependsOn: { security: "^0.2.0", auth: "^0.2.0", jobs: "^0.1.1?", ops: "^0.2.0?" },
|
|
56
56
|
dbSchema: "mcp",
|
|
57
57
|
tables: ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window", "used_confirmations", "operation_tasks"],
|
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
// import { readBuildInfo } from "@softure-ai/ops/server";
|
|
12
12
|
// createMcpServerFactory({ name: "acme", registerTools, serverInfoTool: { buildInfo: () => readBuildInfo() } });
|
|
13
13
|
import type { McpServer } from "@modelcontextprotocol/server";
|
|
14
|
-
import { errorLogLabel } from "@softure-ai/core";
|
|
14
|
+
import { errorLogLabel, type SoftureConfig } from "@softure-ai/core";
|
|
15
15
|
import { z } from "zod";
|
|
16
16
|
import { en } from "../messages/en.js";
|
|
17
|
+
import type { McpAccessMessages } from "../messages/index.js";
|
|
18
|
+
import { getMcpAccessMessages } from "./options.js";
|
|
17
19
|
import type { ServedTool } from "./tool-list.js";
|
|
18
20
|
import { toolResult } from "./tools.js";
|
|
19
21
|
|
|
@@ -37,10 +39,17 @@ export interface ServerInfoToolOptions {
|
|
|
37
39
|
* it on changes the tool's input schema, so the version changes once. Default: off.
|
|
38
40
|
*/
|
|
39
41
|
readonly tools?: boolean;
|
|
40
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* The app's config: the tool's texts (`serverInfoTool` of the messages) follow its locale and overrides (#1117).
|
|
44
|
+
* Default: the built-in English dictionary.
|
|
45
|
+
*/
|
|
46
|
+
readonly config?: SoftureConfig;
|
|
47
|
+
/** Default: `serverInfoTool.description` (or `descriptionWithTools`) of the messages. */
|
|
41
48
|
readonly description?: string;
|
|
42
49
|
}
|
|
43
50
|
|
|
51
|
+
type ServerInfoToolMessages = McpAccessMessages["serverInfoTool"];
|
|
52
|
+
|
|
44
53
|
/** One served tool's contract, exactly as `tools/list` answers it. */
|
|
45
54
|
export interface ServedToolContract {
|
|
46
55
|
readonly name: string;
|
|
@@ -82,7 +91,8 @@ export type ServerInfoAnswer = McpBuildInfo & { readonly server: ServedServerInf
|
|
|
82
91
|
*/
|
|
83
92
|
export function registerServerInfoTool(server: McpServer, options: RegisterServerInfoToolOptions): void {
|
|
84
93
|
const annotations = { readOnlyHint: true, idempotentHint: true, openWorldHint: false };
|
|
85
|
-
const
|
|
94
|
+
const messages = options.config === undefined ? en.serverInfoTool : getMcpAccessMessages(options.config).serverInfoTool;
|
|
95
|
+
const description = options.description ?? (options.tools === true ? messages.descriptionWithTools : messages.description);
|
|
86
96
|
if (options.tools !== true) {
|
|
87
97
|
// An empty object rather than no schema, so strict input refuses a field sent to it.
|
|
88
98
|
server.registerTool(SERVER_INFO_TOOL_NAME, { description, inputSchema: z.object({}), annotations }, async () => toolResult(await readServerInfo(options)));
|
|
@@ -94,10 +104,10 @@ export function registerServerInfoTool(server: McpServer, options: RegisterServe
|
|
|
94
104
|
}
|
|
95
105
|
server.registerTool(
|
|
96
106
|
SERVER_INFO_TOOL_NAME,
|
|
97
|
-
{ description, inputSchema: z.object({ name: z.string().optional().describe(
|
|
107
|
+
{ description, inputSchema: z.object({ name: z.string().optional().describe(messages.nameInputDescription) }), annotations },
|
|
98
108
|
async ({ name }) => {
|
|
99
109
|
const answer = await readServerInfo(options);
|
|
100
|
-
return toolResult({ ...answer, ...describeToolContract(await readServedTools(), name) });
|
|
110
|
+
return toolResult({ ...answer, ...describeToolContract(await readServedTools(), name, messages) });
|
|
101
111
|
},
|
|
102
112
|
);
|
|
103
113
|
}
|
|
@@ -109,12 +119,12 @@ async function readServerInfo(options: RegisterServerInfoToolOptions): Promise<S
|
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
/** The contract of every served tool, or of the one named; an unknown name answers no tool and every name. */
|
|
112
|
-
function describeToolContract(served: readonly ServedTool[], name: string | undefined): ServerInfoToolsAnswer {
|
|
122
|
+
function describeToolContract(served: readonly ServedTool[], name: string | undefined, messages: ServerInfoToolMessages): ServerInfoToolsAnswer {
|
|
113
123
|
const tools = served.map((tool): ServedToolContract => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema }));
|
|
114
|
-
if (name === undefined) return { toolsHint:
|
|
124
|
+
if (name === undefined) return { toolsHint: messages.toolsHint, tools };
|
|
115
125
|
const named = tools.filter((tool) => tool.name === name);
|
|
116
|
-
if (named.length > 0) return { toolsHint:
|
|
117
|
-
return { toolsHint:
|
|
126
|
+
if (named.length > 0) return { toolsHint: messages.toolsHint, tools: named };
|
|
127
|
+
return { toolsHint: messages.unknownToolHint, tools: [], toolNames: tools.map((tool) => tool.name).sort() };
|
|
118
128
|
}
|
|
119
129
|
|
|
120
130
|
/** As the build info route: a failing provider answers `null` and logs the error class, so the build info still answers. */
|