hvtracker-mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 YugantM
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # HVTracker MCP
2
+
3
+ MCP server for checking supply-chain trust before connecting to AI agents,
4
+ frameworks, or MCP servers.
5
+
6
+ The hosted remote server is:
7
+
8
+ ```json
9
+ {
10
+ "mcpServers": {
11
+ "hvtracker": {
12
+ "url": "https://hvtracker.net/mcp"
13
+ }
14
+ }
15
+ }
16
+ ```
17
+
18
+ This repository also provides a local stdio package for clients that prefer
19
+ package-based installation.
20
+
21
+ <!-- mcp-name: io.github.yugantm/hvtracker-mcp -->
22
+
23
+ ## Tools
24
+
25
+ - `verify_mcp_server`: pre-connect trust verdict for an MCP server, package, GitHub repo, or agent name.
26
+ - `check_agent_trust`: compact trust profile for a tracked AI agent or framework.
27
+ - `search_agents`: search the HVTracker registry by name, repo, description, or category.
28
+
29
+ ## Local Install
30
+
31
+ With npm:
32
+
33
+ ```bash
34
+ npm install -g hvtracker-mcp
35
+ ```
36
+
37
+ With PyPI:
38
+
39
+ ```bash
40
+ python3 -m pip install hvtracker-mcp
41
+ ```
42
+
43
+ Example MCP client config:
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "hvtracker": {
49
+ "command": "hvtracker-mcp"
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ ## Development
56
+
57
+ ```bash
58
+ python3 -m pip install -e ".[dev]"
59
+ python3 -m pytest
60
+ hvtracker-mcp
61
+ ```
62
+
63
+ Use a different HVTracker base URL while testing:
64
+
65
+ ```bash
66
+ HVTRACKER_BASE_URL=http://localhost:8080 hvtracker-mcp
67
+ ```
68
+
69
+ ## Registry Publishing
70
+
71
+ The official MCP Registry manifest is `server.json`.
72
+
73
+ ```bash
74
+ mcp-publisher login github
75
+ mcp-publisher publish
76
+ ```
77
+
78
+ In GitHub Actions, run the "Publish MCP Registry" workflow after the npm,
79
+ PyPI, and GHCR packages for the same version are live.
80
+
81
+ The server name is:
82
+
83
+ ```text
84
+ io.github.yugantm/hvtracker-mcp
85
+ ```
86
+
87
+ ## Claude Desktop Extension
88
+
89
+ Tagged releases build an `.mcpb` bundle for Claude Desktop from `manifest.json`.
90
+ To build it locally:
91
+
92
+ ```bash
93
+ npm ci --omit=dev
94
+ npx @anthropic-ai/mcpb@2.1.2 pack
95
+ ```
96
+
97
+ ## Privacy
98
+
99
+ HVTracker MCP sends the user-supplied search string or server identifier to
100
+ `https://hvtracker.net` to fetch public trust data. It does not require an API
101
+ key and does not write to user systems. See the HVTracker site for current data
102
+ and methodology, and see `PRIVACY.md` for the repository privacy note.
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { pathToFileURL } from "node:url";
4
+
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { z } from "zod";
8
+
9
+ const VERSION = "0.1.0";
10
+ const DEFAULT_BASE_URL = "https://hvtracker.net";
11
+ const BASE_URL = (process.env.HVTRACKER_BASE_URL || DEFAULT_BASE_URL).replace(/\/+$/, "");
12
+ const TIMEOUT_MS = Number(process.env.HVTRACKER_TIMEOUT_SECONDS || 20) * 1000;
13
+ const READ_ONLY = {
14
+ readOnlyHint: true,
15
+ destructiveHint: false,
16
+ idempotentHint: true,
17
+ openWorldHint: true
18
+ };
19
+
20
+ export async function apiGet(path, params = {}) {
21
+ const url = new URL(path, BASE_URL);
22
+ for (const [key, value] of Object.entries(params)) {
23
+ if (value !== undefined && value !== null && String(value) !== "") {
24
+ url.searchParams.set(key, String(value));
25
+ }
26
+ }
27
+
28
+ const response = await fetch(url, {
29
+ headers: { "user-agent": `hvtracker-mcp/${VERSION}` },
30
+ signal: AbortSignal.timeout(TIMEOUT_MS)
31
+ });
32
+ if (!response.ok) {
33
+ throw new Error(`HVTracker API returned ${response.status} for ${url.toString()}`);
34
+ }
35
+ const payload = await response.json();
36
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
37
+ throw new Error(`Unexpected response shape from ${url.toString()}`);
38
+ }
39
+ return payload;
40
+ }
41
+
42
+ function asToolResult(value) {
43
+ return {
44
+ content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
45
+ structuredContent: value
46
+ };
47
+ }
48
+
49
+ function agentProfile(agent) {
50
+ const slug = agent.slug;
51
+ return {
52
+ tracked: true,
53
+ name: agent.name,
54
+ repo: agent.repo,
55
+ trust_score: agent.trust_score,
56
+ evidence_grade: agent.evidence_grade,
57
+ rank: agent.rank,
58
+ category: agent.category,
59
+ has_provenance: agent.has_provenance,
60
+ scorecard_score: agent.scorecard_score,
61
+ mcp_server_support: agent.mcp_server_support?.status,
62
+ profile_url: slug ? `${BASE_URL}/agents/${slug}/` : null
63
+ };
64
+ }
65
+
66
+ export async function verifyMcpServer(server) {
67
+ try {
68
+ return await apiGet("/api/v1/mcp/verify", { server });
69
+ } catch (error) {
70
+ return {
71
+ server,
72
+ tracked: false,
73
+ trusted: false,
74
+ error: error instanceof Error ? error.message : String(error),
75
+ reasons: ["HVTracker could not fetch a verdict right now."]
76
+ };
77
+ }
78
+ }
79
+
80
+ export async function checkAgentTrust(nameOrRepo) {
81
+ const verdict = await verifyMcpServer(nameOrRepo);
82
+ if (!verdict.tracked) {
83
+ return {
84
+ query: nameOrRepo,
85
+ tracked: false,
86
+ trusted: false,
87
+ message: "Not in the HVTracker registry; treat as unverified.",
88
+ submit_url: `${BASE_URL}/submit`,
89
+ verdict
90
+ };
91
+ }
92
+
93
+ const slug = verdict.slug;
94
+ return {
95
+ query: nameOrRepo,
96
+ tracked: true,
97
+ trusted: verdict.trusted,
98
+ repo: verdict.resolved,
99
+ slug,
100
+ trust_score: verdict.trust_score,
101
+ evidence_grade: verdict.grade,
102
+ confidence: verdict.confidence,
103
+ mcp_server_support: verdict.mcp_server_support,
104
+ tool_permissions: verdict.tool_permissions || [],
105
+ profile_url: slug ? `${BASE_URL}/agents/${slug}/` : null,
106
+ reasons: verdict.reasons || []
107
+ };
108
+ }
109
+
110
+ export async function searchAgents(query = "", category = "", limit = 10) {
111
+ try {
112
+ const data = await apiGet("/api/v1/agents");
113
+ const ql = String(query || "").trim().toLowerCase();
114
+ const cl = String(category || "").trim().toLowerCase();
115
+ const matches = [];
116
+
117
+ for (const agent of data.agents || []) {
118
+ const haystack = ["name", "repo", "description", "slug"]
119
+ .map((key) => String(agent[key] || ""))
120
+ .join(" ")
121
+ .toLowerCase();
122
+ if (ql && !haystack.includes(ql)) {
123
+ continue;
124
+ }
125
+ if (cl && String(agent.category || "").toLowerCase() !== cl) {
126
+ continue;
127
+ }
128
+ matches.push(agentProfile(agent));
129
+ }
130
+
131
+ matches.sort((a, b) => {
132
+ if (a.trust_score == null && b.trust_score != null) return 1;
133
+ if (a.trust_score != null && b.trust_score == null) return -1;
134
+ return (b.trust_score || 0) - (a.trust_score || 0);
135
+ });
136
+
137
+ const safeLimit = Math.max(1, Math.min(Number.parseInt(limit, 10) || 10, 50));
138
+ return { count: matches.length, results: matches.slice(0, safeLimit) };
139
+ } catch (error) {
140
+ return {
141
+ count: 0,
142
+ results: [],
143
+ error: error instanceof Error ? error.message : String(error)
144
+ };
145
+ }
146
+ }
147
+
148
+ export function createServer() {
149
+ const server = new McpServer({
150
+ name: "hvtracker",
151
+ version: VERSION,
152
+ instructions: "Check trust signals for AI agents and MCP servers."
153
+ });
154
+
155
+ server.registerTool(
156
+ "verify_mcp_server",
157
+ {
158
+ title: "Verify MCP Server",
159
+ description: "Pre-connect trust verdict for an MCP server or AI agent.",
160
+ inputSchema: {
161
+ server: z.string().describe("GitHub repo, package, display name, slug, or MCP URL.")
162
+ },
163
+ annotations: READ_ONLY
164
+ },
165
+ async ({ server }) => asToolResult(await verifyMcpServer(server))
166
+ );
167
+
168
+ server.registerTool(
169
+ "check_agent_trust",
170
+ {
171
+ title: "Check Agent Trust",
172
+ description: "Get the HVTracker trust profile for a tracked AI agent or framework.",
173
+ inputSchema: {
174
+ name_or_repo: z.string().describe("Agent name, slug, GitHub repo, package, or MCP URL.")
175
+ },
176
+ annotations: READ_ONLY
177
+ },
178
+ async ({ name_or_repo }) => asToolResult(await checkAgentTrust(name_or_repo))
179
+ );
180
+
181
+ server.registerTool(
182
+ "search_agents",
183
+ {
184
+ title: "Search Agents",
185
+ description: "Search tracked AI agents and frameworks by name, repo, or description.",
186
+ inputSchema: {
187
+ query: z.string().optional().default(""),
188
+ category: z.string().optional().default(""),
189
+ limit: z.number().int().min(1).max(50).optional().default(10)
190
+ },
191
+ annotations: READ_ONLY
192
+ },
193
+ async ({ query = "", category = "", limit = 10 }) =>
194
+ asToolResult(await searchAgents(query, category, limit))
195
+ );
196
+
197
+ return server;
198
+ }
199
+
200
+ export async function runStdio() {
201
+ const server = createServer();
202
+ await server.connect(new StdioServerTransport());
203
+ }
204
+
205
+ if (import.meta.url === pathToFileURL(process.argv[1]).href) {
206
+ runStdio().catch((error) => {
207
+ console.error(error);
208
+ process.exit(1);
209
+ });
210
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "hvtracker-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for HVTracker trust checks.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "mcpName": "io.github.yugantm/hvtracker-mcp",
8
+ "bin": {
9
+ "hvtracker-mcp": "./bin/hvtracker-mcp.js"
10
+ },
11
+ "files": [
12
+ "bin/",
13
+ "README.md",
14
+ "LICENSE",
15
+ "server.json"
16
+ ],
17
+ "scripts": {
18
+ "test": "node --test",
19
+ "pack:check": "npm pack --dry-run"
20
+ },
21
+ "keywords": [
22
+ "mcp",
23
+ "model-context-protocol",
24
+ "ai-agents",
25
+ "trust",
26
+ "supply-chain"
27
+ ],
28
+ "author": "YugantM",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/YugantM/hvtracker-mcp.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/YugantM/hvtracker-mcp/issues"
35
+ },
36
+ "homepage": "https://hvtracker.net",
37
+ "engines": {
38
+ "node": ">=20"
39
+ },
40
+ "dependencies": {
41
+ "@modelcontextprotocol/sdk": "^1.29.0",
42
+ "zod": "^4.3.0"
43
+ }
44
+ }
package/server.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.yugantm/hvtracker-mcp",
4
+ "title": "HVTracker MCP",
5
+ "description": "Pre-connect trust checks for AI agents and MCP servers using HVTracker's public trust registry.",
6
+ "version": "0.1.0",
7
+ "repository": {
8
+ "url": "https://github.com/YugantM/hvtracker-mcp",
9
+ "source": "github"
10
+ },
11
+ "remotes": [
12
+ {
13
+ "type": "streamable-http",
14
+ "url": "https://hvtracker.net/mcp"
15
+ }
16
+ ],
17
+ "packages": [
18
+ {
19
+ "registryType": "npm",
20
+ "identifier": "hvtracker-mcp",
21
+ "version": "0.1.0",
22
+ "transport": {
23
+ "type": "stdio"
24
+ }
25
+ },
26
+ {
27
+ "registryType": "pypi",
28
+ "identifier": "hvtracker-mcp",
29
+ "version": "0.1.0",
30
+ "transport": {
31
+ "type": "stdio"
32
+ }
33
+ },
34
+ {
35
+ "registryType": "oci",
36
+ "identifier": "ghcr.io/yugantm/hvtracker-mcp:0.1.0",
37
+ "transport": {
38
+ "type": "stdio"
39
+ }
40
+ }
41
+ ],
42
+ "tags": ["security", "trust", "ai-agents", "mcp", "supply-chain"]
43
+ }