kompass-sdk 0.12.0 → 0.14.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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Registry Source Adapter
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Fetches servers from registry.modelcontextprotocol.io
|
|
4
|
+
* Uses local cache + text search against descriptions (not just names)
|
|
5
5
|
*/
|
|
6
6
|
import type { SourceAdapter } from "./types.js";
|
|
7
7
|
export declare const mcpRegistryAdapter: SourceAdapter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-registry.d.ts","sourceRoot":"","sources":["../../src/sources/mcp-registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAqC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-registry.d.ts","sourceRoot":"","sources":["../../src/sources/mcp-registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAqC,MAAM,YAAY,CAAC;AAwFnF,eAAO,MAAM,kBAAkB,EAAE,aA0ChC,CAAC"}
|
|
@@ -1,35 +1,102 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Registry Source Adapter
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Fetches servers from registry.modelcontextprotocol.io
|
|
4
|
+
* Uses local cache + text search against descriptions (not just names)
|
|
5
5
|
*/
|
|
6
6
|
const BASE_URL = "https://registry.modelcontextprotocol.io";
|
|
7
|
+
// In-memory cache of all servers — fetched once, reused
|
|
8
|
+
let serverCache = null;
|
|
9
|
+
let cacheTime = 0;
|
|
10
|
+
const CACHE_TTL = 10 * 60 * 1000; // 10 minutes
|
|
11
|
+
async function fetchAllServers(timeout) {
|
|
12
|
+
// Return cache if fresh
|
|
13
|
+
if (serverCache && Date.now() - cacheTime < CACHE_TTL) {
|
|
14
|
+
return serverCache;
|
|
15
|
+
}
|
|
16
|
+
const allServers = [];
|
|
17
|
+
let cursor;
|
|
18
|
+
// Paginate through all servers (max 3 pages of 96)
|
|
19
|
+
for (let page = 0; page < 3; page++) {
|
|
20
|
+
const url = new URL("/v0.1/servers", BASE_URL);
|
|
21
|
+
url.searchParams.set("limit", "96");
|
|
22
|
+
url.searchParams.set("version", "latest");
|
|
23
|
+
if (cursor)
|
|
24
|
+
url.searchParams.set("cursor", cursor);
|
|
25
|
+
const res = await fetch(url.toString(), { signal: AbortSignal.timeout(timeout) });
|
|
26
|
+
if (!res.ok)
|
|
27
|
+
break;
|
|
28
|
+
const data = await res.json();
|
|
29
|
+
const servers = (data.servers ?? []).map((item) => item.server ?? item);
|
|
30
|
+
allServers.push(...servers);
|
|
31
|
+
cursor = data.metadata?.nextCursor ?? data.nextCursor;
|
|
32
|
+
if (!cursor)
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
serverCache = allServers;
|
|
36
|
+
cacheTime = Date.now();
|
|
37
|
+
return allServers;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Search servers locally by matching query against name + description.
|
|
41
|
+
* Much better than the registry's keyword search which only matches names.
|
|
42
|
+
*/
|
|
43
|
+
function searchLocally(servers, query, limit) {
|
|
44
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
|
|
45
|
+
return servers
|
|
46
|
+
.map((server) => {
|
|
47
|
+
const text = `${server.name} ${server.description ?? ""}`.toLowerCase();
|
|
48
|
+
let score = 0;
|
|
49
|
+
for (const term of queryTerms) {
|
|
50
|
+
// Exact word match in description
|
|
51
|
+
if (text.includes(term))
|
|
52
|
+
score += 3;
|
|
53
|
+
// Name match is stronger
|
|
54
|
+
if (server.name.toLowerCase().includes(term))
|
|
55
|
+
score += 5;
|
|
56
|
+
}
|
|
57
|
+
// Bonus for having remote endpoints (actually callable)
|
|
58
|
+
if (server.remotes && server.remotes.length > 0)
|
|
59
|
+
score += 2;
|
|
60
|
+
// Bonus for no auth required
|
|
61
|
+
const noAuth = server.remotes?.some((r) => !r.headers?.some((h) => h.isRequired && h.name.toLowerCase() === "authorization"));
|
|
62
|
+
if (noAuth)
|
|
63
|
+
score += 1;
|
|
64
|
+
return { server, score };
|
|
65
|
+
})
|
|
66
|
+
.filter((s) => s.score > 0)
|
|
67
|
+
.sort((a, b) => b.score - a.score)
|
|
68
|
+
.slice(0, limit)
|
|
69
|
+
.map((s) => s.server);
|
|
70
|
+
}
|
|
7
71
|
export const mcpRegistryAdapter = {
|
|
8
72
|
name: "mcp-registry",
|
|
9
73
|
displayName: "MCP Registry (Anthropic)",
|
|
10
74
|
async search(query, options) {
|
|
11
|
-
const limit = options?.limit ??
|
|
12
|
-
const timeout = options?.timeout ??
|
|
75
|
+
const limit = options?.limit ?? 20;
|
|
76
|
+
const timeout = options?.timeout ?? 15000;
|
|
13
77
|
try {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
url.searchParams.set("search", query);
|
|
18
|
-
url.searchParams.set("version", "latest");
|
|
19
|
-
const controller = new AbortController();
|
|
20
|
-
const timer = setTimeout(() => controller.abort(), timeout);
|
|
21
|
-
const res = await fetch(url.toString(), { signal: controller.signal });
|
|
22
|
-
clearTimeout(timer);
|
|
23
|
-
if (!res.ok)
|
|
24
|
-
return [];
|
|
25
|
-
const data = await res.json();
|
|
26
|
-
const rawServers = data.servers ?? data.data ?? [];
|
|
27
|
-
// MCP registry wraps in { server: {...} } objects
|
|
28
|
-
const servers = rawServers.map((item) => item.server ?? item);
|
|
29
|
-
return servers.slice(0, limit).map((server) => mapMcpServer(server));
|
|
78
|
+
const allServers = await fetchAllServers(timeout);
|
|
79
|
+
const matched = searchLocally(allServers, query, limit);
|
|
80
|
+
return matched.map(mapMcpServer);
|
|
30
81
|
}
|
|
31
82
|
catch {
|
|
32
|
-
|
|
83
|
+
// Fallback to direct API search if cache fetch fails
|
|
84
|
+
try {
|
|
85
|
+
const url = new URL("/v0.1/servers", BASE_URL);
|
|
86
|
+
url.searchParams.set("limit", String(limit));
|
|
87
|
+
if (query)
|
|
88
|
+
url.searchParams.set("search", query.split(/\s+/)[0]); // Single word fallback
|
|
89
|
+
url.searchParams.set("version", "latest");
|
|
90
|
+
const res = await fetch(url.toString(), { signal: AbortSignal.timeout(timeout) });
|
|
91
|
+
if (!res.ok)
|
|
92
|
+
return [];
|
|
93
|
+
const data = await res.json();
|
|
94
|
+
const servers = (data.servers ?? []).map((item) => item.server ?? item);
|
|
95
|
+
return servers.slice(0, limit).map(mapMcpServer);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
33
100
|
}
|
|
34
101
|
},
|
|
35
102
|
async ping() {
|
|
@@ -45,7 +112,7 @@ export const mcpRegistryAdapter = {
|
|
|
45
112
|
},
|
|
46
113
|
};
|
|
47
114
|
function mapMcpServer(server) {
|
|
48
|
-
const
|
|
115
|
+
const remote = server.remotes?.find((r) => !r.headers?.some((h) => h.isRequired && h.name.toLowerCase() === "authorization")) ?? server.remotes?.[0];
|
|
49
116
|
const categories = extractCategories(server.description ?? server.name);
|
|
50
117
|
return {
|
|
51
118
|
id: `mcp-registry:${server.name}`,
|
|
@@ -57,11 +124,11 @@ function mapMcpServer(server) {
|
|
|
57
124
|
source: "mcp-registry",
|
|
58
125
|
protocol: "mcp",
|
|
59
126
|
endpoints: {
|
|
60
|
-
mcp:
|
|
61
|
-
http: server.website ?? server.repo,
|
|
127
|
+
mcp: remote?.url,
|
|
128
|
+
http: server.websiteUrl ?? server.website ?? server.repository?.url ?? server.repo,
|
|
62
129
|
},
|
|
63
130
|
pricing: { model: "free" },
|
|
64
|
-
verified: !!
|
|
131
|
+
verified: !!remote,
|
|
65
132
|
raw: server,
|
|
66
133
|
};
|
|
67
134
|
}
|
|
@@ -75,6 +142,8 @@ function extractCategories(text) {
|
|
|
75
142
|
file: "tools", browser: "tools", web: "tools",
|
|
76
143
|
ai: "ai", llm: "ai", model: "ai",
|
|
77
144
|
image: "media", video: "media", audio: "media",
|
|
145
|
+
trading: "trading", market: "trading", price: "trading",
|
|
146
|
+
email: "communication", slack: "communication", chat: "communication",
|
|
78
147
|
};
|
|
79
148
|
for (const [keyword, cat] of Object.entries(keywords)) {
|
|
80
149
|
if (lower.includes(keyword) && !cats.includes(cat))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-registry.js","sourceRoot":"","sources":["../../src/sources/mcp-registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,QAAQ,GAAG,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-registry.js","sourceRoot":"","sources":["../../src/sources/mcp-registry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kompass-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Get any job done. Universal agent capability discovery + coordination across ACP, MCP, x402, A2A, skills, L402, and ERC-8004.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Registry Source Adapter
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Fetches servers from registry.modelcontextprotocol.io
|
|
4
|
+
* Uses local cache + text search against descriptions (not just names)
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { SourceAdapter, UnifiedAgent, SourceSearchOptions } from "./types.js";
|
|
@@ -13,9 +13,83 @@ interface McpServer {
|
|
|
13
13
|
description?: string;
|
|
14
14
|
version?: string;
|
|
15
15
|
repo?: string;
|
|
16
|
+
repository?: { url?: string };
|
|
17
|
+
websiteUrl?: string;
|
|
16
18
|
website?: string;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
remotes?: { type: string; url: string; headers?: { name: string; isRequired?: boolean }[] }[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// In-memory cache of all servers — fetched once, reused
|
|
23
|
+
let serverCache: McpServer[] | null = null;
|
|
24
|
+
let cacheTime = 0;
|
|
25
|
+
const CACHE_TTL = 10 * 60 * 1000; // 10 minutes
|
|
26
|
+
|
|
27
|
+
async function fetchAllServers(timeout: number): Promise<McpServer[]> {
|
|
28
|
+
// Return cache if fresh
|
|
29
|
+
if (serverCache && Date.now() - cacheTime < CACHE_TTL) {
|
|
30
|
+
return serverCache;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const allServers: McpServer[] = [];
|
|
34
|
+
let cursor: string | undefined;
|
|
35
|
+
|
|
36
|
+
// Paginate through all servers (max 3 pages of 96)
|
|
37
|
+
for (let page = 0; page < 3; page++) {
|
|
38
|
+
const url = new URL("/v0.1/servers", BASE_URL);
|
|
39
|
+
url.searchParams.set("limit", "96");
|
|
40
|
+
url.searchParams.set("version", "latest");
|
|
41
|
+
if (cursor) url.searchParams.set("cursor", cursor);
|
|
42
|
+
|
|
43
|
+
const res = await fetch(url.toString(), { signal: AbortSignal.timeout(timeout) });
|
|
44
|
+
if (!res.ok) break;
|
|
45
|
+
|
|
46
|
+
const data = await res.json();
|
|
47
|
+
const servers = (data.servers ?? []).map((item: any) => item.server ?? item);
|
|
48
|
+
allServers.push(...servers);
|
|
49
|
+
|
|
50
|
+
cursor = data.metadata?.nextCursor ?? data.nextCursor;
|
|
51
|
+
if (!cursor) break;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
serverCache = allServers;
|
|
55
|
+
cacheTime = Date.now();
|
|
56
|
+
return allServers;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Search servers locally by matching query against name + description.
|
|
61
|
+
* Much better than the registry's keyword search which only matches names.
|
|
62
|
+
*/
|
|
63
|
+
function searchLocally(servers: McpServer[], query: string, limit: number): McpServer[] {
|
|
64
|
+
const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
|
|
65
|
+
|
|
66
|
+
return servers
|
|
67
|
+
.map((server) => {
|
|
68
|
+
const text = `${server.name} ${server.description ?? ""}`.toLowerCase();
|
|
69
|
+
let score = 0;
|
|
70
|
+
|
|
71
|
+
for (const term of queryTerms) {
|
|
72
|
+
// Exact word match in description
|
|
73
|
+
if (text.includes(term)) score += 3;
|
|
74
|
+
// Name match is stronger
|
|
75
|
+
if (server.name.toLowerCase().includes(term)) score += 5;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Bonus for having remote endpoints (actually callable)
|
|
79
|
+
if (server.remotes && server.remotes.length > 0) score += 2;
|
|
80
|
+
|
|
81
|
+
// Bonus for no auth required
|
|
82
|
+
const noAuth = server.remotes?.some((r) =>
|
|
83
|
+
!r.headers?.some((h) => h.isRequired && h.name.toLowerCase() === "authorization")
|
|
84
|
+
);
|
|
85
|
+
if (noAuth) score += 1;
|
|
86
|
+
|
|
87
|
+
return { server, score };
|
|
88
|
+
})
|
|
89
|
+
.filter((s) => s.score > 0)
|
|
90
|
+
.sort((a, b) => b.score - a.score)
|
|
91
|
+
.slice(0, limit)
|
|
92
|
+
.map((s) => s.server);
|
|
19
93
|
}
|
|
20
94
|
|
|
21
95
|
export const mcpRegistryAdapter: SourceAdapter = {
|
|
@@ -23,31 +97,30 @@ export const mcpRegistryAdapter: SourceAdapter = {
|
|
|
23
97
|
displayName: "MCP Registry (Anthropic)",
|
|
24
98
|
|
|
25
99
|
async search(query: string, options?: SourceSearchOptions): Promise<UnifiedAgent[]> {
|
|
26
|
-
const limit = options?.limit ??
|
|
27
|
-
const timeout = options?.timeout ??
|
|
100
|
+
const limit = options?.limit ?? 20;
|
|
101
|
+
const timeout = options?.timeout ?? 15000;
|
|
28
102
|
|
|
29
103
|
try {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (!res.ok) return [];
|
|
104
|
+
const allServers = await fetchAllServers(timeout);
|
|
105
|
+
const matched = searchLocally(allServers, query, limit);
|
|
106
|
+
return matched.map(mapMcpServer);
|
|
107
|
+
} catch {
|
|
108
|
+
// Fallback to direct API search if cache fetch fails
|
|
109
|
+
try {
|
|
110
|
+
const url = new URL("/v0.1/servers", BASE_URL);
|
|
111
|
+
url.searchParams.set("limit", String(limit));
|
|
112
|
+
if (query) url.searchParams.set("search", query.split(/\s+/)[0]); // Single word fallback
|
|
113
|
+
url.searchParams.set("version", "latest");
|
|
42
114
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// MCP registry wraps in { server: {...} } objects
|
|
46
|
-
const servers: McpServer[] = rawServers.map((item: any) => item.server ?? item);
|
|
115
|
+
const res = await fetch(url.toString(), { signal: AbortSignal.timeout(timeout) });
|
|
116
|
+
if (!res.ok) return [];
|
|
47
117
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
118
|
+
const data = await res.json();
|
|
119
|
+
const servers = (data.servers ?? []).map((item: any) => item.server ?? item);
|
|
120
|
+
return servers.slice(0, limit).map(mapMcpServer);
|
|
121
|
+
} catch {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
51
124
|
}
|
|
52
125
|
},
|
|
53
126
|
|
|
@@ -64,7 +137,10 @@ export const mcpRegistryAdapter: SourceAdapter = {
|
|
|
64
137
|
};
|
|
65
138
|
|
|
66
139
|
function mapMcpServer(server: McpServer): UnifiedAgent {
|
|
67
|
-
const
|
|
140
|
+
const remote = server.remotes?.find((r) =>
|
|
141
|
+
!r.headers?.some((h) => h.isRequired && h.name.toLowerCase() === "authorization")
|
|
142
|
+
) ?? server.remotes?.[0];
|
|
143
|
+
|
|
68
144
|
const categories = extractCategories(server.description ?? server.name);
|
|
69
145
|
|
|
70
146
|
return {
|
|
@@ -77,11 +153,11 @@ function mapMcpServer(server: McpServer): UnifiedAgent {
|
|
|
77
153
|
source: "mcp-registry",
|
|
78
154
|
protocol: "mcp",
|
|
79
155
|
endpoints: {
|
|
80
|
-
mcp:
|
|
81
|
-
http: server.website ?? server.repo,
|
|
156
|
+
mcp: remote?.url,
|
|
157
|
+
http: server.websiteUrl ?? server.website ?? (server.repository as any)?.url ?? server.repo,
|
|
82
158
|
},
|
|
83
159
|
pricing: { model: "free" },
|
|
84
|
-
verified: !!
|
|
160
|
+
verified: !!remote,
|
|
85
161
|
raw: server,
|
|
86
162
|
};
|
|
87
163
|
}
|
|
@@ -96,6 +172,8 @@ function extractCategories(text: string): string[] {
|
|
|
96
172
|
file: "tools", browser: "tools", web: "tools",
|
|
97
173
|
ai: "ai", llm: "ai", model: "ai",
|
|
98
174
|
image: "media", video: "media", audio: "media",
|
|
175
|
+
trading: "trading", market: "trading", price: "trading",
|
|
176
|
+
email: "communication", slack: "communication", chat: "communication",
|
|
99
177
|
};
|
|
100
178
|
for (const [keyword, cat] of Object.entries(keywords)) {
|
|
101
179
|
if (lower.includes(keyword) && !cats.includes(cat)) cats.push(cat);
|