@verify-api/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/README.md +59 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +116 -0
- package/dist/server.js.map +1 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# VerifyAPI MCP server
|
|
2
|
+
|
|
3
|
+
A tiny stdio Model Context Protocol server that wraps the VerifyAPI REST endpoints. Install it into any MCP-capable client (Claude Desktop, Cursor, Windsurf, VS Code with the MCP extension, ChatGPT Desktop, custom agents built on the MCP SDKs) and the model gets one tool:
|
|
4
|
+
|
|
5
|
+
- **`verify_claim`** — check a factual claim, get back `{verdict, confidence, source_url, exact_quote, published_date}`.
|
|
6
|
+
|
|
7
|
+
The server is a thin adapter: your API key lives in the client's env, one HTTPS call per invocation, no state. Because it is the same account and same billing surface as REST callers, every MCP verification counts toward the same balance and idempotency semantics.
|
|
8
|
+
|
|
9
|
+
## Install (Claude Desktop, Cursor, Windsurf)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g @verify-api/mcp # (once published; for now, npm link from this dir)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Add to your MCP client config (e.g. `~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"verifyapi": {
|
|
21
|
+
"command": "verifyapi-mcp",
|
|
22
|
+
"env": {
|
|
23
|
+
"VERIFYAPI_API_KEY": "csk_live_...",
|
|
24
|
+
"VERIFYAPI_BASE_URL": "https://api.verify-api.dev"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Restart the client. The `verify_claim` tool now shows up in the model's tool list.
|
|
32
|
+
|
|
33
|
+
## Run from source (during development)
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cd mcp
|
|
37
|
+
npm install
|
|
38
|
+
npm run build
|
|
39
|
+
VERIFYAPI_API_KEY=csk_test_... VERIFYAPI_BASE_URL=http://localhost:8080 node dist/server.js
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then in your MCP client config point `command` at that `node dist/server.js` path.
|
|
43
|
+
|
|
44
|
+
## What the model sees
|
|
45
|
+
|
|
46
|
+
Tool name: `verify_claim`
|
|
47
|
+
Tool description:
|
|
48
|
+
> Verify a single factual claim against live web sources. Returns one of `supported`, `refuted`, `insufficient_evidence`, or `out_of_scope`, with confidence, a source URL, and a verbatim quote. Costs $0.02 per successful verification (unsupported/refuted); free otherwise. Use this when you need to check a specific fact before acting on it.
|
|
49
|
+
|
|
50
|
+
Input schema:
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"claim": "string (a single factual claim, ideally < 300 chars)",
|
|
54
|
+
"as_of": "string (ISO date, optional — for time-sensitive facts)",
|
|
55
|
+
"max_wait_ms": "number (optional, default 15000)"
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Return value: the JSON body of `POST /v1/verify`, unmodified.
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// VerifyAPI MCP server (stdio transport).
|
|
3
|
+
//
|
|
4
|
+
// One tool: verify_claim. Stateless HTTPS wrapper over POST /v1/verify.
|
|
5
|
+
// The user's API key is read from env; every call is billed to that account.
|
|
6
|
+
// Because the MCP surface has no per-tool auth of its own, all we can do at
|
|
7
|
+
// this layer is pass through the caller's key — no key, no tool.
|
|
8
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
9
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
11
|
+
import { randomUUID } from "node:crypto";
|
|
12
|
+
const API_KEY = process.env.VERIFYAPI_API_KEY;
|
|
13
|
+
const BASE_URL = process.env.VERIFYAPI_BASE_URL?.replace(/\/$/, "") ?? "https://api.verify-api.dev";
|
|
14
|
+
const DEFAULT_TIMEOUT_MS = 20_000;
|
|
15
|
+
if (!API_KEY) {
|
|
16
|
+
// Write to stderr so the MCP client shows it in the connection error.
|
|
17
|
+
process.stderr.write("verifyapi-mcp: VERIFYAPI_API_KEY is not set. Add it to the mcpServers env block.\n");
|
|
18
|
+
process.exit(2);
|
|
19
|
+
}
|
|
20
|
+
const TOOLS = [
|
|
21
|
+
{
|
|
22
|
+
name: "verify_claim",
|
|
23
|
+
description: "Verify a single factual claim against live web sources. Returns one of `supported`, `refuted`, `insufficient_evidence`, or `out_of_scope`, with confidence, a source URL, published date, and a verbatim quote drawn from that source. Costs $0.02 per successful verification (supported/refuted); insufficient_evidence, out_of_scope, and malformed are free. Use this before acting on a specific fact you are not sure about.",
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: {
|
|
27
|
+
claim: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description: "A single factual claim, ideally under 300 characters. If you have multiple claims, call verify_claim once per claim.",
|
|
30
|
+
},
|
|
31
|
+
as_of: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Optional ISO date (YYYY-MM-DD). Use for time-sensitive facts, e.g. prices or standings.",
|
|
34
|
+
},
|
|
35
|
+
max_wait_ms: {
|
|
36
|
+
type: "number",
|
|
37
|
+
description: "Optional soft deadline in milliseconds. Default 15000. If the pipeline cannot finish in time you'll get insufficient_evidence.",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
required: ["claim"],
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
const server = new Server({ name: "verifyapi-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
46
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
47
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
48
|
+
if (req.params.name !== "verify_claim") {
|
|
49
|
+
return {
|
|
50
|
+
isError: true,
|
|
51
|
+
content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const args = (req.params.arguments ?? {});
|
|
55
|
+
const claim = typeof args.claim === "string" ? args.claim.trim() : "";
|
|
56
|
+
if (!claim) {
|
|
57
|
+
return {
|
|
58
|
+
isError: true,
|
|
59
|
+
content: [{ type: "text", text: "verify_claim requires a non-empty `claim` string." }],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const body = { claim };
|
|
63
|
+
if (typeof args.as_of === "string" && args.as_of.length > 0)
|
|
64
|
+
body.as_of = args.as_of;
|
|
65
|
+
if (typeof args.max_wait_ms === "number" && args.max_wait_ms > 0)
|
|
66
|
+
body.max_wait_ms = Math.min(args.max_wait_ms, 30_000);
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
const timeout = setTimeout(() => controller.abort(), (Number(body.max_wait_ms) || DEFAULT_TIMEOUT_MS) + 5_000);
|
|
69
|
+
try {
|
|
70
|
+
const resp = await fetch(`${BASE_URL}/v1/verify`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
signal: controller.signal,
|
|
73
|
+
headers: {
|
|
74
|
+
"content-type": "application/json",
|
|
75
|
+
authorization: `Bearer ${API_KEY}`,
|
|
76
|
+
"idempotency-key": randomUUID(),
|
|
77
|
+
"user-agent": "verifyapi-mcp/0.1.0",
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify(body),
|
|
80
|
+
});
|
|
81
|
+
const text = await resp.text();
|
|
82
|
+
let parsed;
|
|
83
|
+
try {
|
|
84
|
+
parsed = JSON.parse(text);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
parsed = { raw: text };
|
|
88
|
+
}
|
|
89
|
+
if (!resp.ok) {
|
|
90
|
+
return {
|
|
91
|
+
isError: true,
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: "text",
|
|
95
|
+
text: `verifyapi ${resp.status}: ${JSON.stringify(parsed)}`,
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: JSON.stringify(parsed, null, 2) }],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
106
|
+
return {
|
|
107
|
+
isError: true,
|
|
108
|
+
content: [{ type: "text", text: `verifyapi request failed: ${msg}` }],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
await server.connect(new StdioServerTransport());
|
|
116
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@verify-api/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for VerifyAPI — one tool: verify_claim.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"verifyapi-mcp": "dist/server.js"
|
|
8
|
+
},
|
|
9
|
+
"files": ["dist"],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc -p tsconfig.json",
|
|
12
|
+
"start": "node dist/server.js",
|
|
13
|
+
"dev": "tsx watch src/server.ts"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
17
|
+
"zod": "^3.23.8"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^22.7.5",
|
|
21
|
+
"tsx": "^4.19.1",
|
|
22
|
+
"typescript": "^5.6.3"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20"
|
|
26
|
+
}
|
|
27
|
+
}
|