@volaticloud/mcp-server 0.1.0-dev.pr507.25e1c71
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 +104 -0
- package/bin/mcp-server.mjs +11 -0
- package/dist/graphql/auth.d.ts +9 -0
- package/dist/graphql/auth.d.ts.map +1 -0
- package/dist/graphql/auth.js +51 -0
- package/dist/graphql/auth.js.map +1 -0
- package/dist/graphql/client.d.ts +10 -0
- package/dist/graphql/client.d.ts.map +1 -0
- package/dist/graphql/client.js +35 -0
- package/dist/graphql/client.js.map +1 -0
- package/dist/graphql/introspect.d.ts +20 -0
- package/dist/graphql/introspect.d.ts.map +1 -0
- package/dist/graphql/introspect.js +184 -0
- package/dist/graphql/introspect.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +94 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/executor.d.ts +10 -0
- package/dist/tools/executor.d.ts.map +1 -0
- package/dist/tools/executor.js +26 -0
- package/dist/tools/executor.js.map +1 -0
- package/dist/tools/formatter.d.ts +4 -0
- package/dist/tools/formatter.d.ts.map +1 -0
- package/dist/tools/formatter.js +34 -0
- package/dist/tools/formatter.js.map +1 -0
- package/dist/tools/generator.d.ts +14 -0
- package/dist/tools/generator.d.ts.map +1 -0
- package/dist/tools/generator.js +159 -0
- package/dist/tools/generator.js.map +1 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# @volaticloud/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for the VolatiCloud GraphQL API. Lets AI agents manage strategies, bots, exchanges, and backtests through natural language.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx -y @volaticloud/mcp-server
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
1. A VolatiCloud account with an organization
|
|
14
|
+
2. An API client (create one at **Organization > API Keys** in the dashboard)
|
|
15
|
+
|
|
16
|
+
## Configuration
|
|
17
|
+
|
|
18
|
+
### Claude Code
|
|
19
|
+
|
|
20
|
+
Add to your project's `.mcp.json`:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"volaticloud": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["-y", "@volaticloud/mcp-server"],
|
|
28
|
+
"env": {
|
|
29
|
+
"VOLATICLOUD_ENDPOINT": "https://api.volaticloud.com/gateway/v1/query",
|
|
30
|
+
"VOLATICLOUD_CLIENT_ID": "<your-client-id>",
|
|
31
|
+
"VOLATICLOUD_CLIENT_SECRET": "<your-client-secret>"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Claude Desktop
|
|
39
|
+
|
|
40
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"volaticloud": {
|
|
46
|
+
"command": "npx",
|
|
47
|
+
"args": ["-y", "@volaticloud/mcp-server"],
|
|
48
|
+
"env": {
|
|
49
|
+
"VOLATICLOUD_ENDPOINT": "https://api.volaticloud.com/gateway/v1/query",
|
|
50
|
+
"VOLATICLOUD_CLIENT_ID": "<your-client-id>",
|
|
51
|
+
"VOLATICLOUD_CLIENT_SECRET": "<your-client-secret>"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Environment Variables
|
|
59
|
+
|
|
60
|
+
| Variable | Required | Default | Description |
|
|
61
|
+
|----------|----------|---------|-------------|
|
|
62
|
+
| `VOLATICLOUD_CLIENT_ID` | Yes | — | API client ID |
|
|
63
|
+
| `VOLATICLOUD_CLIENT_SECRET` | Yes | — | API client secret |
|
|
64
|
+
| `VOLATICLOUD_ENDPOINT` | No | `https://api.volaticloud.com/gateway/v1/query` | GraphQL endpoint URL |
|
|
65
|
+
|
|
66
|
+
## Available Tools
|
|
67
|
+
|
|
68
|
+
### Static Tools
|
|
69
|
+
|
|
70
|
+
| Tool | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `introspect_schema` | Explore the API schema, optionally drill into a specific type |
|
|
73
|
+
| `search_schema` | Search types, fields, and enums by keyword |
|
|
74
|
+
| `execute_query` | Run any GraphQL query with variables |
|
|
75
|
+
| `execute_mutation` | Run any GraphQL mutation with variables |
|
|
76
|
+
|
|
77
|
+
### Dynamic Tools (auto-generated)
|
|
78
|
+
|
|
79
|
+
The server introspects the GraphQL schema at startup and generates individual tools for each query and mutation. Examples:
|
|
80
|
+
|
|
81
|
+
- `strategies`, `bots`, `exchanges`, `runners` — List resources
|
|
82
|
+
- `create_strategy`, `create_bot`, `create_exchange` — Create resources
|
|
83
|
+
- `update_strategy`, `update_bot` — Update resources
|
|
84
|
+
- `delete_strategy`, `delete_bot` — Delete resources
|
|
85
|
+
- `start_bot`, `stop_bot`, `restart_bot` — Bot lifecycle
|
|
86
|
+
- `run_backtest`, `run_simulation` — Run analysis
|
|
87
|
+
- `get_bot_open_positions`, `get_bot_trading_config` — Live data
|
|
88
|
+
|
|
89
|
+
## How It Works
|
|
90
|
+
|
|
91
|
+
1. On startup, authenticates using your API client credentials (OAuth2 client_credentials flow)
|
|
92
|
+
2. Introspects the GraphQL schema to discover all available operations
|
|
93
|
+
3. Generates MCP tool definitions from each query and mutation
|
|
94
|
+
4. Communicates with AI agents via stdio (standard MCP transport)
|
|
95
|
+
5. Automatically refreshes the access token before expiry
|
|
96
|
+
|
|
97
|
+
## Development
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
cd mcp-server
|
|
101
|
+
npm install
|
|
102
|
+
npm run build
|
|
103
|
+
node dist/index.js
|
|
104
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
3
|
+
import { dirname, resolve } from "path";
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const entry = resolve(__dirname, "..", "dist", "index.js");
|
|
7
|
+
|
|
8
|
+
import(entry).catch((err) => {
|
|
9
|
+
console.error("Failed to start VolatiCloud MCP server:", err.message);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/graphql/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8B,YAAY,EAAE,MAAM,aAAa,CAAC;AAY5E,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,MAAM,CAAe;gBAEjB,MAAM,EAAE,YAAY;IAI1B,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;YAQzB,YAAY;CAyC3B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const AUTHENTICATE_MUTATION = `
|
|
2
|
+
mutation AuthenticateAPIClient($clientId: String!, $clientSecret: String!) {
|
|
3
|
+
authenticateAPIClient(clientId: $clientId, clientSecret: $clientSecret) {
|
|
4
|
+
accessToken
|
|
5
|
+
tokenType
|
|
6
|
+
expiresIn
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
export class AuthManager {
|
|
11
|
+
token = null;
|
|
12
|
+
config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
async getAccessToken() {
|
|
17
|
+
if (this.token && Date.now() < this.token.expiresAt - 30_000) {
|
|
18
|
+
return this.token.accessToken;
|
|
19
|
+
}
|
|
20
|
+
await this.authenticate();
|
|
21
|
+
return this.token.accessToken;
|
|
22
|
+
}
|
|
23
|
+
async authenticate() {
|
|
24
|
+
const response = await fetch(this.config.endpoint, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
query: AUTHENTICATE_MUTATION,
|
|
29
|
+
variables: {
|
|
30
|
+
clientId: this.config.clientId,
|
|
31
|
+
clientSecret: this.config.clientSecret,
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
throw new Error(`Authentication failed: HTTP ${response.status} ${response.statusText}`);
|
|
37
|
+
}
|
|
38
|
+
const result = await response.json();
|
|
39
|
+
if (result.errors?.length) {
|
|
40
|
+
throw new Error(`Authentication failed: ${result.errors.map((e) => e.message).join(", ")}`);
|
|
41
|
+
}
|
|
42
|
+
const auth = result.data.authenticateAPIClient;
|
|
43
|
+
this.token = {
|
|
44
|
+
accessToken: auth.accessToken,
|
|
45
|
+
tokenType: auth.tokenType,
|
|
46
|
+
expiresIn: auth.expiresIn,
|
|
47
|
+
expiresAt: Date.now() + auth.expiresIn * 1000,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/graphql/auth.ts"],"names":[],"mappings":"AAEA,MAAM,qBAAqB,GAAG;;;;;;;;CAQ7B,CAAC;AAEF,MAAM,OAAO,WAAW;IACd,KAAK,GAAqB,IAAI,CAAC;IAC/B,MAAM,CAAe;IAE7B,YAAY,MAAoB;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,MAAM,EAAE,CAAC;YAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;QAChC,CAAC;QACD,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,KAAM,CAAC,WAAW,CAAC;IACjC,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;YACjD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,qBAAqB;gBAC5B,SAAS,EAAE;oBACT,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;oBAC9B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;iBACvC;aACF,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,+BAA+B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CACxE,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAMP,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAE3B,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,0BAA0B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3E,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAK,CAAC,qBAAqB,CAAC;QAChD,IAAI,CAAC,KAAK,GAAG;YACX,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI;SAC9C,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GraphQLResponse } from "../types.js";
|
|
2
|
+
import type { AuthManager } from "./auth.js";
|
|
3
|
+
export declare class GraphQLClient {
|
|
4
|
+
private endpoint;
|
|
5
|
+
private auth;
|
|
6
|
+
constructor(endpoint: string, auth: AuthManager);
|
|
7
|
+
execute<T = Record<string, unknown>>(query: string, variables?: Record<string, unknown>): Promise<GraphQLResponse<T>>;
|
|
8
|
+
executeUnauthenticated<T = Record<string, unknown>>(query: string, variables?: Record<string, unknown>): Promise<GraphQLResponse<T>>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/graphql/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAc;gBAEd,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW;IAKzC,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAqBxB,sBAAsB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtD,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;CAe/B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export class GraphQLClient {
|
|
2
|
+
endpoint;
|
|
3
|
+
auth;
|
|
4
|
+
constructor(endpoint, auth) {
|
|
5
|
+
this.endpoint = endpoint;
|
|
6
|
+
this.auth = auth;
|
|
7
|
+
}
|
|
8
|
+
async execute(query, variables) {
|
|
9
|
+
const token = await this.auth.getAccessToken();
|
|
10
|
+
const response = await fetch(this.endpoint, {
|
|
11
|
+
method: "POST",
|
|
12
|
+
headers: {
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
Authorization: `Bearer ${token}`,
|
|
15
|
+
},
|
|
16
|
+
body: JSON.stringify({ query, variables }),
|
|
17
|
+
});
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
throw new Error(`GraphQL request failed: HTTP ${response.status} ${response.statusText}`);
|
|
20
|
+
}
|
|
21
|
+
return response.json();
|
|
22
|
+
}
|
|
23
|
+
async executeUnauthenticated(query, variables) {
|
|
24
|
+
const response = await fetch(this.endpoint, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
body: JSON.stringify({ query, variables }),
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
throw new Error(`GraphQL request failed: HTTP ${response.status} ${response.statusText}`);
|
|
31
|
+
}
|
|
32
|
+
return response.json();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/graphql/client.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,aAAa;IAChB,QAAQ,CAAS;IACjB,IAAI,CAAc;IAE1B,YAAY,QAAgB,EAAE,IAAiB;QAC7C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,OAAO,CACX,KAAa,EACb,SAAmC;QAEnC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;QAE/C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,KAAK,EAAE;aACjC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;SAC3C,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,gCAAgC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CACzE,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAiC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,sBAAsB,CAC1B,KAAa,EACb,SAAmC;QAEnC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;YAC1C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;SAC3C,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,gCAAgC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CACzE,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAiC,CAAC;IACxD,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { GraphQLClient } from "./client.js";
|
|
2
|
+
import type { IntrospectedSchema, IntrospectedField, IntrospectedFullType, IntrospectedType } from "../types.js";
|
|
3
|
+
export declare class SchemaIntrospector {
|
|
4
|
+
private client;
|
|
5
|
+
private schema;
|
|
6
|
+
private typeMap;
|
|
7
|
+
constructor(client: GraphQLClient);
|
|
8
|
+
introspect(): Promise<IntrospectedSchema>;
|
|
9
|
+
getSchema(): IntrospectedSchema;
|
|
10
|
+
getType(name: string): IntrospectedFullType | undefined;
|
|
11
|
+
getQueryFields(): IntrospectedField[];
|
|
12
|
+
getMutationFields(): IntrospectedField[];
|
|
13
|
+
resolveTypeName(type: IntrospectedType): string;
|
|
14
|
+
isRequired(type: IntrospectedType): boolean;
|
|
15
|
+
isList(type: IntrospectedType): boolean;
|
|
16
|
+
searchTypes(keyword: string): IntrospectedFullType[];
|
|
17
|
+
describeType(typeName: string): string;
|
|
18
|
+
formatType(type: IntrospectedType): string;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=introspect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspect.d.ts","sourceRoot":"","sources":["../../src/graphql/introspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAkFrB,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,OAAO,CAAgD;gBAEnD,MAAM,EAAE,aAAa;IAI3B,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAoB/C,SAAS,IAAI,kBAAkB;IAK/B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAIvD,cAAc,IAAI,iBAAiB,EAAE;IAMrC,iBAAiB,IAAI,iBAAiB,EAAE;IAMxC,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM;IAM/C,UAAU,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO;IAI3C,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO;IAMvC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,EAAE;IAUpD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAoCtC,UAAU,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM;CAS3C"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const INTROSPECTION_QUERY = `
|
|
2
|
+
query IntrospectionQuery {
|
|
3
|
+
__schema {
|
|
4
|
+
queryType { name }
|
|
5
|
+
mutationType { name }
|
|
6
|
+
types {
|
|
7
|
+
kind
|
|
8
|
+
name
|
|
9
|
+
description
|
|
10
|
+
fields(includeDeprecated: false) {
|
|
11
|
+
name
|
|
12
|
+
description
|
|
13
|
+
args {
|
|
14
|
+
name
|
|
15
|
+
description
|
|
16
|
+
type {
|
|
17
|
+
kind
|
|
18
|
+
name
|
|
19
|
+
ofType {
|
|
20
|
+
kind
|
|
21
|
+
name
|
|
22
|
+
ofType {
|
|
23
|
+
kind
|
|
24
|
+
name
|
|
25
|
+
ofType {
|
|
26
|
+
kind
|
|
27
|
+
name
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
defaultValue
|
|
33
|
+
}
|
|
34
|
+
type {
|
|
35
|
+
kind
|
|
36
|
+
name
|
|
37
|
+
ofType {
|
|
38
|
+
kind
|
|
39
|
+
name
|
|
40
|
+
ofType {
|
|
41
|
+
kind
|
|
42
|
+
name
|
|
43
|
+
ofType {
|
|
44
|
+
kind
|
|
45
|
+
name
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
inputFields {
|
|
52
|
+
name
|
|
53
|
+
description
|
|
54
|
+
type {
|
|
55
|
+
kind
|
|
56
|
+
name
|
|
57
|
+
ofType {
|
|
58
|
+
kind
|
|
59
|
+
name
|
|
60
|
+
ofType {
|
|
61
|
+
kind
|
|
62
|
+
name
|
|
63
|
+
ofType {
|
|
64
|
+
kind
|
|
65
|
+
name
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
defaultValue
|
|
71
|
+
}
|
|
72
|
+
enumValues(includeDeprecated: false) {
|
|
73
|
+
name
|
|
74
|
+
description
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
export class SchemaIntrospector {
|
|
81
|
+
client;
|
|
82
|
+
schema = null;
|
|
83
|
+
typeMap = new Map();
|
|
84
|
+
constructor(client) {
|
|
85
|
+
this.client = client;
|
|
86
|
+
}
|
|
87
|
+
async introspect() {
|
|
88
|
+
const result = await this.client.executeUnauthenticated(INTROSPECTION_QUERY);
|
|
89
|
+
if (result.errors?.length) {
|
|
90
|
+
throw new Error(`Introspection failed: ${result.errors.map((e) => e.message).join(", ")}`);
|
|
91
|
+
}
|
|
92
|
+
this.schema = result.data.__schema;
|
|
93
|
+
this.typeMap.clear();
|
|
94
|
+
for (const type of this.schema.types) {
|
|
95
|
+
this.typeMap.set(type.name, type);
|
|
96
|
+
}
|
|
97
|
+
return this.schema;
|
|
98
|
+
}
|
|
99
|
+
getSchema() {
|
|
100
|
+
if (!this.schema)
|
|
101
|
+
throw new Error("Schema not introspected yet");
|
|
102
|
+
return this.schema;
|
|
103
|
+
}
|
|
104
|
+
getType(name) {
|
|
105
|
+
return this.typeMap.get(name);
|
|
106
|
+
}
|
|
107
|
+
getQueryFields() {
|
|
108
|
+
if (!this.schema?.queryType)
|
|
109
|
+
return [];
|
|
110
|
+
const queryType = this.typeMap.get(this.schema.queryType.name);
|
|
111
|
+
return queryType?.fields ?? [];
|
|
112
|
+
}
|
|
113
|
+
getMutationFields() {
|
|
114
|
+
if (!this.schema?.mutationType)
|
|
115
|
+
return [];
|
|
116
|
+
const mutationType = this.typeMap.get(this.schema.mutationType.name);
|
|
117
|
+
return mutationType?.fields ?? [];
|
|
118
|
+
}
|
|
119
|
+
resolveTypeName(type) {
|
|
120
|
+
if (type.name)
|
|
121
|
+
return type.name;
|
|
122
|
+
if (type.ofType)
|
|
123
|
+
return this.resolveTypeName(type.ofType);
|
|
124
|
+
return "Unknown";
|
|
125
|
+
}
|
|
126
|
+
isRequired(type) {
|
|
127
|
+
return type.kind === "NON_NULL";
|
|
128
|
+
}
|
|
129
|
+
isList(type) {
|
|
130
|
+
if (type.kind === "LIST")
|
|
131
|
+
return true;
|
|
132
|
+
if (type.ofType)
|
|
133
|
+
return this.isList(type.ofType);
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
searchTypes(keyword) {
|
|
137
|
+
const lower = keyword.toLowerCase();
|
|
138
|
+
return this.schema.types.filter((t) => !t.name.startsWith("__") &&
|
|
139
|
+
(t.name.toLowerCase().includes(lower) ||
|
|
140
|
+
t.description?.toLowerCase().includes(lower)));
|
|
141
|
+
}
|
|
142
|
+
describeType(typeName) {
|
|
143
|
+
const type = this.typeMap.get(typeName);
|
|
144
|
+
if (!type)
|
|
145
|
+
return `Type "${typeName}" not found`;
|
|
146
|
+
const lines = [`${type.kind} ${type.name}`];
|
|
147
|
+
if (type.description)
|
|
148
|
+
lines.push(type.description);
|
|
149
|
+
if (type.fields) {
|
|
150
|
+
lines.push("\nFields:");
|
|
151
|
+
for (const field of type.fields) {
|
|
152
|
+
const typeName = this.formatType(field.type);
|
|
153
|
+
const desc = field.description ? ` — ${field.description}` : "";
|
|
154
|
+
lines.push(` ${field.name}: ${typeName}${desc}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (type.inputFields) {
|
|
158
|
+
lines.push("\nInput Fields:");
|
|
159
|
+
for (const field of type.inputFields) {
|
|
160
|
+
const typeName = this.formatType(field.type);
|
|
161
|
+
const desc = field.description ? ` — ${field.description}` : "";
|
|
162
|
+
lines.push(` ${field.name}: ${typeName}${desc}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (type.enumValues) {
|
|
166
|
+
lines.push("\nValues:");
|
|
167
|
+
for (const val of type.enumValues) {
|
|
168
|
+
const desc = val.description ? ` — ${val.description}` : "";
|
|
169
|
+
lines.push(` ${val.name}${desc}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return lines.join("\n");
|
|
173
|
+
}
|
|
174
|
+
formatType(type) {
|
|
175
|
+
if (type.kind === "NON_NULL") {
|
|
176
|
+
return `${this.formatType(type.ofType)}!`;
|
|
177
|
+
}
|
|
178
|
+
if (type.kind === "LIST") {
|
|
179
|
+
return `[${this.formatType(type.ofType)}]`;
|
|
180
|
+
}
|
|
181
|
+
return type.name ?? "Unknown";
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=introspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspect.js","sourceRoot":"","sources":["../../src/graphql/introspect.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2
|
+
import { createServer } from "./server.js";
|
|
3
|
+
function getConfig() {
|
|
4
|
+
const endpoint = process.env.VOLATICLOUD_ENDPOINT ??
|
|
5
|
+
"https://api.volaticloud.com/gateway/v1/query";
|
|
6
|
+
const clientId = process.env.VOLATICLOUD_CLIENT_ID;
|
|
7
|
+
const clientSecret = process.env.VOLATICLOUD_CLIENT_SECRET;
|
|
8
|
+
if (!clientId || !clientSecret) {
|
|
9
|
+
console.error("Error: VOLATICLOUD_CLIENT_ID and VOLATICLOUD_CLIENT_SECRET environment variables are required.\n\n" +
|
|
10
|
+
"Create an API client at: https://console.volaticloud.com/organization/api-keys\n" +
|
|
11
|
+
"Then configure:\n" +
|
|
12
|
+
" VOLATICLOUD_CLIENT_ID=<your client id>\n" +
|
|
13
|
+
" VOLATICLOUD_CLIENT_SECRET=<your client secret>\n" +
|
|
14
|
+
" VOLATICLOUD_ENDPOINT=https://api.volaticloud.com/gateway/v1/query (optional)");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
return { endpoint, clientId, clientSecret };
|
|
18
|
+
}
|
|
19
|
+
async function main() {
|
|
20
|
+
const config = getConfig();
|
|
21
|
+
const server = await createServer(config);
|
|
22
|
+
const transport = new StdioServerTransport();
|
|
23
|
+
await server.connect(transport);
|
|
24
|
+
}
|
|
25
|
+
main().catch((err) => {
|
|
26
|
+
console.error("Fatal:", err);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,SAAS,SAAS;IAChB,MAAM,QAAQ,GACZ,OAAO,CAAC,GAAG,CAAC,oBAAoB;QAChC,8CAA8C,CAAC;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IACnD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;IAE3D,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,CACX,oGAAoG;YAClG,kFAAkF;YAClF,mBAAmB;YACnB,4CAA4C;YAC5C,oDAAoD;YACpD,gFAAgF,CACnF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AAC9C,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAW/C,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAgI3E"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { AuthManager } from "./graphql/auth.js";
|
|
4
|
+
import { GraphQLClient } from "./graphql/client.js";
|
|
5
|
+
import { SchemaIntrospector } from "./graphql/introspect.js";
|
|
6
|
+
import { ToolGenerator } from "./tools/generator.js";
|
|
7
|
+
import { ToolExecutor } from "./tools/executor.js";
|
|
8
|
+
import { formatSchemaOverview, formatSearchResults, } from "./tools/formatter.js";
|
|
9
|
+
export async function createServer(config) {
|
|
10
|
+
const server = new McpServer({
|
|
11
|
+
name: "volaticloud",
|
|
12
|
+
version: "0.1.0",
|
|
13
|
+
});
|
|
14
|
+
// Initialize auth and client
|
|
15
|
+
const auth = new AuthManager(config);
|
|
16
|
+
const client = new GraphQLClient(config.endpoint, auth);
|
|
17
|
+
const introspector = new SchemaIntrospector(client);
|
|
18
|
+
// Introspect schema
|
|
19
|
+
await introspector.introspect();
|
|
20
|
+
// Generate dynamic tools from schema
|
|
21
|
+
const generator = new ToolGenerator(introspector);
|
|
22
|
+
const dynamicTools = generator.generate();
|
|
23
|
+
const executor = new ToolExecutor(client, dynamicTools);
|
|
24
|
+
// --- Static tools ---
|
|
25
|
+
server.tool("introspect_schema", "Get the VolatiCloud GraphQL schema overview, or drill into a specific type by name", { typeName: z.string().optional().describe("Specific type name to inspect (e.g. 'Bot', 'Strategy', 'CreateBotInput')") }, async ({ typeName }) => {
|
|
26
|
+
if (typeName) {
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: "text", text: introspector.describeType(typeName) }],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: "text", text: formatSchemaOverview(introspector) }],
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
server.tool("search_schema", "Search the GraphQL schema for types, fields, or enums matching a keyword", { keyword: z.string().describe("Search keyword") }, async ({ keyword }) => ({
|
|
36
|
+
content: [
|
|
37
|
+
{ type: "text", text: formatSearchResults(introspector, keyword) },
|
|
38
|
+
],
|
|
39
|
+
}));
|
|
40
|
+
server.tool("execute_query", "Execute an arbitrary GraphQL query against the VolatiCloud API", {
|
|
41
|
+
query: z.string().describe("GraphQL query string"),
|
|
42
|
+
variables: z.record(z.string(), z.unknown()).optional().describe("Query variables as JSON object"),
|
|
43
|
+
}, async ({ query, variables }) => {
|
|
44
|
+
const result = await client.execute(query, variables);
|
|
45
|
+
if (result.errors?.length) {
|
|
46
|
+
return {
|
|
47
|
+
content: [
|
|
48
|
+
{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: JSON.stringify({ errors: result.errors, data: result.data }, null, 2),
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
isError: true,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
server.tool("execute_mutation", "Execute a GraphQL mutation against the VolatiCloud API (creates, updates, or deletes resources)", {
|
|
61
|
+
query: z.string().describe("GraphQL mutation string"),
|
|
62
|
+
variables: z.record(z.string(), z.unknown()).optional().describe("Mutation variables as JSON object"),
|
|
63
|
+
}, async ({ query, variables }) => {
|
|
64
|
+
const result = await client.execute(query, variables);
|
|
65
|
+
if (result.errors?.length) {
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: JSON.stringify({ errors: result.errors, data: result.data }, null, 2),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
isError: true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
// --- Dynamic tools (auto-generated from schema) ---
|
|
81
|
+
for (const tool of dynamicTools) {
|
|
82
|
+
server.tool(tool.name, tool.description, tool.zodParams, async (args) => {
|
|
83
|
+
const result = await executor.execute(tool.name, args);
|
|
84
|
+
const parsed = JSON.parse(result);
|
|
85
|
+
const isError = parsed !== null && typeof parsed === "object" && "error" in parsed;
|
|
86
|
+
return {
|
|
87
|
+
content: [{ type: "text", text: result }],
|
|
88
|
+
isError,
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return server;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GraphQLClient } from "../graphql/client.js";
|
|
2
|
+
import type { GeneratedTool } from "../types.js";
|
|
3
|
+
export declare class ToolExecutor {
|
|
4
|
+
private client;
|
|
5
|
+
private toolMap;
|
|
6
|
+
constructor(client: GraphQLClient, tools: GeneratedTool[]);
|
|
7
|
+
execute(toolName: string, args: Record<string, unknown>): Promise<string>;
|
|
8
|
+
getTool(name: string): GeneratedTool | undefined;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAA6B;gBAEhC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE;IAKnD,OAAO,CACX,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,MAAM,CAAC;IAkBlB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;CAGjD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class ToolExecutor {
|
|
2
|
+
client;
|
|
3
|
+
toolMap;
|
|
4
|
+
constructor(client, tools) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
this.toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
7
|
+
}
|
|
8
|
+
async execute(toolName, args) {
|
|
9
|
+
const tool = this.toolMap.get(toolName);
|
|
10
|
+
if (!tool) {
|
|
11
|
+
return JSON.stringify({ error: `Unknown tool: ${toolName}` });
|
|
12
|
+
}
|
|
13
|
+
const result = await this.client.execute(tool.graphqlQuery, args);
|
|
14
|
+
if (result.errors?.length) {
|
|
15
|
+
return JSON.stringify({
|
|
16
|
+
error: result.errors.map((e) => e.message).join("; "),
|
|
17
|
+
data: result.data ?? null,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return JSON.stringify(result.data, null, 2);
|
|
21
|
+
}
|
|
22
|
+
getTool(name) {
|
|
23
|
+
return this.toolMap.get(name);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,YAAY;IACf,MAAM,CAAgB;IACtB,OAAO,CAA6B;IAE5C,YAAY,MAAqB,EAAE,KAAsB;QACvD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,OAAO,CACX,QAAgB,EAChB,IAA6B;QAE7B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,iBAAiB,QAAQ,EAAE,EAAE,CAAC,CAAC;QAChE,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAElE,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAC,SAAS,CAAC;gBACpB,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACrD,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI;aAC1B,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,CAAC,IAAY;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SchemaIntrospector } from "../graphql/introspect.js";
|
|
2
|
+
export declare function formatSchemaOverview(introspector: SchemaIntrospector): string;
|
|
3
|
+
export declare function formatSearchResults(introspector: SchemaIntrospector, keyword: string): string;
|
|
4
|
+
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/tools/formatter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,kBAAkB,GAC/B,MAAM,CA8BR;AAED,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,kBAAkB,EAChC,OAAO,EAAE,MAAM,GACd,MAAM,CAQR"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function formatSchemaOverview(introspector) {
|
|
2
|
+
const queries = introspector.getQueryFields();
|
|
3
|
+
const mutations = introspector.getMutationFields();
|
|
4
|
+
const lines = ["# VolatiCloud GraphQL Schema\n"];
|
|
5
|
+
lines.push("## Queries\n");
|
|
6
|
+
for (const q of queries) {
|
|
7
|
+
if (q.name.startsWith("__"))
|
|
8
|
+
continue;
|
|
9
|
+
const args = q.args.map((a) => `${a.name}: ${introspector.formatType(a.type)}`);
|
|
10
|
+
const argsStr = args.length > 0 ? `(${args.join(", ")})` : "";
|
|
11
|
+
const ret = introspector.formatType(q.type);
|
|
12
|
+
const desc = q.description ? ` — ${q.description}` : "";
|
|
13
|
+
lines.push(`- **${q.name}**${argsStr}: ${ret}${desc}`);
|
|
14
|
+
}
|
|
15
|
+
lines.push("\n## Mutations\n");
|
|
16
|
+
for (const m of mutations) {
|
|
17
|
+
const args = m.args.map((a) => `${a.name}: ${introspector.formatType(a.type)}`);
|
|
18
|
+
const argsStr = args.length > 0 ? `(${args.join(", ")})` : "";
|
|
19
|
+
const ret = introspector.formatType(m.type);
|
|
20
|
+
const desc = m.description ? ` — ${m.description}` : "";
|
|
21
|
+
lines.push(`- **${m.name}**${argsStr}: ${ret}${desc}`);
|
|
22
|
+
}
|
|
23
|
+
return lines.join("\n");
|
|
24
|
+
}
|
|
25
|
+
export function formatSearchResults(introspector, keyword) {
|
|
26
|
+
const types = introspector.searchTypes(keyword);
|
|
27
|
+
if (types.length === 0)
|
|
28
|
+
return `No types found matching "${keyword}"`;
|
|
29
|
+
return types
|
|
30
|
+
.slice(0, 20)
|
|
31
|
+
.map((t) => introspector.describeType(t.name))
|
|
32
|
+
.join("\n\n---\n\n");
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/tools/formatter.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,oBAAoB,CAClC,YAAgC;IAEhC,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,EAAE,CAAC;IAC9C,MAAM,SAAS,GAAG,YAAY,CAAC,iBAAiB,EAAE,CAAC;IAEnD,MAAM,KAAK,GAAa,CAAC,gCAAgC,CAAC,CAAC;IAE3D,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QACtC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CACrB,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CACvD,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,OAAO,KAAK,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CACrB,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CACvD,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,OAAO,KAAK,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,YAAgC,EAChC,OAAe;IAEf,MAAM,KAAK,GAAG,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,4BAA4B,OAAO,GAAG,CAAC;IAEtE,OAAO,KAAK;SACT,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SAC7C,IAAI,CAAC,aAAa,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SchemaIntrospector } from "../graphql/introspect.js";
|
|
2
|
+
import type { GeneratedTool } from "../types.js";
|
|
3
|
+
export declare class ToolGenerator {
|
|
4
|
+
private introspector;
|
|
5
|
+
constructor(introspector: SchemaIntrospector);
|
|
6
|
+
generate(): GeneratedTool[];
|
|
7
|
+
private fieldToTool;
|
|
8
|
+
private argToZod;
|
|
9
|
+
private typeToZod;
|
|
10
|
+
private buildGraphQLOperation;
|
|
11
|
+
private buildSelectionSet;
|
|
12
|
+
private toSnakeCase;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/tools/generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EACV,aAAa,EAId,MAAM,aAAa,CAAC;AAKrB,qBAAa,aAAa;IACxB,OAAO,CAAC,YAAY,CAAqB;gBAE7B,YAAY,EAAE,kBAAkB;IAI5C,QAAQ,IAAI,aAAa,EAAE;IAkB3B,OAAO,CAAC,WAAW;IA6BnB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,SAAS;IA6DjB,OAAO,CAAC,qBAAqB;IAsB7B,OAAO,CAAC,iBAAiB;IAqCzB,OAAO,CAAC,WAAW;CAMpB"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const SKIP_QUERIES = new Set(["node", "nodes", "__schema", "__type"]);
|
|
3
|
+
const SKIP_MUTATIONS = new Set(["authenticateAPIClient"]);
|
|
4
|
+
export class ToolGenerator {
|
|
5
|
+
introspector;
|
|
6
|
+
constructor(introspector) {
|
|
7
|
+
this.introspector = introspector;
|
|
8
|
+
}
|
|
9
|
+
generate() {
|
|
10
|
+
const tools = [];
|
|
11
|
+
for (const field of this.introspector.getQueryFields()) {
|
|
12
|
+
if (SKIP_QUERIES.has(field.name))
|
|
13
|
+
continue;
|
|
14
|
+
const tool = this.fieldToTool(field, "query");
|
|
15
|
+
if (tool)
|
|
16
|
+
tools.push(tool);
|
|
17
|
+
}
|
|
18
|
+
for (const field of this.introspector.getMutationFields()) {
|
|
19
|
+
if (SKIP_MUTATIONS.has(field.name))
|
|
20
|
+
continue;
|
|
21
|
+
const tool = this.fieldToTool(field, "mutation");
|
|
22
|
+
if (tool)
|
|
23
|
+
tools.push(tool);
|
|
24
|
+
}
|
|
25
|
+
return tools;
|
|
26
|
+
}
|
|
27
|
+
fieldToTool(field, operationType) {
|
|
28
|
+
const toolName = this.toSnakeCase(field.name);
|
|
29
|
+
const description = field.description || `${operationType}: ${field.name}`;
|
|
30
|
+
const zodParams = {};
|
|
31
|
+
for (const arg of field.args) {
|
|
32
|
+
let schema = this.argToZod(arg, new Set());
|
|
33
|
+
if (!this.introspector.isRequired(arg.type)) {
|
|
34
|
+
schema = schema.optional();
|
|
35
|
+
}
|
|
36
|
+
zodParams[arg.name] = schema;
|
|
37
|
+
}
|
|
38
|
+
const graphqlQuery = this.buildGraphQLOperation(field, operationType);
|
|
39
|
+
return {
|
|
40
|
+
name: toolName,
|
|
41
|
+
description,
|
|
42
|
+
zodParams,
|
|
43
|
+
operationType,
|
|
44
|
+
operationName: field.name,
|
|
45
|
+
graphqlQuery,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
argToZod(arg, visited) {
|
|
49
|
+
let schema = this.typeToZod(arg.type, visited);
|
|
50
|
+
if (arg.description) {
|
|
51
|
+
schema = schema.describe(arg.description);
|
|
52
|
+
}
|
|
53
|
+
return schema;
|
|
54
|
+
}
|
|
55
|
+
typeToZod(type, visited) {
|
|
56
|
+
if (type.kind === "NON_NULL") {
|
|
57
|
+
return this.typeToZod(type.ofType, visited);
|
|
58
|
+
}
|
|
59
|
+
if (type.kind === "LIST") {
|
|
60
|
+
return z.array(this.typeToZod(type.ofType, visited));
|
|
61
|
+
}
|
|
62
|
+
const name = type.name ?? "Unknown";
|
|
63
|
+
switch (name) {
|
|
64
|
+
case "String":
|
|
65
|
+
case "ID":
|
|
66
|
+
case "Cursor":
|
|
67
|
+
case "Time":
|
|
68
|
+
case "UUID":
|
|
69
|
+
return z.string();
|
|
70
|
+
case "Int":
|
|
71
|
+
return z.number().int();
|
|
72
|
+
case "Float":
|
|
73
|
+
return z.number();
|
|
74
|
+
case "Boolean":
|
|
75
|
+
return z.boolean();
|
|
76
|
+
case "Map":
|
|
77
|
+
case "JSON":
|
|
78
|
+
return z.record(z.string(), z.unknown());
|
|
79
|
+
default: {
|
|
80
|
+
const fullType = this.introspector.getType(name);
|
|
81
|
+
if (fullType?.kind === "ENUM" && fullType.enumValues) {
|
|
82
|
+
const values = fullType.enumValues.map((v) => v.name);
|
|
83
|
+
if (values.length > 0) {
|
|
84
|
+
return z.enum(values);
|
|
85
|
+
}
|
|
86
|
+
return z.string();
|
|
87
|
+
}
|
|
88
|
+
if (fullType?.kind === "INPUT_OBJECT" && fullType.inputFields) {
|
|
89
|
+
// Cycle detection for self-referential WhereInput types
|
|
90
|
+
if (visited.has(name)) {
|
|
91
|
+
return z.record(z.string(), z.unknown()).describe(`${name} (recursive, accepts any object)`);
|
|
92
|
+
}
|
|
93
|
+
visited.add(name);
|
|
94
|
+
const shape = {};
|
|
95
|
+
for (const field of fullType.inputFields) {
|
|
96
|
+
let fieldSchema = this.argToZod(field, visited);
|
|
97
|
+
if (!this.introspector.isRequired(field.type)) {
|
|
98
|
+
fieldSchema = fieldSchema.optional();
|
|
99
|
+
}
|
|
100
|
+
shape[field.name] = fieldSchema;
|
|
101
|
+
}
|
|
102
|
+
return z.object(shape).passthrough();
|
|
103
|
+
}
|
|
104
|
+
return z.record(z.string(), z.unknown());
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
buildGraphQLOperation(field, operationType) {
|
|
109
|
+
const varDefs = field.args
|
|
110
|
+
.map((a) => `$${a.name}: ${this.introspector.formatType(a.type)}`)
|
|
111
|
+
.join(", ");
|
|
112
|
+
const args = field.args
|
|
113
|
+
.map((a) => `${a.name}: $${a.name}`)
|
|
114
|
+
.join(", ");
|
|
115
|
+
const returnTypeName = this.introspector.resolveTypeName(field.type);
|
|
116
|
+
const selectionSet = this.buildSelectionSet(returnTypeName, 2);
|
|
117
|
+
const opName = field.name.charAt(0).toUpperCase() + field.name.slice(1);
|
|
118
|
+
const varDefsStr = varDefs ? `(${varDefs})` : "";
|
|
119
|
+
const argsStr = args ? `(${args})` : "";
|
|
120
|
+
return `${operationType} ${opName}${varDefsStr} {\n ${field.name}${argsStr} ${selectionSet}\n}`;
|
|
121
|
+
}
|
|
122
|
+
buildSelectionSet(typeName, depth) {
|
|
123
|
+
if (depth <= 0)
|
|
124
|
+
return "";
|
|
125
|
+
const type = this.introspector.getType(typeName);
|
|
126
|
+
if (!type?.fields)
|
|
127
|
+
return "";
|
|
128
|
+
if (typeName.endsWith("Connection")) {
|
|
129
|
+
const edgesField = type.fields.find((f) => f.name === "edges");
|
|
130
|
+
if (edgesField) {
|
|
131
|
+
const edgeTypeName = this.introspector.resolveTypeName(edgesField.type);
|
|
132
|
+
const edgeType = this.introspector.getType(edgeTypeName);
|
|
133
|
+
const nodeField = edgeType?.fields?.find((f) => f.name === "node");
|
|
134
|
+
if (nodeField) {
|
|
135
|
+
const nodeTypeName = this.introspector.resolveTypeName(nodeField.type);
|
|
136
|
+
const nodeSelection = this.buildSelectionSet(nodeTypeName, depth - 1);
|
|
137
|
+
return `{\n totalCount\n edges {\n node ${nodeSelection}\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const scalars = type.fields.filter((f) => {
|
|
142
|
+
const resolvedName = this.introspector.resolveTypeName(f.type);
|
|
143
|
+
const resolved = this.introspector.getType(resolvedName);
|
|
144
|
+
return ((resolved !== undefined && !resolved.fields) ||
|
|
145
|
+
["String", "Int", "Float", "Boolean", "ID", "Time", "UUID", "Map", "JSON"].includes(resolvedName));
|
|
146
|
+
});
|
|
147
|
+
if (scalars.length === 0)
|
|
148
|
+
return "";
|
|
149
|
+
const fields = scalars.map((f) => f.name).join("\n ");
|
|
150
|
+
return `{\n ${fields}\n }`;
|
|
151
|
+
}
|
|
152
|
+
toSnakeCase(name) {
|
|
153
|
+
return name
|
|
154
|
+
.replace(/([A-Z])/g, "_$1")
|
|
155
|
+
.toLowerCase()
|
|
156
|
+
.replace(/^_/, "");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/tools/generator.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface ServerConfig {
|
|
2
|
+
endpoint: string;
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AuthToken {
|
|
7
|
+
accessToken: string;
|
|
8
|
+
tokenType: string;
|
|
9
|
+
expiresIn: number;
|
|
10
|
+
expiresAt: number;
|
|
11
|
+
}
|
|
12
|
+
export interface GraphQLResponse<T = Record<string, unknown>> {
|
|
13
|
+
data?: T;
|
|
14
|
+
errors?: GraphQLError[];
|
|
15
|
+
}
|
|
16
|
+
export interface GraphQLError {
|
|
17
|
+
message: string;
|
|
18
|
+
path?: string[];
|
|
19
|
+
extensions?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
export interface IntrospectedField {
|
|
22
|
+
name: string;
|
|
23
|
+
description: string | null;
|
|
24
|
+
args: IntrospectedArg[];
|
|
25
|
+
type: IntrospectedType;
|
|
26
|
+
}
|
|
27
|
+
export interface IntrospectedArg {
|
|
28
|
+
name: string;
|
|
29
|
+
description: string | null;
|
|
30
|
+
type: IntrospectedType;
|
|
31
|
+
defaultValue: string | null;
|
|
32
|
+
}
|
|
33
|
+
export interface IntrospectedType {
|
|
34
|
+
kind: string;
|
|
35
|
+
name: string | null;
|
|
36
|
+
ofType: IntrospectedType | null;
|
|
37
|
+
}
|
|
38
|
+
export interface IntrospectedSchema {
|
|
39
|
+
queryType: {
|
|
40
|
+
name: string;
|
|
41
|
+
} | null;
|
|
42
|
+
mutationType: {
|
|
43
|
+
name: string;
|
|
44
|
+
} | null;
|
|
45
|
+
types: IntrospectedFullType[];
|
|
46
|
+
}
|
|
47
|
+
export interface IntrospectedFullType {
|
|
48
|
+
kind: string;
|
|
49
|
+
name: string;
|
|
50
|
+
description: string | null;
|
|
51
|
+
fields: IntrospectedField[] | null;
|
|
52
|
+
inputFields: IntrospectedArg[] | null;
|
|
53
|
+
enumValues: {
|
|
54
|
+
name: string;
|
|
55
|
+
description: string | null;
|
|
56
|
+
}[] | null;
|
|
57
|
+
}
|
|
58
|
+
import type { ZodTypeAny } from "zod";
|
|
59
|
+
export interface GeneratedTool {
|
|
60
|
+
name: string;
|
|
61
|
+
description: string;
|
|
62
|
+
zodParams: Record<string, ZodTypeAny>;
|
|
63
|
+
operationType: "query" | "mutation";
|
|
64
|
+
operationName: string;
|
|
65
|
+
graphqlQuery: string;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACnC,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACtC,KAAK,EAAE,oBAAoB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,iBAAiB,EAAE,GAAG,IAAI,CAAC;IACnC,WAAW,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACtC,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,GAAG,IAAI,CAAC;CACnE;AAED,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEtC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACtC,aAAa,EAAE,OAAO,GAAG,UAAU,CAAC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@volaticloud/mcp-server",
|
|
3
|
+
"version": "0.1.0-dev.pr507.25e1c71",
|
|
4
|
+
"description": "MCP server for the VolatiCloud GraphQL API — manage strategies, bots, exchanges, and backtests via AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"volaticloud-mcp": "bin/mcp-server.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"bin"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"lint": "tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"model-context-protocol",
|
|
23
|
+
"volaticloud",
|
|
24
|
+
"graphql",
|
|
25
|
+
"trading",
|
|
26
|
+
"ai-agent"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
31
|
+
"zod": "^3.25 || ^4.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^22.0.0",
|
|
35
|
+
"typescript": "^5.7.0"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
}
|
|
40
|
+
}
|