@juspay/neurolink 9.13.0 → 9.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +15 -15
- package/dist/auth/anthropicOAuth.d.ts +377 -0
- package/dist/auth/anthropicOAuth.js +914 -0
- package/dist/auth/index.d.ts +20 -0
- package/dist/auth/index.js +29 -0
- package/dist/auth/tokenStore.d.ts +225 -0
- package/dist/auth/tokenStore.js +521 -0
- package/dist/cli/commands/auth.d.ts +50 -0
- package/dist/cli/commands/auth.js +1115 -0
- package/dist/cli/commands/docs.d.ts +10 -0
- package/dist/cli/commands/docs.js +48 -0
- package/dist/cli/factories/authCommandFactory.d.ts +52 -0
- package/dist/cli/factories/authCommandFactory.js +146 -0
- package/dist/cli/factories/commandFactory.d.ts +6 -0
- package/dist/cli/factories/commandFactory.js +92 -2
- package/dist/cli/parser.js +14 -2
- package/dist/constants/enums.d.ts +20 -0
- package/dist/constants/enums.js +30 -0
- package/dist/constants/index.d.ts +3 -1
- package/dist/constants/index.js +11 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/lib/auth/anthropicOAuth.d.ts +377 -0
- package/dist/lib/auth/anthropicOAuth.js +915 -0
- package/dist/lib/auth/index.d.ts +20 -0
- package/dist/lib/auth/index.js +30 -0
- package/dist/lib/auth/tokenStore.d.ts +225 -0
- package/dist/lib/auth/tokenStore.js +522 -0
- package/dist/lib/constants/enums.d.ts +20 -0
- package/dist/lib/constants/enums.js +30 -0
- package/dist/lib/constants/index.d.ts +3 -1
- package/dist/lib/constants/index.js +11 -1
- package/dist/lib/index.d.ts +4 -4
- package/dist/lib/index.js +3 -3
- package/dist/lib/models/anthropicModels.d.ts +267 -0
- package/dist/lib/models/anthropicModels.js +528 -0
- package/dist/lib/neurolink.d.ts +2 -2
- package/dist/lib/neurolink.js +2 -2
- package/dist/lib/providers/anthropic.d.ts +123 -2
- package/dist/lib/providers/anthropic.js +800 -10
- package/dist/lib/types/errors.d.ts +62 -0
- package/dist/lib/types/errors.js +107 -0
- package/dist/lib/types/index.d.ts +2 -1
- package/dist/lib/types/index.js +2 -0
- package/dist/lib/types/providers.d.ts +107 -0
- package/dist/lib/types/providers.js +69 -0
- package/dist/lib/types/subscriptionTypes.d.ts +893 -0
- package/dist/lib/types/subscriptionTypes.js +8 -0
- package/dist/lib/utils/providerConfig.d.ts +167 -0
- package/dist/lib/utils/providerConfig.js +619 -9
- package/dist/models/anthropicModels.d.ts +267 -0
- package/dist/models/anthropicModels.js +527 -0
- package/dist/neurolink.d.ts +2 -2
- package/dist/neurolink.js +2 -2
- package/dist/providers/anthropic.d.ts +123 -2
- package/dist/providers/anthropic.js +800 -10
- package/dist/types/errors.d.ts +62 -0
- package/dist/types/errors.js +107 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.js +2 -0
- package/dist/types/providers.d.ts +107 -0
- package/dist/types/providers.js +69 -0
- package/dist/types/subscriptionTypes.d.ts +893 -0
- package/dist/types/subscriptionTypes.js +7 -0
- package/dist/utils/providerConfig.d.ts +167 -0
- package/dist/utils/providerConfig.js +619 -9
- package/docs-site/mcp-server/index.d.ts +4 -0
- package/docs-site/mcp-server/index.js +165 -0
- package/docs-site/mcp-server/search.d.ts +13 -0
- package/docs-site/mcp-server/search.js +81 -0
- package/docs-site/mcp-server/tools.d.ts +96 -0
- package/docs-site/mcp-server/tools.js +342 -0
- package/docs-site/mcp-server/types.d.ts +32 -0
- package/docs-site/mcp-server/types.js +2 -0
- package/package.json +7 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { DocsSearch } from "./search.js";
|
|
5
|
+
import { createToolDefinitions } from "./tools.js";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
|
|
12
|
+
function resolveIndexPath() {
|
|
13
|
+
const localPath = path.resolve(__dirname, "../static/search-index.json");
|
|
14
|
+
if (fs.existsSync(localPath)) return localPath;
|
|
15
|
+
|
|
16
|
+
const pkgPath = path.resolve(
|
|
17
|
+
__dirname,
|
|
18
|
+
"../../docs-site/static/search-index.json",
|
|
19
|
+
);
|
|
20
|
+
if (fs.existsSync(pkgPath)) return pkgPath;
|
|
21
|
+
|
|
22
|
+
throw new Error(
|
|
23
|
+
"search-index.json not found. Run docs-site build first: cd docs-site && pnpm build",
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function initSearch() {
|
|
28
|
+
const indexPath = resolveIndexPath();
|
|
29
|
+
const raw = fs.readFileSync(indexPath, "utf-8");
|
|
30
|
+
const indexData = JSON.parse(raw);
|
|
31
|
+
|
|
32
|
+
const search = new DocsSearch();
|
|
33
|
+
search.loadIndex(indexData);
|
|
34
|
+
|
|
35
|
+
return search;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function createServer(search) {
|
|
39
|
+
const server = new McpServer({
|
|
40
|
+
name: "neurolink-docs",
|
|
41
|
+
version: "1.0.0",
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const tools = createToolDefinitions(search);
|
|
45
|
+
|
|
46
|
+
for (const tool of Object.values(tools)) {
|
|
47
|
+
server.tool(
|
|
48
|
+
tool.name,
|
|
49
|
+
tool.description,
|
|
50
|
+
tool.paramsSchema,
|
|
51
|
+
async (args) => {
|
|
52
|
+
return tool.handler(args);
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return server;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function startStdio(server) {
|
|
61
|
+
const transport = new StdioServerTransport();
|
|
62
|
+
await server.connect(transport);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function startHttp(server, port) {
|
|
66
|
+
const { StreamableHTTPServerTransport } = await import(
|
|
67
|
+
"@modelcontextprotocol/sdk/server/streamableHttp.js"
|
|
68
|
+
);
|
|
69
|
+
const http = await import("http");
|
|
70
|
+
|
|
71
|
+
const transport = new StreamableHTTPServerTransport({
|
|
72
|
+
sessionIdGenerator: () => randomUUID(),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await server.connect(transport);
|
|
76
|
+
|
|
77
|
+
const httpServer = http.createServer(async (req, res) => {
|
|
78
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
79
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
80
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
81
|
+
|
|
82
|
+
if (req.method === "OPTIONS") {
|
|
83
|
+
res.writeHead(204);
|
|
84
|
+
res.end();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (req.url === "/mcp" && req.method === "POST") {
|
|
89
|
+
try {
|
|
90
|
+
await transport.handleRequest(req, res);
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.error("MCP transport error:", err);
|
|
93
|
+
if (!res.headersSent) {
|
|
94
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
95
|
+
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} else if (req.url === "/health") {
|
|
99
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
100
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
101
|
+
} else {
|
|
102
|
+
res.writeHead(404);
|
|
103
|
+
res.end("Not Found");
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const host = process.env.BIND_HOST || "127.0.0.1";
|
|
108
|
+
await new Promise((resolve, reject) => {
|
|
109
|
+
httpServer.once("error", reject);
|
|
110
|
+
httpServer.listen(port, host, () => {
|
|
111
|
+
httpServer.removeListener("error", reject);
|
|
112
|
+
console.error(
|
|
113
|
+
`NeuroLink MCP Docs Server listening on http://${host}:${port}/mcp`,
|
|
114
|
+
);
|
|
115
|
+
console.error(`Health check: http://${host}:${port}/health`);
|
|
116
|
+
resolve();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function startDocsServer(args) {
|
|
122
|
+
const search = initSearch();
|
|
123
|
+
const server = createServer(search);
|
|
124
|
+
const transport = args.transport || "stdio";
|
|
125
|
+
const port = args.port || 3001;
|
|
126
|
+
|
|
127
|
+
console.error(
|
|
128
|
+
`NeuroLink MCP Docs Server — ${search.documentCount} docs indexed`,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (transport === "http") {
|
|
132
|
+
await startHttp(server, port);
|
|
133
|
+
} else {
|
|
134
|
+
await startStdio(server);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const isDirectExecution =
|
|
139
|
+
typeof process !== "undefined" &&
|
|
140
|
+
process.argv[1] &&
|
|
141
|
+
fileURLToPath(import.meta.url) === process.argv[1];
|
|
142
|
+
|
|
143
|
+
if (isDirectExecution) {
|
|
144
|
+
const args = process.argv.slice(2);
|
|
145
|
+
const transportFlag = args.includes("--transport")
|
|
146
|
+
? args[args.indexOf("--transport") + 1]
|
|
147
|
+
: "stdio";
|
|
148
|
+
if (transportFlag !== "stdio" && transportFlag !== "http") {
|
|
149
|
+
console.error(
|
|
150
|
+
`Invalid transport "${transportFlag}". Must be "stdio" or "http".`,
|
|
151
|
+
);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
const portRaw = args.includes("--port")
|
|
155
|
+
? parseInt(args[args.indexOf("--port") + 1], 10)
|
|
156
|
+
: 3001;
|
|
157
|
+
const portFlag =
|
|
158
|
+
Number.isNaN(portRaw) || portRaw < 1 || portRaw > 65535 ? 3001 : portRaw;
|
|
159
|
+
|
|
160
|
+
startDocsServer({ transport: transportFlag, port: portFlag }).catch((err) => {
|
|
161
|
+
console.error("Failed to start MCP docs server:", err);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IndexDocument, SearchIndex, SearchResult, SectionInfo } from "./types.js";
|
|
2
|
+
export declare class DocsSearch {
|
|
3
|
+
private miniSearch;
|
|
4
|
+
private documents;
|
|
5
|
+
private sections;
|
|
6
|
+
constructor();
|
|
7
|
+
loadIndex(indexData: SearchIndex): void;
|
|
8
|
+
search(query: string, limit?: number, section?: string): SearchResult[];
|
|
9
|
+
getPage(docPath: string): IndexDocument | undefined;
|
|
10
|
+
listSections(): SectionInfo[];
|
|
11
|
+
getBySection(section: string): IndexDocument[];
|
|
12
|
+
get documentCount(): number;
|
|
13
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import MiniSearch from "minisearch";
|
|
2
|
+
|
|
3
|
+
const MINISEARCH_CONFIG = {
|
|
4
|
+
fields: ["title", "description", "content", "tags"],
|
|
5
|
+
storeFields: ["title", "description", "section", "path"],
|
|
6
|
+
searchOptions: {
|
|
7
|
+
boost: { title: 3, description: 2, tags: 1.5 },
|
|
8
|
+
fuzzy: 0.2,
|
|
9
|
+
prefix: true,
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export class DocsSearch {
|
|
14
|
+
miniSearch;
|
|
15
|
+
documents = new Map();
|
|
16
|
+
sections = new Map();
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
this.miniSearch = new MiniSearch(MINISEARCH_CONFIG);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
loadIndex(indexData) {
|
|
23
|
+
this.documents.clear();
|
|
24
|
+
this.sections.clear();
|
|
25
|
+
this.miniSearch = new MiniSearch(MINISEARCH_CONFIG);
|
|
26
|
+
for (const doc of indexData.documents) {
|
|
27
|
+
this.documents.set(doc.id, doc);
|
|
28
|
+
}
|
|
29
|
+
for (const doc of this.documents.values()) {
|
|
30
|
+
const sectionDocs = this.sections.get(doc.section) || [];
|
|
31
|
+
sectionDocs.push(doc);
|
|
32
|
+
this.sections.set(doc.section, sectionDocs);
|
|
33
|
+
}
|
|
34
|
+
this.miniSearch.addAll(Array.from(this.documents.values()));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
search(query, limit = 10, section) {
|
|
38
|
+
const options = section
|
|
39
|
+
? {
|
|
40
|
+
filter: (result) => result["section"] === section,
|
|
41
|
+
}
|
|
42
|
+
: undefined;
|
|
43
|
+
const results = this.miniSearch.search(query, options);
|
|
44
|
+
return results.slice(0, limit).map((r) => ({
|
|
45
|
+
id: String(r.id),
|
|
46
|
+
title: String(r["title"] ?? ""),
|
|
47
|
+
description: String(r["description"] ?? ""),
|
|
48
|
+
section: String(r["section"] ?? ""),
|
|
49
|
+
path: String(r["path"] ?? ""),
|
|
50
|
+
score: r.score,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
getPage(docPath) {
|
|
55
|
+
return (
|
|
56
|
+
this.documents.get(docPath) ||
|
|
57
|
+
this.documents.get(docPath.replace(/^\//, ""))
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
listSections() {
|
|
62
|
+
const result = [];
|
|
63
|
+
for (const [name, docs] of this.sections) {
|
|
64
|
+
result.push({
|
|
65
|
+
name,
|
|
66
|
+
pageCount: docs.length,
|
|
67
|
+
pages: docs.map((d) => ({ title: d.title, path: d.path })),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return result.sort((a, b) => a.name.localeCompare(b.name));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getBySection(section) {
|
|
74
|
+
return this.sections.get(section) || [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get documentCount() {
|
|
78
|
+
return this.documents.size;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { DocsSearch } from "./search.js";
|
|
3
|
+
export declare function createToolDefinitions(search: DocsSearch): {
|
|
4
|
+
search_docs: {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
paramsSchema: {
|
|
8
|
+
query: z.ZodString;
|
|
9
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
section: z.ZodOptional<z.ZodString>;
|
|
11
|
+
};
|
|
12
|
+
handler: (args: {
|
|
13
|
+
query: string;
|
|
14
|
+
limit?: number;
|
|
15
|
+
section?: string;
|
|
16
|
+
}) => {
|
|
17
|
+
content: {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}[];
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
get_page: {
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
paramsSchema: {
|
|
27
|
+
path: z.ZodString;
|
|
28
|
+
};
|
|
29
|
+
handler: (args: {
|
|
30
|
+
path: string;
|
|
31
|
+
}) => {
|
|
32
|
+
content: {
|
|
33
|
+
type: "text";
|
|
34
|
+
text: string;
|
|
35
|
+
}[];
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
list_sections: {
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
paramsSchema: {};
|
|
42
|
+
handler: () => {
|
|
43
|
+
content: {
|
|
44
|
+
type: "text";
|
|
45
|
+
text: string;
|
|
46
|
+
}[];
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
get_api_reference: {
|
|
50
|
+
name: string;
|
|
51
|
+
description: string;
|
|
52
|
+
paramsSchema: {
|
|
53
|
+
method: z.ZodOptional<z.ZodString>;
|
|
54
|
+
};
|
|
55
|
+
handler: (args: {
|
|
56
|
+
method?: string;
|
|
57
|
+
}) => {
|
|
58
|
+
content: {
|
|
59
|
+
type: "text";
|
|
60
|
+
text: string;
|
|
61
|
+
}[];
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
get_examples: {
|
|
65
|
+
name: string;
|
|
66
|
+
description: string;
|
|
67
|
+
paramsSchema: {
|
|
68
|
+
topic: z.ZodOptional<z.ZodString>;
|
|
69
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
70
|
+
};
|
|
71
|
+
handler: (args: {
|
|
72
|
+
topic?: string;
|
|
73
|
+
provider?: string;
|
|
74
|
+
}) => {
|
|
75
|
+
content: {
|
|
76
|
+
type: "text";
|
|
77
|
+
text: string;
|
|
78
|
+
}[];
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
get_changelog: {
|
|
82
|
+
name: string;
|
|
83
|
+
description: string;
|
|
84
|
+
paramsSchema: {
|
|
85
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
86
|
+
};
|
|
87
|
+
handler: (args: {
|
|
88
|
+
limit?: number;
|
|
89
|
+
}) => {
|
|
90
|
+
content: {
|
|
91
|
+
type: "text";
|
|
92
|
+
text: string;
|
|
93
|
+
}[];
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
};
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export function createToolDefinitions(search) {
|
|
4
|
+
return {
|
|
5
|
+
search_docs: {
|
|
6
|
+
name: "search_docs",
|
|
7
|
+
description:
|
|
8
|
+
"Full-text search across all NeuroLink documentation. Returns ranked results with title, description, section, and path.",
|
|
9
|
+
paramsSchema: {
|
|
10
|
+
query: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe(
|
|
13
|
+
"Search query (e.g. 'RAG pipeline', 'MCP configuration', 'streaming')",
|
|
14
|
+
),
|
|
15
|
+
limit: z
|
|
16
|
+
.number()
|
|
17
|
+
.int()
|
|
18
|
+
.min(1)
|
|
19
|
+
.max(50)
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("Max results to return (default: 10, max: 50)"),
|
|
22
|
+
section: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe(
|
|
26
|
+
"Filter by section (e.g. 'features', 'sdk', 'cli', 'mcp', 'rag', 'examples')",
|
|
27
|
+
),
|
|
28
|
+
},
|
|
29
|
+
handler: (args) => {
|
|
30
|
+
const limit = Math.max(1, Math.min(args.limit || 10, 50));
|
|
31
|
+
const results = search.search(args.query, limit, args.section);
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: JSON.stringify(
|
|
37
|
+
{
|
|
38
|
+
query: args.query,
|
|
39
|
+
resultCount: results.length,
|
|
40
|
+
results: results.map((r) => ({
|
|
41
|
+
title: r.title,
|
|
42
|
+
description: r.description,
|
|
43
|
+
section: r.section,
|
|
44
|
+
path: r.path,
|
|
45
|
+
url: `https://docs.neurolink.ink/docs/${r.path}`,
|
|
46
|
+
score: Math.round(r.score * 100) / 100,
|
|
47
|
+
})),
|
|
48
|
+
},
|
|
49
|
+
null,
|
|
50
|
+
2,
|
|
51
|
+
),
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
get_page: {
|
|
59
|
+
name: "get_page",
|
|
60
|
+
description:
|
|
61
|
+
"Get the full content of a specific documentation page by its path.",
|
|
62
|
+
paramsSchema: {
|
|
63
|
+
path: z
|
|
64
|
+
.string()
|
|
65
|
+
.describe(
|
|
66
|
+
"Document path (e.g. 'getting-started/installation', 'features/multimodal')",
|
|
67
|
+
),
|
|
68
|
+
},
|
|
69
|
+
handler: (args) => {
|
|
70
|
+
const doc = search.getPage(args.path);
|
|
71
|
+
if (!doc) {
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: "text",
|
|
76
|
+
text: JSON.stringify({
|
|
77
|
+
error: "Page not found",
|
|
78
|
+
path: args.path,
|
|
79
|
+
hint: "Use search_docs or list_sections to find valid paths",
|
|
80
|
+
}),
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: JSON.stringify(
|
|
90
|
+
{
|
|
91
|
+
title: doc.title,
|
|
92
|
+
description: doc.description,
|
|
93
|
+
section: doc.section,
|
|
94
|
+
path: doc.path,
|
|
95
|
+
url: `https://docs.neurolink.ink/docs/${doc.path}`,
|
|
96
|
+
content: doc.content,
|
|
97
|
+
},
|
|
98
|
+
null,
|
|
99
|
+
2,
|
|
100
|
+
),
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
list_sections: {
|
|
108
|
+
name: "list_sections",
|
|
109
|
+
description: "List all documentation sections and their pages.",
|
|
110
|
+
paramsSchema: {},
|
|
111
|
+
handler: () => {
|
|
112
|
+
const sections = search.listSections();
|
|
113
|
+
return {
|
|
114
|
+
content: [
|
|
115
|
+
{
|
|
116
|
+
type: "text",
|
|
117
|
+
text: JSON.stringify(
|
|
118
|
+
{
|
|
119
|
+
totalSections: sections.length,
|
|
120
|
+
totalPages: sections.reduce((sum, s) => sum + s.pageCount, 0),
|
|
121
|
+
sections: sections.map((s) => ({
|
|
122
|
+
name: s.name,
|
|
123
|
+
pageCount: s.pageCount,
|
|
124
|
+
pages: s.pages.map((p) => ({
|
|
125
|
+
title: p.title,
|
|
126
|
+
path: p.path,
|
|
127
|
+
})),
|
|
128
|
+
})),
|
|
129
|
+
},
|
|
130
|
+
null,
|
|
131
|
+
2,
|
|
132
|
+
),
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
get_api_reference: {
|
|
140
|
+
name: "get_api_reference",
|
|
141
|
+
description:
|
|
142
|
+
"Get SDK API reference documentation. Optionally filter by method name.",
|
|
143
|
+
paramsSchema: {
|
|
144
|
+
method: z
|
|
145
|
+
.string()
|
|
146
|
+
.optional()
|
|
147
|
+
.describe(
|
|
148
|
+
"Filter by method name (e.g. 'generate', 'stream'). Omit for full reference.",
|
|
149
|
+
),
|
|
150
|
+
},
|
|
151
|
+
handler: (args) => {
|
|
152
|
+
if (args.method) {
|
|
153
|
+
const results = search.search(args.method, 5, "sdk");
|
|
154
|
+
return {
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: "text",
|
|
158
|
+
text: JSON.stringify(
|
|
159
|
+
{
|
|
160
|
+
query: args.method,
|
|
161
|
+
results: results.map((r) => ({
|
|
162
|
+
title: r.title,
|
|
163
|
+
path: r.path,
|
|
164
|
+
url: `https://docs.neurolink.ink/docs/${r.path}`,
|
|
165
|
+
})),
|
|
166
|
+
},
|
|
167
|
+
null,
|
|
168
|
+
2,
|
|
169
|
+
),
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const sdkDocs = search.getBySection("sdk");
|
|
175
|
+
return {
|
|
176
|
+
content: [
|
|
177
|
+
{
|
|
178
|
+
type: "text",
|
|
179
|
+
text: JSON.stringify(
|
|
180
|
+
{
|
|
181
|
+
section: "sdk",
|
|
182
|
+
pageCount: sdkDocs.length,
|
|
183
|
+
pages: sdkDocs.map((d) => ({
|
|
184
|
+
title: d.title,
|
|
185
|
+
description: d.description,
|
|
186
|
+
path: d.path,
|
|
187
|
+
url: `https://docs.neurolink.ink/docs/${d.path}`,
|
|
188
|
+
})),
|
|
189
|
+
},
|
|
190
|
+
null,
|
|
191
|
+
2,
|
|
192
|
+
),
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
get_examples: {
|
|
200
|
+
name: "get_examples",
|
|
201
|
+
description:
|
|
202
|
+
"Get code examples from the documentation. Optionally filter by topic or provider.",
|
|
203
|
+
paramsSchema: {
|
|
204
|
+
topic: z
|
|
205
|
+
.string()
|
|
206
|
+
.optional()
|
|
207
|
+
.describe(
|
|
208
|
+
"Filter by topic (e.g. 'rag', 'streaming', 'agents', 'mcp')",
|
|
209
|
+
),
|
|
210
|
+
provider: z
|
|
211
|
+
.string()
|
|
212
|
+
.optional()
|
|
213
|
+
.describe(
|
|
214
|
+
"Filter by provider (e.g. 'openai', 'anthropic', 'google')",
|
|
215
|
+
),
|
|
216
|
+
},
|
|
217
|
+
handler: (args) => {
|
|
218
|
+
const query = [args.topic, args.provider].filter(Boolean).join(" ");
|
|
219
|
+
if (!query) {
|
|
220
|
+
const exampleDocs = [
|
|
221
|
+
...search.getBySection("examples"),
|
|
222
|
+
...search.getBySection("cookbook"),
|
|
223
|
+
...search.getBySection("demos"),
|
|
224
|
+
];
|
|
225
|
+
return {
|
|
226
|
+
content: [
|
|
227
|
+
{
|
|
228
|
+
type: "text",
|
|
229
|
+
text: JSON.stringify(
|
|
230
|
+
{
|
|
231
|
+
pageCount: exampleDocs.length,
|
|
232
|
+
pages: exampleDocs.map((d) => ({
|
|
233
|
+
title: d.title,
|
|
234
|
+
description: d.description,
|
|
235
|
+
section: d.section,
|
|
236
|
+
path: d.path,
|
|
237
|
+
url: `https://docs.neurolink.ink/docs/${d.path}`,
|
|
238
|
+
})),
|
|
239
|
+
},
|
|
240
|
+
null,
|
|
241
|
+
2,
|
|
242
|
+
),
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const exampleSections = ["examples", "cookbook", "demos"];
|
|
248
|
+
const allResults = exampleSections.flatMap((section) =>
|
|
249
|
+
search.search(query, 10, section),
|
|
250
|
+
);
|
|
251
|
+
const seen = new Map();
|
|
252
|
+
for (const r of allResults) {
|
|
253
|
+
const existing = seen.get(r.id);
|
|
254
|
+
if (!existing || r.score > existing.score) {
|
|
255
|
+
seen.set(r.id, r);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const results = Array.from(seen.values())
|
|
259
|
+
.sort((a, b) => b.score - a.score)
|
|
260
|
+
.slice(0, 10);
|
|
261
|
+
return {
|
|
262
|
+
content: [
|
|
263
|
+
{
|
|
264
|
+
type: "text",
|
|
265
|
+
text: JSON.stringify(
|
|
266
|
+
{
|
|
267
|
+
query,
|
|
268
|
+
results: results.map((r) => ({
|
|
269
|
+
title: r.title,
|
|
270
|
+
description: r.description,
|
|
271
|
+
section: r.section,
|
|
272
|
+
path: r.path,
|
|
273
|
+
url: `https://docs.neurolink.ink/docs/${r.path}`,
|
|
274
|
+
})),
|
|
275
|
+
},
|
|
276
|
+
null,
|
|
277
|
+
2,
|
|
278
|
+
),
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
};
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
get_changelog: {
|
|
286
|
+
name: "get_changelog",
|
|
287
|
+
description: "Get recent changelog entries for NeuroLink releases.",
|
|
288
|
+
paramsSchema: {
|
|
289
|
+
limit: z
|
|
290
|
+
.number()
|
|
291
|
+
.int()
|
|
292
|
+
.min(1)
|
|
293
|
+
.max(50)
|
|
294
|
+
.optional()
|
|
295
|
+
.describe("Max entries to return (default: 5)"),
|
|
296
|
+
},
|
|
297
|
+
handler: (args) => {
|
|
298
|
+
const changelogDocs = search.getBySection("community");
|
|
299
|
+
const changelog = changelogDocs
|
|
300
|
+
.filter(
|
|
301
|
+
(d) =>
|
|
302
|
+
d.path.includes("changelog") ||
|
|
303
|
+
d.title.toLowerCase().includes("changelog") ||
|
|
304
|
+
d.title.toLowerCase().includes("release notes"),
|
|
305
|
+
)
|
|
306
|
+
.sort((a, b) => {
|
|
307
|
+
const toEpoch = (p) => {
|
|
308
|
+
const m = p.match(/(\d{4})[-/](\d{1,2})[-/](\d{1,2})/);
|
|
309
|
+
if (!m) return Number.NEGATIVE_INFINITY;
|
|
310
|
+
const [, y, mo, d] = m;
|
|
311
|
+
return Date.UTC(Number(y), Number(mo) - 1, Number(d));
|
|
312
|
+
};
|
|
313
|
+
return (
|
|
314
|
+
toEpoch(b.path) - toEpoch(a.path) || b.path.localeCompare(a.path)
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
const limit = Math.max(1, Math.min(args.limit || 5, 50));
|
|
318
|
+
return {
|
|
319
|
+
content: [
|
|
320
|
+
{
|
|
321
|
+
type: "text",
|
|
322
|
+
text: JSON.stringify(
|
|
323
|
+
{
|
|
324
|
+
entries: changelog.slice(0, limit).map((d) => ({
|
|
325
|
+
title: d.title,
|
|
326
|
+
description: d.description,
|
|
327
|
+
path: d.path,
|
|
328
|
+
url: `https://docs.neurolink.ink/docs/${d.path}`,
|
|
329
|
+
content: d.content.slice(0, 2000),
|
|
330
|
+
})),
|
|
331
|
+
},
|
|
332
|
+
null,
|
|
333
|
+
2,
|
|
334
|
+
),
|
|
335
|
+
},
|
|
336
|
+
],
|
|
337
|
+
};
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
//# sourceMappingURL=tools.js.map
|