mcp-dataverse 0.2.5 → 0.3.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.
Files changed (132) hide show
  1. package/dist/doctor.d.ts +7 -0
  2. package/dist/doctor.d.ts.map +1 -0
  3. package/dist/doctor.js +103 -0
  4. package/dist/doctor.js.map +1 -0
  5. package/dist/http-server.d.ts +3 -0
  6. package/dist/http-server.d.ts.map +1 -0
  7. package/dist/http-server.js +61 -0
  8. package/dist/http-server.js.map +1 -0
  9. package/dist/resources/resource-provider.d.ts +11 -0
  10. package/dist/resources/resource-provider.d.ts.map +1 -0
  11. package/dist/resources/resource-provider.js +79 -0
  12. package/dist/resources/resource-provider.js.map +1 -0
  13. package/dist/server.js +132 -111
  14. package/dist/server.js.map +1 -1
  15. package/dist/tools/actions.tools.d.ts +36 -0
  16. package/dist/tools/actions.tools.d.ts.map +1 -1
  17. package/dist/tools/actions.tools.js +59 -24
  18. package/dist/tools/actions.tools.js.map +1 -1
  19. package/dist/tools/annotations.tools.d.ts +12 -0
  20. package/dist/tools/annotations.tools.d.ts.map +1 -1
  21. package/dist/tools/annotations.tools.js +26 -27
  22. package/dist/tools/annotations.tools.js.map +1 -1
  23. package/dist/tools/audit.tools.d.ts +6 -0
  24. package/dist/tools/audit.tools.d.ts.map +1 -1
  25. package/dist/tools/audit.tools.js +12 -9
  26. package/dist/tools/audit.tools.js.map +1 -1
  27. package/dist/tools/auth.tools.d.ts +6 -0
  28. package/dist/tools/auth.tools.d.ts.map +1 -1
  29. package/dist/tools/auth.tools.js +18 -14
  30. package/dist/tools/auth.tools.js.map +1 -1
  31. package/dist/tools/batch.tools.d.ts +8 -1
  32. package/dist/tools/batch.tools.d.ts.map +1 -1
  33. package/dist/tools/batch.tools.js +15 -10
  34. package/dist/tools/batch.tools.js.map +1 -1
  35. package/dist/tools/crud.tools.d.ts +36 -0
  36. package/dist/tools/crud.tools.d.ts.map +1 -1
  37. package/dist/tools/crud.tools.js +64 -58
  38. package/dist/tools/crud.tools.js.map +1 -1
  39. package/dist/tools/customization.tools.d.ts +18 -0
  40. package/dist/tools/customization.tools.d.ts.map +1 -1
  41. package/dist/tools/customization.tools.js +30 -32
  42. package/dist/tools/customization.tools.js.map +1 -1
  43. package/dist/tools/environment.tools.d.ts +12 -0
  44. package/dist/tools/environment.tools.d.ts.map +1 -1
  45. package/dist/tools/environment.tools.js +17 -8
  46. package/dist/tools/environment.tools.js.map +1 -1
  47. package/dist/tools/file.tools.d.ts +12 -0
  48. package/dist/tools/file.tools.d.ts.map +1 -1
  49. package/dist/tools/file.tools.js +31 -32
  50. package/dist/tools/file.tools.js.map +1 -1
  51. package/dist/tools/guardrails.d.ts +22 -0
  52. package/dist/tools/guardrails.d.ts.map +1 -0
  53. package/dist/tools/guardrails.js +55 -0
  54. package/dist/tools/guardrails.js.map +1 -0
  55. package/dist/tools/impersonate.tools.d.ts +8 -1
  56. package/dist/tools/impersonate.tools.d.ts.map +1 -1
  57. package/dist/tools/impersonate.tools.js +13 -13
  58. package/dist/tools/impersonate.tools.js.map +1 -1
  59. package/dist/tools/metadata.tools.d.ts +42 -0
  60. package/dist/tools/metadata.tools.d.ts.map +1 -1
  61. package/dist/tools/metadata.tools.js +99 -54
  62. package/dist/tools/metadata.tools.js.map +1 -1
  63. package/dist/tools/org.tools.d.ts +6 -0
  64. package/dist/tools/org.tools.d.ts.map +1 -1
  65. package/dist/tools/org.tools.js +11 -9
  66. package/dist/tools/org.tools.js.map +1 -1
  67. package/dist/tools/output.utils.d.ts +21 -0
  68. package/dist/tools/output.utils.d.ts.map +1 -0
  69. package/dist/tools/output.utils.js +31 -0
  70. package/dist/tools/output.utils.js.map +1 -0
  71. package/dist/tools/progress.d.ts +15 -0
  72. package/dist/tools/progress.d.ts.map +1 -0
  73. package/dist/tools/progress.js +29 -0
  74. package/dist/tools/progress.js.map +1 -0
  75. package/dist/tools/quality.tools.d.ts +6 -0
  76. package/dist/tools/quality.tools.d.ts.map +1 -1
  77. package/dist/tools/quality.tools.js +9 -4
  78. package/dist/tools/quality.tools.js.map +1 -1
  79. package/dist/tools/query.tools.d.ts +20 -1
  80. package/dist/tools/query.tools.d.ts.map +1 -1
  81. package/dist/tools/query.tools.js +48 -13
  82. package/dist/tools/query.tools.js.map +1 -1
  83. package/dist/tools/relations.tools.d.ts +12 -0
  84. package/dist/tools/relations.tools.d.ts.map +1 -1
  85. package/dist/tools/relations.tools.js +17 -22
  86. package/dist/tools/relations.tools.js.map +1 -1
  87. package/dist/tools/router.tools.d.ts +5 -0
  88. package/dist/tools/router.tools.d.ts.map +1 -0
  89. package/dist/tools/router.tools.js +247 -0
  90. package/dist/tools/router.tools.js.map +1 -0
  91. package/dist/tools/search.tools.d.ts +6 -0
  92. package/dist/tools/search.tools.d.ts.map +1 -1
  93. package/dist/tools/search.tools.js +12 -4
  94. package/dist/tools/search.tools.js.map +1 -1
  95. package/dist/tools/solution.tools.d.ts +18 -0
  96. package/dist/tools/solution.tools.d.ts.map +1 -1
  97. package/dist/tools/solution.tools.js +32 -17
  98. package/dist/tools/solution.tools.js.map +1 -1
  99. package/dist/tools/teams.tools.d.ts +6 -0
  100. package/dist/tools/teams.tools.d.ts.map +1 -1
  101. package/dist/tools/teams.tools.js +12 -9
  102. package/dist/tools/teams.tools.js.map +1 -1
  103. package/dist/tools/tool-registry.d.ts +35 -0
  104. package/dist/tools/tool-registry.d.ts.map +1 -0
  105. package/dist/tools/tool-registry.js +31 -0
  106. package/dist/tools/tool-registry.js.map +1 -0
  107. package/dist/tools/trace.tools.d.ts +12 -0
  108. package/dist/tools/trace.tools.d.ts.map +1 -1
  109. package/dist/tools/trace.tools.js +19 -8
  110. package/dist/tools/trace.tools.js.map +1 -1
  111. package/dist/tools/tracking.tools.d.ts +6 -0
  112. package/dist/tools/tracking.tools.d.ts.map +1 -1
  113. package/dist/tools/tracking.tools.js +14 -4
  114. package/dist/tools/tracking.tools.js.map +1 -1
  115. package/dist/tools/users.tools.d.ts +12 -0
  116. package/dist/tools/users.tools.d.ts.map +1 -1
  117. package/dist/tools/users.tools.js +23 -24
  118. package/dist/tools/users.tools.js.map +1 -1
  119. package/dist/tools/views.tools.d.ts +6 -0
  120. package/dist/tools/views.tools.d.ts.map +1 -1
  121. package/dist/tools/views.tools.js +16 -17
  122. package/dist/tools/views.tools.js.map +1 -1
  123. package/dist/tools/workflow.tools.d.ts +53 -0
  124. package/dist/tools/workflow.tools.d.ts.map +1 -0
  125. package/dist/tools/workflow.tools.js +198 -0
  126. package/dist/tools/workflow.tools.js.map +1 -0
  127. package/dist/transport.d.ts +6 -0
  128. package/dist/transport.d.ts.map +1 -0
  129. package/dist/transport.js +21 -0
  130. package/dist/transport.js.map +1 -0
  131. package/package.json +2 -1
  132. package/server.json +2 -2
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Diagnostic CLI command for mcp-dataverse.
4
+ * Usage: npx mcp-dataverse doctor
5
+ */
6
+ export declare function runDoctor(): Promise<void>;
7
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAyG/C"}
package/dist/doctor.js ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Diagnostic CLI command for mcp-dataverse.
4
+ * Usage: npx mcp-dataverse doctor
5
+ */
6
+ export async function runDoctor() {
7
+ const out = (msg) => process.stdout.write(msg + "\n");
8
+ const ok = (msg) => out(` ✅ ${msg}`);
9
+ const fail = (msg) => out(` ❌ ${msg}`);
10
+ out("");
11
+ out("🏥 mcp-dataverse doctor");
12
+ out("─".repeat(50));
13
+ out("");
14
+ let allPassed = true;
15
+ // 1. Node.js version check
16
+ out("📋 Environment");
17
+ const nodeVersion = process.version;
18
+ const major = parseInt(nodeVersion.slice(1).split(".")[0], 10);
19
+ if (major >= 20) {
20
+ ok(`Node.js ${nodeVersion}`);
21
+ }
22
+ else {
23
+ fail(`Node.js ${nodeVersion} — requires v20+`);
24
+ allPassed = false;
25
+ }
26
+ out("");
27
+ // 2. Configuration check
28
+ out("⚙️ Configuration");
29
+ try {
30
+ const { loadConfig } = await import("./config/config.loader.js");
31
+ const config = loadConfig();
32
+ ok(`Environment URL: ${config.environmentUrl}`);
33
+ ok(`Timeout: ${config.requestTimeoutMs}ms, Retries: ${config.maxRetries}`);
34
+ }
35
+ catch (err) {
36
+ const msg = err instanceof Error ? err.message : String(err);
37
+ fail(`Configuration error: ${msg}`);
38
+ allPassed = false;
39
+ // Can't proceed without config
40
+ out("");
41
+ out(allPassed ? "✅ All checks passed!" : "❌ Some checks failed.");
42
+ process.exit(allPassed ? 0 : 1);
43
+ }
44
+ out("");
45
+ // 3. Authentication check
46
+ out("🔑 Authentication");
47
+ try {
48
+ const { loadConfig } = await import("./config/config.loader.js");
49
+ const config = loadConfig();
50
+ const { createAuthProvider } = await import("./auth/auth-provider.factory.js");
51
+ const authProvider = createAuthProvider(config);
52
+ const token = await authProvider.getToken();
53
+ if (token) {
54
+ ok("Token acquired successfully");
55
+ const parts = token.split(".");
56
+ if (parts.length === 3) {
57
+ ok("Valid JWT token format");
58
+ }
59
+ }
60
+ else {
61
+ fail("No token returned");
62
+ allPassed = false;
63
+ }
64
+ }
65
+ catch (err) {
66
+ const msg = err instanceof Error ? err.message : String(err);
67
+ fail(`Auth failed: ${msg}`);
68
+ allPassed = false;
69
+ }
70
+ out("");
71
+ // 4. API Connectivity (WhoAmI)
72
+ out("🌐 Dataverse API");
73
+ try {
74
+ const { loadConfig } = await import("./config/config.loader.js");
75
+ const config = loadConfig();
76
+ const { createAuthProvider } = await import("./auth/auth-provider.factory.js");
77
+ const { DataverseAdvancedClient } = await import("./dataverse/dataverse-client-advanced.js");
78
+ const authProvider = createAuthProvider(config);
79
+ const client = new DataverseAdvancedClient(authProvider, config.maxRetries, config.requestTimeoutMs);
80
+ const result = await client.whoAmI();
81
+ ok(`Organization: ${result.OrganizationName || "N/A"}`);
82
+ ok(`User ID: ${result.UserId || "N/A"}`);
83
+ ok(`Business Unit: ${result.BusinessUnitId || "N/A"}`);
84
+ ok(`Environment: ${result.EnvironmentUrl || config.environmentUrl}`);
85
+ }
86
+ catch (err) {
87
+ const msg = err instanceof Error ? err.message : String(err);
88
+ fail(`API call failed: ${msg}`);
89
+ allPassed = false;
90
+ }
91
+ out("");
92
+ // Summary
93
+ out("─".repeat(50));
94
+ if (allPassed) {
95
+ out("✅ All checks passed! Your mcp-dataverse setup is healthy.");
96
+ }
97
+ else {
98
+ out("❌ Some checks failed. Review the errors above.");
99
+ }
100
+ out("");
101
+ process.exit(allPassed ? 0 : 1);
102
+ }
103
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ export declare function startHttpTransport(server: Server, port: number, version: string, toolCount: number): Promise<void>;
3
+ //# sourceMappingURL=http-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAInE,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA2Ef"}
@@ -0,0 +1,61 @@
1
+ import { createServer } from "http";
2
+ import { randomUUID } from "crypto";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ export async function startHttpTransport(server, port, version, toolCount) {
5
+ const transport = new StreamableHTTPServerTransport({
6
+ sessionIdGenerator: () => randomUUID(),
7
+ enableJsonResponse: true,
8
+ });
9
+ await server.connect(transport);
10
+ const httpServer = createServer(async (req, res) => {
11
+ // CORS headers for browser-based clients
12
+ res.setHeader("Access-Control-Allow-Origin", "*");
13
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
14
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, mcp-session-id");
15
+ if (req.method === "OPTIONS") {
16
+ res.writeHead(204);
17
+ res.end();
18
+ return;
19
+ }
20
+ const url = new URL(req.url ?? "/", `http://localhost:${port}`);
21
+ if (url.pathname === "/health" && req.method === "GET") {
22
+ res.writeHead(200, { "Content-Type": "application/json" });
23
+ res.end(JSON.stringify({ status: "ok", version, tools: toolCount }));
24
+ return;
25
+ }
26
+ if (url.pathname === "/mcp") {
27
+ try {
28
+ await transport.handleRequest(req, res);
29
+ }
30
+ catch {
31
+ if (!res.headersSent) {
32
+ res.writeHead(500, { "Content-Type": "application/json" });
33
+ res.end(JSON.stringify({ error: "Internal server error" }));
34
+ }
35
+ }
36
+ return;
37
+ }
38
+ res.writeHead(404, { "Content-Type": "application/json" });
39
+ res.end(JSON.stringify({ error: "Not found" }));
40
+ });
41
+ await new Promise((resolve) => {
42
+ httpServer.listen(port, () => {
43
+ process.stderr.write(`MCP Dataverse HTTP server listening on http://localhost:${port}/mcp\n`);
44
+ resolve();
45
+ });
46
+ });
47
+ // Keep the process alive; clean shutdown on signals
48
+ const shutdown = async () => {
49
+ process.stderr.write("Shutting down HTTP server...\n");
50
+ await transport.close();
51
+ httpServer.close();
52
+ process.exit(0);
53
+ };
54
+ process.on("SIGINT", shutdown);
55
+ process.on("SIGTERM", shutdown);
56
+ // Block until server closes
57
+ await new Promise((resolve) => {
58
+ httpServer.on("close", resolve);
59
+ });
60
+ }
61
+ //# sourceMappingURL=http-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Resource, ResourceTemplate } from "@modelcontextprotocol/sdk/types.js";
2
+ import type { DataverseAdvancedClient } from "../dataverse/dataverse-client-advanced.js";
3
+ export interface ResourceContent {
4
+ uri: string;
5
+ mimeType: string;
6
+ text: string;
7
+ }
8
+ export declare function listResources(): Resource[];
9
+ export declare function listResourceTemplates(): ResourceTemplate[];
10
+ export declare function readResource(uri: string, client: DataverseAdvancedClient, serverInstructions: string): Promise<ResourceContent>;
11
+ //# sourceMappingURL=resource-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-provider.d.ts","sourceRoot":"","sources":["../../src/resources/resource-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AA8EzF,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,IAAI,QAAQ,EAAE,CAE1C;AAED,wBAAgB,qBAAqB,IAAI,gBAAgB,EAAE,CAE1D;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,uBAAuB,EAC/B,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,eAAe,CAAC,CAoB1B"}
@@ -0,0 +1,79 @@
1
+ // ── Resource Templates (dynamic URIs with parameters) ────────────────────────
2
+ const RESOURCE_TEMPLATES = [
3
+ {
4
+ uriTemplate: "dataverse://tables/{tableName}/schema",
5
+ name: "Table Schema",
6
+ description: "Returns the full schema (columns, types, requirements) for a Dataverse table",
7
+ mimeType: "application/json",
8
+ },
9
+ {
10
+ uriTemplate: "dataverse://tables/{tableName}/relationships",
11
+ name: "Table Relationships",
12
+ description: "Returns all 1:N and N:N relationships for a Dataverse table",
13
+ mimeType: "application/json",
14
+ },
15
+ ];
16
+ // ── Static Resources (fixed URIs) ────────────────────────────────────────────
17
+ const STATIC_RESOURCES = [
18
+ {
19
+ uri: "dataverse://tables",
20
+ name: "Available Tables",
21
+ description: "Lists all custom tables in the connected Dataverse environment",
22
+ mimeType: "application/json",
23
+ },
24
+ {
25
+ uri: "dataverse://server/instructions",
26
+ name: "Server Instructions",
27
+ description: "Usage guidelines and best practices for interacting with this Dataverse MCP server",
28
+ mimeType: "text/plain",
29
+ },
30
+ ];
31
+ function parseResourceUri(uri) {
32
+ const PREFIX = "dataverse://";
33
+ if (!uri.startsWith(PREFIX)) {
34
+ throw new Error(`Unknown resource URI: ${uri}`);
35
+ }
36
+ const path = uri.slice(PREFIX.length);
37
+ if (path === "tables") {
38
+ return { type: "tables" };
39
+ }
40
+ if (path === "server/instructions") {
41
+ return { type: "instructions" };
42
+ }
43
+ const schemaMatch = /^tables\/([^/]+)\/schema$/.exec(path);
44
+ if (schemaMatch) {
45
+ return { type: "schema", tableName: schemaMatch[1] };
46
+ }
47
+ const relMatch = /^tables\/([^/]+)\/relationships$/.exec(path);
48
+ if (relMatch) {
49
+ return { type: "relationships", tableName: relMatch[1] };
50
+ }
51
+ throw new Error(`Unknown resource URI: ${uri}`);
52
+ }
53
+ export function listResources() {
54
+ return STATIC_RESOURCES;
55
+ }
56
+ export function listResourceTemplates() {
57
+ return RESOURCE_TEMPLATES;
58
+ }
59
+ export async function readResource(uri, client, serverInstructions) {
60
+ const parsed = parseResourceUri(uri);
61
+ switch (parsed.type) {
62
+ case "tables": {
63
+ const tables = await client.listTables(true);
64
+ return { uri, mimeType: "application/json", text: JSON.stringify(tables, null, 2) };
65
+ }
66
+ case "schema": {
67
+ const metadata = await client.getTableMetadata(parsed.tableName);
68
+ return { uri, mimeType: "application/json", text: JSON.stringify(metadata, null, 2) };
69
+ }
70
+ case "relationships": {
71
+ const rels = await client.getRelationships(parsed.tableName);
72
+ return { uri, mimeType: "application/json", text: JSON.stringify(rels, null, 2) };
73
+ }
74
+ case "instructions": {
75
+ return { uri, mimeType: "text/plain", text: serverInstructions };
76
+ }
77
+ }
78
+ }
79
+ //# sourceMappingURL=resource-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-provider.js","sourceRoot":"","sources":["../../src/resources/resource-provider.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -1,13 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
5
  import { readFileSync } from "fs";
6
6
  import { join, dirname } from "path";
7
7
  import { fileURLToPath } from "url";
8
+ import { parseTransportArgs } from "./transport.js";
8
9
  import { loadConfig } from "./config/config.loader.js";
9
10
  import { createAuthProvider } from "./auth/auth-provider.factory.js";
10
11
  import { DataverseAdvancedClient } from "./dataverse/dataverse-client-advanced.js";
12
+ import { createToolRegistry } from "./tools/tool-registry.js";
13
+ import { ProgressReporter } from "./tools/progress.js";
11
14
  import { authTools, handleAuthTool } from "./tools/auth.tools.js";
12
15
  import { metadataTools, handleMetadataTool } from "./tools/metadata.tools.js";
13
16
  import { queryTools, handleQueryTool } from "./tools/query.tools.js";
@@ -30,120 +33,102 @@ import { viewTools, handleViewTool } from "./tools/views.tools.js";
30
33
  import { orgTools, handleOrgTool } from "./tools/org.tools.js";
31
34
  import { fileTools, handleFileTool } from "./tools/file.tools.js";
32
35
  import { teamTools, handleTeamTool } from "./tools/teams.tools.js";
33
- const ALL_TOOLS = [
34
- ...authTools,
35
- ...metadataTools,
36
- ...queryTools,
37
- ...crudTools,
38
- ...relationTools,
39
- ...actionTools,
40
- ...batchTools,
41
- ...trackingTools,
42
- ...solutionTools,
43
- ...impersonateTools,
44
- ...customizationTools,
45
- ...environmentTools,
46
- ...traceTools,
47
- ...searchTools,
48
- ...auditTools,
49
- ...qualityTools,
50
- ...annotationTools,
51
- ...userTools,
52
- ...viewTools,
53
- ...orgTools,
54
- ...fileTools,
55
- ...teamTools,
56
- ];
57
- // Pre-build routing sets once at startup to avoid per-request allocations
58
- const AUTH_TOOL_NAMES = new Set(authTools.map((t) => t.name));
59
- const METADATA_TOOL_NAMES = new Set(metadataTools.map((t) => t.name));
60
- const QUERY_TOOL_NAMES = new Set(queryTools.map((t) => t.name));
61
- const CRUD_TOOL_NAMES = new Set(crudTools.map((t) => t.name));
62
- const RELATION_TOOL_NAMES = new Set(relationTools.map((t) => t.name));
63
- const ACTION_TOOL_NAMES = new Set(actionTools.map((t) => t.name));
64
- const BATCH_TOOL_NAMES = new Set(batchTools.map((t) => t.name));
65
- const TRACKING_TOOL_NAMES = new Set(trackingTools.map((t) => t.name));
66
- const SOLUTION_TOOL_NAMES = new Set(solutionTools.map((t) => t.name));
67
- const IMPERSONATE_TOOL_NAMES = new Set(impersonateTools.map((t) => t.name));
68
- const CUSTOMIZATION_TOOL_NAMES = new Set(customizationTools.map((t) => t.name));
69
- const ENVIRONMENT_TOOL_NAMES = new Set(environmentTools.map((t) => t.name));
70
- const TRACE_TOOL_NAMES = new Set(traceTools.map((t) => t.name));
71
- const SEARCH_TOOL_NAMES = new Set(searchTools.map((t) => t.name));
72
- const AUDIT_TOOL_NAMES = new Set(auditTools.map((t) => t.name));
73
- const QUALITY_TOOL_NAMES = new Set(qualityTools.map((t) => t.name));
74
- const ANNOTATION_TOOL_NAMES = new Set(annotationTools.map((t) => t.name));
75
- const USER_TOOL_NAMES = new Set(userTools.map((t) => t.name));
76
- const VIEW_TOOL_NAMES = new Set(viewTools.map((t) => t.name));
77
- const ORG_TOOL_NAMES = new Set(orgTools.map((t) => t.name));
78
- const FILE_TOOL_NAMES = new Set(fileTools.map((t) => t.name));
79
- const TEAM_TOOL_NAMES = new Set(teamTools.map((t) => t.name));
36
+ import { routerTools, handleRouterTool } from "./tools/router.tools.js";
37
+ import { listResources, listResourceTemplates, readResource, } from "./resources/resource-provider.js";
38
+ import { workflowTools, handleWorkflowTool } from "./tools/workflow.tools.js";
39
+ // ── Tool Registry — Map-based O(1) dispatch ──────────────────────────────────
40
+ const registry = createToolRegistry([
41
+ { tools: authTools, handler: handleAuthTool },
42
+ { tools: metadataTools, handler: handleMetadataTool },
43
+ { tools: queryTools, handler: handleQueryTool },
44
+ { tools: crudTools, handler: handleCrudTool },
45
+ { tools: relationTools, handler: handleRelationTool },
46
+ { tools: actionTools, handler: handleActionTool },
47
+ { tools: batchTools, handler: handleBatchTool },
48
+ { tools: trackingTools, handler: handleTrackingTool },
49
+ { tools: solutionTools, handler: handleSolutionTool },
50
+ { tools: customizationTools, handler: handleCustomizationTool },
51
+ { tools: environmentTools, handler: handleEnvironmentTool },
52
+ { tools: traceTools, handler: handleTraceTool },
53
+ { tools: searchTools, handler: handleSearchTool },
54
+ { tools: auditTools, handler: handleAuditTool },
55
+ { tools: qualityTools, handler: handleQualityTool },
56
+ { tools: annotationTools, handler: handleAnnotationTool },
57
+ { tools: userTools, handler: handleUserTool },
58
+ { tools: viewTools, handler: handleViewTool },
59
+ { tools: orgTools, handler: handleOrgTool },
60
+ { tools: fileTools, handler: handleFileTool },
61
+ { tools: teamTools, handler: handleTeamTool },
62
+ { tools: workflowTools, handler: handleWorkflowTool },
63
+ { tools: routerTools, handler: handleRouterTool },
64
+ ]);
65
+ // Impersonate is registered separately it has a special dispatch signature
66
+ const IMPERSONATE_NAMES = new Set(impersonateTools.map((t) => t.name));
80
67
  // Read version from package.json so server.ts never drifts out of sync
81
68
  const __dirname = dirname(fileURLToPath(import.meta.url));
82
69
  const SERVER_VERSION = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")).version;
70
+ // ── Global MCP Instructions ──────────────────────────────────────────────────
71
+ const SERVER_INSTRUCTIONS = `You are connected to a Microsoft Dataverse environment via the mcp-dataverse server.
72
+
73
+ ## Recommended Workflow
74
+ 1. Start with dataverse_whoami to verify authentication.
75
+ 2. Use dataverse_list_tables to discover available tables (custom tables only by default).
76
+ 3. Use dataverse_get_table_metadata to inspect column names, types, and required fields before querying or writing.
77
+ 4. Query data with dataverse_query (OData) or dataverse_execute_fetchxml (complex joins/aggregations).
78
+ 5. Use dataverse_create / dataverse_update / dataverse_delete for record operations.
79
+
80
+ ## Best Practices
81
+ - Always specify $select to minimize payload size — never fetch all columns.
82
+ - Use $top to limit results (default 50, max 5000 per page).
83
+ - Prefer dataverse_query for simple reads; use dataverse_execute_fetchxml for aggregations, multi-table joins, or many-to-many traversal.
84
+ - Use dataverse_get_table_metadata before creating/updating records to confirm correct logical field names.
85
+ - For bulk operations (>5 records), use dataverse_batch_execute to reduce HTTP round-trips.
86
+ - Use dataverse_search for full-text search across multiple tables when you don't know which table contains the data.
87
+ - Check dataverse_get_relationships before building FetchXML joins or using dataverse_associate/dataverse_disassociate.
88
+
89
+ ## Safety
90
+ - dataverse_delete is irreversible — always confirm with the user first.
91
+ - Use optimistic concurrency (etag parameter) on updates to prevent lost changes.
92
+ - Impersonation requires explicit privilege and is denied for System Administrator users.
93
+
94
+ ## Performance
95
+ - Avoid retrieving more than 5000 records unless explicitly needed (use dataverse_retrieve_multiple_with_paging with maxTotal).
96
+ - Use server-side filtering ($filter / FetchXML conditions) instead of client-side filtering.
97
+ - Cache table metadata — it rarely changes during a session.
98
+ `;
83
99
  /**
84
- * Routes a tool call to its handler. Used directly by the request handler
85
- * and passed as the dispatch function to handleImpersonateTool.
100
+ * Routes a tool call to its handler via the registry Map.
101
+ * Used directly by the request handler and passed as the dispatch
102
+ * function to handleImpersonateTool.
86
103
  */
87
- async function dispatchTool(name, args, client) {
88
- if (AUTH_TOOL_NAMES.has(name))
89
- return handleAuthTool(name, args, client);
90
- if (METADATA_TOOL_NAMES.has(name))
91
- return handleMetadataTool(name, args, client);
92
- if (QUERY_TOOL_NAMES.has(name))
93
- return handleQueryTool(name, args, client);
94
- if (CRUD_TOOL_NAMES.has(name))
95
- return handleCrudTool(name, args, client);
96
- if (RELATION_TOOL_NAMES.has(name))
97
- return handleRelationTool(name, args, client);
98
- if (ACTION_TOOL_NAMES.has(name))
99
- return handleActionTool(name, args, client);
100
- if (BATCH_TOOL_NAMES.has(name))
101
- return handleBatchTool(name, args, client);
102
- if (TRACKING_TOOL_NAMES.has(name))
103
- return handleTrackingTool(name, args, client);
104
- if (SOLUTION_TOOL_NAMES.has(name))
105
- return handleSolutionTool(name, args, client);
106
- if (CUSTOMIZATION_TOOL_NAMES.has(name))
107
- return handleCustomizationTool(name, args, client);
108
- if (ENVIRONMENT_TOOL_NAMES.has(name))
109
- return handleEnvironmentTool(name, args, client);
110
- if (TRACE_TOOL_NAMES.has(name))
111
- return handleTraceTool(name, args, client);
112
- if (SEARCH_TOOL_NAMES.has(name))
113
- return handleSearchTool(name, args, client);
114
- if (AUDIT_TOOL_NAMES.has(name))
115
- return handleAuditTool(name, args, client);
116
- if (QUALITY_TOOL_NAMES.has(name))
117
- return handleQualityTool(name, args, client);
118
- if (ANNOTATION_TOOL_NAMES.has(name))
119
- return handleAnnotationTool(name, args, client);
120
- if (USER_TOOL_NAMES.has(name))
121
- return handleUserTool(name, args, client);
122
- if (VIEW_TOOL_NAMES.has(name))
123
- return handleViewTool(name, args, client);
124
- if (ORG_TOOL_NAMES.has(name))
125
- return handleOrgTool(name, args, client);
126
- if (FILE_TOOL_NAMES.has(name))
127
- return handleFileTool(name, args, client);
128
- if (TEAM_TOOL_NAMES.has(name))
129
- return handleTeamTool(name, args, client);
130
- throw new Error(`Unknown tool: ${name}`);
104
+ function dispatchTool(name, args, client, progress) {
105
+ const handler = registry.getHandler(name);
106
+ if (!handler)
107
+ throw new Error(`Unknown tool: ${name}`);
108
+ return handler(name, args, client, progress);
131
109
  }
132
110
  async function main() {
133
111
  const config = loadConfig();
134
112
  const authProvider = createAuthProvider(config);
135
113
  const client = new DataverseAdvancedClient(authProvider, config.maxRetries, config.requestTimeoutMs);
136
- const server = new Server({ name: "mcp-dataverse", version: SERVER_VERSION }, { capabilities: { tools: {} } });
114
+ const server = new Server({ name: "mcp-dataverse", version: SERVER_VERSION }, {
115
+ capabilities: { tools: {}, resources: {} },
116
+ instructions: SERVER_INSTRUCTIONS,
117
+ });
118
+ // Combine registry definitions with impersonate tools
119
+ const allToolDefs = [...registry.getAllDefinitions(), ...impersonateTools];
137
120
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
138
- tools: ALL_TOOLS,
121
+ tools: allToolDefs,
139
122
  }));
140
123
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
141
124
  const { name, arguments: args } = request.params;
125
+ const progressToken = request.params._meta?.progressToken;
126
+ const progress = new ProgressReporter(progressToken != null ? server : undefined, progressToken);
142
127
  try {
143
- if (IMPERSONATE_TOOL_NAMES.has(name)) {
128
+ if (IMPERSONATE_NAMES.has(name)) {
144
129
  return handleImpersonateTool(name, args, client, dispatchTool);
145
130
  }
146
- return await dispatchTool(name, args, client);
131
+ return await dispatchTool(name, args, client, progress);
147
132
  }
148
133
  catch (error) {
149
134
  const message = error instanceof Error ? error.message : String(error);
@@ -153,26 +138,62 @@ async function main() {
153
138
  };
154
139
  }
155
140
  });
156
- const transport = new StdioServerTransport();
157
- await server.connect(transport);
158
- // Do not log to stdout — stdio transport uses stdout for protocol messages
159
- process.stderr.write("MCP Dataverse server started\n");
160
- // Proactively trigger authentication at startup so the device-code prompt
161
- // appears immediately in the VS Code MCP Output panel (View → Output → MCP),
162
- // rather than only on the first tool call.
163
- authProvider.getToken().then(() => {
164
- process.stderr.write("[mcp-dataverse] Authenticated ✓\n");
165
- }).catch((err) => {
166
- const msg = err instanceof Error ? err.message : String(err);
167
- process.stderr.write(`[mcp-dataverse] Authentication failed: ${msg}\n`);
141
+ // ── Resource Handlers ────────────────────────────────────────────────────
142
+ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
143
+ resources: listResources(),
144
+ }));
145
+ server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
146
+ resourceTemplates: listResourceTemplates(),
147
+ }));
148
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
149
+ const contents = await readResource(request.params.uri, client, SERVER_INSTRUCTIONS);
150
+ return { contents: [contents] };
168
151
  });
152
+ const transportArgs = parseTransportArgs();
153
+ if (transportArgs.transport === "http") {
154
+ const { startHttpTransport } = await import("./http-server.js");
155
+ const toolCount = allToolDefs.length;
156
+ process.stderr.write(`Starting HTTP transport on port ${transportArgs.port}...\n`);
157
+ // Trigger auth before accepting requests
158
+ try {
159
+ await authProvider.getToken();
160
+ process.stderr.write("[mcp-dataverse] Authenticated ✓\n");
161
+ }
162
+ catch (err) {
163
+ const msg = err instanceof Error ? err.message : String(err);
164
+ process.stderr.write(`[mcp-dataverse] Authentication failed: ${msg}\n`);
165
+ }
166
+ await startHttpTransport(server, transportArgs.port, SERVER_VERSION, toolCount);
167
+ }
168
+ else {
169
+ const transport = new StdioServerTransport();
170
+ await server.connect(transport);
171
+ // Do not log to stdout — stdio transport uses stdout for protocol messages
172
+ process.stderr.write("MCP Dataverse server started\n");
173
+ // Proactively trigger authentication at startup so the device-code prompt
174
+ // appears immediately in the VS Code MCP Output panel (View → Output → MCP),
175
+ // rather than only on the first tool call.
176
+ authProvider
177
+ .getToken()
178
+ .then(() => {
179
+ process.stderr.write("[mcp-dataverse] Authenticated ✓\n");
180
+ })
181
+ .catch((err) => {
182
+ const msg = err instanceof Error ? err.message : String(err);
183
+ process.stderr.write(`[mcp-dataverse] Authentication failed: ${msg}\n`);
184
+ });
185
+ }
169
186
  }
170
187
  async function entry() {
171
- if (process.argv[2] === "install") {
188
+ if (process.argv.includes("install")) {
172
189
  const { runInstall } = await import("./install.js");
173
190
  await runInstall();
174
191
  process.exit(0);
175
192
  }
193
+ if (process.argv.includes("doctor")) {
194
+ const { runDoctor } = await import("./doctor.js");
195
+ await runDoctor();
196
+ }
176
197
  await main();
177
198
  }
178
199
  entry().catch((error) => {