@transcend-io/mcp-server-discovery 0.3.4 → 0.4.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/README.md +36 -12
- package/dist/cli.mjs +5 -3
- package/dist/cli.mjs.map +1 -1
- package/dist/graphql-piEf44KX.mjs +429 -0
- package/dist/graphql-piEf44KX.mjs.map +1 -0
- package/dist/index.d.mts +7 -22
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/package.json +6 -3
- package/dist/graphql-C5tZOWZa.mjs +0 -303
- package/dist/graphql-C5tZOWZa.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Transcend MCP Server for data discovery. Provides tools for scanning, classifyin
|
|
|
6
6
|
|
|
7
7
|
Requires **Node.js ≥ 22.12** (see `engines` in `package.json`).
|
|
8
8
|
|
|
9
|
-
For local runs from this repository, copy [`secret.env.example`](../../../secret.env.example) to **`secret.env`** at the repo root (gitignored) and set
|
|
9
|
+
For local runs from this repository, copy [`secret.env.example`](../../../secret.env.example) to **`secret.env`** at the repo root (gitignored) and set the OAuth environment variables (see **Run from the monorepo**).
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
@@ -21,12 +21,31 @@ Or run from a checkout of this repository (see **Run from the monorepo** below).
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
# With
|
|
25
|
-
|
|
24
|
+
# With OAuth env vars in the environment; from the monorepo use secret.env (see Run from the monorepo)
|
|
25
|
+
TRANSCEND_OAUTH_CLIENT_ID=your-client-id \
|
|
26
|
+
TRANSCEND_OAUTH_CLIENT_SECRET=your-client-secret \
|
|
27
|
+
TRANSCEND_OAUTH_REDIRECT_PORT=your-client-redirect-port \
|
|
28
|
+
transcend-mcp-discovery
|
|
26
29
|
```
|
|
27
30
|
|
|
28
31
|
The process speaks MCP over **stdio** and is meant to be launched by an MCP client (for example Cursor or Claude Desktop), not used as an interactive shell.
|
|
29
32
|
|
|
33
|
+
### OAuth client setup
|
|
34
|
+
|
|
35
|
+
OAuth stdio is the recommended path for MCP clients (Cursor, Claude Desktop). Requires **org admin** access to create OAuth clients.
|
|
36
|
+
|
|
37
|
+
1. Navigate to [app.transcend.com/admin/oauth-clients](https://app.transcend.com/admin/oauth-clients) and create an OAuth client.
|
|
38
|
+
2. Copy the **client ID** and **client secret**.
|
|
39
|
+
3. Register `http://127.0.0.1:{port}/callback` — use **`127.0.0.1`, not `localhost`**, and ensure the path is `/callback`. Set `TRANSCEND_OAUTH_REDIRECT_PORT` to the matching port.
|
|
40
|
+
|
|
41
|
+
At startup the server verifies client ID, secret, and redirect URI. On first tool call it opens a browser for login. Tokens are session-only (in-memory).
|
|
42
|
+
|
|
43
|
+
**OAuth scopes:** `ViewDataMap`, `ViewAssignedIntegrations`, `ViewCodeScanning`, `ManageCodeScanning`, `ViewPrompts`, `ViewPromptRuns`, `ExecutePrompt`. The signed-in user must hold these permissions. See [`src/scopes.ts`](./src/scopes.ts).
|
|
44
|
+
|
|
45
|
+
Full setup, troubleshooting, and multi-server guidance: [MCP root README](../README.md#oauth-client-setup).
|
|
46
|
+
|
|
47
|
+
> **API key alternative:** set `TRANSCEND_API_KEY` instead of OAuth vars for stdio (OAuth is disabled when both are set).
|
|
48
|
+
|
|
30
49
|
### MCP client configuration
|
|
31
50
|
|
|
32
51
|
`npx` runs the package’s `transcend-mcp-discovery` binary (see `bin` in `package.json`).
|
|
@@ -38,7 +57,9 @@ The process speaks MCP over **stdio** and is meant to be launched by an MCP clie
|
|
|
38
57
|
"command": "npx",
|
|
39
58
|
"args": ["-y", "@transcend-io/mcp-server-discovery"],
|
|
40
59
|
"env": {
|
|
41
|
-
"
|
|
60
|
+
"TRANSCEND_OAUTH_CLIENT_ID": "your-client-id",
|
|
61
|
+
"TRANSCEND_OAUTH_CLIENT_SECRET": "your-client-secret",
|
|
62
|
+
"TRANSCEND_OAUTH_REDIRECT_PORT": "your-client-redirect-port"
|
|
42
63
|
}
|
|
43
64
|
}
|
|
44
65
|
}
|
|
@@ -49,7 +70,7 @@ When developing in this repository, reuse the same variable names from root **`s
|
|
|
49
70
|
|
|
50
71
|
### Run from the monorepo
|
|
51
72
|
|
|
52
|
-
1. **Credentials** — From the repository root, copy [`secret.env.example`](../../../secret.env.example) to **`secret.env`** and set `
|
|
73
|
+
1. **Credentials** — From the repository root, copy [`secret.env.example`](../../../secret.env.example) to **`secret.env`** and set `TRANSCEND_OAUTH_CLIENT_ID`, `TRANSCEND_OAUTH_CLIENT_SECRET`, and `TRANSCEND_OAUTH_REDIRECT_PORT` (and optional URL overrides).
|
|
53
74
|
|
|
54
75
|
2. **Build and run** — `node ./dist/cli.mjs` matches the `transcend-mcp-discovery` `bin` (use `node` because `pnpm exec transcend-mcp-discovery` may not resolve this package’s own binary in a pnpm workspace):
|
|
55
76
|
|
|
@@ -66,19 +87,22 @@ See [CONTRIBUTING.md](../../../CONTRIBUTING.md#mcp-servers) for workspace layout
|
|
|
66
87
|
|
|
67
88
|
### Environment variables
|
|
68
89
|
|
|
69
|
-
| Variable
|
|
70
|
-
|
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
90
|
+
| Variable | Required (stdio OAuth) | Default | Description |
|
|
91
|
+
| ------------------------------- | ---------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
|
|
92
|
+
| `TRANSCEND_OAUTH_CLIENT_ID` | Yes | — | Client ID from [app.transcend.com/admin/oauth-clients](https://app.transcend.com/admin/oauth-clients) |
|
|
93
|
+
| `TRANSCEND_OAUTH_CLIENT_SECRET` | Yes | — | Client secret from the same OAuth clients page |
|
|
94
|
+
| `TRANSCEND_OAUTH_REDIRECT_PORT` | Yes | — | Localhost port for the OAuth callback server; **must match the port in your registered redirect URI** |
|
|
95
|
+
| `TRANSCEND_OAUTH_REDIRECT_HOST` | No | `127.0.0.1` | Loopback host for the OAuth callback (`127.0.0.1` or `::1` for `http://[::1]:{port}/callback`) |
|
|
96
|
+
| `TRANSCEND_OAUTH_ISSUER` | No | auto-detected | OAuth issuer URL; production auto-detects region. Test-only override |
|
|
97
|
+
| `TRANSCEND_API_KEY` | No | — | API key for stdio (alternative to OAuth). Disables OAuth when set alongside client ID |
|
|
98
|
+
| `TRANSCEND_API_URL` | No | `https://api.transcend.io` | GraphQL backend API URL (matches CLI convention) |
|
|
99
|
+
| `SOMBRA_URL` | No | `https://multi-tenant.sombra.transcend.io` | Sombra REST API URL (matches CLI / SDK convention) |
|
|
74
100
|
|
|
75
101
|
**Monorepo:** keep these in root **`secret.env`** (from [`secret.env.example`](../../../secret.env.example)); see **Run from the monorepo**.
|
|
76
102
|
|
|
77
103
|
## Tools
|
|
78
104
|
|
|
79
105
|
- `discovery_list_scans` — List data discovery scans
|
|
80
|
-
- `discovery_get_scan` — Get scan details
|
|
81
|
-
- `discovery_start_scan` — Start a new scan
|
|
82
106
|
- `discovery_list_plugins` — List discovery plugins
|
|
83
107
|
- `discovery_classify_text` — Classify text into data categories
|
|
84
108
|
- `discovery_ner_extract` — Extract named entities from text
|
package/dist/cli.mjs
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as getDiscoveryTools, t as DiscoveryMixin } from "./graphql-
|
|
2
|
+
import { n as DISCOVERY_OAUTH_SCOPES, r as getDiscoveryTools, t as DiscoveryMixin } from "./graphql-piEf44KX.mjs";
|
|
3
3
|
import { TranscendRestClient, createMCPServer } from "@transcend-io/mcp-server-base";
|
|
4
4
|
//#region src/cli.ts
|
|
5
5
|
createMCPServer({
|
|
6
6
|
name: "transcend-mcp-discovery",
|
|
7
7
|
version: "1.0.0",
|
|
8
|
+
oauthScopes: DISCOVERY_OAUTH_SCOPES,
|
|
8
9
|
getTools: getDiscoveryTools,
|
|
9
|
-
createClients: (auth, sombraUrl, graphqlUrl) => ({
|
|
10
|
+
createClients: ({ auth, sombraUrl, graphqlUrl, dashboardUrl }) => ({
|
|
10
11
|
rest: new TranscendRestClient(auth, sombraUrl),
|
|
11
|
-
graphql: new DiscoveryMixin(auth, graphqlUrl)
|
|
12
|
+
graphql: new DiscoveryMixin(auth, graphqlUrl),
|
|
13
|
+
dashboardUrl
|
|
12
14
|
})
|
|
13
15
|
});
|
|
14
16
|
//#endregion
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { createMCPServer, TranscendRestClient } from '@transcend-io/mcp-server-base';\n\nimport { DiscoveryMixin } from './graphql.js';\nimport { getDiscoveryTools } from './tools/index.js';\n\ncreateMCPServer({\n name: 'transcend-mcp-discovery',\n version: '1.0.0',\n getTools: getDiscoveryTools,\n createClients: (auth, sombraUrl, graphqlUrl) => ({\n rest: new TranscendRestClient(auth, sombraUrl),\n graphql: new DiscoveryMixin(auth, graphqlUrl),\n }),\n});\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { createMCPServer, TranscendRestClient } from '@transcend-io/mcp-server-base';\n\nimport { DiscoveryMixin } from './graphql.js';\nimport { DISCOVERY_OAUTH_SCOPES } from './scopes.js';\nimport { getDiscoveryTools } from './tools/index.js';\n\ncreateMCPServer({\n name: 'transcend-mcp-discovery',\n version: '1.0.0',\n oauthScopes: DISCOVERY_OAUTH_SCOPES,\n getTools: getDiscoveryTools,\n createClients: ({ auth, sombraUrl, graphqlUrl, dashboardUrl }) => ({\n rest: new TranscendRestClient(auth, sombraUrl),\n graphql: new DiscoveryMixin(auth, graphqlUrl),\n dashboardUrl,\n }),\n});\n"],"mappings":";;;;AAOA,gBAAgB;CACd,MAAM;CACN,SAAS;CACT,aAAa;CACb,UAAU;CACV,gBAAgB,EAAE,MAAM,WAAW,YAAY,oBAAoB;EACjE,MAAM,IAAI,oBAAoB,MAAM,UAAU;EAC9C,SAAS,IAAI,eAAe,MAAM,WAAW;EAC7C;EACD;CACF,CAAC"}
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import { PaginationSchema, TranscendGraphQLBase, createListResult, createToolResult, defineTool, z } from "@transcend-io/mcp-server-base";
|
|
2
|
+
import { ScopeName } from "@transcend-io/privacy-types";
|
|
3
|
+
//#region src/tools/discovery_classify_text.ts
|
|
4
|
+
const ClassifyTextSchema = z.object({
|
|
5
|
+
texts: z.array(z.string()).describe("Array of text strings to classify"),
|
|
6
|
+
categories: z.array(z.string()).optional().describe("Specific categories to classify against (optional)"),
|
|
7
|
+
model: z.string().optional().describe("LLM model to use for classification (optional)")
|
|
8
|
+
});
|
|
9
|
+
function createDiscoveryClassifyTextTool(clients) {
|
|
10
|
+
const { rest } = clients;
|
|
11
|
+
return defineTool({
|
|
12
|
+
name: "discovery_classify_text",
|
|
13
|
+
description: "Classify text content using Transcend's LLM classifier to identify data categories",
|
|
14
|
+
category: "Data Discovery",
|
|
15
|
+
readOnly: true,
|
|
16
|
+
annotations: {
|
|
17
|
+
readOnlyHint: true,
|
|
18
|
+
destructiveHint: false,
|
|
19
|
+
idempotentHint: true
|
|
20
|
+
},
|
|
21
|
+
zodSchema: ClassifyTextSchema,
|
|
22
|
+
handler: async ({ texts, categories, model }) => {
|
|
23
|
+
return createToolResult(true, {
|
|
24
|
+
results: await rest.classifyText({
|
|
25
|
+
texts,
|
|
26
|
+
categories,
|
|
27
|
+
model
|
|
28
|
+
}),
|
|
29
|
+
inputCount: texts.length,
|
|
30
|
+
message: `Classified ${texts.length} text(s) successfully`
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/tools/discovery_list_plugins.ts
|
|
37
|
+
const ListPluginsSchema = PaginationSchema.extend({ cursor: z.string().optional().describe("Pagination cursor from previous response (where supported)") });
|
|
38
|
+
function createDiscoveryListPluginsTool(clients) {
|
|
39
|
+
const graphql = clients.graphql;
|
|
40
|
+
return defineTool({
|
|
41
|
+
name: "discovery_list_plugins",
|
|
42
|
+
description: "List all available discovery plugins (integration types) in your organization.",
|
|
43
|
+
category: "Data Discovery",
|
|
44
|
+
readOnly: true,
|
|
45
|
+
annotations: {
|
|
46
|
+
readOnlyHint: true,
|
|
47
|
+
destructiveHint: false,
|
|
48
|
+
idempotentHint: true
|
|
49
|
+
},
|
|
50
|
+
zodSchema: ListPluginsSchema,
|
|
51
|
+
handler: async ({ limit, cursor }) => {
|
|
52
|
+
const result = await graphql.listDiscoveryPlugins({
|
|
53
|
+
first: limit,
|
|
54
|
+
after: cursor
|
|
55
|
+
});
|
|
56
|
+
return createListResult(result.nodes, {
|
|
57
|
+
totalCount: result.totalCount,
|
|
58
|
+
hasNextPage: result.pageInfo?.hasNextPage
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/tools/discovery_list_scans.ts
|
|
65
|
+
const ListScansSchema = PaginationSchema.extend({ cursor: z.string().optional().describe("Pagination cursor from previous response (where supported)") });
|
|
66
|
+
function createDiscoveryListScansTool(clients) {
|
|
67
|
+
const graphql = clients.graphql;
|
|
68
|
+
return defineTool({
|
|
69
|
+
name: "discovery_list_scans",
|
|
70
|
+
description: "List all data classification scans. Returns data silos with classification info.",
|
|
71
|
+
category: "Data Discovery",
|
|
72
|
+
readOnly: true,
|
|
73
|
+
annotations: {
|
|
74
|
+
readOnlyHint: true,
|
|
75
|
+
destructiveHint: false,
|
|
76
|
+
idempotentHint: true
|
|
77
|
+
},
|
|
78
|
+
zodSchema: ListScansSchema,
|
|
79
|
+
handler: async ({ limit, cursor }) => {
|
|
80
|
+
const result = await graphql.listClassificationScans({
|
|
81
|
+
first: limit,
|
|
82
|
+
after: cursor
|
|
83
|
+
});
|
|
84
|
+
return createListResult(result.nodes, {
|
|
85
|
+
totalCount: result.totalCount,
|
|
86
|
+
hasNextPage: result.pageInfo?.hasNextPage
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/tools/discovery_ner_extract.ts
|
|
93
|
+
const NerExtractSchema = z.object({
|
|
94
|
+
text: z.string().describe("Text to extract entities from"),
|
|
95
|
+
entityTypes: z.array(z.string()).optional().describe("Specific entity types to extract (optional)")
|
|
96
|
+
});
|
|
97
|
+
function createDiscoveryNerExtractTool(clients) {
|
|
98
|
+
const { rest } = clients;
|
|
99
|
+
return defineTool({
|
|
100
|
+
name: "discovery_ner_extract",
|
|
101
|
+
description: "Extract named entities (PII, organizations, locations, etc.) from text using NER",
|
|
102
|
+
category: "Data Discovery",
|
|
103
|
+
readOnly: true,
|
|
104
|
+
annotations: {
|
|
105
|
+
readOnlyHint: true,
|
|
106
|
+
destructiveHint: false,
|
|
107
|
+
idempotentHint: true
|
|
108
|
+
},
|
|
109
|
+
zodSchema: NerExtractSchema,
|
|
110
|
+
handler: async ({ text, entityTypes }) => {
|
|
111
|
+
const result = await rest.extractEntities({
|
|
112
|
+
text,
|
|
113
|
+
entityTypes
|
|
114
|
+
});
|
|
115
|
+
return createToolResult(true, {
|
|
116
|
+
entities: result.entities,
|
|
117
|
+
entityCount: result.entities.length,
|
|
118
|
+
entityTypes: [...new Set(result.entities.map((e) => e.type))],
|
|
119
|
+
message: `Extracted ${result.entities.length} entities from text`
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/tools/index.ts
|
|
126
|
+
function getDiscoveryTools(clients) {
|
|
127
|
+
return [
|
|
128
|
+
createDiscoveryClassifyTextTool(clients),
|
|
129
|
+
createDiscoveryNerExtractTool(clients),
|
|
130
|
+
createDiscoveryListScansTool(clients),
|
|
131
|
+
createDiscoveryListPluginsTool(clients)
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/scopes.ts
|
|
136
|
+
/** OAuth scopes required for Discovery MCP tools (offline_access added by base). */
|
|
137
|
+
const DISCOVERY_OAUTH_SCOPES = [
|
|
138
|
+
ScopeName.ViewDataMap,
|
|
139
|
+
ScopeName.ViewAssignedIntegrations,
|
|
140
|
+
ScopeName.ViewCodeScanning,
|
|
141
|
+
ScopeName.ManageCodeScanning,
|
|
142
|
+
ScopeName.ViewPrompts,
|
|
143
|
+
ScopeName.ViewPromptRuns,
|
|
144
|
+
ScopeName.ExecutePrompt
|
|
145
|
+
];
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/__generated__/gql.ts
|
|
148
|
+
const documents = {
|
|
149
|
+
"\n query DiscoveryListDataSilos($first: Int) {\n dataSilos(first: $first) {\n nodes {\n id\n title\n type\n createdAt\n }\n totalCount\n }\n }\n": {
|
|
150
|
+
"kind": "Document",
|
|
151
|
+
"definitions": [{
|
|
152
|
+
"kind": "OperationDefinition",
|
|
153
|
+
"operation": "query",
|
|
154
|
+
"name": {
|
|
155
|
+
"kind": "Name",
|
|
156
|
+
"value": "DiscoveryListDataSilos"
|
|
157
|
+
},
|
|
158
|
+
"variableDefinitions": [{
|
|
159
|
+
"kind": "VariableDefinition",
|
|
160
|
+
"variable": {
|
|
161
|
+
"kind": "Variable",
|
|
162
|
+
"name": {
|
|
163
|
+
"kind": "Name",
|
|
164
|
+
"value": "first"
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
"type": {
|
|
168
|
+
"kind": "NamedType",
|
|
169
|
+
"name": {
|
|
170
|
+
"kind": "Name",
|
|
171
|
+
"value": "Int"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}],
|
|
175
|
+
"selectionSet": {
|
|
176
|
+
"kind": "SelectionSet",
|
|
177
|
+
"selections": [{
|
|
178
|
+
"kind": "Field",
|
|
179
|
+
"name": {
|
|
180
|
+
"kind": "Name",
|
|
181
|
+
"value": "dataSilos"
|
|
182
|
+
},
|
|
183
|
+
"arguments": [{
|
|
184
|
+
"kind": "Argument",
|
|
185
|
+
"name": {
|
|
186
|
+
"kind": "Name",
|
|
187
|
+
"value": "first"
|
|
188
|
+
},
|
|
189
|
+
"value": {
|
|
190
|
+
"kind": "Variable",
|
|
191
|
+
"name": {
|
|
192
|
+
"kind": "Name",
|
|
193
|
+
"value": "first"
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}],
|
|
197
|
+
"selectionSet": {
|
|
198
|
+
"kind": "SelectionSet",
|
|
199
|
+
"selections": [{
|
|
200
|
+
"kind": "Field",
|
|
201
|
+
"name": {
|
|
202
|
+
"kind": "Name",
|
|
203
|
+
"value": "nodes"
|
|
204
|
+
},
|
|
205
|
+
"selectionSet": {
|
|
206
|
+
"kind": "SelectionSet",
|
|
207
|
+
"selections": [
|
|
208
|
+
{
|
|
209
|
+
"kind": "Field",
|
|
210
|
+
"name": {
|
|
211
|
+
"kind": "Name",
|
|
212
|
+
"value": "id"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"kind": "Field",
|
|
217
|
+
"name": {
|
|
218
|
+
"kind": "Name",
|
|
219
|
+
"value": "title"
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"kind": "Field",
|
|
224
|
+
"name": {
|
|
225
|
+
"kind": "Name",
|
|
226
|
+
"value": "type"
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"kind": "Field",
|
|
231
|
+
"name": {
|
|
232
|
+
"kind": "Name",
|
|
233
|
+
"value": "createdAt"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
}, {
|
|
239
|
+
"kind": "Field",
|
|
240
|
+
"name": {
|
|
241
|
+
"kind": "Name",
|
|
242
|
+
"value": "totalCount"
|
|
243
|
+
}
|
|
244
|
+
}]
|
|
245
|
+
}
|
|
246
|
+
}]
|
|
247
|
+
}
|
|
248
|
+
}]
|
|
249
|
+
},
|
|
250
|
+
"\n query DiscoveryListDataSiloTypes($first: Int) {\n dataSilos(first: $first) {\n nodes {\n id\n title\n type\n description\n }\n totalCount\n }\n }\n": {
|
|
251
|
+
"kind": "Document",
|
|
252
|
+
"definitions": [{
|
|
253
|
+
"kind": "OperationDefinition",
|
|
254
|
+
"operation": "query",
|
|
255
|
+
"name": {
|
|
256
|
+
"kind": "Name",
|
|
257
|
+
"value": "DiscoveryListDataSiloTypes"
|
|
258
|
+
},
|
|
259
|
+
"variableDefinitions": [{
|
|
260
|
+
"kind": "VariableDefinition",
|
|
261
|
+
"variable": {
|
|
262
|
+
"kind": "Variable",
|
|
263
|
+
"name": {
|
|
264
|
+
"kind": "Name",
|
|
265
|
+
"value": "first"
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
"type": {
|
|
269
|
+
"kind": "NamedType",
|
|
270
|
+
"name": {
|
|
271
|
+
"kind": "Name",
|
|
272
|
+
"value": "Int"
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}],
|
|
276
|
+
"selectionSet": {
|
|
277
|
+
"kind": "SelectionSet",
|
|
278
|
+
"selections": [{
|
|
279
|
+
"kind": "Field",
|
|
280
|
+
"name": {
|
|
281
|
+
"kind": "Name",
|
|
282
|
+
"value": "dataSilos"
|
|
283
|
+
},
|
|
284
|
+
"arguments": [{
|
|
285
|
+
"kind": "Argument",
|
|
286
|
+
"name": {
|
|
287
|
+
"kind": "Name",
|
|
288
|
+
"value": "first"
|
|
289
|
+
},
|
|
290
|
+
"value": {
|
|
291
|
+
"kind": "Variable",
|
|
292
|
+
"name": {
|
|
293
|
+
"kind": "Name",
|
|
294
|
+
"value": "first"
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}],
|
|
298
|
+
"selectionSet": {
|
|
299
|
+
"kind": "SelectionSet",
|
|
300
|
+
"selections": [{
|
|
301
|
+
"kind": "Field",
|
|
302
|
+
"name": {
|
|
303
|
+
"kind": "Name",
|
|
304
|
+
"value": "nodes"
|
|
305
|
+
},
|
|
306
|
+
"selectionSet": {
|
|
307
|
+
"kind": "SelectionSet",
|
|
308
|
+
"selections": [
|
|
309
|
+
{
|
|
310
|
+
"kind": "Field",
|
|
311
|
+
"name": {
|
|
312
|
+
"kind": "Name",
|
|
313
|
+
"value": "id"
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
"kind": "Field",
|
|
318
|
+
"name": {
|
|
319
|
+
"kind": "Name",
|
|
320
|
+
"value": "title"
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"kind": "Field",
|
|
325
|
+
"name": {
|
|
326
|
+
"kind": "Name",
|
|
327
|
+
"value": "type"
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"kind": "Field",
|
|
332
|
+
"name": {
|
|
333
|
+
"kind": "Name",
|
|
334
|
+
"value": "description"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
]
|
|
338
|
+
}
|
|
339
|
+
}, {
|
|
340
|
+
"kind": "Field",
|
|
341
|
+
"name": {
|
|
342
|
+
"kind": "Name",
|
|
343
|
+
"value": "totalCount"
|
|
344
|
+
}
|
|
345
|
+
}]
|
|
346
|
+
}
|
|
347
|
+
}]
|
|
348
|
+
}
|
|
349
|
+
}]
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
function graphql(source) {
|
|
353
|
+
return documents[source] ?? {};
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
356
|
+
//#region src/graphql.ts
|
|
357
|
+
const ListDataSilosForClassificationDoc = graphql(`
|
|
358
|
+
query DiscoveryListDataSilos($first: Int) {
|
|
359
|
+
dataSilos(first: $first) {
|
|
360
|
+
nodes {
|
|
361
|
+
id
|
|
362
|
+
title
|
|
363
|
+
type
|
|
364
|
+
createdAt
|
|
365
|
+
}
|
|
366
|
+
totalCount
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
`);
|
|
370
|
+
const ListDataSiloTypesDoc = graphql(`
|
|
371
|
+
query DiscoveryListDataSiloTypes($first: Int) {
|
|
372
|
+
dataSilos(first: $first) {
|
|
373
|
+
nodes {
|
|
374
|
+
id
|
|
375
|
+
title
|
|
376
|
+
type
|
|
377
|
+
description
|
|
378
|
+
}
|
|
379
|
+
totalCount
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
`);
|
|
383
|
+
var DiscoveryMixin = class extends TranscendGraphQLBase {
|
|
384
|
+
async listClassificationScans(options) {
|
|
385
|
+
const data = await this.makeRequest(ListDataSilosForClassificationDoc, { first: Math.min(options?.first ?? 50, 100) });
|
|
386
|
+
const scans = data.dataSilos.nodes.map((silo) => ({
|
|
387
|
+
id: silo.id,
|
|
388
|
+
name: `Classification: ${silo.title}`,
|
|
389
|
+
type: silo.type,
|
|
390
|
+
status: "COMPLETED",
|
|
391
|
+
dataSiloId: silo.id,
|
|
392
|
+
createdAt: silo.createdAt
|
|
393
|
+
}));
|
|
394
|
+
return {
|
|
395
|
+
nodes: scans,
|
|
396
|
+
pageInfo: {
|
|
397
|
+
hasNextPage: scans.length < data.dataSilos.totalCount,
|
|
398
|
+
hasPreviousPage: false
|
|
399
|
+
},
|
|
400
|
+
totalCount: data.dataSilos.totalCount
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
async listDiscoveryPlugins(options) {
|
|
404
|
+
const data = await this.makeRequest(ListDataSiloTypesDoc, { first: options?.first ?? 50 });
|
|
405
|
+
const typeMap = /* @__PURE__ */ new Map();
|
|
406
|
+
data.dataSilos.nodes.forEach((silo) => {
|
|
407
|
+
if (!typeMap.has(silo.type)) typeMap.set(silo.type, {
|
|
408
|
+
id: silo.type,
|
|
409
|
+
name: silo.type.replace(/([A-Z])/g, " $1").trim(),
|
|
410
|
+
type: silo.type,
|
|
411
|
+
description: `Integration for ${silo.type}`,
|
|
412
|
+
isEnabled: true
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
const plugins = Array.from(typeMap.values());
|
|
416
|
+
return {
|
|
417
|
+
nodes: plugins,
|
|
418
|
+
pageInfo: {
|
|
419
|
+
hasNextPage: false,
|
|
420
|
+
hasPreviousPage: false
|
|
421
|
+
},
|
|
422
|
+
totalCount: plugins.length
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
//#endregion
|
|
427
|
+
export { ListScansSchema as a, NerExtractSchema as i, DISCOVERY_OAUTH_SCOPES as n, ListPluginsSchema as o, getDiscoveryTools as r, ClassifyTextSchema as s, DiscoveryMixin as t };
|
|
428
|
+
|
|
429
|
+
//# sourceMappingURL=graphql-piEf44KX.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql-piEf44KX.mjs","names":["types.DiscoveryListDataSilosDocument","types.DiscoveryListDataSiloTypesDocument"],"sources":["../src/tools/discovery_classify_text.ts","../src/tools/discovery_list_plugins.ts","../src/tools/discovery_list_scans.ts","../src/tools/discovery_ner_extract.ts","../src/tools/index.ts","../src/scopes.ts","../src/__generated__/graphql.ts","../src/__generated__/gql.ts","../src/graphql.ts"],"sourcesContent":["import { createToolResult, defineTool, z, type ToolClients } from '@transcend-io/mcp-server-base';\n\nexport const ClassifyTextSchema = z.object({\n texts: z.array(z.string()).describe('Array of text strings to classify'),\n categories: z\n .array(z.string())\n .optional()\n .describe('Specific categories to classify against (optional)'),\n model: z.string().optional().describe('LLM model to use for classification (optional)'),\n});\nexport type ClassifyTextInput = z.infer<typeof ClassifyTextSchema>;\n\nexport function createDiscoveryClassifyTextTool(clients: ToolClients) {\n const { rest } = clients;\n return defineTool({\n name: 'discovery_classify_text',\n description:\n \"Classify text content using Transcend's LLM classifier to identify data categories\",\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: ClassifyTextSchema,\n handler: async ({ texts, categories, model }) => {\n const results = await rest.classifyText({\n texts,\n categories,\n model,\n });\n\n return createToolResult(true, {\n results,\n inputCount: texts.length,\n message: `Classified ${texts.length} text(s) successfully`,\n });\n },\n });\n}\n","import {\n createListResult,\n defineTool,\n PaginationSchema,\n z,\n type ToolClients,\n} from '@transcend-io/mcp-server-base';\n\nimport type { DiscoveryMixin } from '../graphql.js';\n\nexport const ListPluginsSchema = PaginationSchema.extend({\n cursor: z\n .string()\n .optional()\n .describe('Pagination cursor from previous response (where supported)'),\n});\nexport type ListPluginsInput = z.infer<typeof ListPluginsSchema>;\n\nexport function createDiscoveryListPluginsTool(clients: ToolClients) {\n const graphql = clients.graphql as DiscoveryMixin;\n return defineTool({\n name: 'discovery_list_plugins',\n description: 'List all available discovery plugins (integration types) in your organization.',\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: ListPluginsSchema,\n handler: async ({ limit, cursor }) => {\n const result = await graphql.listDiscoveryPlugins({\n first: limit,\n after: cursor,\n });\n return createListResult(result.nodes, {\n totalCount: result.totalCount,\n hasNextPage: result.pageInfo?.hasNextPage,\n });\n },\n });\n}\n","import {\n createListResult,\n defineTool,\n PaginationSchema,\n z,\n type ToolClients,\n} from '@transcend-io/mcp-server-base';\n\nimport type { DiscoveryMixin } from '../graphql.js';\n\nexport const ListScansSchema = PaginationSchema.extend({\n cursor: z\n .string()\n .optional()\n .describe('Pagination cursor from previous response (where supported)'),\n});\nexport type ListScansInput = z.infer<typeof ListScansSchema>;\n\nexport function createDiscoveryListScansTool(clients: ToolClients) {\n const graphql = clients.graphql as DiscoveryMixin;\n return defineTool({\n name: 'discovery_list_scans',\n description: 'List all data classification scans. Returns data silos with classification info.',\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: ListScansSchema,\n handler: async ({ limit, cursor }) => {\n const result = await graphql.listClassificationScans({\n first: limit,\n after: cursor,\n });\n return createListResult(result.nodes, {\n totalCount: result.totalCount,\n hasNextPage: result.pageInfo?.hasNextPage,\n });\n },\n });\n}\n","import { createToolResult, defineTool, z, type ToolClients } from '@transcend-io/mcp-server-base';\n\nexport const NerExtractSchema = z.object({\n text: z.string().describe('Text to extract entities from'),\n entityTypes: z\n .array(z.string())\n .optional()\n .describe('Specific entity types to extract (optional)'),\n});\nexport type NerExtractInput = z.infer<typeof NerExtractSchema>;\n\nexport function createDiscoveryNerExtractTool(clients: ToolClients) {\n const { rest } = clients;\n return defineTool({\n name: 'discovery_ner_extract',\n description: 'Extract named entities (PII, organizations, locations, etc.) from text using NER',\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: NerExtractSchema,\n handler: async ({ text, entityTypes }) => {\n const result = await rest.extractEntities({\n text,\n entityTypes,\n });\n\n return createToolResult(true, {\n entities: result.entities,\n entityCount: result.entities.length,\n entityTypes: [...new Set(result.entities.map((e) => e.type))],\n message: `Extracted ${result.entities.length} entities from text`,\n });\n },\n });\n}\n","import type { ToolDefinition, ToolClients } from '@transcend-io/mcp-server-base';\n\nimport { createDiscoveryClassifyTextTool } from './discovery_classify_text.js';\nimport { createDiscoveryListPluginsTool } from './discovery_list_plugins.js';\nimport { createDiscoveryListScansTool } from './discovery_list_scans.js';\nimport { createDiscoveryNerExtractTool } from './discovery_ner_extract.js';\n\nexport function getDiscoveryTools(clients: ToolClients): ToolDefinition[] {\n return [\n createDiscoveryClassifyTextTool(clients),\n createDiscoveryNerExtractTool(clients),\n createDiscoveryListScansTool(clients),\n createDiscoveryListPluginsTool(clients),\n ];\n}\n","import { ScopeName } from '@transcend-io/privacy-types';\n\n/** OAuth scopes required for Discovery MCP tools (offline_access added by base). */\nexport const DISCOVERY_OAUTH_SCOPES = [\n ScopeName.ViewDataMap,\n ScopeName.ViewAssignedIntegrations,\n ScopeName.ViewCodeScanning,\n ScopeName.ManageCodeScanning,\n ScopeName.ViewPrompts,\n ScopeName.ViewPromptRuns,\n ScopeName.ExecutePrompt,\n] as const;\n","/* eslint-disable */\n/** Internal type. DO NOT USE DIRECTLY. */\ntype Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };\n/** Internal type. DO NOT USE DIRECTLY. */\nexport type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };\nimport type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';\nexport type DiscoveryListDataSilosQueryVariables = Exact<{\n first?: number | null | undefined;\n}>;\n\n\nexport type DiscoveryListDataSilosQuery = { dataSilos: { totalCount: number, nodes: Array<{ id: string, title: string, type: string, createdAt: string }> } };\n\nexport type DiscoveryListDataSiloTypesQueryVariables = Exact<{\n first?: number | null | undefined;\n}>;\n\n\nexport type DiscoveryListDataSiloTypesQuery = { dataSilos: { totalCount: number, nodes: Array<{ id: string, title: string, type: string, description: string }> } };\n\n\nexport const DiscoveryListDataSilosDocument = {\"kind\":\"Document\",\"definitions\":[{\"kind\":\"OperationDefinition\",\"operation\":\"query\",\"name\":{\"kind\":\"Name\",\"value\":\"DiscoveryListDataSilos\"},\"variableDefinitions\":[{\"kind\":\"VariableDefinition\",\"variable\":{\"kind\":\"Variable\",\"name\":{\"kind\":\"Name\",\"value\":\"first\"}},\"type\":{\"kind\":\"NamedType\",\"name\":{\"kind\":\"Name\",\"value\":\"Int\"}}}],\"selectionSet\":{\"kind\":\"SelectionSet\",\"selections\":[{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"dataSilos\"},\"arguments\":[{\"kind\":\"Argument\",\"name\":{\"kind\":\"Name\",\"value\":\"first\"},\"value\":{\"kind\":\"Variable\",\"name\":{\"kind\":\"Name\",\"value\":\"first\"}}}],\"selectionSet\":{\"kind\":\"SelectionSet\",\"selections\":[{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"nodes\"},\"selectionSet\":{\"kind\":\"SelectionSet\",\"selections\":[{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"id\"}},{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"title\"}},{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"type\"}},{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"createdAt\"}}]}},{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"totalCount\"}}]}}]}}]} as unknown as DocumentNode<DiscoveryListDataSilosQuery, DiscoveryListDataSilosQueryVariables>;\nexport const DiscoveryListDataSiloTypesDocument = {\"kind\":\"Document\",\"definitions\":[{\"kind\":\"OperationDefinition\",\"operation\":\"query\",\"name\":{\"kind\":\"Name\",\"value\":\"DiscoveryListDataSiloTypes\"},\"variableDefinitions\":[{\"kind\":\"VariableDefinition\",\"variable\":{\"kind\":\"Variable\",\"name\":{\"kind\":\"Name\",\"value\":\"first\"}},\"type\":{\"kind\":\"NamedType\",\"name\":{\"kind\":\"Name\",\"value\":\"Int\"}}}],\"selectionSet\":{\"kind\":\"SelectionSet\",\"selections\":[{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"dataSilos\"},\"arguments\":[{\"kind\":\"Argument\",\"name\":{\"kind\":\"Name\",\"value\":\"first\"},\"value\":{\"kind\":\"Variable\",\"name\":{\"kind\":\"Name\",\"value\":\"first\"}}}],\"selectionSet\":{\"kind\":\"SelectionSet\",\"selections\":[{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"nodes\"},\"selectionSet\":{\"kind\":\"SelectionSet\",\"selections\":[{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"id\"}},{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"title\"}},{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"type\"}},{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"description\"}}]}},{\"kind\":\"Field\",\"name\":{\"kind\":\"Name\",\"value\":\"totalCount\"}}]}}]}}]} as unknown as DocumentNode<DiscoveryListDataSiloTypesQuery, DiscoveryListDataSiloTypesQueryVariables>;","/* eslint-disable */\nimport * as types from './graphql.js';\nimport type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';\n\n/**\n * Map of all GraphQL operations in the project.\n *\n * This map has several performance disadvantages:\n * 1. It is not tree-shakeable, so it will include all operations in the project.\n * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.\n * 3. It does not support dead code elimination, so it will add unused operations.\n *\n * Therefore it is highly recommended to use the babel or swc plugin for production.\n * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size\n */\ntype Documents = {\n \"\\n query DiscoveryListDataSilos($first: Int) {\\n dataSilos(first: $first) {\\n nodes {\\n id\\n title\\n type\\n createdAt\\n }\\n totalCount\\n }\\n }\\n\": typeof types.DiscoveryListDataSilosDocument,\n \"\\n query DiscoveryListDataSiloTypes($first: Int) {\\n dataSilos(first: $first) {\\n nodes {\\n id\\n title\\n type\\n description\\n }\\n totalCount\\n }\\n }\\n\": typeof types.DiscoveryListDataSiloTypesDocument,\n};\nconst documents: Documents = {\n \"\\n query DiscoveryListDataSilos($first: Int) {\\n dataSilos(first: $first) {\\n nodes {\\n id\\n title\\n type\\n createdAt\\n }\\n totalCount\\n }\\n }\\n\": types.DiscoveryListDataSilosDocument,\n \"\\n query DiscoveryListDataSiloTypes($first: Int) {\\n dataSilos(first: $first) {\\n nodes {\\n id\\n title\\n type\\n description\\n }\\n totalCount\\n }\\n }\\n\": types.DiscoveryListDataSiloTypesDocument,\n};\n\n/**\n * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.\n *\n *\n * @example\n * ```ts\n * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);\n * ```\n *\n * The query argument is unknown!\n * Please regenerate the types.\n */\nexport function graphql(source: string): unknown;\n\n/**\n * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.\n */\nexport function graphql(source: \"\\n query DiscoveryListDataSilos($first: Int) {\\n dataSilos(first: $first) {\\n nodes {\\n id\\n title\\n type\\n createdAt\\n }\\n totalCount\\n }\\n }\\n\"): (typeof documents)[\"\\n query DiscoveryListDataSilos($first: Int) {\\n dataSilos(first: $first) {\\n nodes {\\n id\\n title\\n type\\n createdAt\\n }\\n totalCount\\n }\\n }\\n\"];\n/**\n * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.\n */\nexport function graphql(source: \"\\n query DiscoveryListDataSiloTypes($first: Int) {\\n dataSilos(first: $first) {\\n nodes {\\n id\\n title\\n type\\n description\\n }\\n totalCount\\n }\\n }\\n\"): (typeof documents)[\"\\n query DiscoveryListDataSiloTypes($first: Int) {\\n dataSilos(first: $first) {\\n nodes {\\n id\\n title\\n type\\n description\\n }\\n totalCount\\n }\\n }\\n\"];\n\nexport function graphql(source: string) {\n return (documents as any)[source] ?? {};\n}\n\nexport type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;","import {\n TranscendGraphQLBase,\n type ClassificationScan,\n type DiscoveryPlugin,\n type ListOptions,\n type PaginatedResponse,\n} from '@transcend-io/mcp-server-base';\n\nimport { graphql } from './__generated__/gql.js';\n\nconst ListDataSilosForClassificationDoc = graphql(/* GraphQL */ `\n query DiscoveryListDataSilos($first: Int) {\n dataSilos(first: $first) {\n nodes {\n id\n title\n type\n createdAt\n }\n totalCount\n }\n }\n`);\n\nconst ListDataSiloTypesDoc = graphql(/* GraphQL */ `\n query DiscoveryListDataSiloTypes($first: Int) {\n dataSilos(first: $first) {\n nodes {\n id\n title\n type\n description\n }\n totalCount\n }\n }\n`);\n\nexport class DiscoveryMixin extends TranscendGraphQLBase {\n async listClassificationScans(\n options?: ListOptions,\n ): Promise<PaginatedResponse<ClassificationScan>> {\n const data = await this.makeRequest(ListDataSilosForClassificationDoc, {\n first: Math.min(options?.first ?? 50, 100),\n });\n const scans: ClassificationScan[] = data.dataSilos.nodes.map((silo) => ({\n id: silo.id,\n name: `Classification: ${silo.title}`,\n type: silo.type,\n status: 'COMPLETED',\n dataSiloId: silo.id,\n createdAt: silo.createdAt,\n }));\n return {\n nodes: scans,\n pageInfo: { hasNextPage: scans.length < data.dataSilos.totalCount, hasPreviousPage: false },\n totalCount: data.dataSilos.totalCount,\n };\n }\n\n async listDiscoveryPlugins(options?: ListOptions): Promise<PaginatedResponse<DiscoveryPlugin>> {\n const data = await this.makeRequest(ListDataSiloTypesDoc, {\n first: options?.first ?? 50,\n });\n const typeMap = new Map<string, DiscoveryPlugin>();\n data.dataSilos.nodes.forEach((silo) => {\n if (!typeMap.has(silo.type)) {\n typeMap.set(silo.type, {\n id: silo.type,\n name: silo.type.replace(/([A-Z])/g, ' $1').trim(),\n type: silo.type,\n description: `Integration for ${silo.type}`,\n isEnabled: true,\n });\n }\n });\n const plugins = Array.from(typeMap.values());\n return {\n nodes: plugins,\n pageInfo: { hasNextPage: false, hasPreviousPage: false },\n totalCount: plugins.length,\n };\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { ClassificationScan, DiscoveryPlugin, ListOptions, PaginatedResponse, ToolClients, ToolDefinition, TranscendGraphQLBase, z } from "@transcend-io/mcp-server-base";
|
|
2
|
+
import { ScopeName } from "@transcend-io/privacy-types";
|
|
2
3
|
|
|
3
4
|
//#region src/tools/index.d.ts
|
|
4
5
|
declare function getDiscoveryTools(clients: ToolClients): ToolDefinition[];
|
|
5
6
|
//#endregion
|
|
7
|
+
//#region src/scopes.d.ts
|
|
8
|
+
/** OAuth scopes required for Discovery MCP tools (offline_access added by base). */
|
|
9
|
+
declare const DISCOVERY_OAUTH_SCOPES: readonly [ScopeName.ViewDataMap, ScopeName.ViewAssignedIntegrations, ScopeName.ViewCodeScanning, ScopeName.ManageCodeScanning, ScopeName.ViewPrompts, ScopeName.ViewPromptRuns, ScopeName.ExecutePrompt];
|
|
10
|
+
//#endregion
|
|
6
11
|
//#region src/graphql.d.ts
|
|
7
12
|
declare class DiscoveryMixin extends TranscendGraphQLBase {
|
|
8
13
|
listClassificationScans(options?: ListOptions): Promise<PaginatedResponse<ClassificationScan>>;
|
|
9
|
-
startClassificationScan(input: {
|
|
10
|
-
name: string;
|
|
11
|
-
dataSiloId?: string;
|
|
12
|
-
type?: string;
|
|
13
|
-
}): Promise<ClassificationScan>;
|
|
14
|
-
getClassificationScan(id: string): Promise<ClassificationScan>;
|
|
15
14
|
listDiscoveryPlugins(options?: ListOptions): Promise<PaginatedResponse<DiscoveryPlugin>>;
|
|
16
15
|
}
|
|
17
16
|
//#endregion
|
|
@@ -23,12 +22,6 @@ declare const ClassifyTextSchema: z.ZodObject<{
|
|
|
23
22
|
}, z.core.$strip>;
|
|
24
23
|
type ClassifyTextInput = z.infer<typeof ClassifyTextSchema>;
|
|
25
24
|
//#endregion
|
|
26
|
-
//#region src/tools/discovery_get_scan.d.ts
|
|
27
|
-
declare const GetScanSchema: z.ZodObject<{
|
|
28
|
-
scan_id: z.ZodString;
|
|
29
|
-
}, z.core.$strip>;
|
|
30
|
-
type GetScanInput = z.infer<typeof GetScanSchema>;
|
|
31
|
-
//#endregion
|
|
32
25
|
//#region src/tools/discovery_list_plugins.d.ts
|
|
33
26
|
declare const ListPluginsSchema: z.ZodObject<{
|
|
34
27
|
limit: z.ZodDefault<z.ZodOptional<z.ZodCoercedNumber<unknown>>>;
|
|
@@ -46,17 +39,9 @@ type ListScansInput = z.infer<typeof ListScansSchema>;
|
|
|
46
39
|
//#region src/tools/discovery_ner_extract.d.ts
|
|
47
40
|
declare const NerExtractSchema: z.ZodObject<{
|
|
48
41
|
text: z.ZodString;
|
|
49
|
-
|
|
42
|
+
entityTypes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
50
43
|
}, z.core.$strip>;
|
|
51
44
|
type NerExtractInput = z.infer<typeof NerExtractSchema>;
|
|
52
45
|
//#endregion
|
|
53
|
-
|
|
54
|
-
declare const StartScanSchema: z.ZodObject<{
|
|
55
|
-
name: z.ZodString;
|
|
56
|
-
data_silo_id: z.ZodOptional<z.ZodString>;
|
|
57
|
-
type: z.ZodOptional<z.ZodString>;
|
|
58
|
-
}, z.core.$strip>;
|
|
59
|
-
type StartScanInput = z.infer<typeof StartScanSchema>;
|
|
60
|
-
//#endregion
|
|
61
|
-
export { type ClassifyTextInput, ClassifyTextSchema, DiscoveryMixin, type GetScanInput, GetScanSchema, type ListPluginsInput, ListPluginsSchema, type ListScansInput, ListScansSchema, type NerExtractInput, NerExtractSchema, type StartScanInput, StartScanSchema, getDiscoveryTools };
|
|
46
|
+
export { type ClassifyTextInput, ClassifyTextSchema, DISCOVERY_OAUTH_SCOPES, DiscoveryMixin, type ListPluginsInput, ListPluginsSchema, type ListScansInput, ListScansSchema, type NerExtractInput, NerExtractSchema, getDiscoveryTools };
|
|
62
47
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/tools/index.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/tools/index.ts","../src/scopes.ts","../src/graphql.ts","../src/tools/discovery_classify_text.ts","../src/tools/discovery_list_plugins.ts","../src/tools/discovery_list_scans.ts","../src/tools/discovery_ner_extract.ts"],"mappings":";;;;iBAOgB,iBAAA,CAAkB,OAAA,EAAS,WAAA,GAAc,cAAA;;;;cCJ5C,sBAAA,YAAsB,SAAA,CAAA,WAAA,EAAA,SAAA,CAAA,wBAAA,EAAA,SAAA,CAAA,gBAAA,EAAA,SAAA,CAAA,kBAAA,EAAA,SAAA,CAAA,WAAA,EAAA,SAAA,CAAA,cAAA,EAAA,SAAA,CAAA,aAAA;;;cCmCtB,cAAA,SAAuB,oBAAA;EAC5B,uBAAA,CACJ,OAAA,GAAU,WAAA,GACT,OAAA,CAAQ,iBAAA,CAAkB,kBAAA;EAmBvB,oBAAA,CAAqB,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,iBAAA,CAAkB,eAAA;AAAA;;;cC1DlE,kBAAA,EAAkB,CAAA,CAAA,SAAA;;;;;KAQnB,iBAAA,GAAoB,CAAA,CAAE,KAAA,QAAa,kBAAA;;;cCAlC,iBAAA,EAAiB,CAAA,CAAA,SAAA;;;;KAMlB,gBAAA,GAAmB,CAAA,CAAE,KAAA,QAAa,iBAAA;;;cCNjC,eAAA,EAAe,CAAA,CAAA,SAAA;;;;KAMhB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,eAAA;;;cCd/B,gBAAA,EAAgB,CAAA,CAAA,SAAA;;;;KAOjB,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,gBAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ListScansSchema,
|
|
2
|
-
export { ClassifyTextSchema,
|
|
1
|
+
import { a as ListScansSchema, i as NerExtractSchema, n as DISCOVERY_OAUTH_SCOPES, o as ListPluginsSchema, r as getDiscoveryTools, s as ClassifyTextSchema, t as DiscoveryMixin } from "./graphql-piEf44KX.mjs";
|
|
2
|
+
export { ClassifyTextSchema, DISCOVERY_OAUTH_SCOPES, DiscoveryMixin, ListPluginsSchema, ListScansSchema, NerExtractSchema, getDiscoveryTools };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transcend-io/mcp-server-discovery",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Transcend MCP Server — Data Discovery tools.",
|
|
5
5
|
"homepage": "https://github.com/transcend-io/tools/tree/main/packages/mcp/mcp-server-discovery",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,16 +30,19 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@graphql-typed-document-node/core": "^3.2.0",
|
|
33
34
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
35
|
+
"graphql": "^16.14.0",
|
|
34
36
|
"zod": "^4.3.6",
|
|
35
|
-
"@transcend-io/mcp-server-base": "0.
|
|
37
|
+
"@transcend-io/mcp-server-base": "0.5.0",
|
|
38
|
+
"@transcend-io/privacy-types": "5.3.2"
|
|
36
39
|
},
|
|
37
40
|
"devDependencies": {
|
|
38
41
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
39
42
|
"@types/node": "^22.19.15",
|
|
40
43
|
"publint": "^0.3.18",
|
|
41
44
|
"tsdown": "^0.21.2",
|
|
42
|
-
"typescript": "^
|
|
45
|
+
"typescript": "^6.0.0",
|
|
43
46
|
"vitest": "^4.0.18"
|
|
44
47
|
},
|
|
45
48
|
"engines": {
|
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
import { PaginationSchema, TranscendGraphQLBase, createListResult, createToolResult, defineTool, z } from "@transcend-io/mcp-server-base";
|
|
2
|
-
//#region src/tools/discovery_classify_text.ts
|
|
3
|
-
const ClassifyTextSchema = z.object({
|
|
4
|
-
texts: z.array(z.string()).describe("Array of text strings to classify"),
|
|
5
|
-
categories: z.array(z.string()).optional().describe("Specific categories to classify against (optional)"),
|
|
6
|
-
model: z.string().optional().describe("LLM model to use for classification (optional)")
|
|
7
|
-
});
|
|
8
|
-
function createDiscoveryClassifyTextTool(clients) {
|
|
9
|
-
const { rest } = clients;
|
|
10
|
-
return defineTool({
|
|
11
|
-
name: "discovery_classify_text",
|
|
12
|
-
description: "Classify text content using Transcend's LLM classifier to identify data categories",
|
|
13
|
-
category: "Data Discovery",
|
|
14
|
-
readOnly: true,
|
|
15
|
-
annotations: {
|
|
16
|
-
readOnlyHint: true,
|
|
17
|
-
destructiveHint: false,
|
|
18
|
-
idempotentHint: true
|
|
19
|
-
},
|
|
20
|
-
zodSchema: ClassifyTextSchema,
|
|
21
|
-
handler: async ({ texts, categories, model }) => {
|
|
22
|
-
return createToolResult(true, {
|
|
23
|
-
results: await rest.classifyText({
|
|
24
|
-
texts,
|
|
25
|
-
categories,
|
|
26
|
-
model
|
|
27
|
-
}),
|
|
28
|
-
inputCount: texts.length,
|
|
29
|
-
message: `Classified ${texts.length} text(s) successfully`
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
//#endregion
|
|
35
|
-
//#region src/tools/discovery_get_scan.ts
|
|
36
|
-
const GetScanSchema = z.object({ scan_id: z.string().describe("ID of the classification scan to retrieve") });
|
|
37
|
-
function createDiscoveryGetScanTool(clients) {
|
|
38
|
-
const graphql = clients.graphql;
|
|
39
|
-
return defineTool({
|
|
40
|
-
name: "discovery_get_scan",
|
|
41
|
-
description: "Get detailed information about a specific classification scan including results.",
|
|
42
|
-
category: "Data Discovery",
|
|
43
|
-
readOnly: true,
|
|
44
|
-
annotations: {
|
|
45
|
-
readOnlyHint: true,
|
|
46
|
-
destructiveHint: false,
|
|
47
|
-
idempotentHint: true
|
|
48
|
-
},
|
|
49
|
-
zodSchema: GetScanSchema,
|
|
50
|
-
handler: async ({ scan_id }) => {
|
|
51
|
-
return createToolResult(true, await graphql.getClassificationScan(scan_id));
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region src/tools/discovery_list_plugins.ts
|
|
57
|
-
const ListPluginsSchema = PaginationSchema.extend({ cursor: z.string().optional().describe("Pagination cursor from previous response (where supported)") });
|
|
58
|
-
function createDiscoveryListPluginsTool(clients) {
|
|
59
|
-
const graphql = clients.graphql;
|
|
60
|
-
return defineTool({
|
|
61
|
-
name: "discovery_list_plugins",
|
|
62
|
-
description: "List all available discovery plugins (integration types) in your organization.",
|
|
63
|
-
category: "Data Discovery",
|
|
64
|
-
readOnly: true,
|
|
65
|
-
annotations: {
|
|
66
|
-
readOnlyHint: true,
|
|
67
|
-
destructiveHint: false,
|
|
68
|
-
idempotentHint: true
|
|
69
|
-
},
|
|
70
|
-
zodSchema: ListPluginsSchema,
|
|
71
|
-
handler: async ({ limit, cursor }) => {
|
|
72
|
-
const result = await graphql.listDiscoveryPlugins({
|
|
73
|
-
first: limit,
|
|
74
|
-
after: cursor
|
|
75
|
-
});
|
|
76
|
-
return createListResult(result.nodes, {
|
|
77
|
-
totalCount: result.totalCount,
|
|
78
|
-
hasNextPage: result.pageInfo?.hasNextPage
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
//#endregion
|
|
84
|
-
//#region src/tools/discovery_list_scans.ts
|
|
85
|
-
const ListScansSchema = PaginationSchema.extend({ cursor: z.string().optional().describe("Pagination cursor from previous response (where supported)") });
|
|
86
|
-
function createDiscoveryListScansTool(clients) {
|
|
87
|
-
const graphql = clients.graphql;
|
|
88
|
-
return defineTool({
|
|
89
|
-
name: "discovery_list_scans",
|
|
90
|
-
description: "List all data classification scans. Returns data silos with classification info.",
|
|
91
|
-
category: "Data Discovery",
|
|
92
|
-
readOnly: true,
|
|
93
|
-
annotations: {
|
|
94
|
-
readOnlyHint: true,
|
|
95
|
-
destructiveHint: false,
|
|
96
|
-
idempotentHint: true
|
|
97
|
-
},
|
|
98
|
-
zodSchema: ListScansSchema,
|
|
99
|
-
handler: async ({ limit, cursor }) => {
|
|
100
|
-
const result = await graphql.listClassificationScans({
|
|
101
|
-
first: limit,
|
|
102
|
-
after: cursor
|
|
103
|
-
});
|
|
104
|
-
return createListResult(result.nodes, {
|
|
105
|
-
totalCount: result.totalCount,
|
|
106
|
-
hasNextPage: result.pageInfo?.hasNextPage
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
//#endregion
|
|
112
|
-
//#region src/tools/discovery_ner_extract.ts
|
|
113
|
-
const NerExtractSchema = z.object({
|
|
114
|
-
text: z.string().describe("Text to extract entities from"),
|
|
115
|
-
entity_types: z.array(z.string()).optional().describe("Specific entity types to extract (optional)")
|
|
116
|
-
});
|
|
117
|
-
function createDiscoveryNerExtractTool(clients) {
|
|
118
|
-
const { rest } = clients;
|
|
119
|
-
return defineTool({
|
|
120
|
-
name: "discovery_ner_extract",
|
|
121
|
-
description: "Extract named entities (PII, organizations, locations, etc.) from text using NER",
|
|
122
|
-
category: "Data Discovery",
|
|
123
|
-
readOnly: true,
|
|
124
|
-
annotations: {
|
|
125
|
-
readOnlyHint: true,
|
|
126
|
-
destructiveHint: false,
|
|
127
|
-
idempotentHint: true
|
|
128
|
-
},
|
|
129
|
-
zodSchema: NerExtractSchema,
|
|
130
|
-
handler: async ({ text, entity_types }) => {
|
|
131
|
-
const result = await rest.extractEntities({
|
|
132
|
-
text,
|
|
133
|
-
entityTypes: entity_types
|
|
134
|
-
});
|
|
135
|
-
return createToolResult(true, {
|
|
136
|
-
entities: result.entities,
|
|
137
|
-
entityCount: result.entities.length,
|
|
138
|
-
entityTypes: [...new Set(result.entities.map((e) => e.type))],
|
|
139
|
-
message: `Extracted ${result.entities.length} entities from text`
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
//#endregion
|
|
145
|
-
//#region src/tools/discovery_start_scan.ts
|
|
146
|
-
const StartScanSchema = z.object({
|
|
147
|
-
name: z.string().describe("Name for the classification scan"),
|
|
148
|
-
data_silo_id: z.string().optional().describe("ID of the data silo to scan (optional)"),
|
|
149
|
-
type: z.string().optional().describe("Type of scan (optional)")
|
|
150
|
-
});
|
|
151
|
-
function createDiscoveryStartScanTool(clients) {
|
|
152
|
-
const graphql = clients.graphql;
|
|
153
|
-
return defineTool({
|
|
154
|
-
name: "discovery_start_scan",
|
|
155
|
-
description: "Start a new data classification scan on a data silo.",
|
|
156
|
-
category: "Data Discovery",
|
|
157
|
-
readOnly: false,
|
|
158
|
-
confirmationHint: "Starts a new classification scan on the data silo",
|
|
159
|
-
annotations: {
|
|
160
|
-
readOnlyHint: false,
|
|
161
|
-
destructiveHint: false,
|
|
162
|
-
idempotentHint: false
|
|
163
|
-
},
|
|
164
|
-
zodSchema: StartScanSchema,
|
|
165
|
-
handler: async ({ name, data_silo_id, type }) => {
|
|
166
|
-
return createToolResult(true, {
|
|
167
|
-
scan: await graphql.startClassificationScan({
|
|
168
|
-
name,
|
|
169
|
-
dataSiloId: data_silo_id,
|
|
170
|
-
type
|
|
171
|
-
}),
|
|
172
|
-
message: `Classification scan "${name}" started successfully`
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
//#endregion
|
|
178
|
-
//#region src/tools/index.ts
|
|
179
|
-
function getDiscoveryTools(clients) {
|
|
180
|
-
return [
|
|
181
|
-
createDiscoveryClassifyTextTool(clients),
|
|
182
|
-
createDiscoveryNerExtractTool(clients),
|
|
183
|
-
createDiscoveryListScansTool(clients),
|
|
184
|
-
createDiscoveryStartScanTool(clients),
|
|
185
|
-
createDiscoveryGetScanTool(clients),
|
|
186
|
-
createDiscoveryListPluginsTool(clients)
|
|
187
|
-
];
|
|
188
|
-
}
|
|
189
|
-
//#endregion
|
|
190
|
-
//#region src/graphql.ts
|
|
191
|
-
var DiscoveryMixin = class extends TranscendGraphQLBase {
|
|
192
|
-
async listClassificationScans(options) {
|
|
193
|
-
const data = await this.makeRequest(`
|
|
194
|
-
query ListDataSilosForClassification($first: Int) {
|
|
195
|
-
dataSilos(first: $first) {
|
|
196
|
-
nodes {
|
|
197
|
-
id
|
|
198
|
-
title
|
|
199
|
-
type
|
|
200
|
-
createdAt
|
|
201
|
-
}
|
|
202
|
-
totalCount
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
`, { first: Math.min(options?.first || 50, 100) });
|
|
206
|
-
const scans = data.dataSilos.nodes.map((silo) => ({
|
|
207
|
-
id: silo.id,
|
|
208
|
-
name: `Classification: ${silo.title}`,
|
|
209
|
-
type: silo.type,
|
|
210
|
-
status: "COMPLETED",
|
|
211
|
-
dataSiloId: silo.id,
|
|
212
|
-
createdAt: silo.createdAt
|
|
213
|
-
}));
|
|
214
|
-
return {
|
|
215
|
-
nodes: scans,
|
|
216
|
-
pageInfo: {
|
|
217
|
-
hasNextPage: scans.length < data.dataSilos.totalCount,
|
|
218
|
-
hasPreviousPage: false
|
|
219
|
-
},
|
|
220
|
-
totalCount: data.dataSilos.totalCount
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
async startClassificationScan(input) {
|
|
224
|
-
return (await this.makeRequest(`
|
|
225
|
-
mutation StartClassificationScan($input: StartClassificationScanInput!) {
|
|
226
|
-
startClassificationScan(input: $input) {
|
|
227
|
-
scan {
|
|
228
|
-
id
|
|
229
|
-
name
|
|
230
|
-
type
|
|
231
|
-
status
|
|
232
|
-
startedAt
|
|
233
|
-
createdAt
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
`, { input })).startClassificationScan.scan;
|
|
238
|
-
}
|
|
239
|
-
async getClassificationScan(id) {
|
|
240
|
-
return (await this.makeRequest(`
|
|
241
|
-
query GetClassificationScan($id: ID!) {
|
|
242
|
-
classificationScan(id: $id) {
|
|
243
|
-
id
|
|
244
|
-
name
|
|
245
|
-
type
|
|
246
|
-
status
|
|
247
|
-
startedAt
|
|
248
|
-
completedAt
|
|
249
|
-
dataSiloId
|
|
250
|
-
results {
|
|
251
|
-
id
|
|
252
|
-
path
|
|
253
|
-
dataCategory {
|
|
254
|
-
id
|
|
255
|
-
name
|
|
256
|
-
category
|
|
257
|
-
}
|
|
258
|
-
confidence
|
|
259
|
-
}
|
|
260
|
-
createdAt
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
`, { id })).classificationScan;
|
|
264
|
-
}
|
|
265
|
-
async listDiscoveryPlugins(options) {
|
|
266
|
-
const data = await this.makeRequest(`
|
|
267
|
-
query ListDataSiloTypes($first: Int) {
|
|
268
|
-
dataSilos(first: $first) {
|
|
269
|
-
nodes {
|
|
270
|
-
id
|
|
271
|
-
title
|
|
272
|
-
type
|
|
273
|
-
description
|
|
274
|
-
}
|
|
275
|
-
totalCount
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
`, { first: options?.first || 50 });
|
|
279
|
-
const typeMap = /* @__PURE__ */ new Map();
|
|
280
|
-
data.dataSilos.nodes.forEach((silo) => {
|
|
281
|
-
if (!typeMap.has(silo.type)) typeMap.set(silo.type, {
|
|
282
|
-
id: silo.type,
|
|
283
|
-
name: silo.type.replace(/([A-Z])/g, " $1").trim(),
|
|
284
|
-
type: silo.type,
|
|
285
|
-
description: `Integration for ${silo.type}`,
|
|
286
|
-
isEnabled: true
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
const plugins = Array.from(typeMap.values());
|
|
290
|
-
return {
|
|
291
|
-
nodes: plugins,
|
|
292
|
-
pageInfo: {
|
|
293
|
-
hasNextPage: false,
|
|
294
|
-
hasPreviousPage: false
|
|
295
|
-
},
|
|
296
|
-
totalCount: plugins.length
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
//#endregion
|
|
301
|
-
export { ListScansSchema as a, ClassifyTextSchema as c, NerExtractSchema as i, getDiscoveryTools as n, ListPluginsSchema as o, StartScanSchema as r, GetScanSchema as s, DiscoveryMixin as t };
|
|
302
|
-
|
|
303
|
-
//# sourceMappingURL=graphql-C5tZOWZa.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"graphql-C5tZOWZa.mjs","names":[],"sources":["../src/tools/discovery_classify_text.ts","../src/tools/discovery_get_scan.ts","../src/tools/discovery_list_plugins.ts","../src/tools/discovery_list_scans.ts","../src/tools/discovery_ner_extract.ts","../src/tools/discovery_start_scan.ts","../src/tools/index.ts","../src/graphql.ts"],"sourcesContent":["import { createToolResult, defineTool, z, type ToolClients } from '@transcend-io/mcp-server-base';\n\nexport const ClassifyTextSchema = z.object({\n texts: z.array(z.string()).describe('Array of text strings to classify'),\n categories: z\n .array(z.string())\n .optional()\n .describe('Specific categories to classify against (optional)'),\n model: z.string().optional().describe('LLM model to use for classification (optional)'),\n});\nexport type ClassifyTextInput = z.infer<typeof ClassifyTextSchema>;\n\nexport function createDiscoveryClassifyTextTool(clients: ToolClients) {\n const { rest } = clients;\n return defineTool({\n name: 'discovery_classify_text',\n description:\n \"Classify text content using Transcend's LLM classifier to identify data categories\",\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: ClassifyTextSchema,\n handler: async ({ texts, categories, model }) => {\n const results = await rest.classifyText({\n texts,\n categories,\n model,\n });\n\n return createToolResult(true, {\n results,\n inputCount: texts.length,\n message: `Classified ${texts.length} text(s) successfully`,\n });\n },\n });\n}\n","import { createToolResult, defineTool, z, type ToolClients } from '@transcend-io/mcp-server-base';\n\nimport type { DiscoveryMixin } from '../graphql.js';\n\nexport const GetScanSchema = z.object({\n scan_id: z.string().describe('ID of the classification scan to retrieve'),\n});\nexport type GetScanInput = z.infer<typeof GetScanSchema>;\n\nexport function createDiscoveryGetScanTool(clients: ToolClients) {\n const graphql = clients.graphql as DiscoveryMixin;\n return defineTool({\n name: 'discovery_get_scan',\n description: 'Get detailed information about a specific classification scan including results.',\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: GetScanSchema,\n handler: async ({ scan_id }) => {\n const result = await graphql.getClassificationScan(scan_id);\n return createToolResult(true, result);\n },\n });\n}\n","import {\n createListResult,\n defineTool,\n PaginationSchema,\n z,\n type ToolClients,\n} from '@transcend-io/mcp-server-base';\n\nimport type { DiscoveryMixin } from '../graphql.js';\n\nexport const ListPluginsSchema = PaginationSchema.extend({\n cursor: z\n .string()\n .optional()\n .describe('Pagination cursor from previous response (where supported)'),\n});\nexport type ListPluginsInput = z.infer<typeof ListPluginsSchema>;\n\nexport function createDiscoveryListPluginsTool(clients: ToolClients) {\n const graphql = clients.graphql as DiscoveryMixin;\n return defineTool({\n name: 'discovery_list_plugins',\n description: 'List all available discovery plugins (integration types) in your organization.',\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: ListPluginsSchema,\n handler: async ({ limit, cursor }) => {\n const result = await graphql.listDiscoveryPlugins({\n first: limit,\n after: cursor,\n });\n return createListResult(result.nodes, {\n totalCount: result.totalCount,\n hasNextPage: result.pageInfo?.hasNextPage,\n });\n },\n });\n}\n","import {\n createListResult,\n defineTool,\n PaginationSchema,\n z,\n type ToolClients,\n} from '@transcend-io/mcp-server-base';\n\nimport type { DiscoveryMixin } from '../graphql.js';\n\nexport const ListScansSchema = PaginationSchema.extend({\n cursor: z\n .string()\n .optional()\n .describe('Pagination cursor from previous response (where supported)'),\n});\nexport type ListScansInput = z.infer<typeof ListScansSchema>;\n\nexport function createDiscoveryListScansTool(clients: ToolClients) {\n const graphql = clients.graphql as DiscoveryMixin;\n return defineTool({\n name: 'discovery_list_scans',\n description: 'List all data classification scans. Returns data silos with classification info.',\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: ListScansSchema,\n handler: async ({ limit, cursor }) => {\n const result = await graphql.listClassificationScans({\n first: limit,\n after: cursor,\n });\n return createListResult(result.nodes, {\n totalCount: result.totalCount,\n hasNextPage: result.pageInfo?.hasNextPage,\n });\n },\n });\n}\n","import { createToolResult, defineTool, z, type ToolClients } from '@transcend-io/mcp-server-base';\n\nexport const NerExtractSchema = z.object({\n text: z.string().describe('Text to extract entities from'),\n entity_types: z\n .array(z.string())\n .optional()\n .describe('Specific entity types to extract (optional)'),\n});\nexport type NerExtractInput = z.infer<typeof NerExtractSchema>;\n\nexport function createDiscoveryNerExtractTool(clients: ToolClients) {\n const { rest } = clients;\n return defineTool({\n name: 'discovery_ner_extract',\n description: 'Extract named entities (PII, organizations, locations, etc.) from text using NER',\n category: 'Data Discovery',\n readOnly: true,\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n zodSchema: NerExtractSchema,\n handler: async ({ text, entity_types }) => {\n const result = await rest.extractEntities({\n text,\n entityTypes: entity_types,\n });\n\n return createToolResult(true, {\n entities: result.entities,\n entityCount: result.entities.length,\n entityTypes: [...new Set(result.entities.map((e) => e.type))],\n message: `Extracted ${result.entities.length} entities from text`,\n });\n },\n });\n}\n","import { createToolResult, defineTool, z, type ToolClients } from '@transcend-io/mcp-server-base';\n\nimport type { DiscoveryMixin } from '../graphql.js';\n\nexport const StartScanSchema = z.object({\n name: z.string().describe('Name for the classification scan'),\n data_silo_id: z.string().optional().describe('ID of the data silo to scan (optional)'),\n type: z.string().optional().describe('Type of scan (optional)'),\n});\nexport type StartScanInput = z.infer<typeof StartScanSchema>;\n\nexport function createDiscoveryStartScanTool(clients: ToolClients) {\n const graphql = clients.graphql as DiscoveryMixin;\n return defineTool({\n name: 'discovery_start_scan',\n description: 'Start a new data classification scan on a data silo.',\n category: 'Data Discovery',\n readOnly: false,\n confirmationHint: 'Starts a new classification scan on the data silo',\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false },\n zodSchema: StartScanSchema,\n handler: async ({ name, data_silo_id, type }) => {\n const result = await graphql.startClassificationScan({\n name,\n dataSiloId: data_silo_id,\n type,\n });\n return createToolResult(true, {\n scan: result,\n message: `Classification scan \"${name}\" started successfully`,\n });\n },\n });\n}\n","import type { ToolDefinition, ToolClients } from '@transcend-io/mcp-server-base';\n\nimport { createDiscoveryClassifyTextTool } from './discovery_classify_text.js';\nimport { createDiscoveryGetScanTool } from './discovery_get_scan.js';\nimport { createDiscoveryListPluginsTool } from './discovery_list_plugins.js';\nimport { createDiscoveryListScansTool } from './discovery_list_scans.js';\nimport { createDiscoveryNerExtractTool } from './discovery_ner_extract.js';\nimport { createDiscoveryStartScanTool } from './discovery_start_scan.js';\n\nexport function getDiscoveryTools(clients: ToolClients): ToolDefinition[] {\n return [\n createDiscoveryClassifyTextTool(clients),\n createDiscoveryNerExtractTool(clients),\n createDiscoveryListScansTool(clients),\n createDiscoveryStartScanTool(clients),\n createDiscoveryGetScanTool(clients),\n createDiscoveryListPluginsTool(clients),\n ];\n}\n","import {\n TranscendGraphQLBase,\n type PaginatedResponse,\n type ClassificationScan,\n type DiscoveryPlugin,\n type ListOptions,\n} from '@transcend-io/mcp-server-base';\n\nexport class DiscoveryMixin extends TranscendGraphQLBase {\n async listClassificationScans(\n options?: ListOptions,\n ): Promise<PaginatedResponse<ClassificationScan>> {\n const query = `\n query ListDataSilosForClassification($first: Int) {\n dataSilos(first: $first) {\n nodes {\n id\n title\n type\n createdAt\n }\n totalCount\n }\n }\n `;\n const data = await this.makeRequest<{\n dataSilos: {\n nodes: Array<{ id: string; title: string; type: string; createdAt: string }>;\n totalCount: number;\n };\n }>(query, { first: Math.min(options?.first || 50, 100) });\n const scans: ClassificationScan[] = data.dataSilos.nodes.map((silo) => ({\n id: silo.id,\n name: `Classification: ${silo.title}`,\n type: silo.type,\n status: 'COMPLETED',\n dataSiloId: silo.id,\n createdAt: silo.createdAt,\n }));\n return {\n nodes: scans,\n pageInfo: { hasNextPage: scans.length < data.dataSilos.totalCount, hasPreviousPage: false },\n totalCount: data.dataSilos.totalCount,\n };\n }\n\n async startClassificationScan(input: {\n name: string;\n dataSiloId?: string;\n type?: string;\n }): Promise<ClassificationScan> {\n const mutation = `\n mutation StartClassificationScan($input: StartClassificationScanInput!) {\n startClassificationScan(input: $input) {\n scan {\n id\n name\n type\n status\n startedAt\n createdAt\n }\n }\n }\n `;\n const data = await this.makeRequest<{ startClassificationScan: { scan: ClassificationScan } }>(\n mutation,\n { input },\n );\n return data.startClassificationScan.scan;\n }\n\n async getClassificationScan(id: string): Promise<ClassificationScan> {\n const query = `\n query GetClassificationScan($id: ID!) {\n classificationScan(id: $id) {\n id\n name\n type\n status\n startedAt\n completedAt\n dataSiloId\n results {\n id\n path\n dataCategory {\n id\n name\n category\n }\n confidence\n }\n createdAt\n }\n }\n `;\n const data = await this.makeRequest<{ classificationScan: ClassificationScan }>(query, { id });\n return data.classificationScan;\n }\n\n async listDiscoveryPlugins(options?: ListOptions): Promise<PaginatedResponse<DiscoveryPlugin>> {\n const query = `\n query ListDataSiloTypes($first: Int) {\n dataSilos(first: $first) {\n nodes {\n id\n title\n type\n description\n }\n totalCount\n }\n }\n `;\n const data = await this.makeRequest<{\n dataSilos: {\n nodes: Array<{ id: string; title: string; type: string; description: string | null }>;\n totalCount: number;\n };\n }>(query, { first: options?.first || 50 });\n const typeMap = new Map<string, DiscoveryPlugin>();\n data.dataSilos.nodes.forEach((silo) => {\n if (!typeMap.has(silo.type)) {\n typeMap.set(silo.type, {\n id: silo.type,\n name: silo.type.replace(/([A-Z])/g, ' $1').trim(),\n type: silo.type,\n description: `Integration for ${silo.type}`,\n isEnabled: true,\n });\n }\n });\n const plugins = Array.from(typeMap.values());\n return {\n nodes: plugins,\n pageInfo: { hasNextPage: false, hasPreviousPage: false },\n totalCount: plugins.length,\n };\n }\n}\n"],"mappings":"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"}
|