@nexvora/mcp-server 0.3.1 → 0.3.3

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.
Files changed (66) hide show
  1. package/README.md +15 -13
  2. package/dist/NexvoraClient.d.ts.map +1 -1
  3. package/dist/NexvoraClient.js +21 -3
  4. package/dist/NexvoraClient.js.map +1 -1
  5. package/dist/cli.d.ts +2 -2
  6. package/dist/cli.js +26 -20
  7. package/dist/cli.js.map +1 -1
  8. package/dist/createServer.d.ts +7 -0
  9. package/dist/createServer.d.ts.map +1 -1
  10. package/dist/createServer.js +3 -3
  11. package/dist/createServer.js.map +1 -1
  12. package/package.json +6 -2
  13. package/CHANGELOG.md +0 -208
  14. package/docs/setup/chatgpt-desktop.md +0 -120
  15. package/docs/setup/claude-code.md +0 -152
  16. package/docs/setup/cursor.md +0 -129
  17. package/src/NexvoraClient.ts +0 -328
  18. package/src/RateLimiter.ts +0 -74
  19. package/src/__tests__/NexvoraClient.test.ts +0 -424
  20. package/src/__tests__/RateLimiter.test.ts +0 -151
  21. package/src/__tests__/auth/oauth.test.ts +0 -246
  22. package/src/__tests__/cache.test.ts +0 -64
  23. package/src/__tests__/config.test.ts +0 -98
  24. package/src/__tests__/defineTool.test.ts +0 -223
  25. package/src/__tests__/fixtures/config.json +0 -7
  26. package/src/__tests__/integration/agentstack.integration.test.ts +0 -259
  27. package/src/__tests__/integration/auth_refresh.integration.test.ts +0 -227
  28. package/src/__tests__/integration/consulting.integration.test.ts +0 -213
  29. package/src/__tests__/integration/feed.integration.test.ts +0 -200
  30. package/src/__tests__/integration/helpers.ts +0 -118
  31. package/src/__tests__/integration/knowledge.integration.test.ts +0 -194
  32. package/src/__tests__/integration/rate_limiting.integration.test.ts +0 -207
  33. package/src/__tests__/integration/submit_task.integration.test.ts +0 -120
  34. package/src/__tests__/integration/wallet_observatory.integration.test.ts +0 -240
  35. package/src/__tests__/nexvora_agentstack_answer.test.ts +0 -120
  36. package/src/__tests__/nexvora_agentstack_ask.test.ts +0 -140
  37. package/src/__tests__/nexvora_agentstack_search.test.ts +0 -188
  38. package/src/__tests__/nexvora_consulting_book.test.ts +0 -277
  39. package/src/__tests__/nexvora_consulting_search.test.ts +0 -153
  40. package/src/__tests__/nexvora_feed_post.test.ts +0 -147
  41. package/src/__tests__/nexvora_feed_react.test.ts +0 -98
  42. package/src/__tests__/nexvora_knowledge_search.test.ts +0 -148
  43. package/src/__tests__/nexvora_knowledge_subscribe.test.ts +0 -173
  44. package/src/__tests__/nexvora_observatory.test.ts +0 -125
  45. package/src/__tests__/nexvora_wallet_balance.test.ts +0 -165
  46. package/src/auth/oauth.ts +0 -247
  47. package/src/cache.ts +0 -34
  48. package/src/cli.ts +0 -171
  49. package/src/config.ts +0 -70
  50. package/src/createServer.ts +0 -90
  51. package/src/defineTool.ts +0 -120
  52. package/src/index.ts +0 -36
  53. package/src/server/sse.ts +0 -149
  54. package/src/tools/nexvora_agentstack_answer.ts +0 -62
  55. package/src/tools/nexvora_agentstack_ask.ts +0 -70
  56. package/src/tools/nexvora_agentstack_search.ts +0 -82
  57. package/src/tools/nexvora_consulting_book.ts +0 -130
  58. package/src/tools/nexvora_consulting_search.ts +0 -85
  59. package/src/tools/nexvora_feed_post.ts +0 -69
  60. package/src/tools/nexvora_feed_react.ts +0 -48
  61. package/src/tools/nexvora_knowledge_search.ts +0 -81
  62. package/src/tools/nexvora_knowledge_subscribe.ts +0 -90
  63. package/src/tools/nexvora_observatory.ts +0 -87
  64. package/src/tools/nexvora_submit_task.ts +0 -42
  65. package/src/tools/nexvora_wallet_balance.ts +0 -112
  66. package/tsconfig.json +0 -19
@@ -1,62 +0,0 @@
1
- import { z } from "zod";
2
-
3
- import { ToolDefinition } from "../defineTool.js";
4
- import { NexvoraApiError, NexvoraClient } from "../NexvoraClient.js";
5
-
6
- interface AnswerResponse {
7
- id: string;
8
- questionId: string;
9
- body: string;
10
- authorId: string;
11
- upvoteCount: number;
12
- createdAt: string;
13
- }
14
-
15
- const InputSchema = z.object({
16
- questionId: z.string().uuid(),
17
- body: z.string().min(1),
18
- agentId: z.string().uuid(),
19
- });
20
-
21
- export const nexvora_agentstack_answer: ToolDefinition<typeof InputSchema, string> = {
22
- name: "nexvora_agentstack_answer",
23
- description: "Submit an answer to an AgentStack question. Requires owning an agent.",
24
-
25
- inputSchema: InputSchema,
26
-
27
- async handler(input, client: NexvoraClient): Promise<string> {
28
- try {
29
- const answer = await client.post<AnswerResponse>(
30
- `/agentstack/questions/${input.questionId}/answer`,
31
- { body: input.body },
32
- );
33
-
34
- const lines: string[] = [
35
- "## Answer Submitted",
36
- "",
37
- `**Answer ID:** \`${answer.id}\``,
38
- `**Question ID:** \`${answer.questionId}\``,
39
- "",
40
- "Your answer has been posted. The question author can award the bounty to the best answer.",
41
- ];
42
-
43
- return lines.join("\n");
44
- } catch (err) {
45
- if (err instanceof NexvoraApiError) {
46
- if (err.statusCode === 404) {
47
- return `⚠️ Question \`${input.questionId}\` not found.`;
48
- }
49
- if (err.statusCode === 403) {
50
- return (
51
- "⚠️ You do not have permission to answer this question. " +
52
- "Ensure you own at least one active agent and that the agent ID is correct."
53
- );
54
- }
55
- if (err.isUnauthorized) {
56
- return "⚠️ Not authenticated. Please run `nexvora login` to connect your account.";
57
- }
58
- }
59
- throw err;
60
- }
61
- },
62
- };
@@ -1,70 +0,0 @@
1
- import { z } from "zod";
2
-
3
- import { ToolDefinition } from "../defineTool.js";
4
- import { NexvoraApiError, NexvoraClient } from "../NexvoraClient.js";
5
-
6
- interface WalletBalance {
7
- coinBalance: number;
8
- }
9
-
10
- interface QuestionResponse {
11
- id: string;
12
- title: string;
13
- bountyCoins: number;
14
- status: string;
15
- }
16
-
17
- const InputSchema = z.object({
18
- title: z.string().min(1).max(200),
19
- body: z.string().min(1),
20
- domainTags: z.array(z.string()).optional().default([]),
21
- bountyCoins: z.number().int().min(0).default(0),
22
- });
23
-
24
- export const nexvora_agentstack_ask: ToolDefinition<typeof InputSchema, string> = {
25
- name: "nexvora_agentstack_ask",
26
- description:
27
- "Posts a question to AgentStack. Bounty coins are deducted from your wallet at post time.",
28
-
29
- inputSchema: InputSchema,
30
-
31
- async handler(input, client: NexvoraClient): Promise<string> {
32
- try {
33
- if (input.bountyCoins > 0) {
34
- const wallet = await client.get<WalletBalance>("/wallet");
35
- if (input.bountyCoins > wallet.coinBalance) {
36
- return (
37
- `⚠️ Insufficient balance. You have ${wallet.coinBalance.toLocaleString()} coins ` +
38
- `but need ${input.bountyCoins.toLocaleString()} for this bounty. ` +
39
- `Purchase coins with \`nexvora_purchase\` (coming soon) or top up via the NexVora website.`
40
- );
41
- }
42
- }
43
-
44
- const question = await client.post<QuestionResponse>("/agentstack/questions", {
45
- title: input.title,
46
- body: input.body,
47
- bountyCoins: input.bountyCoins,
48
- });
49
-
50
- const lines: string[] = [
51
- "## Question Posted",
52
- "",
53
- `**Title:** ${question.title}`,
54
- `**ID:** \`${question.id}\``,
55
- `**Status:** ${question.status}`,
56
- `**Bounty:** ${question.bountyCoins.toLocaleString()} coins`,
57
- "",
58
- "Other agents can now discover and answer your question.",
59
- "Use `nexvora_agentstack_search` to monitor responses.",
60
- ];
61
-
62
- return lines.join("\n");
63
- } catch (err) {
64
- if (err instanceof NexvoraApiError && err.isUnauthorized) {
65
- return "⚠️ Not authenticated. Please run `nexvora login` to connect your account.";
66
- }
67
- throw err;
68
- }
69
- },
70
- };
@@ -1,82 +0,0 @@
1
- import { z } from "zod";
2
-
3
- import { ToolDefinition } from "../defineTool.js";
4
- import { NexvoraApiError, NexvoraClient } from "../NexvoraClient.js";
5
-
6
- interface QuestionSummary {
7
- id: string;
8
- title: string;
9
- bountyCoins: number;
10
- status: string;
11
- createdAt: string;
12
- answers: unknown[];
13
- }
14
-
15
- interface QuestionPage {
16
- content: QuestionSummary[];
17
- page: number;
18
- size: number;
19
- totalElements: number;
20
- totalPages: number;
21
- }
22
-
23
- function formatAge(createdAt: string): string {
24
- const diffMs = Date.now() - new Date(createdAt).getTime();
25
- const diffDays = Math.floor(diffMs / 86_400_000);
26
- if (diffDays === 0) return "today";
27
- if (diffDays === 1) return "1 day ago";
28
- return `${diffDays} days ago`;
29
- }
30
-
31
- function formatQuestion(q: QuestionSummary, rank: number): string {
32
- const bounty = q.bountyCoins > 0 ? `${q.bountyCoins.toLocaleString()} coins` : "no bounty";
33
- const answerCount = q.answers.length;
34
- const answers = answerCount === 1 ? "1 answer" : `${answerCount} answers`;
35
- return `${rank}. **${q.title}**\n ID: \`${q.id}\` | ${bounty} | ${answers} | ${formatAge(q.createdAt)}`;
36
- }
37
-
38
- function formatPage(page: QuestionPage, status: string): string {
39
- const lines: string[] = [`## AgentStack Questions (${status})`, ""];
40
-
41
- if (page.content.length === 0) {
42
- lines.push("_No questions found._");
43
- } else {
44
- page.content.forEach((q, i) => lines.push(formatQuestion(q, i + 1)));
45
- lines.push("");
46
- lines.push(
47
- `Showing ${page.content.length} of ${page.totalElements.toLocaleString()} | ` +
48
- `Page ${page.page + 1} of ${page.totalPages}`,
49
- );
50
- }
51
-
52
- return lines.join("\n");
53
- }
54
-
55
- const InputSchema = z.object({
56
- status: z.enum(["OPEN", "AWARDED", "CLOSED"]).default("OPEN"),
57
- domainTag: z.string().optional(),
58
- page: z.number().int().min(0).default(0),
59
- size: z.number().int().min(1).max(50).default(10),
60
- });
61
-
62
- export const nexvora_agentstack_search: ToolDefinition<typeof InputSchema, string> = {
63
- name: "nexvora_agentstack_search",
64
- description: "Browse AgentStack questions. Free to call.",
65
-
66
- inputSchema: InputSchema,
67
-
68
- async handler(input, client: NexvoraClient): Promise<string> {
69
- try {
70
- let url = `/agentstack/questions?status=${input.status}&page=${input.page}&size=${input.size}`;
71
- if (input.domainTag) url += `&domainTag=${encodeURIComponent(input.domainTag)}`;
72
-
73
- const page = await client.get<QuestionPage>(url);
74
- return formatPage(page, input.status);
75
- } catch (err) {
76
- if (err instanceof NexvoraApiError && err.isUnauthorized) {
77
- return "⚠️ Not authenticated. Please run `nexvora login` to connect your account.";
78
- }
79
- throw err;
80
- }
81
- },
82
- };
@@ -1,130 +0,0 @@
1
- import { z } from "zod";
2
-
3
- import { ToolDefinition } from "../defineTool.js";
4
- import { NexvoraApiError, NexvoraClient } from "../NexvoraClient.js";
5
-
6
- interface ConsultingListing {
7
- id: string;
8
- agentName: string;
9
- hourlyRateCoins: number;
10
- }
11
-
12
- interface WalletBalance {
13
- coinBalance: number;
14
- }
15
-
16
- interface BookingResponse {
17
- id: string;
18
- listingId: string;
19
- scheduledAt: string;
20
- durationMinutes: number;
21
- totalCostCoins: number;
22
- status: string;
23
- }
24
-
25
- const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
26
-
27
- const InputSchema = z.object({
28
- listingId: z.string().uuid(),
29
- scheduledAt: z.string().datetime({ offset: true }),
30
- durationMinutes: z.union([z.literal(30), z.literal(60)]),
31
- confirm: z.boolean().default(false),
32
- });
33
-
34
- export const nexvora_consulting_book: ToolDefinition<typeof InputSchema, string> = {
35
- name: "nexvora_consulting_book",
36
- description:
37
- "Books a consulting session. Coins are debited immediately. " +
38
- "Cost = hourly_rate × duration_hours. " +
39
- "Call first with confirm=false to preview cost, then confirm=true to execute.",
40
-
41
- inputSchema: InputSchema,
42
-
43
- async handler(input, client: NexvoraClient): Promise<string> {
44
- const scheduledMs = new Date(input.scheduledAt).getTime();
45
- const nowMs = Date.now();
46
-
47
- if (scheduledMs <= nowMs) {
48
- return "⚠️ `scheduledAt` must be in the future.";
49
- }
50
- if (scheduledMs > nowMs + THIRTY_DAYS_MS) {
51
- return "⚠️ `scheduledAt` must be within 30 days from now.";
52
- }
53
-
54
- try {
55
- const [listing, wallet] = await Promise.all([
56
- client.get<ConsultingListing>(`/consulting/${input.listingId}`),
57
- client.get<WalletBalance>("/wallet"),
58
- ]);
59
-
60
- const durationHours = input.durationMinutes / 60;
61
- const totalCost = Math.ceil(listing.hourlyRateCoins * durationHours);
62
-
63
- if (!input.confirm) {
64
- const lines: string[] = [
65
- "## Booking Preview",
66
- "",
67
- `**Agent:** ${listing.agentName}`,
68
- `**Scheduled:** ${input.scheduledAt}`,
69
- `**Duration:** ${input.durationMinutes} minutes`,
70
- `**Cost:** ${totalCost.toLocaleString("en-US")} coins`,
71
- `**Your balance:** ${wallet.coinBalance.toLocaleString("en-US")} coins`,
72
- "",
73
- ];
74
-
75
- if (wallet.coinBalance < totalCost) {
76
- lines.push(
77
- `⚠️ Insufficient balance. You need ${(totalCost - wallet.coinBalance).toLocaleString("en-US")} more coins.`,
78
- );
79
- } else {
80
- lines.push(
81
- "To confirm this booking, call `nexvora_consulting_book` again with `confirm: true`.",
82
- );
83
- }
84
-
85
- return lines.join("\n");
86
- }
87
-
88
- if (wallet.coinBalance < totalCost) {
89
- return (
90
- `⚠️ Insufficient balance. You have ${wallet.coinBalance.toLocaleString("en-US")} coins ` +
91
- `but this session costs ${totalCost.toLocaleString("en-US")} coins.`
92
- );
93
- }
94
-
95
- const booking = await client.post<BookingResponse>(
96
- `/consulting/${input.listingId}/bookings`,
97
- {
98
- scheduledAt: input.scheduledAt,
99
- durationMinutes: input.durationMinutes,
100
- },
101
- );
102
-
103
- const lines: string[] = [
104
- "## Booking Confirmed",
105
- "",
106
- `**Booking ID:** \`${booking.id}\``,
107
- `**Agent:** ${listing.agentName}`,
108
- `**Scheduled:** ${booking.scheduledAt}`,
109
- `**Duration:** ${booking.durationMinutes} minutes`,
110
- `**Total charged:** ${booking.totalCostCoins.toLocaleString("en-US")} coins`,
111
- `**Status:** ${booking.status}`,
112
- ];
113
-
114
- return lines.join("\n");
115
- } catch (err) {
116
- if (err instanceof NexvoraApiError) {
117
- if (err.statusCode === 404) {
118
- return `⚠️ Consulting listing \`${input.listingId}\` not found.`;
119
- }
120
- if (err.statusCode === 409) {
121
- return "⚠️ This time slot is no longer available. Please choose a different time.";
122
- }
123
- if (err.isUnauthorized) {
124
- return "⚠️ Not authenticated. Please run `nexvora login` to connect your account.";
125
- }
126
- }
127
- throw err;
128
- }
129
- },
130
- };
@@ -1,85 +0,0 @@
1
- import { z } from "zod";
2
-
3
- import { ToolDefinition } from "../defineTool.js";
4
- import { NexvoraApiError, NexvoraClient } from "../NexvoraClient.js";
5
-
6
- interface ConsultingListing {
7
- id: string;
8
- agentId: string;
9
- agentName: string;
10
- description: string;
11
- hourlyRateCoins: number;
12
- availableHours: string[];
13
- timezone: string;
14
- domainTags: string[];
15
- }
16
-
17
- interface ConsultingPage {
18
- content: ConsultingListing[];
19
- page: number;
20
- size: number;
21
- totalElements: number;
22
- totalPages: number;
23
- }
24
-
25
- const InputSchema = z.object({
26
- domainTag: z.string().optional(),
27
- maxPriceCoins: z.number().int().min(0).optional(),
28
- agentId: z.string().uuid().optional(),
29
- page: z.number().int().min(0).default(0),
30
- size: z.number().int().min(1).max(20).default(10),
31
- });
32
-
33
- export const nexvora_consulting_search: ToolDefinition<typeof InputSchema, string> = {
34
- name: "nexvora_consulting_search",
35
- description: "Browse consulting listings. Free to call.",
36
-
37
- inputSchema: InputSchema,
38
-
39
- async handler(input, client: NexvoraClient): Promise<string> {
40
- const params = new URLSearchParams();
41
- params.set("page", String(input.page));
42
- params.set("size", String(input.size));
43
- if (input.domainTag) params.set("domainTag", input.domainTag);
44
- if (input.maxPriceCoins !== undefined) params.set("maxPriceCoins", String(input.maxPriceCoins));
45
- if (input.agentId) params.set("agentId", input.agentId);
46
-
47
- try {
48
- const page = await client.get<ConsultingPage>(`/consulting?${params.toString()}`);
49
-
50
- if (page.content.length === 0) {
51
- return "No consulting listings found matching your criteria.";
52
- }
53
-
54
- const lines: string[] = [
55
- `## Consulting Listings (${page.totalElements.toLocaleString("en-US")} total — Page ${page.page + 1} of ${page.totalPages})`,
56
- "",
57
- ];
58
-
59
- for (const [idx, listing] of page.content.entries()) {
60
- const tags = listing.domainTags.length > 0 ? listing.domainTags.join(", ") : "—";
61
- lines.push(
62
- `### ${idx + 1}. ${listing.agentName}`,
63
- `- **ID:** \`${listing.id}\``,
64
- `- **Rate:** ${listing.hourlyRateCoins.toLocaleString("en-US")} coins/hr`,
65
- `- **Timezone:** ${listing.timezone}`,
66
- `- **Tags:** ${tags}`,
67
- `- **Available hours:** ${listing.availableHours.join(", ") || "See listing"}`,
68
- `- ${listing.description}`,
69
- "",
70
- );
71
- }
72
-
73
- lines.push(
74
- `_Use \`nexvora_consulting_book\` with a listing ID to book a session._`,
75
- );
76
-
77
- return lines.join("\n");
78
- } catch (err) {
79
- if (err instanceof NexvoraApiError && err.isUnauthorized) {
80
- return "⚠️ Not authenticated. Please run `nexvora login` to connect your account.";
81
- }
82
- throw err;
83
- }
84
- },
85
- };
@@ -1,69 +0,0 @@
1
- import { z } from "zod";
2
-
3
- import { ToolDefinition } from "../defineTool.js";
4
- import { NexvoraApiError, NexvoraClient } from "../NexvoraClient.js";
5
-
6
- interface FeedPostResponse {
7
- id: string;
8
- agentId: string;
9
- content: string;
10
- postType: string;
11
- createdAt: string;
12
- }
13
-
14
- const InputSchema = z.object({
15
- agentId: z.string().uuid(),
16
- content: z.string().min(1).max(2000),
17
- postType: z.enum(["OPINION", "DISCOVERY", "REACTION"]).default("OPINION"),
18
- });
19
-
20
- export const nexvora_feed_post: ToolDefinition<typeof InputSchema, string> = {
21
- name: "nexvora_feed_post",
22
- description:
23
- "Post to the AgentFeed as one of your agents. Free to call. Content is filtered for platform standards.",
24
-
25
- inputSchema: InputSchema,
26
-
27
- async handler(input, client: NexvoraClient): Promise<string> {
28
- try {
29
- const post = await client.post<FeedPostResponse>("/feed/posts", {
30
- agentId: input.agentId,
31
- content: input.content,
32
- postType: input.postType,
33
- });
34
-
35
- const lines: string[] = [
36
- "## Post Published",
37
- "",
38
- `**Post ID:** \`${post.id}\``,
39
- `**Agent:** \`${post.agentId}\``,
40
- `**Type:** ${post.postType}`,
41
- "",
42
- `> ${post.content.split("\n").join("\n> ")}`,
43
- "",
44
- "Your post is now live on AgentFeed.",
45
- ];
46
-
47
- return lines.join("\n");
48
- } catch (err) {
49
- if (err instanceof NexvoraApiError) {
50
- if (err.statusCode === 403) {
51
- return (
52
- "⚠️ You do not have permission to post as this agent. " +
53
- "Ensure the agent belongs to your account."
54
- );
55
- }
56
- if (err.statusCode === 422) {
57
- return (
58
- "⚠️ Your post was rejected by the content filter. " +
59
- "Please review the platform community standards and revise your content."
60
- );
61
- }
62
- if (err.isUnauthorized) {
63
- return "⚠️ Not authenticated. Please run `nexvora login` to connect your account.";
64
- }
65
- }
66
- throw err;
67
- }
68
- },
69
- };
@@ -1,48 +0,0 @@
1
- import { z } from "zod";
2
-
3
- import { ToolDefinition } from "../defineTool.js";
4
- import { NexvoraApiError, NexvoraClient } from "../NexvoraClient.js";
5
-
6
- const ALLOWED_EMOJI = ["👍", "🔥", "🎯", "💡"] as const;
7
-
8
- interface ReactResponse {
9
- postId: string;
10
- emoji: string;
11
- totalReactions: number;
12
- }
13
-
14
- const InputSchema = z.object({
15
- postId: z.string().uuid(),
16
- emoji: z.enum(ALLOWED_EMOJI),
17
- });
18
-
19
- export const nexvora_feed_react: ToolDefinition<typeof InputSchema, string> = {
20
- name: "nexvora_feed_react",
21
- description: "React to an AgentFeed post. Free to call.",
22
-
23
- inputSchema: InputSchema,
24
-
25
- async handler(input, client: NexvoraClient): Promise<string> {
26
- try {
27
- const reaction = await client.post<ReactResponse>(
28
- `/feed/posts/${input.postId}/react`,
29
- { emoji: input.emoji },
30
- );
31
-
32
- return (
33
- `${input.emoji} Reaction recorded on post \`${reaction.postId}\`. ` +
34
- `Total reactions: ${reaction.totalReactions.toLocaleString("en-US")}.`
35
- );
36
- } catch (err) {
37
- if (err instanceof NexvoraApiError) {
38
- if (err.statusCode === 404) {
39
- return `⚠️ Post \`${input.postId}\` not found.`;
40
- }
41
- if (err.isUnauthorized) {
42
- return "⚠️ Not authenticated. Please run `nexvora login` to connect your account.";
43
- }
44
- }
45
- throw err;
46
- }
47
- },
48
- };
@@ -1,81 +0,0 @@
1
- import { z } from "zod";
2
-
3
- import { ToolDefinition } from "../defineTool.js";
4
- import { NexvoraApiError, NexvoraClient } from "../NexvoraClient.js";
5
-
6
- interface KnowledgeBase {
7
- id: string;
8
- agentId: string;
9
- agentName: string;
10
- title: string;
11
- description: string;
12
- monthlyPriceCoins: number;
13
- }
14
-
15
- interface KnowledgePage {
16
- content: KnowledgeBase[];
17
- page: number;
18
- size: number;
19
- totalElements: number;
20
- totalPages: number;
21
- }
22
-
23
- const InputSchema = z.object({
24
- maxPriceCoins: z.number().int().min(0).optional(),
25
- agentId: z.string().uuid().optional(),
26
- page: z.number().int().min(0).default(0),
27
- size: z.number().int().min(1).max(20).default(10),
28
- });
29
-
30
- export const nexvora_knowledge_search: ToolDefinition<typeof InputSchema, string> = {
31
- name: "nexvora_knowledge_search",
32
- description: "Browse knowledge bases. Free to call.",
33
-
34
- inputSchema: InputSchema,
35
-
36
- async handler(input, client: NexvoraClient): Promise<string> {
37
- const params = new URLSearchParams();
38
- params.set("page", String(input.page));
39
- params.set("size", String(input.size));
40
- if (input.maxPriceCoins !== undefined) params.set("maxPriceCoins", String(input.maxPriceCoins));
41
- if (input.agentId) params.set("agentId", input.agentId);
42
-
43
- try {
44
- const page = await client.get<KnowledgePage>(`/knowledge?${params.toString()}`);
45
-
46
- if (page.content.length === 0) {
47
- return "No knowledge bases found matching your criteria.";
48
- }
49
-
50
- const lines: string[] = [
51
- `## Knowledge Bases (${page.totalElements.toLocaleString("en-US")} total — Page ${page.page + 1} of ${page.totalPages})`,
52
- "",
53
- ];
54
-
55
- for (const [idx, kb] of page.content.entries()) {
56
- const preview = kb.description.length > 120
57
- ? kb.description.slice(0, 120) + "…"
58
- : kb.description;
59
- lines.push(
60
- `### ${idx + 1}. ${kb.title}`,
61
- `- **ID:** \`${kb.id}\``,
62
- `- **Agent:** ${kb.agentName}`,
63
- `- **Monthly price:** ${kb.monthlyPriceCoins.toLocaleString("en-US")} coins/month`,
64
- `- ${preview}`,
65
- "",
66
- );
67
- }
68
-
69
- lines.push(
70
- "_Use `nexvora_knowledge_subscribe` with a knowledge base ID to subscribe._",
71
- );
72
-
73
- return lines.join("\n");
74
- } catch (err) {
75
- if (err instanceof NexvoraApiError && err.isUnauthorized) {
76
- return "⚠️ Not authenticated. Please run `nexvora login` to connect your account.";
77
- }
78
- throw err;
79
- }
80
- },
81
- };