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.
- package/dist/doctor.d.ts +7 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +103 -0
- package/dist/doctor.js.map +1 -0
- package/dist/http-server.d.ts +3 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +61 -0
- package/dist/http-server.js.map +1 -0
- package/dist/resources/resource-provider.d.ts +11 -0
- package/dist/resources/resource-provider.d.ts.map +1 -0
- package/dist/resources/resource-provider.js +79 -0
- package/dist/resources/resource-provider.js.map +1 -0
- package/dist/server.js +132 -111
- package/dist/server.js.map +1 -1
- package/dist/tools/actions.tools.d.ts +36 -0
- package/dist/tools/actions.tools.d.ts.map +1 -1
- package/dist/tools/actions.tools.js +59 -24
- package/dist/tools/actions.tools.js.map +1 -1
- package/dist/tools/annotations.tools.d.ts +12 -0
- package/dist/tools/annotations.tools.d.ts.map +1 -1
- package/dist/tools/annotations.tools.js +26 -27
- package/dist/tools/annotations.tools.js.map +1 -1
- package/dist/tools/audit.tools.d.ts +6 -0
- package/dist/tools/audit.tools.d.ts.map +1 -1
- package/dist/tools/audit.tools.js +12 -9
- package/dist/tools/audit.tools.js.map +1 -1
- package/dist/tools/auth.tools.d.ts +6 -0
- package/dist/tools/auth.tools.d.ts.map +1 -1
- package/dist/tools/auth.tools.js +18 -14
- package/dist/tools/auth.tools.js.map +1 -1
- package/dist/tools/batch.tools.d.ts +8 -1
- package/dist/tools/batch.tools.d.ts.map +1 -1
- package/dist/tools/batch.tools.js +15 -10
- package/dist/tools/batch.tools.js.map +1 -1
- package/dist/tools/crud.tools.d.ts +36 -0
- package/dist/tools/crud.tools.d.ts.map +1 -1
- package/dist/tools/crud.tools.js +64 -58
- package/dist/tools/crud.tools.js.map +1 -1
- package/dist/tools/customization.tools.d.ts +18 -0
- package/dist/tools/customization.tools.d.ts.map +1 -1
- package/dist/tools/customization.tools.js +30 -32
- package/dist/tools/customization.tools.js.map +1 -1
- package/dist/tools/environment.tools.d.ts +12 -0
- package/dist/tools/environment.tools.d.ts.map +1 -1
- package/dist/tools/environment.tools.js +17 -8
- package/dist/tools/environment.tools.js.map +1 -1
- package/dist/tools/file.tools.d.ts +12 -0
- package/dist/tools/file.tools.d.ts.map +1 -1
- package/dist/tools/file.tools.js +31 -32
- package/dist/tools/file.tools.js.map +1 -1
- package/dist/tools/guardrails.d.ts +22 -0
- package/dist/tools/guardrails.d.ts.map +1 -0
- package/dist/tools/guardrails.js +55 -0
- package/dist/tools/guardrails.js.map +1 -0
- package/dist/tools/impersonate.tools.d.ts +8 -1
- package/dist/tools/impersonate.tools.d.ts.map +1 -1
- package/dist/tools/impersonate.tools.js +13 -13
- package/dist/tools/impersonate.tools.js.map +1 -1
- package/dist/tools/metadata.tools.d.ts +42 -0
- package/dist/tools/metadata.tools.d.ts.map +1 -1
- package/dist/tools/metadata.tools.js +99 -54
- package/dist/tools/metadata.tools.js.map +1 -1
- package/dist/tools/org.tools.d.ts +6 -0
- package/dist/tools/org.tools.d.ts.map +1 -1
- package/dist/tools/org.tools.js +11 -9
- package/dist/tools/org.tools.js.map +1 -1
- package/dist/tools/output.utils.d.ts +21 -0
- package/dist/tools/output.utils.d.ts.map +1 -0
- package/dist/tools/output.utils.js +31 -0
- package/dist/tools/output.utils.js.map +1 -0
- package/dist/tools/progress.d.ts +15 -0
- package/dist/tools/progress.d.ts.map +1 -0
- package/dist/tools/progress.js +29 -0
- package/dist/tools/progress.js.map +1 -0
- package/dist/tools/quality.tools.d.ts +6 -0
- package/dist/tools/quality.tools.d.ts.map +1 -1
- package/dist/tools/quality.tools.js +9 -4
- package/dist/tools/quality.tools.js.map +1 -1
- package/dist/tools/query.tools.d.ts +20 -1
- package/dist/tools/query.tools.d.ts.map +1 -1
- package/dist/tools/query.tools.js +48 -13
- package/dist/tools/query.tools.js.map +1 -1
- package/dist/tools/relations.tools.d.ts +12 -0
- package/dist/tools/relations.tools.d.ts.map +1 -1
- package/dist/tools/relations.tools.js +17 -22
- package/dist/tools/relations.tools.js.map +1 -1
- package/dist/tools/router.tools.d.ts +5 -0
- package/dist/tools/router.tools.d.ts.map +1 -0
- package/dist/tools/router.tools.js +247 -0
- package/dist/tools/router.tools.js.map +1 -0
- package/dist/tools/search.tools.d.ts +6 -0
- package/dist/tools/search.tools.d.ts.map +1 -1
- package/dist/tools/search.tools.js +12 -4
- package/dist/tools/search.tools.js.map +1 -1
- package/dist/tools/solution.tools.d.ts +18 -0
- package/dist/tools/solution.tools.d.ts.map +1 -1
- package/dist/tools/solution.tools.js +32 -17
- package/dist/tools/solution.tools.js.map +1 -1
- package/dist/tools/teams.tools.d.ts +6 -0
- package/dist/tools/teams.tools.d.ts.map +1 -1
- package/dist/tools/teams.tools.js +12 -9
- package/dist/tools/teams.tools.js.map +1 -1
- package/dist/tools/tool-registry.d.ts +35 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +31 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/trace.tools.d.ts +12 -0
- package/dist/tools/trace.tools.d.ts.map +1 -1
- package/dist/tools/trace.tools.js +19 -8
- package/dist/tools/trace.tools.js.map +1 -1
- package/dist/tools/tracking.tools.d.ts +6 -0
- package/dist/tools/tracking.tools.d.ts.map +1 -1
- package/dist/tools/tracking.tools.js +14 -4
- package/dist/tools/tracking.tools.js.map +1 -1
- package/dist/tools/users.tools.d.ts +12 -0
- package/dist/tools/users.tools.d.ts.map +1 -1
- package/dist/tools/users.tools.js +23 -24
- package/dist/tools/users.tools.js.map +1 -1
- package/dist/tools/views.tools.d.ts +6 -0
- package/dist/tools/views.tools.d.ts.map +1 -1
- package/dist/tools/views.tools.js +16 -17
- package/dist/tools/views.tools.js.map +1 -1
- package/dist/tools/workflow.tools.d.ts +53 -0
- package/dist/tools/workflow.tools.d.ts.map +1 -0
- package/dist/tools/workflow.tools.js +198 -0
- package/dist/tools/workflow.tools.js.map +1 -0
- package/dist/transport.d.ts +6 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +21 -0
- package/dist/transport.js.map +1 -0
- package/package.json +2 -1
- package/server.json +2 -2
package/dist/doctor.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
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
|
|
85
|
-
* and passed as the dispatch
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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 }, {
|
|
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:
|
|
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 (
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
|
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) => {
|