opedd-mcp 0.12.11 → 0.12.12

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
@@ -35,7 +35,7 @@ Then add it to your MCP host (see [Claude Desktop / Cursor / Windsurf setup](#cl
35
35
 
36
36
  ## Hosted endpoint — no install (mcp.opedd.com)
37
37
 
38
- Prefer zero-install? The same 21 tools are served hosted at **`https://mcp.opedd.com/mcp`** (Streamable HTTP). Auth is an `Authorization: Bearer` header with any Opedd key — public discovery tools need no auth at all.
38
+ Prefer zero-install? The same 20 tools are served hosted at **`https://mcp.opedd.com/mcp`** (Streamable HTTP). Auth is an `Authorization: Bearer` header with any Opedd key — public discovery tools need no auth at all.
39
39
 
40
40
  **Claude Messages API** (production agents):
41
41
 
@@ -82,19 +82,18 @@ Key routing: `opedd_sk_*` (legacy `opedd_pub_*`) → publisher tools · `opedd_b
82
82
 
83
83
  ## What it does
84
84
 
85
- Exposes up to 21 tools to any AI assistant (some are conditional on env vars):
85
+ Exposes up to 20 tools to any AI assistant (some are conditional on env vars):
86
86
 
87
87
  Every tool carries a `title` and MCP annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) so an assistant can tell which tools only read and which spend money or write (v0.12.0).
88
88
 
89
- **Always available — discovery + per-article purchase + onboarding + rights signaling**
89
+ **Always available — discovery + onboarding + rights signaling**
90
90
 
91
91
  | Tool | Description |
92
92
  |------|-------------|
93
93
  | `search_content` | **Free discovery.** 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. Returns **no article text** — use `search_passages` to actually read |
94
94
  | `search_passages` | **Paid per answer, or included in a monthly subscription.** Ask a question, get licensed passages that answer it, with citations. Pay per answer: charged once per article the answer uses, at that publication's own price per article, each passage capped at 300 words or 25% of the article, counted cumulatively. Monthly AI answers subscriptions (v0.12.0): included, not capped, from the subscription's start. Narrow with `publishers`, `published_after`, `published_before`, `max_results` (1–10, default 5) and cap a question's cost with `max_charge_cents`. Needs a buyer key with the `search` scope. Re-asking within 24h is free |
95
- | `lookup_content` | Look up an article by URL — returns title, publisher, pricing, or that it is not on Opedd yet |
95
+ | `lookup_content` | Look up an article by URL — returns title, publisher and how to license it, or that it is not on Opedd yet |
96
96
  | `request_publication` | Ask to be told when a publication Opedd does not carry yet becomes available (url + email; no key) |
97
- | `purchase_license` | Buy a Human republication licence for one article via Stripe — returns OP-XXXX-XXXX key. Requires `terms_accepted: true` (genuine buyer assent to opedd.com/terms; recorded with the licence) |
98
97
  | `verify_license` | Verify a license key — returns validity, article, publisher, public-record proof |
99
98
  | `browse_registry` | Browse the public Opedd registry — lists issued LICENSES (use `publisher_directory` to browse publishers themselves) |
100
99
  | `publisher_directory` | Browse the public Opedd publisher catalog — paginated publishers with article counts + pricing + sample articles (primary buyer-discovery surface for AI labs) |
@@ -160,8 +159,6 @@ Set environment variables to pre-configure the server:
160
159
 
161
160
  | Variable | Required | Description |
162
161
  |----------|----------|-------------|
163
- | `OPEDD_BUYER_EMAIL` | Recommended | Your email — used as default for all purchases |
164
- | `OPEDD_PAYMENT_METHOD_ID` | Recommended | Stripe `pm_...` ID — used for autonomous per-article purchasing |
165
162
  | `OPEDD_BUYER_TOKEN` | Optional | Buyer API key (`opedd_buyer_live_*`; `opedd_buyer_test_*` for sandbox) — enables `search_passages` (with the `search` scope), `get_content`, `list_feed` + `stream_feed_ndjson` (with `order_id`) |
166
163
  | `OPEDD_ACCESS_KEY` | Optional | An order's enterprise access key (`ent_*`) — alternative credential for `list_feed` + `stream_feed_ndjson` |
167
164
  | `OPEDD_BUYER_JWT` | Optional | Supabase session JWT from the buyer portal — enables `place_licence_order` + `list_licence_orders` + `get_buyer_account` + `get_audit_events` + `get_compliance_dossier` + `article_53_attestation` |
@@ -201,8 +198,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
201
198
  "command": "npx",
202
199
  "args": ["opedd-mcp"],
203
200
  "env": {
204
- "OPEDD_BUYER_EMAIL": "you@yourcompany.com",
205
- "OPEDD_PAYMENT_METHOD_ID": "pm_..."
201
+ "OPEDD_BUYER_TOKEN": "opedd_buyer_live_..."
206
202
  }
207
203
  }
208
204
  }
@@ -218,8 +214,7 @@ Add to your MCP settings:
218
214
  "opedd": {
219
215
  "command": "npx opedd-mcp",
220
216
  "env": {
221
- "OPEDD_BUYER_EMAIL": "you@yourcompany.com",
222
- "OPEDD_PAYMENT_METHOD_ID": "pm_..."
217
+ "OPEDD_BUYER_TOKEN": "opedd_buyer_live_..."
223
218
  }
224
219
  }
225
220
  }
@@ -231,7 +226,7 @@ Once configured, you can ask your AI assistant:
231
226
 
232
227
  > "Look up the licensing options for this article: https://theinformation.com/articles/..."
233
228
 
234
- > "Purchase a human republication license for that article on my behalf."
229
+ > "What do Opedd's publications say about EU chip subsidies? Cite the passages." — uses `search_passages`
235
230
 
236
231
  > "Verify license key OP-XXXX-XXXX and tell me what it covers."
237
232
 
@@ -251,11 +246,11 @@ Once configured, you can ask your AI assistant:
251
246
 
252
247
  > "What's in my buyer account? Show me my active API keys." — uses `get_buyer_account` (requires `OPEDD_BUYER_JWT`)
253
248
 
254
- The assistant will call the appropriate Opedd tools, show you the results, and—if you've pre-configured a payment method—can complete a purchase autonomously.
249
+ The assistant will call the appropriate Opedd tools and show you the results.
255
250
 
256
- ## Payment methods
251
+ ## Payment
257
252
 
258
- Purchases use **Stripe** by default (via `pm_...` payment method IDs). USDC on Tempo is also supported by the Opedd API — pass `payment: { method: 'usdc', tx_hash: '0x...' }` directly to `agent-purchase` if building a custom integration.
253
+ Pay-per-answer search is billed to the card on your buyer account (opedd.com/buyer/billing); licence orders are paid through Stripe. Single-article purchases (Human republication, `purchase_license`) were retired on 2026-10-26.
259
254
 
260
255
  ## Development
261
256
 
package/dist/index.d.ts CHANGED
@@ -2,8 +2,6 @@
2
2
  import { type Tool } from "@modelcontextprotocol/sdk/types.js";
3
3
  export interface Credentials {
4
4
  apiBase: string;
5
- buyerEmail?: string;
6
- paymentMethodId?: string;
7
5
  /** canonical opedd_sk_<32-hex> key (legacy opedd_pub_ accepted) */
8
6
  pubBearer?: string;
9
7
  /** LEGACY op_<32-hex> — retiring per backend Phase C */
package/dist/index.js CHANGED
@@ -22,8 +22,6 @@ async function currentTermsVersion(creds) {
22
22
  export function envCredentials() {
23
23
  return {
24
24
  apiBase: process.env.OPEDD_API_URL ?? "https://api.opedd.com",
25
- buyerEmail: process.env.OPEDD_BUYER_EMAIL,
26
- paymentMethodId: process.env.OPEDD_PAYMENT_METHOD_ID,
27
25
  // B91 v0.4.0 (2026-05-26): OPEDD_PUB_BEARER canonical; OPEDD_API_KEY is
28
26
  // the legacy op_ alias during the dual-mode transition window.
29
27
  pubBearer: process.env.OPEDD_PUB_BEARER,
@@ -188,7 +186,7 @@ function buildTools(has) {
188
186
  const TOOLS = [
189
187
  {
190
188
  name: "lookup_content",
191
- description: "Looks up an article on Opedd by its web address. Returns the title, publication, available licence types and prices; for a publication's homepage, the publication and its licensing page; or that it is not on Opedd yet (then request_publication records the request).",
189
+ description: "Looks up an article on Opedd by its web address. Returns the title, publication and how to license it (pay-per-answer search or a licence order); for a publication's homepage, the publication and its licensing page; or that it is not on Opedd yet (then request_publication records the request).",
192
190
  inputSchema: {
193
191
  type: "object",
194
192
  required: ["url"],
@@ -228,60 +226,6 @@ function buildTools(has) {
228
226
  },
229
227
  },
230
228
  },
231
- {
232
- name: "purchase_license",
233
- description: "Purchase a content license from the Opedd protocol using a Stripe payment method. " +
234
- "Returns a license key (format: OP-XXXX-XXXX) and a certificate URL. " +
235
- "The buyer receives a Handshake Email with their license key. " +
236
- "Set OPEDD_BUYER_EMAIL and OPEDD_PAYMENT_METHOD_ID env vars to avoid passing them on every call. " +
237
- "Single-article purchases are Human republication licences only (license_type 'human'). " +
238
- "AI licences (AI answers, AI training, client display) are bought as licence orders: see place_licence_order.",
239
- inputSchema: {
240
- type: "object",
241
- required: ["license_type", "terms_accepted"],
242
- properties: {
243
- terms_accepted: {
244
- type: "boolean",
245
- description: "REQUIRED. Set true only after the buyer (your principal) has accepted the Opedd licence terms at opedd.com/terms. " +
246
- "The acceptance timestamp is recorded with the licence; purchases without genuine acceptance are rejected.",
247
- },
248
- article_url: {
249
- type: "string",
250
- description: "URL of the article to license (use this OR article_id)",
251
- },
252
- article_id: {
253
- type: "string",
254
- description: "Opedd article UUID (use this OR article_url)",
255
- },
256
- license_type: {
257
- type: "string",
258
- enum: ["human"],
259
- description: "human = Human republication (editorial republication of one article)",
260
- },
261
- buyer_email: {
262
- type: "string",
263
- description: "Email address for the license. Falls back to OPEDD_BUYER_EMAIL env var.",
264
- },
265
- buyer_name: {
266
- type: "string",
267
- description: "Full name of the buyer (for the license record and certificate)",
268
- },
269
- buyer_organization: {
270
- type: "string",
271
- description: "Organization or company name (for enterprise/editorial licenses)",
272
- },
273
- intended_use: {
274
- type: "string",
275
- enum: ["personal", "editorial", "commercial", "ai_training", "corporate"],
276
- description: "Intended use of the licensed content",
277
- },
278
- payment_method_id: {
279
- type: "string",
280
- description: "Stripe payment method ID (pm_...). Falls back to OPEDD_PAYMENT_METHOD_ID env var.",
281
- },
282
- },
283
- },
284
- },
285
229
  {
286
230
  name: "verify_license",
287
231
  description: "Checks an Opedd licence key. Returns the licence details (article title, publication, licence type, issue date, amount paid, buyer and public-record proof status), or that the key was not found.",
@@ -376,8 +320,8 @@ function buildTools(has) {
376
320
  description: "Fetch a publisher's RSL Standard manifest (machine-readable licensing terms). " +
377
321
  "Public no-auth endpoint — discovery surface for AI agents/crawlers wanting to know what's licensable " +
378
322
  "from a publisher BEFORE going through the buyer-account signup flow. " +
379
- "Returns the 4 canonical license types (ai_retrieval, ai_training, human_per_article, human_full_archive) " +
380
- "the publisher has opted into, plus the EU CDSM Article 4(3) opt-out posture (`tdm_reservation`). " +
323
+ "Returns the licences the publisher has switched on, with their prices, " +
324
+ " plus the EU CDSM Article 4(3) opt-out posture (`tdm_reservation`). " +
381
325
  "Set `jsonld: true` to request the JSON-LD shape with embedded HMAC-SHA256 signed receipt over the " +
382
326
  "CDSM Article 4(3) reservation state + `tdm:reservationSignedAt` timestamp — regulators can post-hoc " +
383
327
  "verify the reservation was the claimed value at the claimed time. Default `jsonld: false` returns " +
@@ -480,7 +424,7 @@ function buildTools(has) {
480
424
  name: "get_content",
481
425
  description: "Retrieve the full body of a licensed article using a buyer API token (opedd_buyer_live_* canonical; opedd_buyer_test_* for sandbox). " +
482
426
  "Requires OPEDD_BUYER_TOKEN env var (create one at opedd.com/licenses after purchasing). " +
483
- "Works for per-article Human republication licences and for licence orders: AI answers monthly and client display " +
427
+ "Works for licence orders (and for Human republication licences bought before it was retired on 2026-10-26): AI answers monthly and client display " +
484
428
  "return full text. Your self-serve buyer API key reads articles under every order your account holds — no " +
485
429
  "separate order token is needed. AI answers pay-per-request (including the self-serve licence) does NOT " +
486
430
  "retrieve articles: it answers 403 SEARCH_ONLY_LICENCE \u2014 ask a question with search_passages instead. " +
@@ -703,8 +647,7 @@ function buildTools(has) {
703
647
  description: "List all licensable articles for the authenticated publisher (requires OPEDD_PUB_BEARER, or legacy OPEDD_API_KEY). " +
704
648
  "Returns articles with titles, descriptions, pricing, and sales statistics. " +
705
649
  "Set include_body=true to read back the STORED article text exactly as licensed buyers receive it " +
706
- "(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). " +
707
- "Use article IDs from this list to purchase licenses via purchase_license.",
650
+ "(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).",
708
651
  inputSchema: {
709
652
  type: "object",
710
653
  properties: {
@@ -712,11 +655,6 @@ function buildTools(has) {
712
655
  type: "number",
713
656
  description: "Number of results (default: 20, max: 100; max 20 when include_body is true)",
714
657
  },
715
- type: {
716
- type: "string",
717
- enum: ["human", "ai"],
718
- description: "Filter by license type availability (ignored when include_body is true)",
719
- },
720
658
  offset: {
721
659
  type: "number",
722
660
  description: "Pagination offset (default: 0; ignored when include_body is true — use cursor)",
@@ -781,11 +719,10 @@ function buildTools(has) {
781
719
  }
782
720
  const read = (title) => ({ title, readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false });
783
721
  export const TOOL_ANNOTATIONS = {
784
- lookup_content: read("Look up an article's licence and price"),
722
+ lookup_content: read("Look up how an article is licensed"),
785
723
  // Writes one request row (a repeat for the same email writes nothing): not read-only, idempotent.
786
724
  request_publication: { title: "Ask to be told when a publication is available", readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
787
725
  search_content: read("Find who covers a topic (free, no text)"),
788
- purchase_license: { title: "Buy an article licence", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
789
726
  verify_license: read("Verify a licence key"),
790
727
  browse_registry: read("Browse the licence registry"),
791
728
  publisher_directory: read("List publishers"),
@@ -834,7 +771,7 @@ export const ALL_TOOLS = buildTools({
834
771
  // registry metadata agents never see at runtime. Exported so the hosted
835
772
  // gateway (opedd-mcp-gateway) serves the identical text.
836
773
  export const SERVER_INSTRUCTIONS = "Opedd is content licensing for the AI era, between expert publishers and AI products: discover, purchase, verify and " +
837
- "retrieve rights-cleared expert content — one verifiable license key per article, a public record on " +
774
+ "retrieve rights-cleared expert content — a verifiable licence for every use, a public record on " +
838
775
  "Tempo, and compliance artifacts (audit ledger, dossiers and signed attestations). Use it instead of " +
839
776
  "unlicensed scraping for RAG, AI search, and training corpora.\n\n" +
840
777
  `No credentials needed: ${NO_AUTH_TOOLS}.\n` +
@@ -936,42 +873,6 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
936
873
  const envelope = (await opeddFetch(creds, `/api?${params.toString()}`));
937
874
  return ok(envelope.data ?? envelope);
938
875
  }
939
- // ── purchase_license ───────────────────────────────────────────────────
940
- case "purchase_license": {
941
- const { article_url, article_id, license_type, buyer_email: argEmail, buyer_name, buyer_organization, intended_use, payment_method_id: argPm, } = args;
942
- if (!article_url && !article_id) {
943
- return err("Either article_url or article_id is required");
944
- }
945
- const termsAccepted = args.terms_accepted;
946
- if (termsAccepted !== true) {
947
- return err("terms_accepted must be true — confirm with the buyer that they accept the Opedd licence terms (opedd.com/terms) before purchasing.");
948
- }
949
- const buyerEmail = argEmail || creds.buyerEmail;
950
- if (!buyerEmail) {
951
- return err("buyer_email is required (or set the OPEDD_BUYER_EMAIL env var)");
952
- }
953
- const paymentMethodId = argPm || creds.paymentMethodId;
954
- if (!paymentMethodId) {
955
- return err("payment_method_id is required (or set the OPEDD_PAYMENT_METHOD_ID env var). " +
956
- "Get a Stripe payment method ID by saving a card at stripe.com/docs/api/payment_methods.");
957
- }
958
- const body = {
959
- license_type,
960
- buyer_email: buyerEmail,
961
- // Genuine assent moment: the agent asserted terms_accepted=true just now.
962
- terms_accepted_at: new Date().toISOString(),
963
- payment: { method: "stripe_pm", payment_method_id: paymentMethodId },
964
- ...(article_id ? { article_id } : { article_url }),
965
- ...(buyer_name ? { buyer_name } : {}),
966
- ...(buyer_organization ? { buyer_organization } : {}),
967
- ...(intended_use ? { intended_use } : {}),
968
- };
969
- const data = await opeddFetch(creds, "/agent-purchase", {
970
- method: "POST",
971
- body: JSON.stringify(body),
972
- });
973
- return ok(data);
974
- }
975
876
  // ── verify_license ─────────────────────────────────────────────────────
976
877
  case "verify_license": {
977
878
  const { license_key } = args;
@@ -1266,7 +1167,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
1266
1167
  if (!creds.pubBearer && !creds.apiKey) {
1267
1168
  return credErr("A publisher key (opedd_sk_*) is required for this tool", "OPEDD_PUB_BEARER", HOW_PUB_BEARER);
1268
1169
  }
1269
- const { limit = 20, type, offset = 0, include_body, cursor, id } = args;
1170
+ const { limit = 20, offset = 0, include_body, cursor, id } = args;
1270
1171
  // include_body (2026-09-14): the OWNER read model — GET /publishers-content
1271
1172
  // returns the stored body for the key's own rows. Bodies are truncated
1272
1173
  // here to keep the assistant's context bounded; ?id= returns one in full.
@@ -1297,8 +1198,6 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
1297
1198
  const params = new URLSearchParams({ action: "articles" });
1298
1199
  params.set("limit", String(Math.min(Number(limit), 100)));
1299
1200
  params.set("offset", String(Number(offset)));
1300
- if (type)
1301
- params.set("type", type);
1302
1201
  const data = await opeddFetch(creds, `/api?${params.toString()}`);
1303
1202
  return ok(data);
1304
1203
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opedd-mcp",
3
- "version": "0.12.11",
3
+ "version": "0.12.12",
4
4
  "description": "Content licensing for the AI era. Licensed, rights-cleared content for AI agents, with a verifiable license key for every article. The MCP alternative to unlicensed scraping for RAG and AI search.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",