@forcedream/mcp-server
Advanced tools
| import { z } from 'zod'; | ||
| const FD_API = process.env.FD_API_BASE || 'https://api.forcedream.ai'; | ||
| function authHeader() { | ||
| const key = process.env.FD_API_KEY || ''; | ||
| return key ? { Authorization: `Bearer ${key}` } : {}; | ||
| } | ||
| async function postJson(url, body) { | ||
| const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...authHeader() }, body: JSON.stringify(body) }); | ||
| let json = null; | ||
| try { | ||
| json = await res.json(); | ||
| } | ||
| catch { } | ||
| return { status: res.status, json }; | ||
| } | ||
| // --- forcedream_check_fraud --- | ||
| export const checkFraudSchema = { | ||
| ip: z.string().optional().describe('Optional IP address to check against AbuseIPDB reputation data.'), | ||
| }; | ||
| /** | ||
| * Real, direct fraud risk assessment -- a single, synchronous call, no polling. SPENDS | ||
| * your balance -- requires FD_API_KEY. Uses real AbuseIPDB reputation data when an IP is | ||
| * provided. | ||
| * @param args.ip - Optional IP address to check. | ||
| */ | ||
| export async function checkFraud(args) { | ||
| if (process.env.FD_MOCK_MODE === 'true') { | ||
| return { status: 'completed', risk_score: 0, signals: {}, verdict: 'allow', ip_reputation: { abuseipdb_score: null }, mock: true, message: 'MOCK MODE ACTIVE (FD_MOCK_MODE=true): no real balance was spent, no real AbuseIPDB lookup was made.' }; | ||
| } | ||
| if (!process.env.FD_API_KEY) { | ||
| return { status: 'error', message: 'FD_API_KEY is required (this tool spends your balance). Set it in the MCP server env.' }; | ||
| } | ||
| const res = await postJson(`${FD_API}/v1/tools/check-fraud`, { ip: args.ip || '' }); | ||
| if (res.status === 401) | ||
| return { status: 'error', message: 'Invalid FD_API_KEY (401).' }; | ||
| if (res.status === 402) | ||
| return { status: 'error', message: `Insufficient balance: ${JSON.stringify(res.json)}` }; | ||
| if (res.status !== 200 || !res.json) | ||
| return { status: 'error', message: `Request failed (HTTP ${res.status}): ${JSON.stringify(res.json)}` }; | ||
| return { status: 'completed', ...res.json }; | ||
| } | ||
| // --- forcedream_generate_embedding --- | ||
| export const generateEmbeddingSchema = { | ||
| text: z.string().describe('Text to embed (max ~32000 chars).'), | ||
| input_type: z.string().optional().describe('Optional: "query" or "document".'), | ||
| }; | ||
| /** | ||
| * Real, direct text embedding via Voyage voyage-3.5 -- a single, synchronous call, no | ||
| * polling. SPENDS your balance (per-token charge) -- requires FD_API_KEY. | ||
| * @param args.text - Text to embed. | ||
| * @param args.input_type - Optional "query" or "document". | ||
| */ | ||
| export async function generateEmbedding(args) { | ||
| if (process.env.FD_MOCK_MODE === 'true') { | ||
| return { status: 'completed', dimensions: 1024, tokens: 0, embedding: [], cost_pence: 0, mock: true, message: 'MOCK MODE ACTIVE (FD_MOCK_MODE=true): no real balance was spent, no real embedding was generated.' }; | ||
| } | ||
| if (!process.env.FD_API_KEY) { | ||
| return { status: 'error', message: 'FD_API_KEY is required (this tool spends your balance). Set it in the MCP server env.' }; | ||
| } | ||
| const res = await postJson(`${FD_API}/v1/embeddings`, { text: args.text, input_type: args.input_type }); | ||
| if (res.status === 401) | ||
| return { status: 'error', message: 'Invalid FD_API_KEY (401).' }; | ||
| if (res.status !== 200 || !res.json) | ||
| return { status: 'error', message: `Request failed (HTTP ${res.status}): ${JSON.stringify(res.json)}` }; | ||
| return { status: 'completed', ...res.json }; | ||
| } | ||
| // --- forcedream_market_quote --- | ||
| export const marketQuoteSchema = { | ||
| symbol: z.string().describe('Ticker symbol, e.g. "AAPL", "IBM".'), | ||
| }; | ||
| /** | ||
| * Real, direct, live market quote via Alpha Vantage -- a single, synchronous call, no | ||
| * polling. SPENDS your balance -- requires FD_API_KEY. Hard-cached server-side. | ||
| * @param args.symbol - Ticker symbol, e.g. "AAPL". | ||
| */ | ||
| export async function marketQuote(args) { | ||
| if (process.env.FD_MOCK_MODE === 'true') { | ||
| return { status: 'completed', symbol: args.symbol, price: 0, change_percent: 0, volume: 0, mock: true, message: 'MOCK MODE ACTIVE (FD_MOCK_MODE=true): no real balance was spent, no real market data was fetched.' }; | ||
| } | ||
| if (!process.env.FD_API_KEY) { | ||
| return { status: 'error', message: 'FD_API_KEY is required (this tool spends your balance). Set it in the MCP server env.' }; | ||
| } | ||
| const res = await postJson(`${FD_API}/v1/tools/market-quote`, { symbol: args.symbol }); | ||
| if (res.status === 401) | ||
| return { status: 'error', message: 'Invalid FD_API_KEY (401).' }; | ||
| if (res.status === 402) | ||
| return { status: 'error', message: `Insufficient balance: ${JSON.stringify(res.json)}` }; | ||
| if (res.status !== 200 || !res.json) | ||
| return { status: 'error', message: `Request failed (HTTP ${res.status}): ${JSON.stringify(res.json)}` }; | ||
| return { status: 'completed', ...res.json }; | ||
| } |
+49
-0
@@ -10,2 +10,3 @@ #!/usr/bin/env node | ||
| import { extractData, extractDataSchema } from './extract_data.js'; | ||
| import { checkFraud, checkFraudSchema, generateEmbedding, generateEmbeddingSchema, marketQuote, marketQuoteSchema } from './direct_tools.js'; | ||
| import { searchReliability, searchReliabilitySchema } from './search_reliability.js'; | ||
@@ -113,2 +114,50 @@ import { searchCosts, searchCostsSchema } from './search_costs.js'; | ||
| }); | ||
| // forcedream_check_fraud — real, direct, synchronous call (no polling). Spends balance | ||
| // (needs FD_API_KEY). Uses the new, dedicated fd_live_-accepting backend endpoint. | ||
| server.registerTool('forcedream_check_fraud', { | ||
| title: 'Check IP / account fraud risk', | ||
| description: 'Real fraud risk assessment using AbuseIPDB IP reputation data. SPENDS your balance — requires FD_API_KEY. ' + | ||
| 'Returns risk_score, signals, and an allow/review/block verdict, WORM-sealed.', | ||
| inputSchema: checkFraudSchema, | ||
| }, async ({ ip }) => { | ||
| try { | ||
| const result = await checkFraud({ ip }); | ||
| return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; | ||
| } | ||
| catch (e) { | ||
| return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: e.message }, null, 2) }], isError: true }; | ||
| } | ||
| }); | ||
| // forcedream_generate_embedding — real, direct, synchronous call (no polling). Spends | ||
| // balance (needs FD_API_KEY, per-token charge). | ||
| server.registerTool('forcedream_generate_embedding', { | ||
| title: 'Generate a text embedding', | ||
| description: 'Real 1024-dim vector embedding via Voyage voyage-3.5, retrieval-optimised. SPENDS your balance ' + | ||
| '(per-token charge) — requires FD_API_KEY. Returns the vector, dimensions, token count, WORM-sealed.', | ||
| inputSchema: generateEmbeddingSchema, | ||
| }, async ({ text, input_type }) => { | ||
| try { | ||
| const result = await generateEmbedding({ text, input_type }); | ||
| return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; | ||
| } | ||
| catch (e) { | ||
| return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: e.message }, null, 2) }], isError: true }; | ||
| } | ||
| }); | ||
| // forcedream_market_quote — real, direct, synchronous call (no polling). Spends balance | ||
| // (needs FD_API_KEY). Hard-cached server-side. | ||
| server.registerTool('forcedream_market_quote', { | ||
| title: 'Get a live market quote', | ||
| description: 'Real, live market quote for a stock symbol via Alpha Vantage: price, change %, volume, day high/low, ' + | ||
| 'liquidity score. SPENDS your balance — requires FD_API_KEY. Hard-cached, WORM-sealed.', | ||
| inputSchema: marketQuoteSchema, | ||
| }, async ({ symbol }) => { | ||
| try { | ||
| const result = await marketQuote({ symbol }); | ||
| return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; | ||
| } | ||
| catch (e) { | ||
| return { content: [{ type: 'text', text: JSON.stringify({ status: 'error', error: e.message }, null, 2) }], isError: true }; | ||
| } | ||
| }); | ||
| // forcedream_search_reliability — keyless. Real, system-measured reliability per agent. | ||
@@ -115,0 +164,0 @@ server.registerTool('forcedream_search_reliability', { |
+1
-1
| { | ||
| "name": "@forcedream/mcp-server", | ||
| "version": "0.7.0", | ||
| "version": "0.8.0", | ||
| "mcpName": "io.github.forcedreamai/mcp-server", | ||
@@ -5,0 +5,0 @@ "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.", |
69745
12.07%17
6.25%947
17.35%27
42.11%12
9.09%