opedd-mcp 0.3.0 → 0.4.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 +3 -2
- package/package.json +1 -1
- package/src/index.ts +19 -7
- package/tests/dispatcher.env-gated.test.ts +9 -4
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ Exposes up to 16 tools to any AI assistant (some are conditional on env vars):
|
|
|
45
45
|
| `get_compliance_dossier` | Procurement-defense compliance dossier mapping retrievals to license terms (Phase 11 M4) |
|
|
46
46
|
| `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) |
|
|
47
47
|
|
|
48
|
-
**Requires `
|
|
48
|
+
**Requires `OPEDD_PUB_BEARER` (opedd_pub_*) — publisher-side**
|
|
49
49
|
|
|
50
50
|
| Tool | Description |
|
|
51
51
|
|------|-------------|
|
|
@@ -84,7 +84,8 @@ Set environment variables to pre-configure the server:
|
|
|
84
84
|
| `OPEDD_BUYER_TOKEN` | Optional | Buyer API token (`opedd_buyer_live_*` canonical; `opedd_buyer_test_*` for sandbox) — enables `get_content` |
|
|
85
85
|
| `OPEDD_ACCESS_KEY` | Optional | Enterprise access key (`ent_*`) — enables `list_feed` + `stream_feed_ndjson` |
|
|
86
86
|
| `OPEDD_BUYER_JWT` | Optional | Supabase session JWT from the buyer portal — enables `get_audit_events` + `get_compliance_dossier` |
|
|
87
|
-
| `
|
|
87
|
+
| `OPEDD_PUB_BEARER` | Optional | Canonical Publisher API Bearer key (`opedd_pub_<env>_<32-hex>`; issued via `POST /publishers-api-keys action=create_api_key`) — enables `list_publisher_content`. **v0.4.0 canonical.** |
|
|
88
|
+
| `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`. |
|
|
88
89
|
| `OPEDD_API_URL` | Optional | Override the API base URL (default: Opedd production) |
|
|
89
90
|
|
|
90
91
|
> **Getting a Stripe payment method ID**: Save a card in your Stripe account and retrieve the `pm_...` ID via the [Stripe API](https://stripe.com/docs/api/payment_methods).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opedd-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "MCP server for Opedd — discover, purchase, verify, and audit content licenses from AI assistants. Covers Phase 11 buyer-side surfaces + Phase 12 Wave 1 + 3 regulatory surfaces (CDSM Article 4(3) RSL + EU AI Act Article 53 attestation + platform onboarding helper).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
package/src/index.ts
CHANGED
|
@@ -17,7 +17,16 @@ const API_BASE =
|
|
|
17
17
|
|
|
18
18
|
const BUYER_EMAIL = process.env.OPEDD_BUYER_EMAIL;
|
|
19
19
|
const PAYMENT_METHOD_ID = process.env.OPEDD_PAYMENT_METHOD_ID;
|
|
20
|
-
|
|
20
|
+
// B91 v0.4.0 migration (2026-05-26): canonical Bearer auth.
|
|
21
|
+
// OPEDD_PUB_BEARER is the new canonical opedd_pub_<env>_<32-hex> key
|
|
22
|
+
// (issued via POST /publishers-api-keys action=create_api_key).
|
|
23
|
+
// OPEDD_API_KEY retained as backward-compat alias for legacy op_ keys
|
|
24
|
+
// during the dual-mode transition window on the /api endpoint (Phase A
|
|
25
|
+
// shipped opedd-backend 2026-05-26). Backend Phase C will drop the
|
|
26
|
+
// op_ path entirely; users MUST migrate to OPEDD_PUB_BEARER before
|
|
27
|
+
// then. Prefer Bearer if both set.
|
|
28
|
+
const PUB_BEARER = process.env.OPEDD_PUB_BEARER; // canonical opedd_pub_<env>_<32-hex>
|
|
29
|
+
const API_KEY = process.env.OPEDD_API_KEY; // LEGACY op_<32-hex> — retiring per backend Phase C
|
|
21
30
|
const BUYER_TOKEN = process.env.OPEDD_BUYER_TOKEN; // buyer API token (opedd_buyer_live_... or opedd_buyer_test_...)
|
|
22
31
|
const ACCESS_KEY = process.env.OPEDD_ACCESS_KEY; // enterprise access key (ent_*); for /enterprise-license GET feed
|
|
23
32
|
const BUYER_JWT = process.env.OPEDD_BUYER_JWT; // Supabase JWT; for /buyer-audit + /buyer-compliance-report
|
|
@@ -28,7 +37,9 @@ async function opeddFetch(path: string, options: RequestInit = {}): Promise<unkn
|
|
|
28
37
|
const url = `${API_BASE}${path}`;
|
|
29
38
|
const headers: Record<string, string> = {
|
|
30
39
|
"Content-Type": "application/json",
|
|
31
|
-
|
|
40
|
+
// B91 v0.4.0 (2026-05-26): canonical Bearer preferred; legacy X-API-Key
|
|
41
|
+
// accepted only as fallback during transition window
|
|
42
|
+
...(PUB_BEARER ? { Authorization: `Bearer ${PUB_BEARER}` } : (API_KEY ? { "X-API-Key": API_KEY } : {})),
|
|
32
43
|
...(options.headers as Record<string, string> ?? {}),
|
|
33
44
|
};
|
|
34
45
|
const res = await fetch(url, { ...options, headers });
|
|
@@ -50,7 +61,8 @@ async function opeddFetchNdjson(
|
|
|
50
61
|
const url = `${API_BASE}${path}`;
|
|
51
62
|
const headers: Record<string, string> = {
|
|
52
63
|
Accept: "application/x-ndjson",
|
|
53
|
-
|
|
64
|
+
// B91 v0.4.0 (2026-05-26): canonical Bearer preferred; legacy fallback
|
|
65
|
+
...(PUB_BEARER ? { Authorization: `Bearer ${PUB_BEARER}` } : (API_KEY ? { "X-API-Key": API_KEY } : {})),
|
|
54
66
|
...(options.headers as Record<string, string> ?? {}),
|
|
55
67
|
};
|
|
56
68
|
const res = await fetch(url, { ...options, headers });
|
|
@@ -570,11 +582,11 @@ if (BUYER_JWT) {
|
|
|
570
582
|
}
|
|
571
583
|
|
|
572
584
|
// If a publisher API key is configured, expose publisher-specific tooling
|
|
573
|
-
if (API_KEY) {
|
|
585
|
+
if (PUB_BEARER || API_KEY) {
|
|
574
586
|
TOOLS.push({
|
|
575
587
|
name: "list_publisher_content",
|
|
576
588
|
description:
|
|
577
|
-
"List all licensable articles for the authenticated publisher (requires OPEDD_API_KEY). " +
|
|
589
|
+
"List all licensable articles for the authenticated publisher (requires OPEDD_PUB_BEARER, or legacy OPEDD_API_KEY). " +
|
|
578
590
|
"Returns articles with titles, descriptions, pricing, and sales statistics. " +
|
|
579
591
|
"Use article IDs from this list to purchase licenses via purchase_license.",
|
|
580
592
|
inputSchema: {
|
|
@@ -977,8 +989,8 @@ export async function dispatchTool(
|
|
|
977
989
|
|
|
978
990
|
// ── list_publisher_content ─────────────────────────────────────────────
|
|
979
991
|
case "list_publisher_content": {
|
|
980
|
-
if (!API_KEY) {
|
|
981
|
-
return err("
|
|
992
|
+
if (!PUB_BEARER && !API_KEY) {
|
|
993
|
+
return err("OPEDD_PUB_BEARER env var is required for this tool (canonical Bearer; legacy OPEDD_API_KEY also accepted during transition)");
|
|
982
994
|
}
|
|
983
995
|
|
|
984
996
|
const { limit = 20, type, offset = 0 } = args as {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// article_53_attestation, get_buyer_account, get_audit_events,
|
|
5
5
|
// get_compliance_dossier (require OPEDD_BUYER_JWT)
|
|
6
6
|
// list_feed, stream_feed_ndjson (require OPEDD_ACCESS_KEY)
|
|
7
|
-
// list_publisher_content (requires OPEDD_API_KEY)
|
|
7
|
+
// list_publisher_content (requires OPEDD_PUB_BEARER OR legacy OPEDD_API_KEY)
|
|
8
8
|
//
|
|
9
9
|
// Separate file from dispatcher.test.ts because the TOOLS array push +
|
|
10
10
|
// CallTool switch cases evaluate env-var presence at module-import time;
|
|
@@ -18,6 +18,7 @@ const TEST_BUYER_TOKEN = "opedd_buyer_test_env_gated_xxx";
|
|
|
18
18
|
const TEST_BUYER_JWT = "eyJhbGc.env-gated-test.sig";
|
|
19
19
|
const TEST_ACCESS_KEY = "ent_env_gated_test";
|
|
20
20
|
const TEST_API_KEY = "op_env_gated_test_pub";
|
|
21
|
+
const TEST_PUB_BEARER = "opedd_pub_test_env_gated_test_pub_canonical_xxxx"; // v0.4.0 canonical Bearer
|
|
21
22
|
const TEST_BUYER_EMAIL = "env-gated@opedd-test.com";
|
|
22
23
|
|
|
23
24
|
// Stub ALL env vars before any import — guarantees every conditional
|
|
@@ -27,6 +28,7 @@ beforeAll(() => {
|
|
|
27
28
|
vi.stubEnv("OPEDD_BUYER_JWT", TEST_BUYER_JWT);
|
|
28
29
|
vi.stubEnv("OPEDD_ACCESS_KEY", TEST_ACCESS_KEY);
|
|
29
30
|
vi.stubEnv("OPEDD_API_KEY", TEST_API_KEY);
|
|
31
|
+
vi.stubEnv("OPEDD_PUB_BEARER", TEST_PUB_BEARER);
|
|
30
32
|
vi.stubEnv("OPEDD_BUYER_EMAIL", TEST_BUYER_EMAIL);
|
|
31
33
|
vi.stubEnv("OPEDD_API_URL", "https://api.opedd.com");
|
|
32
34
|
});
|
|
@@ -257,15 +259,18 @@ describe("dispatchTool: stream_feed_ndjson (ACCESS_KEY gated)", () => {
|
|
|
257
259
|
|
|
258
260
|
// ───────────────────────────── API_KEY-gated tool ─────────────────────────────
|
|
259
261
|
|
|
260
|
-
describe("dispatchTool: list_publisher_content (API_KEY
|
|
261
|
-
it("happy path — sends /api?action=articles +
|
|
262
|
+
describe("dispatchTool: list_publisher_content (PUB_BEARER preferred; API_KEY fallback)", () => {
|
|
263
|
+
it("happy path — sends /api?action=articles + Authorization: Bearer canonical (v0.4.0)", async () => {
|
|
262
264
|
const f = mockFetchOk({ success: true, data: { articles: [] } });
|
|
263
265
|
const { dispatchTool } = await loadDispatcher();
|
|
264
266
|
await dispatchTool("list_publisher_content", { limit: 20 });
|
|
265
267
|
const call = f.mock.calls[0];
|
|
266
268
|
expect(String(call[0])).toContain("/api?action=articles");
|
|
267
269
|
const headers = (call[1] as RequestInit).headers as Record<string, string>;
|
|
268
|
-
|
|
270
|
+
// v0.4.0: Bearer preferred when OPEDD_PUB_BEARER is set; X-API-Key
|
|
271
|
+
// legacy fallback only when PUB_BEARER unset.
|
|
272
|
+
expect(headers["Authorization"]).toBe("Bearer " + TEST_PUB_BEARER);
|
|
273
|
+
expect(headers["X-API-Key"]).toBeUndefined();
|
|
269
274
|
});
|
|
270
275
|
|
|
271
276
|
it("limit capped at 100", async () => {
|