opedd-mcp 0.1.0 → 0.1.1

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
@@ -90,7 +90,7 @@ The assistant will call the appropriate Opedd tools, show you the results, and
90
90
 
91
91
  ## Payment methods
92
92
 
93
- Purchases use **Stripe** by default (via `pm_...` payment method IDs). USDC on Base is also supported by the Opedd API — pass `payment: { method: 'usdc', tx_hash: '0x...' }` directly to `agent-purchase` if building a custom integration.
93
+ 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.
94
94
 
95
95
  ## Development
96
96
 
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ const API_BASE = process.env.OPEDD_API_URL ??
8
8
  const BUYER_EMAIL = process.env.OPEDD_BUYER_EMAIL;
9
9
  const PAYMENT_METHOD_ID = process.env.OPEDD_PAYMENT_METHOD_ID;
10
10
  const API_KEY = process.env.OPEDD_API_KEY; // publisher API key (op_...)
11
+ const BUYER_TOKEN = process.env.OPEDD_BUYER_TOKEN; // buyer API token (bk_live_...)
11
12
  // ─── HTTP helpers ─────────────────────────────────────────────────────────────
12
13
  async function opeddFetch(path, options = {}) {
13
14
  const url = `${API_BASE}${path}`;
@@ -17,7 +18,12 @@ async function opeddFetch(path, options = {}) {
17
18
  ...(options.headers ?? {}),
18
19
  };
19
20
  const res = await fetch(url, { ...options, headers });
20
- return res.json();
21
+ const body = await res.json();
22
+ if (!res.ok) {
23
+ const msg = body?.error || body?.message || `HTTP ${res.status}`;
24
+ throw new Error(msg);
25
+ }
26
+ return body;
21
27
  }
22
28
  function ok(data) {
23
29
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
@@ -134,6 +140,30 @@ const TOOLS = [
134
140
  },
135
141
  },
136
142
  ];
143
+ // If a buyer token is configured, expose content delivery tooling
144
+ if (BUYER_TOKEN) {
145
+ TOOLS.push({
146
+ name: "get_content",
147
+ description: "Retrieve the full body of a licensed article using a buyer API token (bk_live_...). " +
148
+ "Requires OPEDD_BUYER_TOKEN env var (create one at opedd.com/licenses after purchasing). " +
149
+ "Works for per-article licenses (token scoped to that article) and archive licenses (token covers all publisher content). " +
150
+ "The publisher must have content delivery enabled and must have pushed content for the article.",
151
+ inputSchema: {
152
+ type: "object",
153
+ required: ["article_id"],
154
+ properties: {
155
+ article_id: {
156
+ type: "string",
157
+ description: "The Opedd article UUID to retrieve content for",
158
+ },
159
+ buyer_token: {
160
+ type: "string",
161
+ description: "Buyer API token (bk_live_...). Falls back to OPEDD_BUYER_TOKEN env var.",
162
+ },
163
+ },
164
+ },
165
+ });
166
+ }
137
167
  // If a publisher API key is configured, expose publisher-specific tooling
138
168
  if (API_KEY) {
139
169
  TOOLS.push({
@@ -226,6 +256,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
226
256
  const data = await opeddFetch(`/registry?${params.toString()}`);
227
257
  return ok(data);
228
258
  }
259
+ // ── get_content ────────────────────────────────────────────────────────
260
+ case "get_content": {
261
+ const { article_id, buyer_token: argToken } = args;
262
+ if (!article_id)
263
+ return err("article_id is required");
264
+ const token = argToken || BUYER_TOKEN;
265
+ if (!token) {
266
+ return err("buyer_token is required (or set the OPEDD_BUYER_TOKEN env var). " +
267
+ "Create a token at opedd.com/licenses after purchasing a license.");
268
+ }
269
+ const data = await opeddFetch(`/content-delivery?article_id=${encodeURIComponent(article_id)}`, { headers: { Authorization: `Bearer ${token}` } });
270
+ return ok(data);
271
+ }
229
272
  // ── list_publisher_content ─────────────────────────────────────────────
230
273
  case "list_publisher_content": {
231
274
  if (!API_KEY) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opedd-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "MCP server for Opedd — discover, purchase, and verify content licenses from AI assistants",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -17,6 +17,7 @@ const API_BASE =
17
17
  const BUYER_EMAIL = process.env.OPEDD_BUYER_EMAIL;
18
18
  const PAYMENT_METHOD_ID = process.env.OPEDD_PAYMENT_METHOD_ID;
19
19
  const API_KEY = process.env.OPEDD_API_KEY; // publisher API key (op_...)
20
+ const BUYER_TOKEN = process.env.OPEDD_BUYER_TOKEN; // buyer API token (bk_live_...)
20
21
 
21
22
  // ─── HTTP helpers ─────────────────────────────────────────────────────────────
22
23
 
@@ -28,7 +29,12 @@ async function opeddFetch(path: string, options: RequestInit = {}): Promise<unkn
28
29
  ...(options.headers as Record<string, string> ?? {}),
29
30
  };
30
31
  const res = await fetch(url, { ...options, headers });
31
- return res.json();
32
+ const body = await res.json();
33
+ if (!res.ok) {
34
+ const msg = (body as any)?.error || (body as any)?.message || `HTTP ${res.status}`;
35
+ throw new Error(msg);
36
+ }
37
+ return body;
32
38
  }
33
39
 
34
40
  // ─── MCP response helpers ─────────────────────────────────────────────────────
@@ -161,6 +167,32 @@ const TOOLS: Tool[] = [
161
167
  },
162
168
  ];
163
169
 
170
+ // If a buyer token is configured, expose content delivery tooling
171
+ if (BUYER_TOKEN) {
172
+ TOOLS.push({
173
+ name: "get_content",
174
+ description:
175
+ "Retrieve the full body of a licensed article using a buyer API token (bk_live_...). " +
176
+ "Requires OPEDD_BUYER_TOKEN env var (create one at opedd.com/licenses after purchasing). " +
177
+ "Works for per-article licenses (token scoped to that article) and archive licenses (token covers all publisher content). " +
178
+ "The publisher must have content delivery enabled and must have pushed content for the article.",
179
+ inputSchema: {
180
+ type: "object",
181
+ required: ["article_id"],
182
+ properties: {
183
+ article_id: {
184
+ type: "string",
185
+ description: "The Opedd article UUID to retrieve content for",
186
+ },
187
+ buyer_token: {
188
+ type: "string",
189
+ description: "Buyer API token (bk_live_...). Falls back to OPEDD_BUYER_TOKEN env var.",
190
+ },
191
+ },
192
+ },
193
+ });
194
+ }
195
+
164
196
  // If a publisher API key is configured, expose publisher-specific tooling
165
197
  if (API_KEY) {
166
198
  TOOLS.push({
@@ -299,6 +331,29 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
299
331
  return ok(data);
300
332
  }
301
333
 
334
+ // ── get_content ────────────────────────────────────────────────────────
335
+ case "get_content": {
336
+ const { article_id, buyer_token: argToken } = args as {
337
+ article_id: string;
338
+ buyer_token?: string;
339
+ };
340
+ if (!article_id) return err("article_id is required");
341
+
342
+ const token = argToken || BUYER_TOKEN;
343
+ if (!token) {
344
+ return err(
345
+ "buyer_token is required (or set the OPEDD_BUYER_TOKEN env var). " +
346
+ "Create a token at opedd.com/licenses after purchasing a license."
347
+ );
348
+ }
349
+
350
+ const data = await opeddFetch(
351
+ `/content-delivery?article_id=${encodeURIComponent(article_id)}`,
352
+ { headers: { Authorization: `Bearer ${token}` } }
353
+ );
354
+ return ok(data);
355
+ }
356
+
302
357
  // ── list_publisher_content ─────────────────────────────────────────────
303
358
  case "list_publisher_content": {
304
359
  if (!API_KEY) {