opedd-mcp 0.6.16 → 0.8.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 +4 -3
- package/dist/index.js +77 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ Prefer zero-install? The same 17 tools are served hosted at **`https://mcp.opedd
|
|
|
78
78
|
}
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
Key routing: `opedd_pub_*` → publisher tools · `opedd_buyer_*` → content retrieval · `ent_*` → bulk feeds · buyer-portal JWT → audit/compliance/EU-AI-Act tools. Your key is forwarded per request and never stored by the gateway.
|
|
81
|
+
Key routing: `opedd_sk_*` (legacy `opedd_pub_*`) → publisher tools · `opedd_buyer_*` → content retrieval · `ent_*` → bulk feeds · buyer-portal JWT → audit/compliance/EU-AI-Act tools. Your key is forwarded per request and never stored by the gateway.
|
|
82
82
|
|
|
83
83
|
## What it does
|
|
84
84
|
|
|
@@ -88,6 +88,7 @@ Exposes up to 17 tools to any AI assistant (some are conditional on env vars):
|
|
|
88
88
|
|
|
89
89
|
| Tool | Description |
|
|
90
90
|
|------|-------------|
|
|
91
|
+
| `search_content` | Full-text search across everything licensable (v0.8.0) — ranked matches with publisher, prices, word count and a description snippet; quotes for phrases, `-word` to exclude |
|
|
91
92
|
| `lookup_content` | Look up an article by URL — returns title, publisher, pricing |
|
|
92
93
|
| `purchase_license` | Buy a single-article license via Stripe — returns OP-XXXX-XXXX key. Requires `terms_accepted: true` (genuine buyer assent to opedd.com/terms; recorded with the licence) |
|
|
93
94
|
| `verify_license` | Verify a license key — returns validity, article, publisher, blockchain proof |
|
|
@@ -119,7 +120,7 @@ Exposes up to 17 tools to any AI assistant (some are conditional on env vars):
|
|
|
119
120
|
| `get_compliance_dossier` | Procurement-defense compliance dossier mapping retrievals to license terms (Phase 11 M4) |
|
|
120
121
|
| `article_53_attestation` | Signed JWT attesting EU AI Act Article 53(1)(d) compliance for a license — the artifact AI labs hand to legal/procurement (Phase 12 W1.4) |
|
|
121
122
|
|
|
122
|
-
**Requires `OPEDD_PUB_BEARER` (opedd_pub_*) — publisher-side**
|
|
123
|
+
**Requires `OPEDD_PUB_BEARER` (opedd_sk_*; legacy opedd_pub_* still works) — publisher-side**
|
|
123
124
|
|
|
124
125
|
| Tool | Description |
|
|
125
126
|
|------|-------------|
|
|
@@ -159,7 +160,7 @@ Set environment variables to pre-configure the server:
|
|
|
159
160
|
| `OPEDD_BUYER_TOKEN` | Optional | Buyer API token (`opedd_buyer_live_*` canonical; `opedd_buyer_test_*` for sandbox) — enables `get_content` |
|
|
160
161
|
| `OPEDD_ACCESS_KEY` | Optional | Enterprise access key (`ent_*`) — enables `list_feed` + `stream_feed_ndjson` |
|
|
161
162
|
| `OPEDD_BUYER_JWT` | Optional | Supabase session JWT from the buyer portal — enables `get_buyer_account` + `get_audit_events` + `get_compliance_dossier` + `article_53_attestation` |
|
|
162
|
-
| `OPEDD_PUB_BEARER` | Optional |
|
|
163
|
+
| `OPEDD_PUB_BEARER` | Optional | Publisher API key (`opedd_sk_<32-hex>`, canonical since 2026-08-27; older `opedd_pub_<32-hex>` keys keep working) — from the Opedd dashboard, Settings → Developers. Enables `list_publisher_content` (+ `include_body`) and `push_content`. |
|
|
163
164
|
| `OPEDD_API_KEY` | Deprecated | Legacy Publisher API key (`op_...`) — fallback during the transition window; will stop working when opedd-backend Phase C deploys. Migrate to `OPEDD_PUB_BEARER`. |
|
|
164
165
|
| `OPEDD_API_URL` | Optional | Override the API base URL (default: Opedd production) |
|
|
165
166
|
| `OPEDD_MCP_TELEMETRY` | Optional | Set to `0` to disable anonymous usage telemetry (see below) |
|
package/dist/index.js
CHANGED
|
@@ -170,6 +170,22 @@ function buildTools(has) {
|
|
|
170
170
|
},
|
|
171
171
|
},
|
|
172
172
|
},
|
|
173
|
+
{
|
|
174
|
+
name: "search_content",
|
|
175
|
+
description: "Full-text search across everything licensable on Opedd (public, no key needed). " +
|
|
176
|
+
"Ask in plain words or use quotes for phrases and -word to exclude. Returns ranked matches with the publisher, " +
|
|
177
|
+
"prices, word count and a short description snippet (never the body). Use it to answer 'does Opedd have coverage on X', " +
|
|
178
|
+
"then lookup_content or get_content for a specific article.",
|
|
179
|
+
inputSchema: {
|
|
180
|
+
type: "object",
|
|
181
|
+
required: ["query"],
|
|
182
|
+
properties: {
|
|
183
|
+
query: { type: "string", description: "Search words (max 200 characters)." },
|
|
184
|
+
limit: { type: "number", description: "Max results (default 20, max 50)." },
|
|
185
|
+
publisher: { type: "string", description: "Optional publisher slug to search within." },
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
},
|
|
173
189
|
{
|
|
174
190
|
name: "purchase_license",
|
|
175
191
|
description: "Purchase a content license from the Opedd protocol using a Stripe payment method. " +
|
|
@@ -629,22 +645,36 @@ function buildTools(has) {
|
|
|
629
645
|
name: "list_publisher_content",
|
|
630
646
|
description: "List all licensable articles for the authenticated publisher (requires OPEDD_PUB_BEARER, or legacy OPEDD_API_KEY). " +
|
|
631
647
|
"Returns articles with titles, descriptions, pricing, and sales statistics. " +
|
|
648
|
+
"Set include_body=true to read back the STORED article text exactly as licensed buyers receive it " +
|
|
649
|
+
"(this is how you check that a push_content call stored what you meant; bodies are truncated to 8,000 characters per article, page size 20, paginate with cursor). " +
|
|
632
650
|
"Use article IDs from this list to purchase licenses via purchase_license.",
|
|
633
651
|
inputSchema: {
|
|
634
652
|
type: "object",
|
|
635
653
|
properties: {
|
|
636
654
|
limit: {
|
|
637
655
|
type: "number",
|
|
638
|
-
description: "Number of results (default: 20, max: 100)",
|
|
656
|
+
description: "Number of results (default: 20, max: 100; max 20 when include_body is true)",
|
|
639
657
|
},
|
|
640
658
|
type: {
|
|
641
659
|
type: "string",
|
|
642
660
|
enum: ["human", "ai"],
|
|
643
|
-
description: "Filter by license type availability",
|
|
661
|
+
description: "Filter by license type availability (ignored when include_body is true)",
|
|
644
662
|
},
|
|
645
663
|
offset: {
|
|
646
664
|
type: "number",
|
|
647
|
-
description: "Pagination offset (default: 0)",
|
|
665
|
+
description: "Pagination offset (default: 0; ignored when include_body is true — use cursor)",
|
|
666
|
+
},
|
|
667
|
+
include_body: {
|
|
668
|
+
type: "boolean",
|
|
669
|
+
description: "Return each article's stored body (what buyers receive). Default false.",
|
|
670
|
+
},
|
|
671
|
+
cursor: {
|
|
672
|
+
type: "string",
|
|
673
|
+
description: "Opaque next_cursor from a previous include_body=true call.",
|
|
674
|
+
},
|
|
675
|
+
id: {
|
|
676
|
+
type: "string",
|
|
677
|
+
description: "With include_body=true: fetch exactly one of your articles by id (full body, no truncation).",
|
|
648
678
|
},
|
|
649
679
|
},
|
|
650
680
|
},
|
|
@@ -754,6 +784,22 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
754
784
|
const data = await opeddFetch(creds, `/lookup-article?url=${encodeURIComponent(url)}`);
|
|
755
785
|
return ok(data);
|
|
756
786
|
}
|
|
787
|
+
// ── search_content ─────────────────────────────────────────────────────
|
|
788
|
+
case "search_content": {
|
|
789
|
+
const { query, limit, publisher } = args;
|
|
790
|
+
const q = (query ?? "").replace(/\s+/g, " ").trim();
|
|
791
|
+
if (!q)
|
|
792
|
+
return err("query is required");
|
|
793
|
+
if (q.length > 200)
|
|
794
|
+
return err("query must be at most 200 characters");
|
|
795
|
+
const params = new URLSearchParams({ action: "search", q });
|
|
796
|
+
if (typeof limit === "number" && Number.isFinite(limit))
|
|
797
|
+
params.set("limit", String(Math.min(Math.max(Math.trunc(limit), 1), 50)));
|
|
798
|
+
if (typeof publisher === "string" && publisher.trim())
|
|
799
|
+
params.set("publisher", publisher.trim());
|
|
800
|
+
const envelope = (await opeddFetch(creds, `/api?${params.toString()}`));
|
|
801
|
+
return ok(envelope.data ?? envelope);
|
|
802
|
+
}
|
|
757
803
|
// ── purchase_license ───────────────────────────────────────────────────
|
|
758
804
|
case "purchase_license": {
|
|
759
805
|
const { article_url, article_id, license_type, buyer_email: argEmail, buyer_name, buyer_organization, intended_use, payment_method_id: argPm, } = args;
|
|
@@ -1023,7 +1069,34 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
1023
1069
|
if (!creds.pubBearer && !creds.apiKey) {
|
|
1024
1070
|
return credErr("A publisher key (opedd_sk_*) is required for this tool", "OPEDD_PUB_BEARER", HOW_PUB_BEARER);
|
|
1025
1071
|
}
|
|
1026
|
-
const { limit = 20, type, offset = 0 } = args;
|
|
1072
|
+
const { limit = 20, type, offset = 0, include_body, cursor, id } = args;
|
|
1073
|
+
// include_body (2026-09-14): the OWNER read model — GET /publishers-content
|
|
1074
|
+
// returns the stored body for the key's own rows. Bodies are truncated
|
|
1075
|
+
// here to keep the assistant's context bounded; ?id= returns one in full.
|
|
1076
|
+
if (include_body === true) {
|
|
1077
|
+
const q = new URLSearchParams({ include_body: "true" });
|
|
1078
|
+
if (typeof id === "string" && id)
|
|
1079
|
+
q.set("id", id);
|
|
1080
|
+
else {
|
|
1081
|
+
q.set("limit", String(Math.min(Math.max(Number(limit) || 20, 1), 20)));
|
|
1082
|
+
if (typeof cursor === "string" && cursor)
|
|
1083
|
+
q.set("cursor", cursor);
|
|
1084
|
+
}
|
|
1085
|
+
// Backend envelope is { success, data: {...} }; unwrap so the assistant
|
|
1086
|
+
// sees the payload, not the wrapper (envelope-unwrap rule).
|
|
1087
|
+
const envelope = (await opeddFetch(creds, `/publishers-content?${q.toString()}`));
|
|
1088
|
+
const data = envelope.data ?? {};
|
|
1089
|
+
const MAX = 8_000;
|
|
1090
|
+
const trim = (a) => {
|
|
1091
|
+
const body = typeof a.content_body === "string" ? a.content_body : null;
|
|
1092
|
+
return body !== null && body.length > MAX
|
|
1093
|
+
? { ...a, content_body: body.slice(0, MAX), body_truncated: true, body_length: body.length }
|
|
1094
|
+
: { ...a, body_truncated: false, body_length: body?.length ?? 0 };
|
|
1095
|
+
};
|
|
1096
|
+
if (data.article)
|
|
1097
|
+
return ok({ article: { ...data.article, body_truncated: false, body_length: typeof data.article.content_body === "string" ? data.article.content_body.length : 0 } });
|
|
1098
|
+
return ok({ articles: (data.articles ?? []).map(trim), pagination: data.pagination ?? null });
|
|
1099
|
+
}
|
|
1027
1100
|
const params = new URLSearchParams({ action: "articles" });
|
|
1028
1101
|
params.set("limit", String(Math.min(Number(limit), 100)));
|
|
1029
1102
|
params.set("offset", String(Number(offset)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opedd-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Licensed, rights-cleared content for AI agents \u2014 verifiable license keys, on-chain proof, and EU AI Act attestation. The MCP alternative to unlicensed scraping for RAG and AI search.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|