substreams-search-mcp 1.0.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/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # Substreams Search MCP Server
2
+
3
+ MCP server that lets AI agents search the [substreams.dev](https://substreams.dev) package registry.
4
+
5
+ ## Tool: `search_substreams`
6
+
7
+ | Parameter | Type | Default | Description |
8
+ |-----------|------|---------|-------------|
9
+ | `query` | string (required) | — | Search term, e.g. `"solana dex"` or `"uniswap"` |
10
+ | `sort` | string | `"most_downloaded"` | `most_downloaded`, `alphabetical`, `most_used`, `last_uploaded` |
11
+ | `network` | string | — | Filter by chain: `ethereum`, `solana`, `arbitrum-one`, etc. |
12
+
13
+ Returns JSON with package name, URL, creator, network, version, published date, and download count.
14
+
15
+ ## Setup
16
+
17
+ ```bash
18
+ git clone https://github.com/PaulieB14/substreams-search-mcp.git
19
+ cd substreams-search-mcp
20
+ python3 -m venv .venv
21
+ source .venv/bin/activate
22
+ pip install -r requirements.txt
23
+ ```
24
+
25
+ ### Claude Desktop
26
+
27
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "substreams-search": {
33
+ "command": "/path/to/substreams-search-mcp/.venv/bin/python3",
34
+ "args": ["/path/to/substreams-search-mcp/server.py"]
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ ### Cursor
41
+
42
+ Add to `~/.cursor/mcp.json`:
43
+
44
+ ```json
45
+ {
46
+ "mcpServers": {
47
+ "substreams-search": {
48
+ "command": "/path/to/substreams-search-mcp/.venv/bin/python3",
49
+ "args": ["/path/to/substreams-search-mcp/server.py"]
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ ### Claude Code
56
+
57
+ Add to `~/.claude/mcp.json`:
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "substreams-search": {
63
+ "command": "/path/to/substreams-search-mcp/.venv/bin/python3",
64
+ "args": ["/path/to/substreams-search-mcp/server.py"]
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ## How it works
71
+
72
+ The substreams.dev registry has no public API. This server scrapes the package listing pages, paginates through all results, deduplicates, and returns structured JSON. Multi-word queries search for the first word server-side and filter the rest client-side.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/build/index.js ADDED
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ import { parse } from "node-html-parser";
6
+ const REGISTRY_URL = "https://substreams.dev/packages";
7
+ const PAGE_SIZE = 24;
8
+ const MAX_PAGES = 50;
9
+ function parseCards(html) {
10
+ const root = parse(html);
11
+ const grid = root.querySelector("#packages-grid");
12
+ if (!grid)
13
+ return [];
14
+ const packages = [];
15
+ for (const link of grid.querySelectorAll("a.block")) {
16
+ const href = link.getAttribute("href");
17
+ if (!href)
18
+ continue;
19
+ const nameEl = link.querySelector("p.font-semibold");
20
+ const name = nameEl?.text?.trim() || href.split("/")[2] || "";
21
+ const creatorBtn = link.querySelector("button.user-filter-link");
22
+ const creator = creatorBtn?.getAttribute("data-user") || creatorBtn?.text?.trim() || "";
23
+ const networkBtn = link.querySelector("button.network-filter-link");
24
+ const network = networkBtn?.getAttribute("data-network") || "";
25
+ const bottom = link.querySelector("div.absolute");
26
+ let version = "";
27
+ let published = "";
28
+ let downloads = "";
29
+ if (bottom) {
30
+ for (const row of bottom.querySelectorAll("div.flex-row")) {
31
+ const labels = row.querySelectorAll("p");
32
+ if (labels.length < 2)
33
+ continue;
34
+ const label = labels[0].text.trim().toLowerCase();
35
+ const value = labels[labels.length - 1].text.trim();
36
+ if (label.includes("version"))
37
+ version = value;
38
+ else if (label.includes("publish"))
39
+ published = value;
40
+ else if (label.includes("download"))
41
+ downloads = value;
42
+ }
43
+ }
44
+ packages.push({
45
+ name,
46
+ url: `https://substreams.dev${href}`,
47
+ creator,
48
+ network,
49
+ version,
50
+ published,
51
+ downloads,
52
+ });
53
+ }
54
+ return packages;
55
+ }
56
+ async function fetchPackages(query, sort = "most_downloaded", network) {
57
+ const words = query.trim().split(/\s+/);
58
+ const searchTerm = words[0] || query;
59
+ const extraWords = words.slice(1).map((w) => w.toLowerCase());
60
+ const allPackages = [];
61
+ const seenUrls = new Set();
62
+ for (let page = 1; page <= MAX_PAGES; page++) {
63
+ const params = new URLSearchParams({
64
+ search: searchTerm,
65
+ sort,
66
+ page: String(page),
67
+ });
68
+ if (network)
69
+ params.set("network", network);
70
+ const resp = await fetch(`${REGISTRY_URL}?${params}`);
71
+ if (!resp.ok)
72
+ throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
73
+ const html = await resp.text();
74
+ const pagePackages = parseCards(html);
75
+ if (pagePackages.length === 0)
76
+ break;
77
+ for (const pkg of pagePackages) {
78
+ if (!seenUrls.has(pkg.url)) {
79
+ seenUrls.add(pkg.url);
80
+ allPackages.push(pkg);
81
+ }
82
+ }
83
+ if (pagePackages.length < PAGE_SIZE)
84
+ break;
85
+ }
86
+ if (extraWords.length > 0) {
87
+ return allPackages.filter((p) => extraWords.every((w) => p.name.toLowerCase().includes(w) ||
88
+ p.creator.toLowerCase().includes(w) ||
89
+ p.network.toLowerCase().includes(w)));
90
+ }
91
+ return allPackages;
92
+ }
93
+ const server = new McpServer({
94
+ name: "substreams-search",
95
+ version: "1.0.0",
96
+ });
97
+ server.registerTool("search_substreams", {
98
+ description: "Search the substreams.dev package registry for blockchain data stream packages. " +
99
+ "Multi-word queries filter results to match all words.",
100
+ inputSchema: {
101
+ query: z
102
+ .string()
103
+ .describe("Search term, e.g. 'solana dex' or 'uniswap'"),
104
+ sort: z
105
+ .enum(["most_downloaded", "alphabetical", "most_used", "last_uploaded"])
106
+ .optional()
107
+ .default("most_downloaded")
108
+ .describe("Sort order"),
109
+ network: z
110
+ .string()
111
+ .optional()
112
+ .describe("Filter by blockchain network, e.g. 'ethereum', 'solana', 'arbitrum-one'"),
113
+ },
114
+ annotations: { readOnlyHint: true },
115
+ }, async ({ query, sort, network }) => {
116
+ const packages = await fetchPackages(query, sort, network);
117
+ const result = packages.length === 0
118
+ ? { results: [], message: `No packages found for '${query}'` }
119
+ : { results: packages, count: packages.length };
120
+ return {
121
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
122
+ };
123
+ });
124
+ async function main() {
125
+ const transport = new StdioServerTransport();
126
+ await server.connect(transport);
127
+ console.error("substreams-search-mcp running on stdio");
128
+ }
129
+ main().catch((err) => {
130
+ console.error("Fatal:", err);
131
+ process.exit(1);
132
+ });
133
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "substreams-search-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server to search the substreams.dev package registry",
5
+ "type": "module",
6
+ "bin": {
7
+ "substreams-search-mcp": "build/index.js"
8
+ },
9
+ "main": "./build/index.js",
10
+ "scripts": {
11
+ "build": "tsc && chmod 755 build/index.js",
12
+ "start": "node build/index.js",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "files": [
16
+ "build"
17
+ ],
18
+ "keywords": [
19
+ "mcp",
20
+ "substreams",
21
+ "blockchain",
22
+ "ai",
23
+ "claude",
24
+ "the-graph"
25
+ ],
26
+ "author": "PaulieB14",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/PaulieB14/substreams-search-mcp.git"
31
+ },
32
+ "dependencies": {
33
+ "@modelcontextprotocol/sdk": "^1.12.1",
34
+ "node-html-parser": "^7.0.1",
35
+ "zod": "^3.24.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^22.0.0",
39
+ "typescript": "^5.7.0"
40
+ },
41
+ "engines": {
42
+ "node": ">=18.0.0"
43
+ }
44
+ }