@softure-ai/mcp-access 0.1.11 → 0.1.13

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.
Files changed (136) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +136 -11
  3. package/dist/cli/bin.d.ts +3 -0
  4. package/dist/cli/bin.d.ts.map +1 -0
  5. package/dist/cli/bin.js +5 -0
  6. package/dist/cli/bin.js.map +1 -0
  7. package/dist/cli/command.d.ts +9 -0
  8. package/dist/cli/command.d.ts.map +1 -0
  9. package/dist/cli/command.js +30 -0
  10. package/dist/cli/command.js.map +1 -0
  11. package/dist/cli/index.d.ts +3 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +4 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/run.d.ts +24 -0
  16. package/dist/cli/run.d.ts.map +1 -0
  17. package/dist/cli/run.js +58 -0
  18. package/dist/cli/run.js.map +1 -0
  19. package/dist/contract.d.ts +4 -2
  20. package/dist/contract.d.ts.map +1 -1
  21. package/dist/index.d.ts +20 -7
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +6 -11
  24. package/dist/index.js.map +1 -1
  25. package/dist/messages/en.d.ts +2 -0
  26. package/dist/messages/en.d.ts.map +1 -1
  27. package/dist/messages/en.js +2 -0
  28. package/dist/messages/en.js.map +1 -1
  29. package/dist/messages/index.d.ts +4 -0
  30. package/dist/messages/index.d.ts.map +1 -1
  31. package/dist/messages/pl.d.ts.map +1 -1
  32. package/dist/messages/pl.js +2 -0
  33. package/dist/messages/pl.js.map +1 -1
  34. package/dist/next/actions.d.ts +2 -2
  35. package/dist/next/actions.d.ts.map +1 -1
  36. package/dist/next/actions.js +8 -47
  37. package/dist/next/actions.js.map +1 -1
  38. package/dist/next/format.d.ts +1 -1
  39. package/dist/next/format.d.ts.map +1 -1
  40. package/dist/next/format.js +3 -1
  41. package/dist/next/format.js.map +1 -1
  42. package/dist/next/index.d.ts +3 -2
  43. package/dist/next/index.d.ts.map +1 -1
  44. package/dist/next/index.js +2 -1
  45. package/dist/next/index.js.map +1 -1
  46. package/dist/next/issue-token.d.ts +15 -0
  47. package/dist/next/issue-token.d.ts.map +1 -0
  48. package/dist/next/issue-token.js +77 -0
  49. package/dist/next/issue-token.js.map +1 -0
  50. package/dist/next/pages.d.ts +9 -1
  51. package/dist/next/pages.d.ts.map +1 -1
  52. package/dist/next/pages.js +2 -2
  53. package/dist/next/pages.js.map +1 -1
  54. package/dist/options.d.ts +16 -0
  55. package/dist/options.d.ts.map +1 -1
  56. package/dist/options.js +7 -3
  57. package/dist/options.js.map +1 -1
  58. package/dist/origins.d.ts +3 -14
  59. package/dist/origins.d.ts.map +1 -1
  60. package/dist/origins.js +4 -20
  61. package/dist/origins.js.map +1 -1
  62. package/dist/routes.d.ts +15 -0
  63. package/dist/routes.d.ts.map +1 -0
  64. package/dist/routes.js +17 -0
  65. package/dist/routes.js.map +1 -0
  66. package/dist/server/action-tool.d.ts +21 -0
  67. package/dist/server/action-tool.d.ts.map +1 -0
  68. package/dist/server/action-tool.js +51 -0
  69. package/dist/server/action-tool.js.map +1 -0
  70. package/dist/server/index.d.ts +3 -0
  71. package/dist/server/index.d.ts.map +1 -1
  72. package/dist/server/index.js +3 -0
  73. package/dist/server/index.js.map +1 -1
  74. package/dist/server/oauth-http.js +1 -1
  75. package/dist/server/oauth-http.js.map +1 -1
  76. package/dist/server/origins.d.ts +1 -1
  77. package/dist/server/origins.d.ts.map +1 -1
  78. package/dist/server/origins.js +7 -2
  79. package/dist/server/origins.js.map +1 -1
  80. package/dist/server/prune.d.ts +8 -0
  81. package/dist/server/prune.d.ts.map +1 -0
  82. package/dist/server/prune.js +10 -0
  83. package/dist/server/prune.js.map +1 -0
  84. package/dist/server/tools.d.ts +25 -0
  85. package/dist/server/tools.d.ts.map +1 -0
  86. package/dist/server/tools.js +61 -0
  87. package/dist/server/tools.js.map +1 -0
  88. package/dist/stdio/index.d.ts +2 -0
  89. package/dist/stdio/index.d.ts.map +1 -0
  90. package/dist/stdio/index.js +4 -0
  91. package/dist/stdio/index.js.map +1 -0
  92. package/dist/stdio/register.d.ts +2 -0
  93. package/dist/stdio/register.d.ts.map +1 -0
  94. package/dist/stdio/register.js +10 -0
  95. package/dist/stdio/register.js.map +1 -0
  96. package/dist/stdio/serve.d.ts +45 -0
  97. package/dist/stdio/serve.d.ts.map +1 -0
  98. package/dist/stdio/serve.js +89 -0
  99. package/dist/stdio/serve.js.map +1 -0
  100. package/dist/testing/catalog.d.ts +15 -0
  101. package/dist/testing/catalog.d.ts.map +1 -0
  102. package/dist/testing/catalog.js +51 -0
  103. package/dist/testing/catalog.js.map +1 -0
  104. package/dist/testing/index.d.ts +2 -0
  105. package/dist/testing/index.d.ts.map +1 -0
  106. package/dist/testing/index.js +3 -0
  107. package/dist/testing/index.js.map +1 -0
  108. package/module.json +1 -1
  109. package/package.json +31 -5
  110. package/src/cli/bin.ts +5 -0
  111. package/src/cli/command.ts +38 -0
  112. package/src/cli/index.ts +3 -0
  113. package/src/cli/run.ts +79 -0
  114. package/src/contract.ts +5 -2
  115. package/src/index.ts +9 -12
  116. package/src/messages/en.ts +2 -0
  117. package/src/messages/pl.ts +2 -0
  118. package/src/next/actions.ts +8 -45
  119. package/src/next/format.ts +2 -2
  120. package/src/next/index.ts +3 -2
  121. package/src/next/issue-token.ts +90 -0
  122. package/src/next/pages.tsx +11 -3
  123. package/src/options.ts +7 -3
  124. package/src/origins.ts +6 -27
  125. package/src/routes.ts +17 -0
  126. package/src/server/action-tool.ts +64 -0
  127. package/src/server/index.ts +3 -0
  128. package/src/server/oauth-http.ts +1 -1
  129. package/src/server/origins.ts +6 -5
  130. package/src/server/prune.ts +14 -0
  131. package/src/server/tools.ts +72 -0
  132. package/src/stdio/index.ts +12 -0
  133. package/src/stdio/register.ts +11 -0
  134. package/src/stdio/serve.ts +133 -0
  135. package/src/testing/catalog.ts +74 -0
  136. package/src/testing/index.ts +2 -0
@@ -0,0 +1,74 @@
1
+ // Catalog parity: the tools listed in softure.config.ts (the token page shows them, agent docs read
2
+ // them) against the tools the app's MCP server really registers, for a read-only and a write identity.
3
+ // Framework-free: `expectToolCatalogMatchesServer` throws, so it works in any test runner.
4
+ import { createMcpHandler } from "@modelcontextprotocol/server";
5
+ import type { SoftureConfig } from "@softure-ai/core";
6
+ import type { McpServerIdentity } from "../contract.js";
7
+ import type { McpServerFactory } from "../server/endpoint.js";
8
+ import { getMcpAccessOptions } from "../server/options.js";
9
+
10
+ export interface ToolCatalogDifferences {
11
+ /** Configured tools the server does not register for the identity that should get them. */
12
+ readonly missing: readonly string[];
13
+ /** Tools the server registers that the catalog does not list. */
14
+ readonly unlisted: readonly string[];
15
+ /** Configured write tools the server gives a read-only identity. */
16
+ readonly writeForReaders: readonly string[];
17
+ }
18
+
19
+ const READER: McpServerIdentity = { userId: "00000000-0000-4000-8000-000000000001", canWrite: false, tokenId: "catalog-check" };
20
+ const WRITER: McpServerIdentity = { ...READER, canWrite: true };
21
+
22
+ /** Every difference between the configured catalog and the server, each list in the catalog's order, then the server's. */
23
+ export async function getToolCatalogDifferences(config: SoftureConfig, createServer: McpServerFactory): Promise<ToolCatalogDifferences> {
24
+ const catalog = getMcpAccessOptions(config).tools;
25
+ const forReaders = await listServerTools(createServer, READER);
26
+ const forWriters = await listServerTools(createServer, WRITER);
27
+ const listed = new Set(catalog.map((tool) => tool.name));
28
+ return {
29
+ missing: catalog.filter((tool) => !(tool.access === "read" ? forReaders.includes(tool.name) && forWriters.includes(tool.name) : forWriters.includes(tool.name))).map((tool) => tool.name),
30
+ unlisted: [...new Set([...forReaders, ...forWriters])].filter((name) => !listed.has(name)),
31
+ writeForReaders: catalog.filter((tool) => tool.access === "write" && forReaders.includes(tool.name)).map((tool) => tool.name),
32
+ };
33
+ }
34
+
35
+ /** Throws a list of every difference, e.g. in a unit test next to the server. */
36
+ export async function expectToolCatalogMatchesServer(config: SoftureConfig, createServer: McpServerFactory): Promise<void> {
37
+ const differences = await getToolCatalogDifferences(config, createServer);
38
+ const problems = [
39
+ differences.missing.length > 0 ? `missing from the server: ${differences.missing.join(", ")}` : null,
40
+ differences.unlisted.length > 0 ? `registered but not in the catalog: ${differences.unlisted.join(", ")}` : null,
41
+ differences.writeForReaders.length > 0 ? `write tools a read-only token gets: ${differences.writeForReaders.join(", ")}` : null,
42
+ ].filter((problem) => problem !== null);
43
+ if (problems.length > 0) {
44
+ throw new Error(`@softure-ai/mcp-access: the tool catalog in softure.config.ts does not match the MCP server: ${problems.join("; ")}`);
45
+ }
46
+ }
47
+
48
+ /** The tool names a fresh server lists for the identity, asked the way the endpoint serves it. */
49
+ async function listServerTools(createServer: McpServerFactory, identity: McpServerIdentity): Promise<string[]> {
50
+ const handler = createMcpHandler(() => createServer(identity), { responseMode: "json" });
51
+ const response = await handler.fetch(
52
+ new Request("http://localhost/api/mcp", {
53
+ method: "POST",
54
+ headers: { "content-type": "application/json", accept: "application/json, text/event-stream" },
55
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list", params: {} }),
56
+ }),
57
+ );
58
+ const answer = readAnswer(await response.text());
59
+ if (answer.result?.tools === undefined) {
60
+ throw new Error(`@softure-ai/mcp-access: listing the server's tools failed: ${typeof answer.error?.message === "string" ? answer.error.message : `HTTP ${String(response.status)}`}`);
61
+ }
62
+ return answer.result.tools.map((tool) => (typeof tool.name === "string" ? tool.name : "")).filter((name) => name !== "");
63
+ }
64
+
65
+ interface ToolsListAnswer {
66
+ readonly result?: { readonly tools?: readonly { readonly name?: unknown }[] };
67
+ readonly error?: { readonly message?: unknown };
68
+ }
69
+
70
+ /** The JSON-RPC answer, sent as JSON or as one SSE `message` event. */
71
+ function readAnswer(body: string): ToolsListAnswer {
72
+ const data = body.startsWith("event:") ? (body.split("\n").find((line) => line.startsWith("data: "))?.slice("data: ".length) ?? "null") : body;
73
+ return (JSON.parse(data) ?? {}) as ToolsListAnswer;
74
+ }
@@ -0,0 +1,2 @@
1
+ // `@softure-ai/mcp-access/testing`: checks for an app's own tests.
2
+ export { expectToolCatalogMatchesServer, getToolCatalogDifferences, type ToolCatalogDifferences } from "./catalog.js";