verifiedworkflows-mcp-server 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.
Files changed (3) hide show
  1. package/README.md +44 -0
  2. package/index.js +245 -0
  3. package/package.json +35 -0
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # @verifiedworkflows/mcp-server
2
+
3
+ MCP server for Verified Workflows — human-in-the-loop review as AI agent tools.
4
+
5
+ ## Quick start
6
+
7
+ ```bash
8
+ export VW_API_KEY="vw_live_xxx"
9
+ npx @verifiedworkflows/mcp-server
10
+ ```
11
+
12
+ ## Claude Desktop
13
+
14
+ Add to `~/.claude/claude_desktop_config.json`:
15
+
16
+ ```json
17
+ {
18
+ "mcpServers": {
19
+ "verifiedworkflows": {
20
+ "command": "npx",
21
+ "args": ["-y", "@verifiedworkflows/mcp-server"],
22
+ "env": {
23
+ "VW_API_KEY": "vw_live_xxx"
24
+ }
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## Cursor / Windsurf / Continue
31
+
32
+ Same config pattern — add the `verifiedworkflows` server to your MCP settings.
33
+
34
+ ## Tools
35
+
36
+ | Tool | Description |
37
+ |------|-------------|
38
+ | `submit_review` | Submit AI output for certified human review |
39
+ | `get_review_status` | Check task status |
40
+ | `get_review_result` | Get verified result with corrections and HMAC signature |
41
+
42
+ ## License
43
+
44
+ MIT
package/index.js ADDED
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Verified Workflows MCP Server
5
+ * ==============================
6
+ * Exposes human-in-the-loop review as MCP tools.
7
+ *
8
+ * Usage:
9
+ * export VW_API_KEY="vw_live_xxx"
10
+ * npx @verifiedworkflows/mcp-server
11
+ *
12
+ * Or in Claude Desktop config:
13
+ * "mcpServers": {
14
+ * "verifiedworkflows": {
15
+ * "command": "npx",
16
+ * "args": ["-y", "@verifiedworkflows/mcp-server"],
17
+ * "env": { "VW_API_KEY": "vw_live_xxx" }
18
+ * }
19
+ * }
20
+ */
21
+
22
+ const API_KEY = process.env.VW_API_KEY || "";
23
+ const BASE_URL = process.env.VW_BASE_URL || "https://api.verifiedworkflows.com";
24
+
25
+ const TOOLS = [
26
+ {
27
+ name: "submit_review",
28
+ description:
29
+ "Submit AI-generated content for certified human review. " +
30
+ "Use this BEFORE sending AI output to users. Returns a task ID — " +
31
+ "the verified result arrives via webhook (typically <24h).",
32
+ inputSchema: {
33
+ type: "object",
34
+ required: ["content"],
35
+ properties: {
36
+ content: { type: "string", description: "The AI-generated content to review" },
37
+ review_type: {
38
+ type: "string",
39
+ enum: ["text-qa", "medical", "code-review", "translation", "fact-check", "decision-approval", "audio-audit", "data-extraction"],
40
+ default: "text-qa",
41
+ description: "Type of review needed",
42
+ },
43
+ priority: {
44
+ type: "string",
45
+ enum: ["standard", "express"],
46
+ default: "standard",
47
+ description: "Standard (24h) or Express (1-4h, 3x cost)",
48
+ },
49
+ instructions: { type: "string", default: "", description: "What the reviewer should check" },
50
+ },
51
+ },
52
+ },
53
+ {
54
+ name: "get_review_status",
55
+ description: "Check the status of a submitted review task.",
56
+ inputSchema: {
57
+ type: "object",
58
+ required: ["task_id"],
59
+ properties: {
60
+ task_id: { type: "string", description: "Task ID (e.g. tsk_live_f8a29)" },
61
+ },
62
+ },
63
+ },
64
+ {
65
+ name: "get_review_result",
66
+ description:
67
+ "Get the verified result of a completed review, including corrections, " +
68
+ "reviewer info, and HMAC signature. Only returns data if completed.",
69
+ inputSchema: {
70
+ type: "object",
71
+ required: ["task_id"],
72
+ properties: {
73
+ task_id: { type: "string", description: "Task ID (e.g. tsk_live_f8a29)" },
74
+ },
75
+ },
76
+ },
77
+ ];
78
+
79
+ async function apiCall(method, path, body) {
80
+ const opts = {
81
+ method,
82
+ headers: {
83
+ Authorization: `Bearer ${API_KEY}`,
84
+ "Content-Type": "application/json",
85
+ },
86
+ };
87
+ if (body) opts.body = JSON.stringify(body);
88
+
89
+ const resp = await fetch(`${BASE_URL}${path}`, opts);
90
+ const text = await resp.text();
91
+
92
+ if (!resp.ok) {
93
+ throw new Error(`API error ${resp.status}: ${text}`);
94
+ }
95
+
96
+ return text ? JSON.parse(text) : {};
97
+ }
98
+
99
+ async function handleTool(name, args) {
100
+ if (!API_KEY) {
101
+ return {
102
+ content: [{
103
+ type: "text",
104
+ text: "Error: VW_API_KEY not set. Get your key at https://verifiedworkflows.com and set: export VW_API_KEY=vw_live_xxx",
105
+ }],
106
+ };
107
+ }
108
+
109
+ try {
110
+ if (name === "submit_review") {
111
+ const { content, review_type = "text-qa", priority = "standard", instructions = "" } = args;
112
+ const result = await apiCall("POST", "/v1/tasks", {
113
+ type: review_type,
114
+ priority,
115
+ title: content.length > 60 ? content.slice(0, 60) + "..." : content,
116
+ instructions: instructions || `Review this ${review_type} output for accuracy and safety.`,
117
+ payload: { content },
118
+ });
119
+
120
+ return {
121
+ content: [{
122
+ type: "text",
123
+ text: JSON.stringify({
124
+ task_id: result.id,
125
+ status: result.status || "pending",
126
+ estimated_turnaround: priority === "express" ? "1-4h" : "24h",
127
+ message: `Submitted for review. Task ID: ${result.id}.`,
128
+ }, null, 2),
129
+ }],
130
+ };
131
+ }
132
+
133
+ if (name === "get_review_status") {
134
+ const result = await apiCall("GET", `/v1/tasks/${args.task_id}`);
135
+ return {
136
+ content: [{
137
+ type: "text",
138
+ text: JSON.stringify({
139
+ task_id: result.id,
140
+ status: result.status,
141
+ age_sec: result.age_sec,
142
+ type: result.type,
143
+ has_result: result.result !== null,
144
+ }, null, 2),
145
+ }],
146
+ };
147
+ }
148
+
149
+ if (name === "get_review_result") {
150
+ const result = await apiCall("GET", `/v1/tasks/${args.task_id}`);
151
+
152
+ if (result.status !== "completed") {
153
+ return {
154
+ content: [{
155
+ type: "text",
156
+ text: `Task ${args.task_id} status: ${result.status}. Not completed yet.`,
157
+ }],
158
+ };
159
+ }
160
+
161
+ const review = result.result || {};
162
+ return {
163
+ content: [{
164
+ type: "text",
165
+ text: JSON.stringify({
166
+ task_id: result.id,
167
+ verified_body: review.body,
168
+ corrections: review.corrections || [],
169
+ reviewer_id: review.reviewer_id,
170
+ hmac_signature: review.hmac_signature,
171
+ }, null, 2),
172
+ }],
173
+ };
174
+ }
175
+
176
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }] };
177
+ } catch (e) {
178
+ return { content: [{ type: "text", text: `Error: ${e.message}` }] };
179
+ }
180
+ }
181
+
182
+ async function main() {
183
+ process.stderr.write(
184
+ API_KEY
185
+ ? "[verifiedworkflows] MCP server started\n"
186
+ : "[verifiedworkflows] WARNING: VW_API_KEY not set\n"
187
+ );
188
+
189
+ process.stdin.setEncoding("utf8");
190
+
191
+ let buffer = "";
192
+
193
+ process.stdin.on("data", (chunk) => {
194
+ buffer += chunk;
195
+
196
+ let newlineIdx;
197
+ while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
198
+ const line = buffer.slice(0, newlineIdx);
199
+ buffer = buffer.slice(newlineIdx + 1);
200
+
201
+ if (!line.trim()) continue;
202
+
203
+ try {
204
+ const msg = JSON.parse(line);
205
+ handleLine(msg);
206
+ } catch (e) {
207
+ // ignore parse errors
208
+ }
209
+ }
210
+ });
211
+
212
+ process.stdin.on("end", () => {
213
+ process.exit(0);
214
+ });
215
+
216
+ async function handleLine(msg) {
217
+ const { id, method, params } = msg;
218
+
219
+ if (method === "initialize") {
220
+ send(id, {
221
+ protocolVersion: "2024-11-05",
222
+ capabilities: { tools: {} },
223
+ serverInfo: { name: "verifiedworkflows", version: "0.1.0" },
224
+ });
225
+ } else if (method === "notifications/initialized") {
226
+ // no response needed
227
+ } else if (method === "tools/list") {
228
+ send(id, { tools: TOOLS });
229
+ } else if (method === "tools/call") {
230
+ const result = await handleTool(params.name, params.arguments || {});
231
+ send(id, { content: result.content, isError: false });
232
+ } else if (method === "ping") {
233
+ send(id, {});
234
+ }
235
+ }
236
+
237
+ function send(id, result) {
238
+ process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, result }) + "\n");
239
+ }
240
+ }
241
+
242
+ main().catch((e) => {
243
+ process.stderr.write(`[verifiedworkflows] Fatal: ${e.message}\n`);
244
+ process.exit(1);
245
+ });
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "verifiedworkflows-mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Verified Workflows — human-in-the-loop review as AI agent tools",
5
+ "license": "MIT",
6
+ "homepage": "https://verifiedworkflows.com",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/verifiedworkflows/mcp-server.git"
10
+ },
11
+ "bin": {
12
+ "verifiedworkflows-mcp": "index.js",
13
+ "vw-mcp": "index.js"
14
+ },
15
+ "files": [
16
+ "index.js",
17
+ "README.md"
18
+ ],
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "human-in-the-loop",
26
+ "ai-review",
27
+ "claude",
28
+ "cursor",
29
+ "windsurf"
30
+ ],
31
+ "author": {
32
+ "name": "Verified Workflows",
33
+ "email": "hello@verifiedworkflows.com"
34
+ }
35
+ }