@vettly/mcp 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/vettly-mcp.cjs +272 -58
- package/dist/bin/vettly-mcp.js +3 -17
- package/dist/chunk-PMBQ22Z2.js +558 -0
- package/dist/index.cjs +281 -42
- package/dist/index.js +11 -1
- package/package.json +3 -2
- package/smithery.yaml +19 -0
- package/dist/bin/vettly-mcp.d.cts +0 -1
- package/dist/bin/vettly-mcp.d.ts +0 -1
- package/dist/chunk-VZJIPBOX.js +0 -330
- package/dist/index.d.cts +0 -9
- package/dist/index.d.ts +0 -9
package/dist/bin/vettly-mcp.cjs
CHANGED
|
@@ -15,7 +15,7 @@ var ModerateInputSchema = import_zod.z.object({
|
|
|
15
15
|
policyId: import_zod.z.string().min(1).describe("The policy ID to use for moderation"),
|
|
16
16
|
contentType: import_zod.z.enum(["text", "image", "video"]).default("text").describe("Type of content being moderated")
|
|
17
17
|
});
|
|
18
|
-
function registerModerateTool(server, client) {
|
|
18
|
+
function registerModerateTool(server, client, demoMode = false) {
|
|
19
19
|
server.tool(
|
|
20
20
|
"moderate_content",
|
|
21
21
|
"Check text, image, or video content against a Vettly moderation policy. Returns safety assessment with category scores.",
|
|
@@ -24,6 +24,13 @@ function registerModerateTool(server, client) {
|
|
|
24
24
|
policyId: ModerateInputSchema.shape.policyId,
|
|
25
25
|
contentType: ModerateInputSchema.shape.contentType
|
|
26
26
|
},
|
|
27
|
+
{
|
|
28
|
+
title: "Moderate Content",
|
|
29
|
+
readOnlyHint: true,
|
|
30
|
+
destructiveHint: false,
|
|
31
|
+
idempotentHint: true,
|
|
32
|
+
openWorldHint: true
|
|
33
|
+
},
|
|
27
34
|
async (args) => {
|
|
28
35
|
const input = ModerateInputSchema.parse(args);
|
|
29
36
|
try {
|
|
@@ -32,24 +39,25 @@ function registerModerateTool(server, client) {
|
|
|
32
39
|
policyId: input.policyId,
|
|
33
40
|
contentType: input.contentType
|
|
34
41
|
});
|
|
42
|
+
const text = JSON.stringify(
|
|
43
|
+
{
|
|
44
|
+
decisionId: result.decisionId,
|
|
45
|
+
safe: result.safe,
|
|
46
|
+
flagged: result.flagged,
|
|
47
|
+
action: result.action,
|
|
48
|
+
categories: result.categories,
|
|
49
|
+
provider: result.provider,
|
|
50
|
+
latency: result.latency,
|
|
51
|
+
cost: result.cost
|
|
52
|
+
},
|
|
53
|
+
null,
|
|
54
|
+
2
|
|
55
|
+
);
|
|
35
56
|
return {
|
|
36
57
|
content: [
|
|
37
58
|
{
|
|
38
59
|
type: "text",
|
|
39
|
-
text:
|
|
40
|
-
{
|
|
41
|
-
decisionId: result.decisionId,
|
|
42
|
-
safe: result.safe,
|
|
43
|
-
flagged: result.flagged,
|
|
44
|
-
action: result.action,
|
|
45
|
-
categories: result.categories,
|
|
46
|
-
provider: result.provider,
|
|
47
|
-
latency: result.latency,
|
|
48
|
-
cost: result.cost
|
|
49
|
-
},
|
|
50
|
-
null,
|
|
51
|
-
2
|
|
52
|
-
)
|
|
60
|
+
text: text + (demoMode ? DEMO_FOOTER : "")
|
|
53
61
|
}
|
|
54
62
|
]
|
|
55
63
|
};
|
|
@@ -73,22 +81,30 @@ var import_zod2 = require("zod");
|
|
|
73
81
|
var ValidateInputSchema = import_zod2.z.object({
|
|
74
82
|
yamlContent: import_zod2.z.string().min(1).describe("The YAML policy content to validate")
|
|
75
83
|
});
|
|
76
|
-
function registerValidateTool(server, client) {
|
|
84
|
+
function registerValidateTool(server, client, demoMode = false) {
|
|
77
85
|
server.tool(
|
|
78
86
|
"validate_policy",
|
|
79
87
|
"Validate a Vettly policy YAML without saving it. Returns validation results with any syntax or configuration errors.",
|
|
80
88
|
{
|
|
81
89
|
yamlContent: ValidateInputSchema.shape.yamlContent
|
|
82
90
|
},
|
|
91
|
+
{
|
|
92
|
+
title: "Validate Policy",
|
|
93
|
+
readOnlyHint: true,
|
|
94
|
+
destructiveHint: false,
|
|
95
|
+
idempotentHint: true,
|
|
96
|
+
openWorldHint: true
|
|
97
|
+
},
|
|
83
98
|
async (args) => {
|
|
84
99
|
const input = ValidateInputSchema.parse(args);
|
|
85
100
|
try {
|
|
86
101
|
const result = await client.validatePolicy(input.yamlContent);
|
|
102
|
+
const text = JSON.stringify(result, null, 2);
|
|
87
103
|
return {
|
|
88
104
|
content: [
|
|
89
105
|
{
|
|
90
106
|
type: "text",
|
|
91
|
-
text:
|
|
107
|
+
text: text + (demoMode ? DEMO_FOOTER : "")
|
|
92
108
|
}
|
|
93
109
|
]
|
|
94
110
|
};
|
|
@@ -108,19 +124,34 @@ function registerValidateTool(server, client) {
|
|
|
108
124
|
}
|
|
109
125
|
|
|
110
126
|
// src/tools/list-policies.ts
|
|
111
|
-
|
|
127
|
+
var import_zod3 = require("zod");
|
|
128
|
+
function registerListPoliciesTool(server, client, demoMode = false) {
|
|
112
129
|
server.tool(
|
|
113
130
|
"list_policies",
|
|
114
131
|
"List all moderation policies available in your Vettly account.",
|
|
115
|
-
{
|
|
116
|
-
|
|
132
|
+
{
|
|
133
|
+
status: import_zod3.z.enum(["active", "all"]).default("active").describe("Filter by policy status: active only or all policies")
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
title: "List Policies",
|
|
137
|
+
readOnlyHint: true,
|
|
138
|
+
destructiveHint: false,
|
|
139
|
+
idempotentHint: true,
|
|
140
|
+
openWorldHint: true
|
|
141
|
+
},
|
|
142
|
+
async (args) => {
|
|
117
143
|
try {
|
|
118
144
|
const result = await client.listPolicies();
|
|
145
|
+
let policies = result;
|
|
146
|
+
if (args.status === "active" && Array.isArray(policies)) {
|
|
147
|
+
policies = policies.filter((p) => p.status !== "archived");
|
|
148
|
+
}
|
|
149
|
+
const text = JSON.stringify(policies, null, 2);
|
|
119
150
|
return {
|
|
120
151
|
content: [
|
|
121
152
|
{
|
|
122
153
|
type: "text",
|
|
123
|
-
text:
|
|
154
|
+
text: text + (demoMode ? DEMO_FOOTER : "")
|
|
124
155
|
}
|
|
125
156
|
]
|
|
126
157
|
};
|
|
@@ -140,26 +171,34 @@ function registerListPoliciesTool(server, client) {
|
|
|
140
171
|
}
|
|
141
172
|
|
|
142
173
|
// src/tools/usage-stats.ts
|
|
143
|
-
var
|
|
144
|
-
var UsageStatsInputSchema =
|
|
145
|
-
days:
|
|
174
|
+
var import_zod4 = require("zod");
|
|
175
|
+
var UsageStatsInputSchema = import_zod4.z.object({
|
|
176
|
+
days: import_zod4.z.number().min(1).max(365).default(30).describe("Number of days to include in statistics")
|
|
146
177
|
});
|
|
147
|
-
function registerUsageStatsTool(server, client) {
|
|
178
|
+
function registerUsageStatsTool(server, client, demoMode = false) {
|
|
148
179
|
server.tool(
|
|
149
180
|
"get_usage_stats",
|
|
150
181
|
"Get usage statistics for your Vettly account including request counts, costs, and moderation outcomes.",
|
|
151
182
|
{
|
|
152
183
|
days: UsageStatsInputSchema.shape.days
|
|
153
184
|
},
|
|
185
|
+
{
|
|
186
|
+
title: "Get Usage Stats",
|
|
187
|
+
readOnlyHint: true,
|
|
188
|
+
destructiveHint: false,
|
|
189
|
+
idempotentHint: true,
|
|
190
|
+
openWorldHint: true
|
|
191
|
+
},
|
|
154
192
|
async (args) => {
|
|
155
193
|
const input = UsageStatsInputSchema.parse(args);
|
|
156
194
|
try {
|
|
157
195
|
const result = await client.getUsageStats(input.days);
|
|
196
|
+
const text = JSON.stringify(result, null, 2);
|
|
158
197
|
return {
|
|
159
198
|
content: [
|
|
160
199
|
{
|
|
161
200
|
type: "text",
|
|
162
|
-
text:
|
|
201
|
+
text: text + (demoMode ? DEMO_FOOTER : "")
|
|
163
202
|
}
|
|
164
203
|
]
|
|
165
204
|
};
|
|
@@ -179,14 +218,14 @@ function registerUsageStatsTool(server, client) {
|
|
|
179
218
|
}
|
|
180
219
|
|
|
181
220
|
// src/tools/decisions.ts
|
|
182
|
-
var
|
|
183
|
-
var DecisionsInputSchema =
|
|
184
|
-
limit:
|
|
185
|
-
flagged:
|
|
186
|
-
policyId:
|
|
187
|
-
contentType:
|
|
221
|
+
var import_zod5 = require("zod");
|
|
222
|
+
var DecisionsInputSchema = import_zod5.z.object({
|
|
223
|
+
limit: import_zod5.z.number().min(1).max(50).default(10).describe("Number of decisions to return"),
|
|
224
|
+
flagged: import_zod5.z.boolean().optional().describe("Filter to only flagged content (true) or safe content (false)"),
|
|
225
|
+
policyId: import_zod5.z.string().optional().describe("Filter by specific policy ID"),
|
|
226
|
+
contentType: import_zod5.z.enum(["text", "image", "video"]).optional().describe("Filter by content type")
|
|
188
227
|
});
|
|
189
|
-
function registerDecisionsTool(server, client) {
|
|
228
|
+
function registerDecisionsTool(server, client, demoMode = false) {
|
|
190
229
|
server.tool(
|
|
191
230
|
"get_recent_decisions",
|
|
192
231
|
"Get recent moderation decisions with optional filtering by outcome, content type, or policy.",
|
|
@@ -196,6 +235,13 @@ function registerDecisionsTool(server, client) {
|
|
|
196
235
|
policyId: DecisionsInputSchema.shape.policyId,
|
|
197
236
|
contentType: DecisionsInputSchema.shape.contentType
|
|
198
237
|
},
|
|
238
|
+
{
|
|
239
|
+
title: "Get Recent Decisions",
|
|
240
|
+
readOnlyHint: true,
|
|
241
|
+
destructiveHint: false,
|
|
242
|
+
idempotentHint: true,
|
|
243
|
+
openWorldHint: true
|
|
244
|
+
},
|
|
199
245
|
async (args) => {
|
|
200
246
|
const input = DecisionsInputSchema.parse(args);
|
|
201
247
|
try {
|
|
@@ -210,11 +256,12 @@ function registerDecisionsTool(server, client) {
|
|
|
210
256
|
if (input.contentType) {
|
|
211
257
|
decisions = decisions.filter((d) => d.contentType === input.contentType);
|
|
212
258
|
}
|
|
259
|
+
const text = JSON.stringify({ decisions }, null, 2);
|
|
213
260
|
return {
|
|
214
261
|
content: [
|
|
215
262
|
{
|
|
216
263
|
type: "text",
|
|
217
|
-
text:
|
|
264
|
+
text: text + (demoMode ? DEMO_FOOTER : "")
|
|
218
265
|
}
|
|
219
266
|
]
|
|
220
267
|
};
|
|
@@ -234,12 +281,13 @@ function registerDecisionsTool(server, client) {
|
|
|
234
281
|
}
|
|
235
282
|
|
|
236
283
|
// src/tools/index.ts
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
284
|
+
var DEMO_FOOTER = "\n\n---\n\u{1F511} Demo mode (10 requests/day). Get your free API key at https://vettly.dev";
|
|
285
|
+
function registerTools(server, client, demoMode = false) {
|
|
286
|
+
registerModerateTool(server, client, demoMode);
|
|
287
|
+
registerValidateTool(server, client, demoMode);
|
|
288
|
+
registerListPoliciesTool(server, client, demoMode);
|
|
289
|
+
registerUsageStatsTool(server, client, demoMode);
|
|
290
|
+
registerDecisionsTool(server, client, demoMode);
|
|
243
291
|
}
|
|
244
292
|
|
|
245
293
|
// src/resources/policies.ts
|
|
@@ -316,18 +364,198 @@ function registerResources(server, client) {
|
|
|
316
364
|
registerPolicyResources(server, client);
|
|
317
365
|
}
|
|
318
366
|
|
|
367
|
+
// src/prompts/moderate-content-guide.ts
|
|
368
|
+
function registerModerateContentGuide(server) {
|
|
369
|
+
server.prompt(
|
|
370
|
+
"moderate-content-guide",
|
|
371
|
+
"Step-by-step guide to moderating content with Vettly. Explains the workflow: list policies, moderate content, and interpret results.",
|
|
372
|
+
async () => ({
|
|
373
|
+
messages: [
|
|
374
|
+
{
|
|
375
|
+
role: "user",
|
|
376
|
+
content: {
|
|
377
|
+
type: "text",
|
|
378
|
+
text: `You are helping a user moderate content with Vettly. Follow this workflow:
|
|
379
|
+
|
|
380
|
+
## Step 1: List available policies
|
|
381
|
+
Use the \`list_policies\` tool to see what moderation policies are configured. Each policy has an ID and defines rules for what content is allowed or flagged.
|
|
382
|
+
|
|
383
|
+
## Step 2: Moderate content
|
|
384
|
+
Use the \`moderate_content\` tool with:
|
|
385
|
+
- \`content\`: The text, image URL, or video URL to check
|
|
386
|
+
- \`policyId\`: The policy ID from step 1
|
|
387
|
+
- \`contentType\`: "text", "image", or "video"
|
|
388
|
+
|
|
389
|
+
## Step 3: Interpret results
|
|
390
|
+
The response includes:
|
|
391
|
+
- \`safe\`: Boolean \u2014 whether the content passed moderation
|
|
392
|
+
- \`flagged\`: Boolean \u2014 whether the content was flagged for review
|
|
393
|
+
- \`action\`: The recommended action ("allow", "flag", or "block")
|
|
394
|
+
- \`categories\`: Breakdown of category scores (e.g. hate speech, violence, sexual content)
|
|
395
|
+
- \`decisionId\`: Unique ID for this decision, useful for auditing
|
|
396
|
+
|
|
397
|
+
## Tips
|
|
398
|
+
- Always list policies first so you know which policy ID to use.
|
|
399
|
+
- For images and video, pass the URL as the \`content\` parameter.
|
|
400
|
+
- Use \`get_recent_decisions\` to review past moderation outcomes.
|
|
401
|
+
- Use \`get_usage_stats\` to check your account's usage and remaining quota.`
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
]
|
|
405
|
+
})
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// src/prompts/write-policy.ts
|
|
410
|
+
var import_zod6 = require("zod");
|
|
411
|
+
function registerWritePolicy(server) {
|
|
412
|
+
server.prompt(
|
|
413
|
+
"write-policy",
|
|
414
|
+
"Guide for writing a Vettly moderation policy in YAML. Optionally tailored to a specific platform type.",
|
|
415
|
+
{ platform: import_zod6.z.string().optional().describe('The type of platform (e.g. "kids app", "marketplace", "social media", "dating app")') },
|
|
416
|
+
async (args) => {
|
|
417
|
+
const platformContext = args.platform ? `
|
|
418
|
+
|
|
419
|
+
The user is building a **${args.platform}**. Tailor your policy suggestions to this platform type \u2014 consider what content categories matter most and what thresholds are appropriate.` : "";
|
|
420
|
+
return {
|
|
421
|
+
messages: [
|
|
422
|
+
{
|
|
423
|
+
role: "user",
|
|
424
|
+
content: {
|
|
425
|
+
type: "text",
|
|
426
|
+
text: `You are helping a user write a Vettly moderation policy in YAML.${platformContext}
|
|
427
|
+
|
|
428
|
+
## Policy YAML structure
|
|
429
|
+
|
|
430
|
+
A Vettly policy is a YAML document that defines moderation rules in plain English. Here's the structure:
|
|
431
|
+
|
|
432
|
+
\`\`\`yaml
|
|
433
|
+
name: My Policy
|
|
434
|
+
description: Brief description of what this policy covers
|
|
435
|
+
|
|
436
|
+
rules:
|
|
437
|
+
- category: hate_speech
|
|
438
|
+
threshold: 0.7
|
|
439
|
+
action: block
|
|
440
|
+
description: Block hateful content targeting protected groups
|
|
441
|
+
|
|
442
|
+
- category: violence
|
|
443
|
+
threshold: 0.8
|
|
444
|
+
action: flag
|
|
445
|
+
description: Flag violent content for human review
|
|
446
|
+
|
|
447
|
+
- category: sexual_content
|
|
448
|
+
threshold: 0.5
|
|
449
|
+
action: block
|
|
450
|
+
description: Block explicit sexual content
|
|
451
|
+
|
|
452
|
+
- category: self_harm
|
|
453
|
+
threshold: 0.6
|
|
454
|
+
action: block
|
|
455
|
+
description: Block content promoting self-harm
|
|
456
|
+
\`\`\`
|
|
457
|
+
|
|
458
|
+
## Available categories
|
|
459
|
+
Common categories: \`hate_speech\`, \`violence\`, \`sexual_content\`, \`self_harm\`, \`harassment\`, \`dangerous_content\`, \`spam\`
|
|
460
|
+
|
|
461
|
+
## Actions
|
|
462
|
+
- \`allow\` \u2014 let the content through
|
|
463
|
+
- \`flag\` \u2014 mark for human review
|
|
464
|
+
- \`block\` \u2014 reject the content
|
|
465
|
+
|
|
466
|
+
## Thresholds
|
|
467
|
+
- 0.0\u20130.3: Very sensitive (catches more, higher false positive rate)
|
|
468
|
+
- 0.4\u20130.6: Moderate sensitivity
|
|
469
|
+
- 0.7\u20131.0: High confidence only (fewer false positives)
|
|
470
|
+
|
|
471
|
+
## Workflow
|
|
472
|
+
1. Draft the YAML policy based on the user's requirements
|
|
473
|
+
2. Use the \`validate_policy\` tool to check for errors
|
|
474
|
+
3. Iterate until validation passes
|
|
475
|
+
4. The user can then save the policy via the Vettly dashboard`
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
]
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// src/prompts/review-flagged-content.ts
|
|
485
|
+
var import_zod7 = require("zod");
|
|
486
|
+
function registerReviewFlaggedContent(server) {
|
|
487
|
+
server.prompt(
|
|
488
|
+
"review-flagged-content",
|
|
489
|
+
"Template for reviewing flagged moderation decisions. Optionally filtered to a specific policy.",
|
|
490
|
+
{ policyId: import_zod7.z.string().optional().describe("Filter flagged decisions to a specific policy ID") },
|
|
491
|
+
async (args) => {
|
|
492
|
+
const policyFilter = args.policyId ? `
|
|
493
|
+
|
|
494
|
+
Filter decisions to policy ID: \`${args.policyId}\`` : "";
|
|
495
|
+
return {
|
|
496
|
+
messages: [
|
|
497
|
+
{
|
|
498
|
+
role: "user",
|
|
499
|
+
content: {
|
|
500
|
+
type: "text",
|
|
501
|
+
text: `You are helping a user review flagged moderation decisions in Vettly.${policyFilter}
|
|
502
|
+
|
|
503
|
+
## Review workflow
|
|
504
|
+
|
|
505
|
+
### Step 1: Fetch flagged decisions
|
|
506
|
+
Use the \`get_recent_decisions\` tool with \`flagged: true\` to get recent flagged content.${args.policyId ? ` Also set \`policyId: "${args.policyId}"\` to filter by that policy.` : " Optionally filter by `policyId` or `contentType`."}
|
|
507
|
+
|
|
508
|
+
### Step 2: Analyze each decision
|
|
509
|
+
For each flagged decision, examine:
|
|
510
|
+
- **Content**: What was submitted
|
|
511
|
+
- **Categories**: Which categories triggered and their scores
|
|
512
|
+
- **Action**: What action was taken (flag vs block)
|
|
513
|
+
- **Policy**: Which policy was applied
|
|
514
|
+
|
|
515
|
+
### Step 3: Provide recommendations
|
|
516
|
+
For each flagged item, suggest one of:
|
|
517
|
+
- **Approve**: The content is acceptable, the flag was a false positive
|
|
518
|
+
- **Confirm block**: The content correctly violates the policy
|
|
519
|
+
- **Adjust policy**: The threshold may need tuning (too sensitive or not enough)
|
|
520
|
+
|
|
521
|
+
### Step 4: Check for patterns
|
|
522
|
+
Use \`get_usage_stats\` to look at overall moderation trends. If many items are being flagged, the policy thresholds may need adjustment.
|
|
523
|
+
|
|
524
|
+
## Tips
|
|
525
|
+
- High category scores (>0.9) are almost always correct flags
|
|
526
|
+
- Scores in the 0.5-0.7 range are where most false positives occur
|
|
527
|
+
- If a category consistently flags incorrectly, raise its threshold in the policy`
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
]
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/prompts/index.ts
|
|
537
|
+
function registerPrompts(server) {
|
|
538
|
+
registerModerateContentGuide(server);
|
|
539
|
+
registerWritePolicy(server);
|
|
540
|
+
registerReviewFlaggedContent(server);
|
|
541
|
+
}
|
|
542
|
+
|
|
319
543
|
// src/server.ts
|
|
544
|
+
var DEMO_API_KEY = "vettly_test_demo_mcp_readonly";
|
|
320
545
|
function createVettlyMcpServer(config) {
|
|
546
|
+
const demoMode = !config.apiKey;
|
|
547
|
+
const apiKey = config.apiKey || DEMO_API_KEY;
|
|
321
548
|
const client = new import_sdk.ModerationClient({
|
|
322
|
-
apiKey
|
|
549
|
+
apiKey,
|
|
323
550
|
apiUrl: config.apiUrl
|
|
324
551
|
});
|
|
325
552
|
const server = new import_mcp2.McpServer({
|
|
326
553
|
name: "vettly",
|
|
327
554
|
version: "0.1.0"
|
|
328
555
|
});
|
|
329
|
-
registerTools(server, client);
|
|
556
|
+
registerTools(server, client, demoMode);
|
|
330
557
|
registerResources(server, client);
|
|
558
|
+
registerPrompts(server);
|
|
331
559
|
return server;
|
|
332
560
|
}
|
|
333
561
|
|
|
@@ -335,22 +563,8 @@ function createVettlyMcpServer(config) {
|
|
|
335
563
|
async function main() {
|
|
336
564
|
const apiKey = process.env.VETTLY_API_KEY;
|
|
337
565
|
if (!apiKey) {
|
|
338
|
-
console.error("
|
|
339
|
-
console.error("");
|
|
340
|
-
console.error("Usage:");
|
|
341
|
-
console.error(" VETTLY_API_KEY=vettly_live_xxx npx @vettly/mcp");
|
|
342
|
-
console.error("");
|
|
343
|
-
console.error("Or configure in Claude Desktop:");
|
|
344
|
-
console.error(" {");
|
|
345
|
-
console.error(' "mcpServers": {');
|
|
346
|
-
console.error(' "vettly": {');
|
|
347
|
-
console.error(' "command": "npx",');
|
|
348
|
-
console.error(' "args": ["-y", "@vettly/mcp"],');
|
|
349
|
-
console.error(' "env": { "VETTLY_API_KEY": "vettly_live_xxx" }');
|
|
350
|
-
console.error(" }");
|
|
351
|
-
console.error(" }");
|
|
352
|
-
console.error(" }");
|
|
353
|
-
process.exit(1);
|
|
566
|
+
console.error("No VETTLY_API_KEY set \u2014 starting in demo mode (limited to 10 requests/day).");
|
|
567
|
+
console.error("Get your free API key at https://vettly.dev");
|
|
354
568
|
}
|
|
355
569
|
const server = createVettlyMcpServer({
|
|
356
570
|
apiKey,
|
package/dist/bin/vettly-mcp.js
CHANGED
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createVettlyMcpServer
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-PMBQ22Z2.js";
|
|
5
5
|
|
|
6
6
|
// src/bin/vettly-mcp.ts
|
|
7
7
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
8
|
async function main() {
|
|
9
9
|
const apiKey = process.env.VETTLY_API_KEY;
|
|
10
10
|
if (!apiKey) {
|
|
11
|
-
console.error("
|
|
12
|
-
console.error("");
|
|
13
|
-
console.error("Usage:");
|
|
14
|
-
console.error(" VETTLY_API_KEY=vettly_live_xxx npx @vettly/mcp");
|
|
15
|
-
console.error("");
|
|
16
|
-
console.error("Or configure in Claude Desktop:");
|
|
17
|
-
console.error(" {");
|
|
18
|
-
console.error(' "mcpServers": {');
|
|
19
|
-
console.error(' "vettly": {');
|
|
20
|
-
console.error(' "command": "npx",');
|
|
21
|
-
console.error(' "args": ["-y", "@vettly/mcp"],');
|
|
22
|
-
console.error(' "env": { "VETTLY_API_KEY": "vettly_live_xxx" }');
|
|
23
|
-
console.error(" }");
|
|
24
|
-
console.error(" }");
|
|
25
|
-
console.error(" }");
|
|
26
|
-
process.exit(1);
|
|
11
|
+
console.error("No VETTLY_API_KEY set \u2014 starting in demo mode (limited to 10 requests/day).");
|
|
12
|
+
console.error("Get your free API key at https://vettly.dev");
|
|
27
13
|
}
|
|
28
14
|
const server = createVettlyMcpServer({
|
|
29
15
|
apiKey,
|