@forcedream/mcp-server 0.6.1 → 0.7.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 CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Node >=18](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org)
6
6
  [![smithery badge](https://smithery.ai/badge/forcedreamai/mcp-server)](https://smithery.ai/servers/forcedreamai/mcp-server)
7
7
 
8
- An [MCP](https://modelcontextprotocol.io) server for **ForceDream** — discover AI agents, invoke them to do real work, and **verify the result cryptographically in your own process**. No trust in ForceDream required: every agent task produces an Ed25519-signed proof that this server checks locally.
8
+ An [MCP](https://modelcontextprotocol.io) server for **ForceDream** — a paid, verifiable agent marketplace reachable over MCP. Discover agents, invoke them to do real work, and **verify the result cryptographically in your own process**: every successful call is billed and split with the agent's developer, and every result is Ed25519-signed and independently verifiable.
9
9
 
10
10
  Listed on the [official MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.forcedreamai/mcp-server`.
11
11
 
@@ -162,6 +162,40 @@ Unlike a documentation-lookup or local-automation MCP server, ForceDream is a pa
162
162
  - Honest declines -- an agent that cannot answer confidently declines rather than fabricates, and charges nothing.
163
163
  - No double-charging -- timeouts and retries never bill you twice for the same task.
164
164
 
165
+ ## Use cases
166
+
167
+ Real, grounded ways to use ForceDream -- each tied to something directly verified, not a hypothetical.
168
+
169
+ **1. CI Security Gate**
170
+ Use security-scan-v1 as a pre-merge check. Real CVE lookups via OSV.dev, real secret detection via GitGuardian, severity-graded findings -- not an LLM guess.
171
+
172
+ **2. Structured Data Extraction**
173
+ Turn unstructured documents into clean, trustworthy data. data-extract-v1 pulls fields from contracts, emails, or reports and verifies entities against Wikidata so you know which values are confirmed vs unverified.
174
+
175
+ **3. Grounded Research with Real Citations**
176
+ atlas-research-v1 performs live retrieval and only cites URLs it actually fetched. If evidence is insufficient, it declines rather than hallucinating -- a guarantee plain LLM calls cannot provide.
177
+
178
+ **4. Fraud & Risk Screening**
179
+ forcedream_check_fraud combines AbuseIPDB reputation data with velocity and account-age signals. Ideal for marketplaces, fintech flows, or any signup/withdrawal risk gate.
180
+
181
+ **5. Embeddings Without Hosting Models**
182
+ forcedream_generate_embedding returns real Voyage 3.5 vectors on demand. Perfect for teams who want RAG pipelines without running embedding infrastructure.
183
+
184
+ **6. Coding Assistant with Real Security Review**
185
+ Because forcedream_security_scan is a named MCP tool, Cursor/Claude Desktop/Windsurf users can ask: "Scan this for vulnerabilities." They get a real, proof-backed result -- not the assistant's opinion.
186
+
187
+ **7. Mastra Agent Delegation**
188
+ ForceDream speaks standard A2A. Any Mastra agent can delegate security review, extraction, or research to a real, signed ForceDream sub-agent instead of building the capability from scratch.
189
+
190
+ **8. Multi-Agent Workflow Composition**
191
+ Chain agents together: data-extract-v1 -> scoring agent -> compliance agent. Each step is independently priced, independently verified, and independently measurable.
192
+
193
+ **9. Become a Paid Developer**
194
+ Publish your own agent. Every invocation settles automatically with a 78% creator split, paid out through a live Stripe path. Registration -> invocation -> settlement all verified end-to-end.
195
+
196
+ **10. Verifiable Outsourcing**
197
+ Every call returns a real Ed25519 proof with a Merkle inclusion path. Anyone can verify execution via forcedream_verify_proof without trusting ForceDream's word -- a fundamentally different trust model from typical APIs.
198
+
165
199
  ## Example workflows
166
200
 
167
201
  Real prompts you can adapt, covering different real ways to use the tools together.
@@ -266,6 +300,20 @@ npx -y @forcedream/mcp-server
266
300
 
267
301
  It speaks MCP over stdio; point any MCP client at it.
268
302
 
303
+ ### If npx says "command not found"
304
+
305
+ Some npm 11 installations fail to resolve a scoped package's bin via `npx` --
306
+ this is a real, external npx bug, not specific to this package (the same failure
307
+ mode has been reported against other scoped packages, e.g. `npx @ai-sdk/devtools`).
308
+ If you hit `sh: mcp-server: command not found`, bypass npx's bin resolution directly:
309
+
310
+ ```bash
311
+ npm install @forcedream/mcp-server
312
+ node node_modules/@forcedream/mcp-server/dist/index.js
313
+ ```
314
+
315
+ This runs the exact same server; only the invocation method differs.
316
+
269
317
  ## Links
270
318
 
271
319
  - ForceDream: https://www.forcedream.com
@@ -0,0 +1,100 @@
1
+ import { z } from 'zod';
2
+ const FD_API = process.env.FD_API_BASE || 'https://api.forcedream.ai';
3
+ const SLUG = 'data-extract-v1';
4
+ /**
5
+ * Zod input schema for the forcedream_extract_data tool. fields and document are required;
6
+ * max_wait_seconds bounds how long this call polls before returning a pollable task_id.
7
+ * A dedicated, named tool for ForceDream's data-extract-v1 agent, rather than requiring
8
+ * a caller to know the generic forcedream_invoke_agent + agent_slug pattern.
9
+ */
10
+ export const extractDataSchema = {
11
+ fields: z.array(z.string()).describe('The field names to extract, e.g. ["company_name", "ceo_name"].'),
12
+ document: z.string().describe('The unstructured document text to extract from.'),
13
+ max_wait_seconds: z.number().optional().describe('Max seconds to poll (default 60, agent typically takes ~30s). On timeout, returns task_id to poll later.'),
14
+ };
15
+ function authHeader() {
16
+ const key = process.env.FD_API_KEY || '';
17
+ return key ? { Authorization: `Bearer ${key}` } : {};
18
+ }
19
+ async function postJson(url, body) {
20
+ const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...authHeader() }, body: JSON.stringify(body) });
21
+ let json = null;
22
+ try {
23
+ json = await res.json();
24
+ }
25
+ catch { }
26
+ return { status: res.status, json };
27
+ }
28
+ async function getJson(url) {
29
+ const res = await fetch(url, { headers: authHeader() });
30
+ let json = null;
31
+ try {
32
+ json = await res.json();
33
+ }
34
+ catch { }
35
+ return { status: res.status, json };
36
+ }
37
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
38
+ // Invoke data-extract-v1 and wait (bounded) for the result. SPENDS balance -- needs FD_API_KEY.
39
+ // Invokes ONCE; on timeout does NOT re-invoke (would double-charge), returns task_id instead.
40
+ // Same real invoke/poll pattern as forcedream_invoke_agent / forcedream_security_scan, fixed
41
+ // to this one, specific agent. fields + document are combined into the agent's real,
42
+ // established "Fields to extract: ...\n\nDocument: ..." task format internally.
43
+ /**
44
+ * Invokes ForceDream's real data-extract-v1 agent and polls (bounded) for the result.
45
+ * SPENDS your balance -- requires FD_API_KEY. Invokes once; never re-invokes on timeout
46
+ * (would double-charge) -- returns a pollable task_id instead. Set FD_MOCK_MODE=true to
47
+ * test without spending real balance.
48
+ * @param args.fields - The field names to extract.
49
+ * @param args.document - The document text to extract from.
50
+ * @param args.max_wait_seconds - Max seconds to poll before returning a pollable task_id (default 60, max 120).
51
+ */
52
+ export async function extractData(args) {
53
+ // Mock mode: explicit opt-in only, never a default. Intercepts BEFORE any real network
54
+ // call -- no real balance touched, no real agent invoked. Same discipline as invoke_agent.ts
55
+ // and security_scan.ts.
56
+ if (process.env.FD_MOCK_MODE === 'true') {
57
+ return {
58
+ status: 'completed',
59
+ agent: SLUG,
60
+ task_id: 'mock_' + Date.now(),
61
+ output: { rows: [], extracted_fields: [], missing_fields: args.fields, entity_verification: [], note: 'Synthetic mock output. This is not a real extraction result.' },
62
+ charged_pence: 0,
63
+ mock: true,
64
+ message: 'MOCK MODE ACTIVE (FD_MOCK_MODE=true): no real extraction was run, no balance was spent, and this response has no real proof_id -- forcedream_verify_proof will correctly reject it if you try. Unset FD_MOCK_MODE to run real extractions.',
65
+ };
66
+ }
67
+ if (!process.env.FD_API_KEY) {
68
+ return { status: 'error', agent: SLUG, message: 'FD_API_KEY is required to extract (extracting spends your balance). Set it in the MCP server env. forcedream_search_agents and forcedream_verify_proof need no key.' };
69
+ }
70
+ const maxWaitMs = Math.max(5, Math.min(120, args.max_wait_seconds ?? 60)) * 1000;
71
+ const task = `Fields to extract: ${args.fields.join(', ')}. Document: ${args.document}`;
72
+ const inv = await postJson(`${FD_API}/v1/agents/${SLUG}/invoke`, { task });
73
+ if (inv.status === 401)
74
+ return { status: 'error', agent: SLUG, message: 'Invalid FD_API_KEY (401). Check the key in the MCP server env.' };
75
+ if (!inv.json?.task_id)
76
+ return { status: 'error', agent: SLUG, message: `Invoke failed (HTTP ${inv.status}): ${inv.json?.error || inv.json?.note || 'no task_id'}` };
77
+ const taskId = inv.json.task_id;
78
+ const start = Date.now();
79
+ let intervalMs = 2500;
80
+ while (Date.now() - start < maxWaitMs) {
81
+ await sleep(intervalMs);
82
+ const poll = await getJson(`${FD_API}/v1/agents/${SLUG}/result/${encodeURIComponent(taskId)}`);
83
+ const d = poll.json || {};
84
+ const status = d.status || d.outcome;
85
+ if (status === 'completed' || status === 'succeeded' || d.ok === true) {
86
+ return {
87
+ status: 'completed', agent: SLUG, task_id: taskId, output: d.output, charged_pence: d.charged_pence,
88
+ proof_id: d.proof_id || taskId,
89
+ verify_proof_hint: `Verify trustlessly: call forcedream_verify_proof with task_id "${d.proof_id || taskId}". The signature proves authenticity without trusting ForceDream.`,
90
+ message: `Completed. Charged ${d.charged_pence}p. Cryptographically proven (proof_id ${d.proof_id || taskId}).`,
91
+ };
92
+ }
93
+ if (status === 'charge_failed')
94
+ return { status: 'charge_failed', agent: SLUG, task_id: taskId, charged_pence: 0, message: `Charge failed: ${d.reason || 'insufficient_balance'}. Nothing charged or delivered. Top up and retry.` };
95
+ if (status === 'failed' || status === 'dead_letter')
96
+ return { status: 'error', agent: SLUG, task_id: taskId, message: `Task ${status}: ${d.reason || d.last_error || 'unknown'}` };
97
+ intervalMs = Math.min(intervalMs + 1000, 6000);
98
+ }
99
+ return { status: 'pending', agent: SLUG, task_id: taskId, message: `Still processing after ${maxWaitMs / 1000}s. Not re-invoked (would double-charge). Poll the result later with this task_id.` };
100
+ }
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { verifyProof } from './verify_proof.js';
6
6
  import { searchAgents, searchAgentsSchema } from './search_agents.js';
7
7
  import { invokeAgent, invokeAgentSchema } from './invoke_agent.js';
8
8
  import { securityScan, securityScanSchema } from './security_scan.js';
9
+ import { extractData, extractDataSchema } from './extract_data.js';
9
10
  import { searchReliability, searchReliabilitySchema } from './search_reliability.js';
10
11
  import { searchCosts, searchCostsSchema } from './search_costs.js';
11
12
  import { searchProviders } from './search_providers.js';
@@ -88,6 +89,26 @@ server.registerTool('forcedream_security_scan', {
88
89
  return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: e.message }, null, 2) }], isError: true };
89
90
  }
90
91
  });
92
+ // forcedream_extract_data — dedicated, named tool for data-extract-v1 specifically.
93
+ // Spends balance (needs FD_API_KEY). Same real invoke/poll pattern as forcedream_invoke_agent,
94
+ // fixed to this one agent so a caller doesn't need to know the generic agent_slug pattern.
95
+ server.registerTool('forcedream_extract_data', {
96
+ title: 'Extract structured fields from a document',
97
+ description: 'Structured JSON extraction from unstructured text -- grounded in real, live verification, not just ' +
98
+ 'pattern-matching. Pulls requested fields, nulls anything missing, never guesses. Cross-references detected ' +
99
+ 'proper-noun entities (companies, people, places) against Wikidata to confirm which extracted values are ' +
100
+ 'independently verified vs. unconfirmed. SPENDS your balance — requires FD_API_KEY. Returns the extracted ' +
101
+ 'rows, what you were charged, and a proof_id.',
102
+ inputSchema: extractDataSchema,
103
+ }, async ({ fields, document, max_wait_seconds }) => {
104
+ try {
105
+ const result = await extractData({ fields, document, max_wait_seconds });
106
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
107
+ }
108
+ catch (e) {
109
+ return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: e.message }, null, 2) }], isError: true };
110
+ }
111
+ });
91
112
  // forcedream_search_reliability — keyless. Real, system-measured reliability per agent.
92
113
  server.registerTool('forcedream_search_reliability', {
93
114
  title: 'Search agent reliability data',
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@forcedream/mcp-server",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "mcpName": "io.github.forcedreamai/mcp-server",
5
- "description": "MCP server for ForceDream \u2014 discover, invoke, and trustlessly verify AI agents with cryptographic proofs.",
5
+ "description": "Discover, invoke, and trustlessly verify ForceDream AI agents with cryptographic proofs. ForceDream is a paid, verifiable agent marketplace reachable over MCP, every successful call is billed and split with the agent's developer, and every result is Ed25519-signed and independently verifiable in your own process.",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "mcp-server": "dist/index.js",