@quarri/claude-data-tools 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -89
- package/dist/index.js +238 -38
- package/dist/index.js.map +1 -1
- package/dist/tools/definitions.d.ts +6 -0
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +23 -106
- package/dist/tools/definitions.js.map +1 -1
- package/dist/ui/resources.d.ts +110 -0
- package/dist/ui/resources.d.ts.map +1 -0
- package/dist/ui/resources.js +263 -0
- package/dist/ui/resources.js.map +1 -0
- package/package.json +5 -3
- package/skills/quarri-chart/SKILL.md +151 -216
package/README.md
CHANGED
|
@@ -1,98 +1,163 @@
|
|
|
1
|
-
# Quarri Claude
|
|
1
|
+
# Quarri Claude Plugin
|
|
2
2
|
|
|
3
3
|
Natural language data analysis with Quarri. Query databases, create visualizations, and get insights using plain English.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### Claude Code
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
claude /install quarri
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Or manually add to your Claude Code configuration:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"quarri": {
|
|
19
|
+
"command": "npx",
|
|
20
|
+
"args": ["@quarri/claude-data-tools"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Claude Desktop
|
|
27
|
+
|
|
28
|
+
1. **Authenticate first** (one-time setup):
|
|
14
29
|
|
|
15
30
|
```bash
|
|
16
|
-
|
|
31
|
+
# New users - create a free trial account
|
|
32
|
+
npx @quarri/claude-data-tools signup
|
|
33
|
+
|
|
34
|
+
# Existing users - log in
|
|
35
|
+
npx @quarri/claude-data-tools auth
|
|
17
36
|
```
|
|
18
37
|
|
|
19
|
-
|
|
38
|
+
2. **Add to Claude Desktop config**:
|
|
39
|
+
|
|
40
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
41
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
20
42
|
|
|
21
43
|
```json
|
|
22
44
|
{
|
|
23
45
|
"mcpServers": {
|
|
24
46
|
"quarri": {
|
|
25
|
-
"command": "
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["@quarri/claude-data-tools"]
|
|
26
49
|
}
|
|
27
50
|
}
|
|
28
51
|
}
|
|
29
52
|
```
|
|
30
53
|
|
|
54
|
+
3. **Restart Claude Desktop**
|
|
55
|
+
|
|
31
56
|
## Authentication
|
|
32
57
|
|
|
33
|
-
|
|
58
|
+
### New Users
|
|
59
|
+
|
|
60
|
+
Create a free trial account:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx @quarri/claude-data-tools signup
|
|
64
|
+
```
|
|
34
65
|
|
|
35
|
-
|
|
66
|
+
You'll receive a verification email to complete signup.
|
|
67
|
+
|
|
68
|
+
### Existing Users
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npx @quarri/claude-data-tools auth
|
|
72
|
+
```
|
|
36
73
|
|
|
37
74
|
1. Enter your email address
|
|
38
75
|
2. Check your email for a 6-digit verification code
|
|
39
76
|
3. Enter the code to complete authentication
|
|
40
77
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
1. Select "invite" when prompted
|
|
44
|
-
2. Enter your email address
|
|
45
|
-
3. Enter the invitation token from your admin's email
|
|
46
|
-
4. Your account will be created automatically
|
|
78
|
+
Credentials are stored securely in `~/.quarri/credentials`.
|
|
47
79
|
|
|
48
80
|
## Features
|
|
49
81
|
|
|
50
|
-
###
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
- `
|
|
68
|
-
- `
|
|
69
|
-
- `
|
|
70
|
-
- `
|
|
71
|
-
- `
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
- `
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- `
|
|
80
|
-
- `
|
|
81
|
-
- `
|
|
82
|
-
|
|
83
|
-
**Team
|
|
84
|
-
- `quarri_list_teams
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- `
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
- `
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
- `
|
|
82
|
+
### Interactive UI Components (MCP Apps)
|
|
83
|
+
|
|
84
|
+
Quarri returns rich, interactive UI components for data display:
|
|
85
|
+
|
|
86
|
+
- **Data Tables** - Sortable, paginated query results
|
|
87
|
+
- **Charts** - Interactive Plotly visualizations
|
|
88
|
+
- **Schema Explorer** - Visual database structure
|
|
89
|
+
- **Metrics Cards** - KPI displays with status badges
|
|
90
|
+
- **Logs View** - Syntax-highlighted log entries
|
|
91
|
+
- **Code View** - Syntax-highlighted source code
|
|
92
|
+
|
|
93
|
+
These render automatically in Claude Desktop and Claude Code when using supported tools.
|
|
94
|
+
|
|
95
|
+
### 39 Tools for Data Analysis
|
|
96
|
+
|
|
97
|
+
**Data Tools:**
|
|
98
|
+
- `quarri_execute_sql` - Run SQL queries → interactive data table
|
|
99
|
+
- `quarri_get_schema` - View database schema → schema explorer
|
|
100
|
+
- `quarri_search_values` - Semantic search → search results
|
|
101
|
+
- `quarri_get_metrics` - List defined metrics → metrics list
|
|
102
|
+
- `quarri_create_metric` - Define new metrics
|
|
103
|
+
- `quarri_approve_metric` - Approve pending metrics
|
|
104
|
+
- `quarri_get_metric_detail` - Metric details → metric card
|
|
105
|
+
- `quarri_search_metrics` - Search metrics → metrics list
|
|
106
|
+
|
|
107
|
+
**Configuration:**
|
|
108
|
+
- `quarri_list_agent_prompts` - View agent prompts → prompts list
|
|
109
|
+
- `quarri_update_agent_prompt` - Update prompts
|
|
110
|
+
- `quarri_list_rules` - Query generation rules → rules list
|
|
111
|
+
- `quarri_create_rule`, `quarri_update_rule`, `quarri_delete_rule`
|
|
112
|
+
- `quarri_vectorize_column_values` - Enable semantic search
|
|
113
|
+
- `quarri_list_searchable_columns` - View searchable columns → columns list
|
|
114
|
+
|
|
115
|
+
**Team & Security:**
|
|
116
|
+
- `quarri_list_teams` - Organization teams → teams list
|
|
117
|
+
- `quarri_get_team_filters` - Row-level security → filters view
|
|
118
|
+
- `quarri_get_team_restrictions` - Column restrictions → restrictions view
|
|
119
|
+
|
|
120
|
+
**Data Extraction:**
|
|
121
|
+
- `quarri_list_extraction_sources` - Data sources → sources list
|
|
122
|
+
- `quarri_configure_extraction` - Configure sources
|
|
123
|
+
- `quarri_discover_tables` - Discover tables → tables list
|
|
124
|
+
- `quarri_propose_transformation` - Propose transforms
|
|
125
|
+
- `quarri_upload_csv` - Upload CSV files
|
|
126
|
+
- `quarri_generate_quarri_schema` - Generate schema config
|
|
127
|
+
- `quarri_list_raw_tables` - Raw tables → tables list
|
|
128
|
+
|
|
129
|
+
**Connectors:**
|
|
130
|
+
- `quarri_get_connector_code` - View connector code → code view
|
|
131
|
+
- `quarri_get_connector_logs` - Connector logs → logs view
|
|
132
|
+
- `quarri_log_analysis_run` - Log analysis runs
|
|
133
|
+
- `quarri_schedule_extraction` - Schedule extractions
|
|
134
|
+
- `quarri_store_generated_code` - Save connector code
|
|
135
|
+
- `quarri_update_connector_code` - Update connector code
|
|
136
|
+
|
|
137
|
+
**Debug:**
|
|
138
|
+
- `quarri_read_server_logs` - Server logs → logs view
|
|
139
|
+
- `quarri_query_repl_activity` - Activity history → activity list
|
|
140
|
+
- `quarri_read_fly_logs` - Production logs → logs view
|
|
141
|
+
|
|
142
|
+
**Session:**
|
|
143
|
+
- `quarri_auth_status` - Check auth → auth status card
|
|
144
|
+
- `quarri_trial_status` - Trial info → trial status card
|
|
145
|
+
- `quarri_list_databases` - Available databases
|
|
146
|
+
- `quarri_select_database` - Switch database
|
|
147
|
+
|
|
148
|
+
### Skills (Slash Commands)
|
|
149
|
+
|
|
150
|
+
Quarri includes intelligent skills for common workflows:
|
|
151
|
+
|
|
152
|
+
- `/quarri-query` - Natural language to SQL
|
|
153
|
+
- `/quarri-analyze` - Full analysis pipeline
|
|
154
|
+
- `/quarri-chart` - Generate visualizations
|
|
155
|
+
- `/quarri-insights` - Statistical insights
|
|
156
|
+
- `/quarri-metric` - Define metrics interactively
|
|
157
|
+
- `/quarri-explain` - Explain SQL queries
|
|
158
|
+
- `/quarri-extract` - Create data pipelines
|
|
159
|
+
- `/quarri-diagnose` - Debug connector issues
|
|
160
|
+
- `/quarri-guide` - Quarri usage guide
|
|
96
161
|
|
|
97
162
|
## Usage Examples
|
|
98
163
|
|
|
@@ -102,64 +167,58 @@ On first use, you'll be prompted to authenticate:
|
|
|
102
167
|
What were our top 10 products by revenue last month?
|
|
103
168
|
```
|
|
104
169
|
|
|
105
|
-
Claude will
|
|
106
|
-
1. Generate SQL from your question
|
|
107
|
-
2. Execute the query
|
|
108
|
-
3. Perform statistical analysis
|
|
109
|
-
4. Generate a chart
|
|
110
|
-
5. Provide key insights
|
|
170
|
+
Claude will generate SQL, execute it, and return results in an interactive data table.
|
|
111
171
|
|
|
112
|
-
### Create a
|
|
172
|
+
### Create a Visualization
|
|
113
173
|
|
|
114
174
|
```
|
|
115
|
-
|
|
175
|
+
/quarri-chart Show monthly revenue trend for 2024
|
|
116
176
|
```
|
|
117
177
|
|
|
118
|
-
|
|
178
|
+
Returns an interactive Plotly chart rendered in the conversation.
|
|
119
179
|
|
|
120
|
-
###
|
|
180
|
+
### Define a Metric
|
|
121
181
|
|
|
122
182
|
```
|
|
123
|
-
|
|
183
|
+
/quarri-metric Help me define customer lifetime value
|
|
124
184
|
```
|
|
125
185
|
|
|
126
|
-
|
|
186
|
+
Guides you through defining a reusable metric with SQL template.
|
|
187
|
+
|
|
188
|
+
### Configure Semantic Search
|
|
127
189
|
|
|
128
|
-
|
|
190
|
+
```
|
|
191
|
+
Enable semantic search on the product_name column
|
|
192
|
+
```
|
|
129
193
|
|
|
130
|
-
|
|
194
|
+
Uses `quarri_vectorize_column_values` to enable natural language search on column values.
|
|
131
195
|
|
|
132
|
-
|
|
196
|
+
## Environment Variables
|
|
133
197
|
|
|
134
198
|
- `QUARRI_API_URL` - API endpoint (default: https://app.quarri.ai)
|
|
135
199
|
|
|
136
200
|
## Development
|
|
137
201
|
|
|
138
|
-
### Building
|
|
139
|
-
|
|
140
202
|
```bash
|
|
203
|
+
# Install dependencies
|
|
141
204
|
npm install
|
|
142
|
-
npm run build
|
|
143
|
-
```
|
|
144
205
|
|
|
145
|
-
|
|
206
|
+
# Build
|
|
207
|
+
npm run build
|
|
146
208
|
|
|
147
|
-
|
|
209
|
+
# Run tests
|
|
148
210
|
npm test
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Local Development
|
|
152
211
|
|
|
153
|
-
|
|
212
|
+
# Local development
|
|
154
213
|
npm run dev
|
|
155
214
|
```
|
|
156
215
|
|
|
157
|
-
## License
|
|
158
|
-
|
|
159
|
-
MIT
|
|
160
|
-
|
|
161
216
|
## Support
|
|
162
217
|
|
|
163
218
|
- GitHub Issues: https://github.com/djayatillake/quarri-claude-plugin/issues
|
|
164
219
|
- Documentation: https://docs.quarri.ai
|
|
165
220
|
- Email: support@quarri.ai
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -13,15 +13,17 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
|
13
13
|
const client_js_1 = require("./api/client.js");
|
|
14
14
|
const token_store_js_1 = require("./auth/token-store.js");
|
|
15
15
|
const definitions_js_1 = require("./tools/definitions.js");
|
|
16
|
+
const resources_js_1 = require("./ui/resources.js");
|
|
16
17
|
// Initialize API client
|
|
17
18
|
const client = new client_js_1.QuarriApiClient();
|
|
18
|
-
// Initialize MCP server
|
|
19
|
+
// Initialize MCP server with resources capability
|
|
19
20
|
const server = new index_js_1.Server({
|
|
20
21
|
name: 'quarri',
|
|
21
22
|
version: '1.0.0',
|
|
22
23
|
}, {
|
|
23
24
|
capabilities: {
|
|
24
25
|
tools: {},
|
|
26
|
+
resources: {},
|
|
25
27
|
},
|
|
26
28
|
});
|
|
27
29
|
/**
|
|
@@ -56,6 +58,40 @@ Not authenticated with Quarri.
|
|
|
56
58
|
After authenticating, restart Claude Code to pick up the credentials.
|
|
57
59
|
`.trim();
|
|
58
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Handle list resources request
|
|
63
|
+
*/
|
|
64
|
+
server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => {
|
|
65
|
+
return {
|
|
66
|
+
resources: resources_js_1.UI_RESOURCES.map((resource) => ({
|
|
67
|
+
uri: resource.uri,
|
|
68
|
+
name: resource.name,
|
|
69
|
+
description: resource.description,
|
|
70
|
+
mimeType: resource.mimeType,
|
|
71
|
+
})),
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Handle read resource request
|
|
76
|
+
*/
|
|
77
|
+
server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) => {
|
|
78
|
+
const { uri } = request.params;
|
|
79
|
+
const resource = resources_js_1.UI_RESOURCES.find((r) => r.uri === uri);
|
|
80
|
+
if (!resource) {
|
|
81
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `Unknown resource: ${uri}`);
|
|
82
|
+
}
|
|
83
|
+
// Resources are populated dynamically by tool responses
|
|
84
|
+
// This handler returns an empty template
|
|
85
|
+
return {
|
|
86
|
+
contents: [
|
|
87
|
+
{
|
|
88
|
+
uri: resource.uri,
|
|
89
|
+
mimeType: resource.mimeType,
|
|
90
|
+
text: JSON.stringify({ type: resource.name, data: null }),
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
});
|
|
59
95
|
/**
|
|
60
96
|
* Handle list tools request
|
|
61
97
|
*/
|
|
@@ -65,6 +101,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
65
101
|
name: tool.name,
|
|
66
102
|
description: tool.description,
|
|
67
103
|
inputSchema: tool.inputSchema,
|
|
104
|
+
...(tool._meta && { _meta: tool._meta }),
|
|
68
105
|
})),
|
|
69
106
|
};
|
|
70
107
|
});
|
|
@@ -78,14 +115,23 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
78
115
|
const credentials = (0, token_store_js_1.loadCredentials)();
|
|
79
116
|
const selected = (0, token_store_js_1.getSelectedDatabase)();
|
|
80
117
|
if (!credentials) {
|
|
118
|
+
const unauthData = {
|
|
119
|
+
authenticated: false,
|
|
120
|
+
message: 'Not authenticated. Run: npx @quarri/claude-data-tools auth',
|
|
121
|
+
};
|
|
81
122
|
return {
|
|
82
123
|
content: [
|
|
83
124
|
{
|
|
84
125
|
type: 'text',
|
|
85
|
-
text: JSON.stringify(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
126
|
+
text: JSON.stringify(unauthData, null, 2),
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'resource',
|
|
130
|
+
resource: {
|
|
131
|
+
uri: 'ui://quarri/auth-status',
|
|
132
|
+
mimeType: 'application/vnd.quarri.auth-status+json',
|
|
133
|
+
text: JSON.stringify((0, resources_js_1.renderAuthStatus)({ authenticated: false })),
|
|
134
|
+
},
|
|
89
135
|
},
|
|
90
136
|
],
|
|
91
137
|
};
|
|
@@ -93,19 +139,34 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
93
139
|
const expiresAt = new Date(credentials.expiresAt);
|
|
94
140
|
const isExpired = expiresAt < new Date();
|
|
95
141
|
const expiresIn = Math.round((expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
|
|
142
|
+
const authData = {
|
|
143
|
+
authenticated: !isExpired,
|
|
144
|
+
email: credentials.email,
|
|
145
|
+
role: credentials.role,
|
|
146
|
+
databases: credentials.databases.map(d => d.display_name || d.database_name),
|
|
147
|
+
selectedDatabase: selected,
|
|
148
|
+
tokenExpires: credentials.expiresAt,
|
|
149
|
+
expiresInDays: isExpired ? 'EXPIRED' : expiresIn,
|
|
150
|
+
};
|
|
96
151
|
return {
|
|
97
152
|
content: [
|
|
98
153
|
{
|
|
99
154
|
type: 'text',
|
|
100
|
-
text: JSON.stringify(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
155
|
+
text: JSON.stringify(authData, null, 2),
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
type: 'resource',
|
|
159
|
+
resource: {
|
|
160
|
+
uri: 'ui://quarri/auth-status',
|
|
161
|
+
mimeType: 'application/vnd.quarri.auth-status+json',
|
|
162
|
+
text: JSON.stringify((0, resources_js_1.renderAuthStatus)({
|
|
163
|
+
authenticated: !isExpired,
|
|
164
|
+
email: credentials.email,
|
|
165
|
+
role: credentials.role,
|
|
166
|
+
databases: credentials.databases.map(d => d.display_name || d.database_name),
|
|
167
|
+
expiresInDays: isExpired ? 'EXPIRED' : expiresIn,
|
|
168
|
+
})),
|
|
169
|
+
},
|
|
109
170
|
},
|
|
110
171
|
],
|
|
111
172
|
};
|
|
@@ -177,35 +238,62 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
177
238
|
}
|
|
178
239
|
const data = result.data;
|
|
179
240
|
if (!data || !data.is_trial) {
|
|
241
|
+
const nonTrialData = {
|
|
242
|
+
is_trial: false,
|
|
243
|
+
message: 'This is not a trial account.',
|
|
244
|
+
database: data?.display_name || data?.database_name,
|
|
245
|
+
};
|
|
180
246
|
return {
|
|
181
247
|
content: [
|
|
182
248
|
{
|
|
183
249
|
type: 'text',
|
|
184
|
-
text: JSON.stringify(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
250
|
+
text: JSON.stringify(nonTrialData, null, 2),
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
type: 'resource',
|
|
254
|
+
resource: {
|
|
255
|
+
uri: 'ui://quarri/trial-status',
|
|
256
|
+
mimeType: 'application/vnd.quarri.trial-status+json',
|
|
257
|
+
text: JSON.stringify((0, resources_js_1.renderTrialStatus)({
|
|
258
|
+
is_trial: false,
|
|
259
|
+
organization: data?.display_name || data?.database_name,
|
|
260
|
+
})),
|
|
261
|
+
},
|
|
189
262
|
},
|
|
190
263
|
],
|
|
191
264
|
};
|
|
192
265
|
}
|
|
266
|
+
const trialData = {
|
|
267
|
+
is_trial: true,
|
|
268
|
+
organization: data.display_name,
|
|
269
|
+
days_remaining: data.days_remaining,
|
|
270
|
+
expires_at: data.expires_at,
|
|
271
|
+
data_limit_gb: data.data_limit_gb,
|
|
272
|
+
signup_type: data.signup_type,
|
|
273
|
+
upgrade_contact: data.upgrade_contact,
|
|
274
|
+
message: data.days_remaining && data.days_remaining <= 2
|
|
275
|
+
? `⚠️ Your trial expires in ${data.days_remaining} day(s). Contact ${data.upgrade_contact} to upgrade.`
|
|
276
|
+
: `Trial active with ${data.days_remaining} days remaining.`,
|
|
277
|
+
};
|
|
193
278
|
return {
|
|
194
279
|
content: [
|
|
195
280
|
{
|
|
196
281
|
type: 'text',
|
|
197
|
-
text: JSON.stringify(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
:
|
|
208
|
-
|
|
282
|
+
text: JSON.stringify(trialData, null, 2),
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
type: 'resource',
|
|
286
|
+
resource: {
|
|
287
|
+
uri: 'ui://quarri/trial-status',
|
|
288
|
+
mimeType: 'application/vnd.quarri.trial-status+json',
|
|
289
|
+
text: JSON.stringify((0, resources_js_1.renderTrialStatus)({
|
|
290
|
+
is_trial: true,
|
|
291
|
+
organization: data.display_name,
|
|
292
|
+
days_remaining: data.days_remaining,
|
|
293
|
+
expires_at: data.expires_at,
|
|
294
|
+
data_limit_gb: data.data_limit_gb,
|
|
295
|
+
})),
|
|
296
|
+
},
|
|
209
297
|
},
|
|
210
298
|
],
|
|
211
299
|
};
|
|
@@ -252,15 +340,127 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
252
340
|
isError: true,
|
|
253
341
|
};
|
|
254
342
|
}
|
|
343
|
+
// Build response with text and optional UI resource
|
|
344
|
+
const content = [
|
|
345
|
+
{
|
|
346
|
+
type: 'text',
|
|
347
|
+
text: formatToolResponse(name, result),
|
|
348
|
+
},
|
|
349
|
+
];
|
|
350
|
+
// Add UI resource if available for this tool
|
|
351
|
+
const uiResourceContent = buildUIResource(name, result);
|
|
352
|
+
if (uiResourceContent) {
|
|
353
|
+
content.push(uiResourceContent);
|
|
354
|
+
}
|
|
355
|
+
return { content };
|
|
356
|
+
});
|
|
357
|
+
/**
|
|
358
|
+
* Build UI resource for a tool response
|
|
359
|
+
*/
|
|
360
|
+
function buildUIResource(toolName, result) {
|
|
361
|
+
const uiResource = (0, resources_js_1.getToolUIResource)(toolName);
|
|
362
|
+
if (!uiResource)
|
|
363
|
+
return null;
|
|
364
|
+
let rendered = null;
|
|
365
|
+
switch (toolName) {
|
|
366
|
+
case 'quarri_execute_sql':
|
|
367
|
+
if (result.rows && Array.isArray(result.rows)) {
|
|
368
|
+
const rows = result.rows;
|
|
369
|
+
const columns = result.columns || (rows.length > 0 ? Object.keys(rows[0]) : []);
|
|
370
|
+
rendered = (0, resources_js_1.renderDataTable)(rows, columns);
|
|
371
|
+
}
|
|
372
|
+
break;
|
|
373
|
+
case 'quarri_get_schema':
|
|
374
|
+
if (result.tables && Array.isArray(result.tables)) {
|
|
375
|
+
rendered = (0, resources_js_1.renderSchemaExplorer)(result.tables);
|
|
376
|
+
}
|
|
377
|
+
break;
|
|
378
|
+
case 'quarri_search_values':
|
|
379
|
+
if (result.results && Array.isArray(result.results)) {
|
|
380
|
+
rendered = (0, resources_js_1.renderSearchResults)(result.results);
|
|
381
|
+
}
|
|
382
|
+
break;
|
|
383
|
+
case 'quarri_get_metrics':
|
|
384
|
+
case 'quarri_search_metrics':
|
|
385
|
+
if (result.metrics && Array.isArray(result.metrics)) {
|
|
386
|
+
rendered = (0, resources_js_1.renderMetricsList)(result.metrics);
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
389
|
+
case 'quarri_get_metric_detail':
|
|
390
|
+
if (result.id) {
|
|
391
|
+
rendered = (0, resources_js_1.renderMetricDetail)(result);
|
|
392
|
+
}
|
|
393
|
+
break;
|
|
394
|
+
case 'quarri_list_agent_prompts':
|
|
395
|
+
if (result.prompts && Array.isArray(result.prompts)) {
|
|
396
|
+
rendered = (0, resources_js_1.renderPromptsList)(result.prompts);
|
|
397
|
+
}
|
|
398
|
+
break;
|
|
399
|
+
case 'quarri_list_rules':
|
|
400
|
+
if (result.rules && Array.isArray(result.rules)) {
|
|
401
|
+
rendered = (0, resources_js_1.renderRulesList)(result.rules);
|
|
402
|
+
}
|
|
403
|
+
break;
|
|
404
|
+
case 'quarri_list_searchable_columns':
|
|
405
|
+
if (result.columns && Array.isArray(result.columns)) {
|
|
406
|
+
rendered = (0, resources_js_1.renderColumnsList)(result.columns);
|
|
407
|
+
}
|
|
408
|
+
break;
|
|
409
|
+
case 'quarri_list_teams':
|
|
410
|
+
if (result.teams && Array.isArray(result.teams)) {
|
|
411
|
+
rendered = (0, resources_js_1.renderTeamsList)(result.teams);
|
|
412
|
+
}
|
|
413
|
+
break;
|
|
414
|
+
case 'quarri_get_team_filters':
|
|
415
|
+
if (result.filters && Array.isArray(result.filters)) {
|
|
416
|
+
rendered = (0, resources_js_1.renderTeamFilters)(result.filters);
|
|
417
|
+
}
|
|
418
|
+
break;
|
|
419
|
+
case 'quarri_get_team_restrictions':
|
|
420
|
+
if (result.restrictions && Array.isArray(result.restrictions)) {
|
|
421
|
+
rendered = (0, resources_js_1.renderTeamRestrictions)(result.restrictions);
|
|
422
|
+
}
|
|
423
|
+
break;
|
|
424
|
+
case 'quarri_list_extraction_sources':
|
|
425
|
+
if (result.sources && Array.isArray(result.sources)) {
|
|
426
|
+
rendered = (0, resources_js_1.renderSourcesList)(result.sources);
|
|
427
|
+
}
|
|
428
|
+
break;
|
|
429
|
+
case 'quarri_discover_tables':
|
|
430
|
+
case 'quarri_list_raw_tables':
|
|
431
|
+
if (result.tables && Array.isArray(result.tables)) {
|
|
432
|
+
rendered = (0, resources_js_1.renderTablesList)(result.tables);
|
|
433
|
+
}
|
|
434
|
+
break;
|
|
435
|
+
case 'quarri_read_server_logs':
|
|
436
|
+
case 'quarri_read_fly_logs':
|
|
437
|
+
case 'quarri_get_connector_logs':
|
|
438
|
+
if (result.logs && Array.isArray(result.logs)) {
|
|
439
|
+
rendered = (0, resources_js_1.renderLogsView)(result.logs);
|
|
440
|
+
}
|
|
441
|
+
break;
|
|
442
|
+
case 'quarri_query_repl_activity':
|
|
443
|
+
if (result.activities && Array.isArray(result.activities)) {
|
|
444
|
+
rendered = (0, resources_js_1.renderActivityList)(result.activities);
|
|
445
|
+
}
|
|
446
|
+
break;
|
|
447
|
+
case 'quarri_get_connector_code':
|
|
448
|
+
if (result.code && typeof result.code === 'string') {
|
|
449
|
+
rendered = (0, resources_js_1.renderCodeView)(result.code, result.language || 'python');
|
|
450
|
+
}
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
if (!rendered)
|
|
454
|
+
return null;
|
|
255
455
|
return {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
456
|
+
type: 'resource',
|
|
457
|
+
resource: {
|
|
458
|
+
uri: uiResource.uri,
|
|
459
|
+
mimeType: uiResource.mimeType,
|
|
460
|
+
text: JSON.stringify(rendered),
|
|
461
|
+
},
|
|
262
462
|
};
|
|
263
|
-
}
|
|
463
|
+
}
|
|
264
464
|
/**
|
|
265
465
|
* Format error response for better readability
|
|
266
466
|
*/
|