structdoc-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 +33 -0
- package/index.mjs +115 -0
- package/package.json +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# structdoc-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for **StructDoc** — turn any document (PDF/image) into structured data for AI agents. OCR, layout-to-Markdown, tables, key-value pairs, invoice/receipt fields. 100+ languages. Pay per call with x402 (USDC on Base/Solana) — no API keys.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
claude mcp add structdoc -e EVM_PRIVATE_KEY=0x<base-wallet-with-usdc> -- npx -y structdoc-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or configure any MCP client to run `npx -y structdoc-mcp` with env:
|
|
12
|
+
|
|
13
|
+
- `EVM_PRIVATE_KEY` — Base wallet private key holding USDC, **and/or**
|
|
14
|
+
- `SVM_PRIVATE_KEY` — Solana wallet private key (base58) holding USDC
|
|
15
|
+
- `STRUCTDOC_BASE_URL` (optional) — default `https://structdoc-api.hp-vladic.workers.dev`
|
|
16
|
+
|
|
17
|
+
## Tools
|
|
18
|
+
|
|
19
|
+
| Tool | Does | Price |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `document_to_markdown` | Layout → Markdown (headings, tables, key-value). RAG-ready. ≤20p | $0.25 |
|
|
22
|
+
| `document_ocr` | OCR full-text, 100+ languages. ≤25p | $0.05 |
|
|
23
|
+
| `extract_invoice` | Invoice fields (vendor, items, totals). ≤4p | $0.08 |
|
|
24
|
+
| `extract_receipt` | Receipt fields (merchant, date, total). ≤2p | $0.04 |
|
|
25
|
+
| `document_ocr_large` | OCR up to 100 pages | $0.20 |
|
|
26
|
+
| `document_to_markdown_large` | Markdown up to 100 pages | $1.10 |
|
|
27
|
+
| `structdoc_catalog` | Free machine-readable catalog | free |
|
|
28
|
+
|
|
29
|
+
Each tool takes `{ url }` or `{ base64 }` (PDF/JPEG/PNG/BMP/TIFF/HEIF).
|
|
30
|
+
|
|
31
|
+
Engine: Azure Document Intelligence v4.0. API: https://structdoc-api.hp-vladic.workers.dev
|
|
32
|
+
|
|
33
|
+
MIT
|
package/index.mjs
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// StructDoc MCP — turn any document into structured data for AI agents, paid per call via x402.
|
|
3
|
+
//
|
|
4
|
+
// Env (at least one):
|
|
5
|
+
// EVM_PRIVATE_KEY Base wallet private key holding USDC (0x...)
|
|
6
|
+
// SVM_PRIVATE_KEY Solana wallet private key holding USDC (base58)
|
|
7
|
+
// Optional:
|
|
8
|
+
// EVM_RPC_URL Base RPC, default https://mainnet.base.org
|
|
9
|
+
// STRUCTDOC_BASE_URL API base, default https://structdoc-api.hp-vladic.workers.dev
|
|
10
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
11
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { x402Client, wrapFetchWithPayment } from '@x402/fetch';
|
|
14
|
+
|
|
15
|
+
const BASE = (process.env.STRUCTDOC_BASE_URL ?? 'https://structdoc-api.hp-vladic.workers.dev').replace(/\/+$/, '');
|
|
16
|
+
const RPC = process.env.EVM_RPC_URL ?? 'https://mainnet.base.org';
|
|
17
|
+
|
|
18
|
+
let payingFetch = null;
|
|
19
|
+
async function getFetch() {
|
|
20
|
+
if (payingFetch) return payingFetch;
|
|
21
|
+
const evmKey = process.env.EVM_PRIVATE_KEY;
|
|
22
|
+
const svmKey = process.env.SVM_PRIVATE_KEY;
|
|
23
|
+
if (!evmKey && !svmKey) {
|
|
24
|
+
throw new Error('Set EVM_PRIVATE_KEY (Base) and/or SVM_PRIVATE_KEY (Solana) — a wallet holding USDC to pay per call ($0.04-$1.10).');
|
|
25
|
+
}
|
|
26
|
+
const client = new x402Client();
|
|
27
|
+
if (evmKey) {
|
|
28
|
+
const { ExactEvmScheme } = await import('@x402/evm/exact/client');
|
|
29
|
+
const { privateKeyToAccount } = await import('viem/accounts');
|
|
30
|
+
client.register('eip155:*', new ExactEvmScheme(privateKeyToAccount(evmKey.startsWith('0x') ? evmKey : `0x${evmKey}`), { rpcUrl: RPC }));
|
|
31
|
+
}
|
|
32
|
+
if (svmKey) {
|
|
33
|
+
const { ExactSvmScheme } = await import('@x402/svm/exact/client');
|
|
34
|
+
const { createKeyPairSignerFromBytes } = await import('@solana/kit');
|
|
35
|
+
const { base58 } = await import('@scure/base');
|
|
36
|
+
client.register('solana:*', new ExactSvmScheme(await createKeyPairSignerFromBytes(base58.decode(svmKey))));
|
|
37
|
+
}
|
|
38
|
+
payingFetch = wrapFetchWithPayment(fetch, client);
|
|
39
|
+
return payingFetch;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function post(path, payload) {
|
|
43
|
+
const f = await getFetch();
|
|
44
|
+
const res = await f(`${BASE}${path}`, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
body: JSON.stringify(payload),
|
|
48
|
+
});
|
|
49
|
+
const text = await res.text();
|
|
50
|
+
if (!res.ok) throw new Error(`API ${res.status}: ${text.slice(0, 300)}`);
|
|
51
|
+
return text;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const asResult = text => ({ content: [{ type: 'text', text }] });
|
|
55
|
+
const asError = e => ({ content: [{ type: 'text', text: `Error: ${String(e.message ?? e)}` }], isError: true });
|
|
56
|
+
|
|
57
|
+
// url または base64 のどちらか必須の共通入力
|
|
58
|
+
const docInput = {
|
|
59
|
+
url: z.string().optional().describe('URL of the document (PDF/JPEG/PNG/BMP/TIFF/HEIF)'),
|
|
60
|
+
base64: z.string().optional().describe('Base64-encoded document bytes (≤~6MB; use url for larger)'),
|
|
61
|
+
};
|
|
62
|
+
const pick = a => ({ url: a.url, base64: a.base64 });
|
|
63
|
+
|
|
64
|
+
const server = new McpServer({ name: 'structdoc', version: '0.1.0' });
|
|
65
|
+
|
|
66
|
+
server.tool(
|
|
67
|
+
'document_to_markdown',
|
|
68
|
+
'Convert any document (PDF/image) into agent-friendly MARKDOWN — headings, paragraphs, tables, key-value pairs. Best tool for feeding documents into an LLM or RAG pipeline. 100+ languages. Up to 20 pages (use document_to_markdown_large for more). Cost: $0.25 (x402/USDC).',
|
|
69
|
+
{ ...docInput, features: z.string().optional().describe('Optional add-ons: comma-separated from languages,barcodes,keyValuePairs'), queryFields: z.string().optional().describe('Optional custom fields to extract, comma-separated (≤8)') },
|
|
70
|
+
async a => { try { return asResult(await post('/layout', { ...pick(a), features: a.features, queryFields: a.queryFields })); } catch (e) { return asError(e); } },
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
server.tool(
|
|
74
|
+
'document_ocr',
|
|
75
|
+
'OCR full-text extraction from a PDF or image in 100+ languages. Returns plain text content. Up to 25 pages. Cost: $0.05 (x402/USDC).',
|
|
76
|
+
{ ...docInput, features: z.string().optional().describe('Optional: languages,barcodes') },
|
|
77
|
+
async a => { try { return asResult(await post('/read', { ...pick(a), features: a.features })); } catch (e) { return asError(e); } },
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
server.tool(
|
|
81
|
+
'extract_invoice',
|
|
82
|
+
'Extract structured invoice fields from a PDF/image invoice: vendor, customer, invoice id/date, line items, subtotal, tax, total, currency. Up to 4 pages. Cost: $0.08 (x402/USDC).',
|
|
83
|
+
{ ...docInput, queryFields: z.string().optional().describe('Optional custom fields to extract, comma-separated (≤8)') },
|
|
84
|
+
async a => { try { return asResult(await post('/invoice', { ...pick(a), queryFields: a.queryFields })); } catch (e) { return asError(e); } },
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
server.tool(
|
|
88
|
+
'extract_receipt',
|
|
89
|
+
'Extract structured receipt fields from a receipt image/PDF: merchant, date/time, line items, subtotal, tax, tip, total, currency. Up to 2 pages. Cost: $0.04 (x402/USDC).',
|
|
90
|
+
{ ...docInput },
|
|
91
|
+
async a => { try { return asResult(await post('/receipt', pick(a))); } catch (e) { return asError(e); } },
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
server.tool(
|
|
95
|
+
'document_ocr_large',
|
|
96
|
+
'OCR full-text extraction for large documents — up to 100 pages. Cost: $0.20 (x402/USDC).',
|
|
97
|
+
{ ...docInput, features: z.string().optional() },
|
|
98
|
+
async a => { try { return asResult(await post('/read-large', { ...pick(a), features: a.features })); } catch (e) { return asError(e); } },
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
server.tool(
|
|
102
|
+
'document_to_markdown_large',
|
|
103
|
+
'Convert a large document (up to 100 pages) into Markdown for LLM/RAG use. Cost: $1.10 (x402/USDC).',
|
|
104
|
+
{ ...docInput, features: z.string().optional() },
|
|
105
|
+
async a => { try { return asResult(await post('/layout-large', { ...pick(a), features: a.features })); } catch (e) { return asError(e); } },
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
server.tool(
|
|
109
|
+
'structdoc_catalog',
|
|
110
|
+
'Free: machine-readable catalog of StructDoc (endpoints, prices, supported formats). No payment required.',
|
|
111
|
+
{},
|
|
112
|
+
async () => { try { const r = await fetch(`${BASE}/catalog`); return asResult(await r.text()); } catch (e) { return asError(e); } },
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
await server.connect(new StdioServerTransport());
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "structdoc-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for StructDoc — turn any document (PDF/image) into structured data for AI agents: OCR, layout-to-Markdown, tables, invoice/receipt fields. Pays per call via x402 (USDC on Base/Solana) — no API keys.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": { "structdoc-mcp": "index.mjs" },
|
|
7
|
+
"files": ["index.mjs", "README.md"],
|
|
8
|
+
"keywords": ["mcp", "x402", "document", "ocr", "pdf", "layout", "markdown", "rag", "invoice", "receipt", "modelcontextprotocol"],
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"homepage": "https://structdoc-api.hp-vladic.workers.dev",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
13
|
+
"@scure/base": "^2.2.0",
|
|
14
|
+
"@solana/kit": "^5.5.1",
|
|
15
|
+
"@x402/evm": "^2.18.0",
|
|
16
|
+
"@x402/fetch": "^2.18.0",
|
|
17
|
+
"@x402/svm": "^2.19.0",
|
|
18
|
+
"viem": "^2.21.26",
|
|
19
|
+
"zod": "^3.24.2"
|
|
20
|
+
}
|
|
21
|
+
}
|