@agentscore-xyz/mcp-server 1.2.3 → 2.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 +90 -123
- package/dist/index.js +17 -32
- package/dist/tools.d.ts +0 -68
- package/dist/tools.js +127 -140
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,123 +1,90 @@
|
|
|
1
|
-
# @agentscore-xyz/mcp-server
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
|
64
|
-
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
##
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
##
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
1. Agent calls `check_agent_trust` → gets score from AgentScore
|
|
93
|
-
2. Agent calls `remember` → stores the result in local SQLite
|
|
94
|
-
3. Next session, agent calls `recall("trust EmberFoundry")` → instant, no network call
|
|
95
|
-
|
|
96
|
-
```json
|
|
97
|
-
{
|
|
98
|
-
"mcpServers": {
|
|
99
|
-
"agentscore": {
|
|
100
|
-
"command": "npx",
|
|
101
|
-
"args": ["-y", "@agentscore-xyz/mcp-server"]
|
|
102
|
-
},
|
|
103
|
-
"memory": {
|
|
104
|
-
"command": "npx",
|
|
105
|
-
"args": ["-y", "agent-recall"]
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Two tools, clean separation. Trust scoring stays in the cloud, memory stays local.
|
|
112
|
-
|
|
113
|
-
## Links
|
|
114
|
-
|
|
115
|
-
- **Website:** https://agentscores.xyz
|
|
116
|
-
- **API Docs:** https://agentscores.xyz/docs
|
|
117
|
-
- **Methodology:** https://agentscores.xyz/methodology
|
|
118
|
-
- **Leaderboard:** https://agentscores.xyz/discover
|
|
119
|
-
- **npm (trust-check):** [@agentscore-xyz/trust-check](https://www.npmjs.com/package/@agentscore-xyz/trust-check)
|
|
120
|
-
|
|
121
|
-
## License
|
|
122
|
-
|
|
123
|
-
MIT
|
|
1
|
+
# @agentscore-xyz/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP security trust layer. Scan packages, get trust verdicts, check incident exposure, query the abuse database. Five tools for MCP security decisions. No API key, zero config.
|
|
4
|
+
|
|
5
|
+
[](https://agentscores.xyz/scan?npm=@agentscore-xyz/mcp-server)
|
|
6
|
+
|
|
7
|
+
> **Scan any MCP package for security issues:** [agentscores.xyz](https://agentscores.xyz)
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
### Claude Desktop
|
|
12
|
+
|
|
13
|
+
Add to your `claude_desktop_config.json`:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"agentscore": {
|
|
19
|
+
"command": "npx",
|
|
20
|
+
"args": ["-y", "@agentscore-xyz/mcp-server"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Cursor / Any MCP Client
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx @agentscore-xyz/mcp-server
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## What This Does
|
|
33
|
+
|
|
34
|
+
Your AI can now make security decisions about MCP packages:
|
|
35
|
+
|
|
36
|
+
> **You:** "Is exa-mcp-server safe to install?"
|
|
37
|
+
>
|
|
38
|
+
> **Claude:** *calls get_verdict* "Verdict: ALLOW. Score 90/100, LOW risk. No provenance attestations (published by personal account). 9 tools exposed including web_search_exa and crawling_exa."
|
|
39
|
+
|
|
40
|
+
> **You:** "The axios package was compromised. Which MCP servers are affected?"
|
|
41
|
+
>
|
|
42
|
+
> **Claude:** *calls check_exposure* "3 monitored MCP servers depend on axios: exa-mcp-server, tavily-mcp, and figma-mcp."
|
|
43
|
+
|
|
44
|
+
> **You:** "Scan @azure-devops/mcp for security issues"
|
|
45
|
+
>
|
|
46
|
+
> **Claude:** *calls scan_package* "Score 75/100, MODERATE risk. Found: preinstall script modifying npm registry config. No provenance attestations."
|
|
47
|
+
|
|
48
|
+
## Available Tools
|
|
49
|
+
|
|
50
|
+
| Tool | What it does |
|
|
51
|
+
|------|-------------|
|
|
52
|
+
| `scan_package` | Full security scan: install scripts, prompt injection, source code patterns, provenance posture, MCP tool extraction |
|
|
53
|
+
| `get_verdict` | Trust decision: allow, warn, or block. Single call for install/connect decisions. |
|
|
54
|
+
| `check_exposure` | Incident response: which monitored MCP servers depend on a given package? |
|
|
55
|
+
| `check_abuse` | Query the KYA abuse database for reported packages or agents |
|
|
56
|
+
| `monitor_status` | Check if a package is under continuous monitoring and get scan history |
|
|
57
|
+
|
|
58
|
+
## Risk Levels
|
|
59
|
+
|
|
60
|
+
| Score | Risk | Meaning |
|
|
61
|
+
|-------|------|---------|
|
|
62
|
+
| 85-100 | LOW | Clean or minor issues only |
|
|
63
|
+
| 70-84 | MODERATE | Some findings, review recommended |
|
|
64
|
+
| 50-69 | ELEVATED | Significant findings, use with caution |
|
|
65
|
+
| 30-49 | HIGH | Serious issues, not recommended |
|
|
66
|
+
| 0-29 | CRITICAL | Do not use |
|
|
67
|
+
|
|
68
|
+
## What the Scanner Checks
|
|
69
|
+
|
|
70
|
+
- Install scripts (postinstall/preinstall hooks with network calls or code execution)
|
|
71
|
+
- Prompt injection patterns in package metadata
|
|
72
|
+
- Suspicious URLs (sketchy TLDs, ngrok, raw IPs)
|
|
73
|
+
- Source code patterns (command injection, unsafe eval, hardcoded secrets)
|
|
74
|
+
- Publisher provenance (trusted publishing, attestations)
|
|
75
|
+
- Dependency count and metadata completeness
|
|
76
|
+
- MCP tool definitions extracted from published source
|
|
77
|
+
|
|
78
|
+
## Monitoring
|
|
79
|
+
|
|
80
|
+
AgentScore continuously monitors 60+ MCP packages. The `check_exposure` and `monitor_status` tools use this live dataset. When a package like axios gets compromised, you can instantly find which MCP servers are affected.
|
|
81
|
+
|
|
82
|
+
## Links
|
|
83
|
+
|
|
84
|
+
- **Website:** [agentscores.xyz](https://agentscores.xyz)
|
|
85
|
+
- **API Docs:** [agentscores.xyz/docs](https://agentscores.xyz/docs)
|
|
86
|
+
- **Methodology:** [agentscores.xyz/methodology](https://agentscores.xyz/methodology)
|
|
87
|
+
|
|
88
|
+
## Licence
|
|
89
|
+
|
|
90
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -3,46 +3,31 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { handleTool } from "./tools.js";
|
|
6
|
-
import { resources, getResourceContent } from "./resources.js";
|
|
7
6
|
const server = new McpServer({
|
|
8
7
|
name: "agentscore",
|
|
9
|
-
version: "
|
|
8
|
+
version: "2.0.0",
|
|
10
9
|
});
|
|
11
10
|
// --- Tools ---
|
|
12
|
-
server.tool("
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
category: z.string().optional().describe("Filter by category (e.g. 'Security', 'Development')"),
|
|
28
|
-
limit: z.number().min(1).max(100).default(10).describe("Number of agents to return (default: 10)"),
|
|
29
|
-
}, async (args) => handleTool("get_leaderboard", args));
|
|
30
|
-
server.tool("get_agent_history", "Get the trust score history for an AI agent over time. Use this to see if an agent's trustworthiness is improving, declining, or stable.", {
|
|
31
|
-
name: z.string().describe("The agent's name"),
|
|
32
|
-
limit: z.number().min(1).max(90).default(30).describe("Number of historical data points (default: 30)"),
|
|
33
|
-
}, async (args) => handleTool("get_agent_history", args));
|
|
34
|
-
// --- Resources ---
|
|
35
|
-
server.resource("methodology", resources[0].uri, { description: resources[0].description, mimeType: resources[0].mimeType }, async () => ({
|
|
36
|
-
contents: [{ uri: resources[0].uri, mimeType: "text/plain", text: getResourceContent(resources[0].uri) }],
|
|
37
|
-
}));
|
|
38
|
-
server.resource("score-bands", resources[1].uri, { description: resources[1].description, mimeType: resources[1].mimeType }, async () => ({
|
|
39
|
-
contents: [{ uri: resources[1].uri, mimeType: "text/plain", text: getResourceContent(resources[1].uri) }],
|
|
40
|
-
}));
|
|
11
|
+
server.tool("scan_package", "Scan an npm package for MCP security issues. Checks install scripts, prompt injection patterns, suspicious URLs, source code patterns, dependency count, metadata completeness, and publisher provenance. Returns score (0-100), risk level, and detailed findings.", {
|
|
12
|
+
npm: z.string().describe("npm package name (e.g. 'exa-mcp-server', '@modelcontextprotocol/server-github')"),
|
|
13
|
+
}, async (args) => handleTool("scan_package", args));
|
|
14
|
+
server.tool("get_verdict", "Get a trust verdict for an MCP package: allow, warn, or block. Combines scan findings, monitoring status, and publisher posture into a single decision. Use this before installing or connecting to an MCP server.", {
|
|
15
|
+
npm: z.string().describe("npm package name"),
|
|
16
|
+
}, async (args) => handleTool("get_verdict", args));
|
|
17
|
+
server.tool("check_exposure", "Check which monitored MCP servers depend on a given package. Use this during incident response to find blast radius. Example: 'which MCP servers use axios?'", {
|
|
18
|
+
npm: z.string().describe("npm package name to check exposure for (e.g. 'axios')"),
|
|
19
|
+
}, async (args) => handleTool("check_exposure", args));
|
|
20
|
+
server.tool("check_abuse", "Check if a package or agent has been reported to the KYA abuse database. Returns whether abuse has been reported and any details.", {
|
|
21
|
+
agent: z.string().describe("Package name or agent identifier to check"),
|
|
22
|
+
}, async (args) => handleTool("check_abuse", args));
|
|
23
|
+
server.tool("monitor_status", "Check if an MCP package is under continuous monitoring and get its scan history. Shows current score, risk level, and recent changes.", {
|
|
24
|
+
npm: z.string().describe("npm package name"),
|
|
25
|
+
}, async (args) => handleTool("monitor_status", args));
|
|
41
26
|
// --- Start ---
|
|
42
27
|
async function main() {
|
|
43
28
|
const transport = new StdioServerTransport();
|
|
44
29
|
await server.connect(transport);
|
|
45
|
-
console.error("AgentScore MCP server running on stdio");
|
|
30
|
+
console.error("AgentScore MCP server v2.0 running on stdio");
|
|
46
31
|
}
|
|
47
32
|
main().catch((err) => {
|
|
48
33
|
console.error("Fatal error:", err);
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
1
|
type ToolResult = {
|
|
3
2
|
content: Array<{
|
|
4
3
|
type: "text";
|
|
@@ -6,72 +5,5 @@ type ToolResult = {
|
|
|
6
5
|
}>;
|
|
7
6
|
isError?: boolean;
|
|
8
7
|
};
|
|
9
|
-
export declare const toolDefinitions: ({
|
|
10
|
-
name: string;
|
|
11
|
-
description: string;
|
|
12
|
-
inputSchema: {
|
|
13
|
-
name: z.ZodString;
|
|
14
|
-
threshold: z.ZodDefault<z.ZodNumber>;
|
|
15
|
-
agents?: undefined;
|
|
16
|
-
query?: undefined;
|
|
17
|
-
limit?: undefined;
|
|
18
|
-
category?: undefined;
|
|
19
|
-
};
|
|
20
|
-
} | {
|
|
21
|
-
name: string;
|
|
22
|
-
description: string;
|
|
23
|
-
inputSchema: {
|
|
24
|
-
name: z.ZodString;
|
|
25
|
-
threshold?: undefined;
|
|
26
|
-
agents?: undefined;
|
|
27
|
-
query?: undefined;
|
|
28
|
-
limit?: undefined;
|
|
29
|
-
category?: undefined;
|
|
30
|
-
};
|
|
31
|
-
} | {
|
|
32
|
-
name: string;
|
|
33
|
-
description: string;
|
|
34
|
-
inputSchema: {
|
|
35
|
-
agents: z.ZodArray<z.ZodString>;
|
|
36
|
-
name?: undefined;
|
|
37
|
-
threshold?: undefined;
|
|
38
|
-
query?: undefined;
|
|
39
|
-
limit?: undefined;
|
|
40
|
-
category?: undefined;
|
|
41
|
-
};
|
|
42
|
-
} | {
|
|
43
|
-
name: string;
|
|
44
|
-
description: string;
|
|
45
|
-
inputSchema: {
|
|
46
|
-
query: z.ZodString;
|
|
47
|
-
limit: z.ZodDefault<z.ZodNumber>;
|
|
48
|
-
name?: undefined;
|
|
49
|
-
threshold?: undefined;
|
|
50
|
-
agents?: undefined;
|
|
51
|
-
category?: undefined;
|
|
52
|
-
};
|
|
53
|
-
} | {
|
|
54
|
-
name: string;
|
|
55
|
-
description: string;
|
|
56
|
-
inputSchema: {
|
|
57
|
-
category: z.ZodOptional<z.ZodString>;
|
|
58
|
-
limit: z.ZodDefault<z.ZodNumber>;
|
|
59
|
-
name?: undefined;
|
|
60
|
-
threshold?: undefined;
|
|
61
|
-
agents?: undefined;
|
|
62
|
-
query?: undefined;
|
|
63
|
-
};
|
|
64
|
-
} | {
|
|
65
|
-
name: string;
|
|
66
|
-
description: string;
|
|
67
|
-
inputSchema: {
|
|
68
|
-
name: z.ZodString;
|
|
69
|
-
limit: z.ZodDefault<z.ZodNumber>;
|
|
70
|
-
threshold?: undefined;
|
|
71
|
-
agents?: undefined;
|
|
72
|
-
query?: undefined;
|
|
73
|
-
category?: undefined;
|
|
74
|
-
};
|
|
75
|
-
})[];
|
|
76
8
|
export declare function handleTool(name: string, args: Record<string, unknown>): Promise<ToolResult>;
|
|
77
9
|
export {};
|
package/dist/tools.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
1
|
import { fetchApi, ApiError } from "./api.js";
|
|
3
|
-
import { formatTrustCheck, formatScore, formatCompare, formatSearch, formatLeaderboard, formatHistory, } from "./format.js";
|
|
4
2
|
function text(s, isError = false) {
|
|
5
3
|
return { content: [{ type: "text", text: s }], isError };
|
|
6
4
|
}
|
|
@@ -11,152 +9,141 @@ function handleApiError(err) {
|
|
|
11
9
|
}
|
|
12
10
|
return text(`AgentScore API error: ${err.message}`, true);
|
|
13
11
|
}
|
|
14
|
-
return text("AgentScore API is temporarily unavailable.
|
|
12
|
+
return text("AgentScore API is temporarily unavailable.", true);
|
|
13
|
+
}
|
|
14
|
+
function formatScan(data) {
|
|
15
|
+
const lines = [
|
|
16
|
+
`Package: ${data.package}@${data.version}`,
|
|
17
|
+
`Score: ${data.score}/100`,
|
|
18
|
+
`Risk: ${data.risk}`,
|
|
19
|
+
`Recommendation: ${data.recommendation}`,
|
|
20
|
+
"",
|
|
21
|
+
];
|
|
22
|
+
if (data.findings?.length > 0) {
|
|
23
|
+
lines.push(`Findings (${data.findings.length}):`);
|
|
24
|
+
for (const f of data.findings) {
|
|
25
|
+
lines.push(` [${f.severity.toUpperCase()}] ${f.type}: ${f.detail}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
lines.push("No security issues found.");
|
|
30
|
+
}
|
|
31
|
+
if (data.posture) {
|
|
32
|
+
lines.push("", "Publisher Posture:");
|
|
33
|
+
lines.push(` Provenance: ${data.posture.provenance ? "Yes" : "No"}`);
|
|
34
|
+
lines.push(` Trusted Publishing: ${data.posture.trusted_publishing ? "Yes" : "No"}`);
|
|
35
|
+
lines.push(` Publisher: ${data.posture.publisher || "unknown"}`);
|
|
36
|
+
}
|
|
37
|
+
if (data.mcp_tools?.length > 0) {
|
|
38
|
+
lines.push("", `MCP Tools (${data.mcp_tools.length}):`);
|
|
39
|
+
for (const t of data.mcp_tools) {
|
|
40
|
+
lines.push(` ${t.name}: ${t.description?.slice(0, 100) || "no description"}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return lines.join("\n");
|
|
44
|
+
}
|
|
45
|
+
function formatVerdict(data) {
|
|
46
|
+
const lines = [
|
|
47
|
+
`Verdict: ${data.verdict.toUpperCase()}`,
|
|
48
|
+
`Package: ${data.package}@${data.version}`,
|
|
49
|
+
`Score: ${data.score}/100`,
|
|
50
|
+
`Risk: ${data.risk}`,
|
|
51
|
+
`Monitored: ${data.monitored ? "Yes" : "No"}`,
|
|
52
|
+
];
|
|
53
|
+
if (data.reasons?.length > 0) {
|
|
54
|
+
lines.push("", `Reasons: ${data.reasons.join(", ")}`);
|
|
55
|
+
}
|
|
56
|
+
if (data.posture) {
|
|
57
|
+
lines.push("", "Publisher Posture:");
|
|
58
|
+
lines.push(` Provenance: ${data.posture.provenance ? "Yes" : "No"}`);
|
|
59
|
+
lines.push(` Trusted Publishing: ${data.posture.trusted_publishing ? "Yes" : "No"}`);
|
|
60
|
+
}
|
|
61
|
+
if (data.tool_count > 0) {
|
|
62
|
+
lines.push("", `Tools exposed: ${data.tool_count}`);
|
|
63
|
+
}
|
|
64
|
+
return lines.join("\n");
|
|
65
|
+
}
|
|
66
|
+
function formatExposure(data) {
|
|
67
|
+
const lines = [
|
|
68
|
+
`Exposure check for: ${data.compromised_package}`,
|
|
69
|
+
`Monitored packages: ${data.total_monitored}`,
|
|
70
|
+
`Affected: ${data.total_affected}`,
|
|
71
|
+
];
|
|
72
|
+
if (data.affected?.length > 0) {
|
|
73
|
+
lines.push("", "Affected MCP servers:");
|
|
74
|
+
for (const a of data.affected) {
|
|
75
|
+
lines.push(` ${a.package} (score: ${a.package_score}/100, risk: ${a.package_risk})`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
lines.push("", "No monitored MCP servers depend on this package.");
|
|
80
|
+
}
|
|
81
|
+
return lines.join("\n");
|
|
82
|
+
}
|
|
83
|
+
function formatAbuse(data) {
|
|
84
|
+
if (data.found) {
|
|
85
|
+
return `ABUSE REPORTED for ${data.agent}\nReason: ${data.reason || "unspecified"}\nSeverity: ${data.severity || "unspecified"}`;
|
|
86
|
+
}
|
|
87
|
+
return `No abuse reports found for ${data.agent || "this identifier"}.`;
|
|
88
|
+
}
|
|
89
|
+
function formatMonitor(data) {
|
|
90
|
+
if (!data.monitored) {
|
|
91
|
+
return `${data.package || "This package"} is not currently under monitoring.`;
|
|
92
|
+
}
|
|
93
|
+
const lines = [
|
|
94
|
+
`Package: ${data.package}`,
|
|
95
|
+
`Monitored: Yes`,
|
|
96
|
+
`Current Score: ${data.current_score}/100`,
|
|
97
|
+
`Current Risk: ${data.current_risk}`,
|
|
98
|
+
`Last Scanned: ${data.last_scanned}`,
|
|
99
|
+
];
|
|
100
|
+
if (data.history?.length > 0) {
|
|
101
|
+
lines.push("", "Recent history:");
|
|
102
|
+
for (const h of data.history.slice(0, 5)) {
|
|
103
|
+
lines.push(` ${h.scanned_at?.split("T")[0]} - Score: ${h.score}/100, Risk: ${h.risk}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return lines.join("\n");
|
|
15
107
|
}
|
|
16
|
-
// --- Tool definitions ---
|
|
17
|
-
export const toolDefinitions = [
|
|
18
|
-
{
|
|
19
|
-
name: "check_agent_trust",
|
|
20
|
-
description: "Check whether an AI agent is trustworthy before transacting with it. Returns a trust verdict (TRUSTED/UNTRUSTED), score (0-100), and trust band. Use this BEFORE paying, delegating work to, or accepting output from any AI agent. No API key needed.",
|
|
21
|
-
inputSchema: {
|
|
22
|
-
name: z.string().describe("The agent's name (e.g. 'EmberFoundry', 'cybercentry')"),
|
|
23
|
-
threshold: z
|
|
24
|
-
.number()
|
|
25
|
-
.min(0)
|
|
26
|
-
.max(100)
|
|
27
|
-
.default(20)
|
|
28
|
-
.describe("Minimum score to consider trusted (default: 20)"),
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
name: "get_agent_score",
|
|
33
|
-
description: "Get a detailed trust score breakdown for an AI agent, showing scores across five dimensions: Identity, Activity, Reputation, Work History, and Consistency. Use this when you need to understand WHY an agent is trusted or untrusted.",
|
|
34
|
-
inputSchema: {
|
|
35
|
-
name: z.string().describe("The agent's name"),
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: "compare_agents",
|
|
40
|
-
description: "Compare trust scores of 2-5 AI agents side by side. Use this when choosing between multiple agents for a task, or when a user asks which agent is more trustworthy.",
|
|
41
|
-
inputSchema: {
|
|
42
|
-
agents: z
|
|
43
|
-
.array(z.string())
|
|
44
|
-
.min(2)
|
|
45
|
-
.max(5)
|
|
46
|
-
.describe("List of 2-5 agent names to compare"),
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
name: "search_agents",
|
|
51
|
-
description: "Search for AI agents by name in the AgentScore database. Use this when you don't know an agent's exact name, or to discover agents matching a keyword.",
|
|
52
|
-
inputSchema: {
|
|
53
|
-
query: z.string().describe("Search term (agent name or keyword)"),
|
|
54
|
-
limit: z
|
|
55
|
-
.number()
|
|
56
|
-
.min(1)
|
|
57
|
-
.max(50)
|
|
58
|
-
.default(10)
|
|
59
|
-
.describe("Maximum results to return (default: 10)"),
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: "get_leaderboard",
|
|
64
|
-
description: "Get the top-rated AI agents by trust score. Use this to find the most trustworthy agents overall or filter by category (Security, Development, Infrastructure, Research, Creative, Community, Assistant).",
|
|
65
|
-
inputSchema: {
|
|
66
|
-
category: z
|
|
67
|
-
.string()
|
|
68
|
-
.optional()
|
|
69
|
-
.describe("Filter by category (e.g. 'Security', 'Development')"),
|
|
70
|
-
limit: z
|
|
71
|
-
.number()
|
|
72
|
-
.min(1)
|
|
73
|
-
.max(100)
|
|
74
|
-
.default(10)
|
|
75
|
-
.describe("Number of agents to return (default: 10)"),
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: "get_agent_history",
|
|
80
|
-
description: "Get the trust score history for an AI agent over time. Use this to see if an agent's trustworthiness is improving, declining, or stable.",
|
|
81
|
-
inputSchema: {
|
|
82
|
-
name: z.string().describe("The agent's name"),
|
|
83
|
-
limit: z
|
|
84
|
-
.number()
|
|
85
|
-
.min(1)
|
|
86
|
-
.max(90)
|
|
87
|
-
.default(30)
|
|
88
|
-
.describe("Number of historical data points (default: 30)"),
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
];
|
|
92
|
-
// --- Tool handlers ---
|
|
93
108
|
export async function handleTool(name, args) {
|
|
94
109
|
try {
|
|
95
110
|
switch (name) {
|
|
96
|
-
case "
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
threshold: String(threshold),
|
|
105
|
-
});
|
|
106
|
-
return text(formatTrustCheck(data));
|
|
107
|
-
}
|
|
108
|
-
case "get_agent_score": {
|
|
109
|
-
const agentName = args.name;
|
|
110
|
-
if (!agentName?.trim()) {
|
|
111
|
-
return text("Agent name is required.", true);
|
|
112
|
-
}
|
|
113
|
-
const data = await fetchApi("/api/score", { name: agentName });
|
|
114
|
-
return text(formatScore(data));
|
|
111
|
+
case "scan_package": {
|
|
112
|
+
const npm = args.npm;
|
|
113
|
+
if (!npm?.trim())
|
|
114
|
+
return text("Package name is required.", true);
|
|
115
|
+
const data = await fetchApi("/api/scan", { npm });
|
|
116
|
+
if (data.status === "not_found")
|
|
117
|
+
return text(`Package "${npm}" not found on npm.`, true);
|
|
118
|
+
return text(formatScan(data));
|
|
115
119
|
}
|
|
116
|
-
case "
|
|
117
|
-
const
|
|
118
|
-
if (!
|
|
119
|
-
return text("
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return text("Maximum 5 agents can be compared at once.", true);
|
|
123
|
-
}
|
|
124
|
-
// Build URL with multiple agent params
|
|
125
|
-
const params = new URLSearchParams();
|
|
126
|
-
for (const a of agents)
|
|
127
|
-
params.append("agent", a);
|
|
128
|
-
const data = await fetchApi(`/api/compare?${params.toString()}`);
|
|
129
|
-
return text(formatCompare(data));
|
|
120
|
+
case "get_verdict": {
|
|
121
|
+
const npm = args.npm;
|
|
122
|
+
if (!npm?.trim())
|
|
123
|
+
return text("Package name is required.", true);
|
|
124
|
+
const data = await fetchApi("/api/verdict", { npm });
|
|
125
|
+
return text(formatVerdict(data));
|
|
130
126
|
}
|
|
131
|
-
case "
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const data = await fetchApi("/api/search", {
|
|
138
|
-
q: query,
|
|
139
|
-
limit: String(limit),
|
|
140
|
-
});
|
|
141
|
-
return text(formatSearch(data));
|
|
127
|
+
case "check_exposure": {
|
|
128
|
+
const npm = args.npm;
|
|
129
|
+
if (!npm?.trim())
|
|
130
|
+
return text("Package name is required.", true);
|
|
131
|
+
const data = await fetchApi("/api/exposure", { npm });
|
|
132
|
+
return text(formatExposure(data));
|
|
142
133
|
}
|
|
143
|
-
case "
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
134
|
+
case "check_abuse": {
|
|
135
|
+
const agent = args.agent;
|
|
136
|
+
if (!agent?.trim())
|
|
137
|
+
return text("Agent or package name is required.", true);
|
|
138
|
+
const data = await fetchApi("/api/abuse/check", { agent });
|
|
139
|
+
return text(formatAbuse(data));
|
|
148
140
|
}
|
|
149
|
-
case "
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const data = await fetchApi("/api/history", {
|
|
156
|
-
name: agentName,
|
|
157
|
-
limit: String(limit),
|
|
158
|
-
});
|
|
159
|
-
return text(formatHistory(data, agentName));
|
|
141
|
+
case "monitor_status": {
|
|
142
|
+
const npm = args.npm;
|
|
143
|
+
if (!npm?.trim())
|
|
144
|
+
return text("Package name is required.", true);
|
|
145
|
+
const data = await fetchApi("/api/monitor", { npm });
|
|
146
|
+
return text(formatMonitor(data));
|
|
160
147
|
}
|
|
161
148
|
default:
|
|
162
149
|
return text(`Unknown tool: ${name}`, true);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentscore-xyz/mcp-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"mcpName": "io.github.Thezenmonster/agentscore",
|
|
5
|
-
"description": "MCP
|
|
5
|
+
"description": "MCP security trust layer. Scan packages, get trust verdicts, check incident exposure, query abuse database. Five tools for MCP security decisions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"agentscore-mcp": "./dist/index.js"
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"prepublishOnly": "npm run build"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
19
|
+
"zod": "^3.22.0"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
21
22
|
"@types/node": "^20.0.0",
|