@datanimbus/dnio-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +20 -0
- package/docs/README.md +35 -0
- package/docs/architecture.md +171 -0
- package/docs/authentication.md +74 -0
- package/docs/tools/apps.md +59 -0
- package/docs/tools/connectors.md +76 -0
- package/docs/tools/data-pipes.md +286 -0
- package/docs/tools/data-services.md +105 -0
- package/docs/tools/deployment-groups.md +152 -0
- package/docs/tools/plugins.md +94 -0
- package/docs/tools/records.md +97 -0
- package/docs/workflows.md +195 -0
- package/env.example +16 -0
- package/package.json +43 -0
- package/readme.md +144 -0
- package/src/clients/api-keys.js +10 -0
- package/src/clients/apps.js +13 -0
- package/src/clients/base-client.js +78 -0
- package/src/clients/bots.js +10 -0
- package/src/clients/connectors.js +30 -0
- package/src/clients/data-formats.js +40 -0
- package/src/clients/data-pipes.js +33 -0
- package/src/clients/deployment-groups.js +59 -0
- package/src/clients/formulas.js +10 -0
- package/src/clients/functions.js +10 -0
- package/src/clients/plugins.js +39 -0
- package/src/clients/records.js +51 -0
- package/src/clients/services.js +63 -0
- package/src/clients/user-groups.js +10 -0
- package/src/clients/users.js +10 -0
- package/src/examples/ai-sdk-client.js +165 -0
- package/src/examples/claude_desktop_config.json +34 -0
- package/src/examples/express-integration.js +181 -0
- package/src/index.js +283 -0
- package/src/schemas/schema-converter.js +179 -0
- package/src/services/auth-manager.js +277 -0
- package/src/services/dnio-client.js +40 -0
- package/src/services/service-registry.js +150 -0
- package/src/services/session-manager.js +161 -0
- package/src/stdio-bridge.js +185 -0
- package/src/tools/_helpers.js +32 -0
- package/src/tools/api-keys.js +5 -0
- package/src/tools/apps.js +185 -0
- package/src/tools/bots.js +5 -0
- package/src/tools/connectors.js +165 -0
- package/src/tools/data-formats.js +806 -0
- package/src/tools/data-pipes.js +1305 -0
- package/src/tools/data-service-registry.js +500 -0
- package/src/tools/deployment-groups.js +511 -0
- package/src/tools/formulas.js +5 -0
- package/src/tools/functions.js +5 -0
- package/src/tools/mcp-tools-registry.js +38 -0
- package/src/tools/plugins.js +250 -0
- package/src/tools/records.js +217 -0
- package/src/tools/services.js +476 -0
- package/src/tools/user-groups.js +5 -0
- package/src/tools/users.js +5 -0
- package/src/utils/constants.js +135 -0
- package/src/utils/logger.js +63 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class DataFormatsClient {
|
|
4
|
+
constructor(http) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
_base(appName) {
|
|
9
|
+
return `api/a/bm/${appName}/dataFormat`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
list(appName, {filter, select, count = -1, page = 1} = {}) {
|
|
13
|
+
const params = new URLSearchParams();
|
|
14
|
+
params.set('filter', JSON.stringify({app: appName, ...(filter || {})}));
|
|
15
|
+
params.set('count', String(count));
|
|
16
|
+
params.set('page', String(page));
|
|
17
|
+
if (select) params.set('select', select);
|
|
18
|
+
return this.http.get(`${this._base(appName)}?${params.toString()}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get(appName, id) {
|
|
22
|
+
return this.http.get(`${this._base(appName)}/${id}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Step 1: POST shell with empty definition. Platform assigns _id.
|
|
26
|
+
create(appName, payload) {
|
|
27
|
+
return this.http.post(this._base(appName), payload);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Step 2 (and all attribute mutations): full PUT with populated definition.
|
|
31
|
+
update(appName, id, payload) {
|
|
32
|
+
return this.http.put(`${this._base(appName)}/${id}`, payload);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
delete(appName, id) {
|
|
36
|
+
return this.http.delete(`${this._base(appName)}/${id}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = DataFormatsClient;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class DataPipesClient {
|
|
4
|
+
constructor(http) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
list(appName, {filter, select, count = -1} = {}) {
|
|
9
|
+
const params = new URLSearchParams();
|
|
10
|
+
params.set('filter', JSON.stringify({app: appName, ...(filter || {})}));
|
|
11
|
+
params.set('count', String(count));
|
|
12
|
+
if (select) params.set('select', select);
|
|
13
|
+
return this.http.get(`api/a/bm/${appName}/flow?${params.toString()}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get(appName, flowId) {
|
|
17
|
+
return this.http.get(`api/a/bm/${appName}/flow/${flowId}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
create(appName, payload) {
|
|
21
|
+
return this.http.post(`api/a/bm/${appName}/flow`, payload);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
update(appName, flowId, payload) {
|
|
25
|
+
return this.http.put(`api/a/bm/${appName}/flow/${flowId}`, payload);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
publish(appName, flowId) {
|
|
29
|
+
return this.http.put(`api/a/bm/${appName}/flow/utils/${flowId}/publish`, {app: appName});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = DataPipesClient;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class DeploymentGroupsClient {
|
|
4
|
+
constructor(http) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
_base(appName) {
|
|
9
|
+
return `api/a/bm/${appName}/deployment/group`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
listAvailableFlows(appName) {
|
|
13
|
+
const filter = encodeURIComponent(JSON.stringify({app: appName}));
|
|
14
|
+
return this.http.get(`${this._base(appName)}/utils/available/flows?filter=${filter}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
list(appName, {filter, count = -1, select} = {}) {
|
|
18
|
+
const params = new URLSearchParams();
|
|
19
|
+
params.set('filter', JSON.stringify({app: appName, ...(filter || {})}));
|
|
20
|
+
params.set('count', String(count));
|
|
21
|
+
if (select) params.set('select', select);
|
|
22
|
+
return this.http.get(`${this._base(appName)}?${params.toString()}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get(appName, groupId) {
|
|
26
|
+
return this.http.get(`${this._base(appName)}/${groupId}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
create(appName, payload) {
|
|
30
|
+
return this.http.post(this._base(appName), payload);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
update(appName, groupId, payload) {
|
|
34
|
+
return this.http.put(`${this._base(appName)}/${groupId}`, payload);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
start(appName, groupId) {
|
|
38
|
+
return this.http.put(`${this._base(appName)}/utils/${groupId}/start`, {});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
stop(appName, groupId) {
|
|
42
|
+
return this.http.put(`${this._base(appName)}/utils/${groupId}/stop`, {});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
sync(appName, groupId) {
|
|
46
|
+
return this.http.put(`${this._base(appName)}/utils/${groupId}/sync`, {});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
delete(appName, groupId) {
|
|
50
|
+
return this.http.delete(`${this._base(appName)}/${groupId}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getYamls(appName, groupId) {
|
|
54
|
+
const filter = encodeURIComponent(JSON.stringify({app: appName}));
|
|
55
|
+
return this.http.get(`${this._base(appName)}/utils/${groupId}/yamls?filter=${filter}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = DeploymentGroupsClient;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class PluginsClient {
|
|
4
|
+
constructor(http) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
listMarketplace(appName, {page = 1, count = -1, select, sort = 'label', filter} = {}) {
|
|
9
|
+
const params = new URLSearchParams();
|
|
10
|
+
params.set('page', String(page));
|
|
11
|
+
params.set('count', String(count));
|
|
12
|
+
params.set('select', select || 'label,type,version,icon');
|
|
13
|
+
params.set('sort', sort);
|
|
14
|
+
params.set('filter', JSON.stringify(filter || {}));
|
|
15
|
+
return this.http.get(`api/a/bm/${appName}/marketplace/node?${params.toString()}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
listInstalled(appName, {count = -1, select, filter} = {}) {
|
|
19
|
+
const params = new URLSearchParams();
|
|
20
|
+
params.set('count', String(count));
|
|
21
|
+
params.set('select', select || 'label,type,version,icon');
|
|
22
|
+
params.set('filter', JSON.stringify({app: appName, ...(filter || {})}));
|
|
23
|
+
return this.http.get(`api/a/bm/${appName}/my-node?${params.toString()}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
install(appName, marketIds) {
|
|
27
|
+
return this.http.post(`api/a/bm/${appName}/my-node/utils/install`, {marketIds});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
update(appName, ids) {
|
|
31
|
+
return this.http.post(`api/a/bm/${appName}/my-node/utils/update`, {app: appName, ids});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
uninstall(appName, ids) {
|
|
35
|
+
return this.http.post(`api/a/bm/${appName}/my-node/utils/uninstall`, {app: appName, ids});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = PluginsClient;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class RecordsClient {
|
|
4
|
+
constructor(http) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
_endpoint(appName, servicePath, recordId) {
|
|
9
|
+
const base = `api/c/${appName}/${servicePath}`;
|
|
10
|
+
return recordId ? `${base}/${recordId}` : base;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
list(appName, servicePath, {filter, sort, select, page = 1, count = 20, expand = false} = {}) {
|
|
14
|
+
const endpoint = this._endpoint(appName, servicePath);
|
|
15
|
+
const params = new URLSearchParams();
|
|
16
|
+
if (filter) params.set('filter', JSON.stringify(filter));
|
|
17
|
+
if (sort) params.set('sort', sort);
|
|
18
|
+
if (select) params.set('select', select);
|
|
19
|
+
params.set('page', String(page));
|
|
20
|
+
params.set('count', String(count));
|
|
21
|
+
if (expand) params.set('expand', 'true');
|
|
22
|
+
const qs = params.toString();
|
|
23
|
+
return this.http.get(`${endpoint}${qs ? '?' + qs : ''}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get(appName, servicePath, recordId, {expand = false} = {}) {
|
|
27
|
+
let endpoint = this._endpoint(appName, servicePath, recordId);
|
|
28
|
+
if (expand) endpoint += '?expand=true';
|
|
29
|
+
return this.http.get(endpoint);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
create(appName, servicePath, data) {
|
|
33
|
+
return this.http.post(this._endpoint(appName, servicePath), data);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
update(appName, servicePath, recordId, data) {
|
|
37
|
+
return this.http.put(this._endpoint(appName, servicePath, recordId), data);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
delete(appName, servicePath, recordId) {
|
|
41
|
+
return this.http.delete(this._endpoint(appName, servicePath, recordId));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
count(appName, servicePath, filter) {
|
|
45
|
+
let endpoint = this._endpoint(appName, servicePath) + '/utils/count';
|
|
46
|
+
if (filter) endpoint += `?filter=${encodeURIComponent(JSON.stringify(filter))}`;
|
|
47
|
+
return this.http.get(endpoint, {timeout: {request: 1000}});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = RecordsClient;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const logger = require('../utils/logger');
|
|
4
|
+
|
|
5
|
+
class ServicesClient {
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
_endpoint(appName, serviceId) {
|
|
11
|
+
const base = `api/a/sm/${appName}/service`;
|
|
12
|
+
return serviceId ? `${base}/${serviceId}` : base;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
list(appName, {filter, select, count = -1} = {}) {
|
|
16
|
+
const params = new URLSearchParams();
|
|
17
|
+
params.set('filter', JSON.stringify({app: appName, ...(filter || {})}));
|
|
18
|
+
params.set('count', String(count));
|
|
19
|
+
if (select) params.set('select', select);
|
|
20
|
+
return this.http.get(`${this._endpoint(appName)}?${params.toString()}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getSchema(appName, serviceId) {
|
|
24
|
+
return this.http.get(`api/a/sm/${appName}/service/${serviceId}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
create(appName, data) {
|
|
28
|
+
return this.http.post(this._endpoint(appName), data);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
update(appName, serviceId, data) {
|
|
32
|
+
return this.http.put(this._endpoint(appName, serviceId), data);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get(appName, serviceId, {draft = false, select} = {}) {
|
|
36
|
+
const params = new URLSearchParams();
|
|
37
|
+
params.set('filter', JSON.stringify({app: appName}));
|
|
38
|
+
if (draft) params.set('draft', 'true');
|
|
39
|
+
if (select) params.set('select', select);
|
|
40
|
+
return this.http.get(`${this._endpoint(appName, serviceId)}?${params.toString()}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
deploy(appName, serviceId) {
|
|
44
|
+
return this.http.put(`api/a/sm/${appName}/service/utils/${serviceId}/deploy`, {app: appName});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
startStop(appName, serviceId, {start = true} = {}) {
|
|
48
|
+
const action = start ? 'start' : 'stop';
|
|
49
|
+
return this.http.put(`api/a/sm/${appName}/service/utils/${serviceId}/${action}`, {app: appName});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async verifyPod(appName, servicePath) {
|
|
53
|
+
try {
|
|
54
|
+
await this.http.records.count(appName, servicePath);
|
|
55
|
+
return true;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.warn(`Pod verification failed for ${appName}/${servicePath}: ${error.message}`);
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = ServicesClient;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AI SDK Integration Example
|
|
5
|
+
*
|
|
6
|
+
* Shows how to connect the DNIO MCP server to AI models via Vercel AI SDK.
|
|
7
|
+
* Supports: Google Vertex AI, OpenAI, Local Ollama
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* PROVIDER=vertex node src/examples/ai-sdk-client.js "List all contracts"
|
|
11
|
+
* PROVIDER=openai node src/examples/ai-sdk-client.js "Create a party named Acme Corp"
|
|
12
|
+
* PROVIDER=ollama node src/examples/ai-sdk-client.js "How many contracts exist?"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// ─── Provider Setup ──────────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
function getModel() {
|
|
18
|
+
const provider = process.env.PROVIDER || 'vertex';
|
|
19
|
+
|
|
20
|
+
switch (provider) {
|
|
21
|
+
case 'vertex': {
|
|
22
|
+
const {createVertex} = require('@ai-sdk/google-vertex');
|
|
23
|
+
const vertex = createVertex({
|
|
24
|
+
project: process.env.GOOGLE_VERTEX_PROJECT || process.env.GOOGLE_CLOUD_PROJECT,
|
|
25
|
+
location: process.env.GOOGLE_VERTEX_LOCATION || 'us-central1',
|
|
26
|
+
...(process.env.GOOGLE_CLIENT_EMAIL && {
|
|
27
|
+
googleAuthOptions: {
|
|
28
|
+
credentials: {
|
|
29
|
+
client_email: process.env.GOOGLE_CLIENT_EMAIL,
|
|
30
|
+
private_key: (process.env.GOOGLE_PRIVATE_KEY || '').replace(/\\n/g, '\n')
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
return vertex(process.env.AI_MODEL || 'gemini-2.5-flash');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
case 'openai': {
|
|
39
|
+
const {createOpenAI} = require('@ai-sdk/openai');
|
|
40
|
+
const openai = createOpenAI({
|
|
41
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
42
|
+
...(process.env.OPENAI_BASE_URL && {baseURL: process.env.OPENAI_BASE_URL})
|
|
43
|
+
});
|
|
44
|
+
return openai(process.env.AI_MODEL || 'gpt-4o');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
case 'ollama': {
|
|
48
|
+
// Ollama is OpenAI-compatible, so we use the OpenAI provider with custom base URL
|
|
49
|
+
const {createOpenAI} = require('@ai-sdk/openai');
|
|
50
|
+
const ollama = createOpenAI({
|
|
51
|
+
baseURL: process.env.OLLAMA_BASE_URL || 'http://localhost:11434/v1',
|
|
52
|
+
apiKey: 'ollama' // Ollama doesn't need a real key
|
|
53
|
+
});
|
|
54
|
+
return ollama(process.env.AI_MODEL || 'llama3.1');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
default:
|
|
58
|
+
throw new Error(`Unknown provider: ${provider}. Use 'vertex', 'openai', or 'ollama'`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ─── MCP Client Connection ───────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
async function connectMCPClient() {
|
|
65
|
+
const {createMCPClient} = require('@ai-sdk/mcp');
|
|
66
|
+
|
|
67
|
+
const mcpTransport = process.env.MCP_TRANSPORT || 'stdio';
|
|
68
|
+
|
|
69
|
+
if (mcpTransport === 'http') {
|
|
70
|
+
// Connect to remote MCP server via HTTP
|
|
71
|
+
const mcpUrl = process.env.MCP_SERVER_URL || 'http://localhost:3100/mcp';
|
|
72
|
+
console.error(`Connecting to MCP server at ${mcpUrl}`);
|
|
73
|
+
|
|
74
|
+
return createMCPClient({
|
|
75
|
+
transport: {
|
|
76
|
+
type: 'http',
|
|
77
|
+
url: mcpUrl
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
// Spawn MCP server as subprocess (stdio)
|
|
82
|
+
const {Experimental_StdioMCPTransport} = require('@ai-sdk/mcp/mcp-stdio');
|
|
83
|
+
|
|
84
|
+
console.error('Starting MCP server via stdio...');
|
|
85
|
+
return createMCPClient({
|
|
86
|
+
transport: new Experimental_StdioMCPTransport({
|
|
87
|
+
command: 'node',
|
|
88
|
+
args: [require('path').resolve(__dirname, '../index.js')],
|
|
89
|
+
env: {
|
|
90
|
+
...process.env,
|
|
91
|
+
TRANSPORT: 'stdio'
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ─── Main Agent Loop ─────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
async function main() {
|
|
101
|
+
const prompt = process.argv[2];
|
|
102
|
+
if (!prompt) {
|
|
103
|
+
console.error('Usage: node ai-sdk-client.js "your question here"');
|
|
104
|
+
console.error('');
|
|
105
|
+
console.error('Environment variables:');
|
|
106
|
+
console.error(' PROVIDER=vertex|openai|ollama');
|
|
107
|
+
console.error(' MCP_TRANSPORT=stdio|http');
|
|
108
|
+
console.error(' MCP_SERVER_URL=http://localhost:3100/mcp (for http transport)');
|
|
109
|
+
console.error(' DNIO_BASE_URL, DNIO_TOKEN, DNIO_APP_NAME');
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const {generateText} = require('ai');
|
|
114
|
+
|
|
115
|
+
let mcpClient;
|
|
116
|
+
try {
|
|
117
|
+
// 1. Get AI model
|
|
118
|
+
const model = getModel();
|
|
119
|
+
console.error(`Using model: ${process.env.AI_MODEL || 'default'} via ${process.env.PROVIDER || 'vertex'}`);
|
|
120
|
+
|
|
121
|
+
// 2. Connect to MCP server
|
|
122
|
+
mcpClient = await connectMCPClient();
|
|
123
|
+
|
|
124
|
+
// 3. Get tools from MCP server
|
|
125
|
+
const tools = await mcpClient.tools();
|
|
126
|
+
console.error(`Loaded ${Object.keys(tools).length} tools from MCP server`);
|
|
127
|
+
|
|
128
|
+
// 4. Run agent with tools
|
|
129
|
+
const result = await generateText({
|
|
130
|
+
model,
|
|
131
|
+
tools,
|
|
132
|
+
maxSteps: 10,
|
|
133
|
+
system: `You are a helpful assistant that manages data on the DataNimbus BaaS platform.
|
|
134
|
+
You have access to tools for CRUD operations on various data services.
|
|
135
|
+
|
|
136
|
+
Start by listing available data services if you need to understand what's available.
|
|
137
|
+
Use the appropriate tools to fulfill user requests.
|
|
138
|
+
Always confirm destructive operations before executing them.
|
|
139
|
+
|
|
140
|
+
When creating records, make sure to follow the schema structure for each service.`,
|
|
141
|
+
messages: [{role: 'user', content: prompt}]
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
console.log('\n' + result.text);
|
|
145
|
+
|
|
146
|
+
// Show tool usage summary
|
|
147
|
+
if (result.steps?.length > 1) {
|
|
148
|
+
console.error(`\n--- Completed in ${result.steps.length} steps ---`);
|
|
149
|
+
for (const step of result.steps) {
|
|
150
|
+
if (step.toolCalls) {
|
|
151
|
+
for (const call of step.toolCalls) {
|
|
152
|
+
console.error(` Tool: ${call.toolName}(${JSON.stringify(call.args).substring(0, 80)}...)`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error('Error:', error.message);
|
|
160
|
+
if (error.cause) console.error('Cause:', error.cause);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
} finally {
|
|
163
|
+
if (mcpClient) await mcpClient.close();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"dnio": {
|
|
4
|
+
"command": "node",
|
|
5
|
+
"args": [
|
|
6
|
+
"<ABSOLUTE_PATH_TO>/dnio-mcp-server/src/index.js"
|
|
7
|
+
],
|
|
8
|
+
"env": {
|
|
9
|
+
"DNIO_BASE_URL": "<YOUR_DNIO_BASE_URL>",
|
|
10
|
+
"DNIO_USERNAME": "<DNIO_ADMIN_USERNAME>",
|
|
11
|
+
"DNIO_PASSWORD": "<DNIO_ADMIN_PASSWORD>",
|
|
12
|
+
"MCP_USER_EMAIL": "<MCP_USER_ACCOUNT_EMAIL>",
|
|
13
|
+
"MCP_USER_PASSWORD": "<MCP_USER_ACCOUNT_PASSWORD>",
|
|
14
|
+
"DNIO_TOKEN_TTL": "1800",
|
|
15
|
+
"DNIO_NAMESPACE": "DNIO",
|
|
16
|
+
"TRANSPORT": "stdio",
|
|
17
|
+
"LOG_LEVEL": "info"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"dnio-bridge": {
|
|
21
|
+
"command": "node",
|
|
22
|
+
"args": [
|
|
23
|
+
"<ABSOLUTE_PATH_TO>/dnio-mcp-server/src/stdio-bridge.js"
|
|
24
|
+
],
|
|
25
|
+
"env": {
|
|
26
|
+
"MCP_REMOTE_URL": "http://localhost:3100/mcp"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"dnio-remote": {
|
|
30
|
+
"type": "streamable-http",
|
|
31
|
+
"url": "<YOUR_DEPLOYED_MCP_SERVER_URL>/mcp"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|