opedd-mcp 0.6.13 → 0.6.15
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/dist/index.d.ts +1 -0
- package/dist/index.js +73 -21
- package/dist/telemetry.d.ts +1 -0
- package/dist/telemetry.js +25 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -27,5 +27,6 @@ type ToolResult = {
|
|
|
27
27
|
};
|
|
28
28
|
export declare const TOOLS: Tool[];
|
|
29
29
|
export declare const ALL_TOOLS: Tool[];
|
|
30
|
+
export declare const SERVER_INSTRUCTIONS: string;
|
|
30
31
|
export declare function dispatchTool(name: string, args: Record<string, unknown>, creds?: Credentials): Promise<ToolResult>;
|
|
31
32
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -118,6 +118,38 @@ function ok(data) {
|
|
|
118
118
|
function err(msg) {
|
|
119
119
|
return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
|
|
120
120
|
}
|
|
121
|
+
// ─── Credential refusals are the conversion surface ──────────────────────────
|
|
122
|
+
// (2026-08-26) In the week before this landed, 19 distinct agents worldwide
|
|
123
|
+
// succeeded on browse_registry and then hit a credential gate whose entire
|
|
124
|
+
// message was "env var is required" — no next action, funnel over. The AUTH
|
|
125
|
+
// MODEL IS UNCHANGED by this block: same gates, same keys, nothing loosened.
|
|
126
|
+
// Only the refusal text changed: what's missing, how to supply it on BOTH
|
|
127
|
+
// channels (env var locally, Authorization header on the hosted gateway),
|
|
128
|
+
// where credentials come from, and which tools need none.
|
|
129
|
+
const NO_AUTH_TOOLS = "lookup_content, publisher_directory, verify_license, browse_registry, rsl_get, detect_platform";
|
|
130
|
+
function credErr(missing, envVar, howToGet) {
|
|
131
|
+
return err(`${missing} — none was provided. ` +
|
|
132
|
+
`Supply it as the ${envVar} env var (local/stdio install) or as an "Authorization: Bearer <value>" header (hosted gateway, https://mcp.opedd.com/mcp). ` +
|
|
133
|
+
`${howToGet} ` +
|
|
134
|
+
`These tools need no credentials at all: ${NO_AUTH_TOOLS}. Docs: https://docs.opedd.com`);
|
|
135
|
+
}
|
|
136
|
+
const HOW_BUYER_JWT = "Buyer signup is free and takes ~2 minutes: https://opedd.com/buyer/signup (an API key is issued instantly at signup). " +
|
|
137
|
+
"This tool authenticates with your buyer session JWT: sign in at https://opedd.com/buyer and use the Supabase session access token. " +
|
|
138
|
+
"Blocked? hello@opedd.com.";
|
|
139
|
+
// Phase 3 scoped keys (2026-08-26, backend PR #336): the three audit/
|
|
140
|
+
// compliance read surfaces also accept a buyer API key carrying the 'audit'
|
|
141
|
+
// scope. The key (OPEDD_BUYER_TOKEN) is long-lived and portal-manageable —
|
|
142
|
+
// the credential agents can actually hold; the JWT path stays for sessions.
|
|
143
|
+
const HOW_AUDIT_CRED = "EITHER a buyer API key with the 'audit' scope (create one free: https://opedd.com/buyer/signup, then " +
|
|
144
|
+
"Account \u2192 API keys \u2192 Create \u2192 tick 'Audit & compliance access'; supply it as OPEDD_BUYER_TOKEN or the " +
|
|
145
|
+
"Authorization header) OR a buyer portal session JWT (OPEDD_BUYER_JWT). Blocked? hello@opedd.com.";
|
|
146
|
+
function auditCred(creds) {
|
|
147
|
+
// Key preferred (durable, revocable, scope-checked server-side); JWT kept.
|
|
148
|
+
return creds.buyerToken || creds.buyerJwt;
|
|
149
|
+
}
|
|
150
|
+
const HOW_ACCESS_KEY = "Enterprise access keys (ent_*) are delivered when an enterprise licence is issued — start at https://opedd.com/enterprise " +
|
|
151
|
+
"or purchase programmatically with the purchase_enterprise_license tool.";
|
|
152
|
+
const HOW_PUB_BEARER = "Publisher keys (opedd_pub_*) come from the publisher dashboard: sign up free at https://opedd.com, then Settings → API keys.";
|
|
121
153
|
// ─── Tool definitions ─────────────────────────────────────────────────────────
|
|
122
154
|
function buildTools(has) {
|
|
123
155
|
const TOOLS = [
|
|
@@ -471,8 +503,11 @@ function buildTools(has) {
|
|
|
471
503
|
},
|
|
472
504
|
});
|
|
473
505
|
}
|
|
474
|
-
//
|
|
475
|
-
|
|
506
|
+
// Expose audit + compliance tools when buyer credentials exist. Since the
|
|
507
|
+
// 2026-08-26 scoped-keys change (backend #336) an 'audit'-scoped buyer API
|
|
508
|
+
// key (OPEDD_BUYER_TOKEN) works on 3 of these 4; get_buyer_account remains
|
|
509
|
+
// JWT-only (its endpoint mints keys — a key must never mint keys).
|
|
510
|
+
if (has.buyerJwt || has.buyerToken) {
|
|
476
511
|
TOOLS.push({
|
|
477
512
|
name: "get_audit_events",
|
|
478
513
|
description: "Browse per-event audit rows for the authenticated buyer via GET /buyer-audit (Phase 9.x). " +
|
|
@@ -480,7 +515,7 @@ function buildTools(has) {
|
|
|
480
515
|
"Optional filter by event_type ('content_access', 'bulk_content_access', 'compliance_report_generated'). " +
|
|
481
516
|
"Window cap 30 days (vs 90-day cap on get_compliance_dossier). " +
|
|
482
517
|
"Attestation inclusion proof is included on every row by default — no separate flag needed (M6.4 consolidation per founder ratification: tools 4 + 6 merged into one cleaner mental model). " +
|
|
483
|
-
"
|
|
518
|
+
"Auth: an audit-scoped buyer API key (OPEDD_BUYER_TOKEN — create at opedd.com/buyer, Account \u2192 API keys) or OPEDD_BUYER_JWT.",
|
|
484
519
|
inputSchema: {
|
|
485
520
|
type: "object",
|
|
486
521
|
properties: {
|
|
@@ -517,7 +552,7 @@ function buildTools(has) {
|
|
|
517
552
|
"Use cases: post-signup verification ('what was just issued to me?'), buyer dashboard mental model " +
|
|
518
553
|
"('what licenses do I currently hold?'), audit prep ('show me the key list before rotation'). " +
|
|
519
554
|
"For full mid-lifecycle license details (filter_rules, billing, payouts), buyers consult the buyer portal at opedd.com/buyer. " +
|
|
520
|
-
"Requires OPEDD_BUYER_JWT.",
|
|
555
|
+
"Requires OPEDD_BUYER_JWT (JWT-only by design: this surface manages API keys, and a key must never mint keys).",
|
|
521
556
|
inputSchema: {
|
|
522
557
|
type: "object",
|
|
523
558
|
properties: {},
|
|
@@ -535,7 +570,7 @@ function buildTools(has) {
|
|
|
535
570
|
"transparency obligation). It does NOT discharge a publisher's CDSM Article 4(3) reservation obligation — " +
|
|
536
571
|
"that lives on the rsl_get tool (jsonld=true variant). Never conflate. " +
|
|
537
572
|
"Optional `content_id` scopes the attestation to one article; default is license-wide. " +
|
|
538
|
-
"Window cap: 365 days.
|
|
573
|
+
"Window cap: 365 days. Auth: an audit-scoped buyer API key (OPEDD_BUYER_TOKEN) or OPEDD_BUYER_JWT.",
|
|
539
574
|
inputSchema: {
|
|
540
575
|
type: "object",
|
|
541
576
|
required: ["license_id"],
|
|
@@ -567,7 +602,7 @@ function buildTools(has) {
|
|
|
567
602
|
"Self-audit invariant: every successful call writes one license_events row with event_type='compliance_report_generated' BEFORE returning. " +
|
|
568
603
|
"Window cap: 90 days per call (vs 30-day cap on get_audit_events). For annual audits, paginate via _meta.next_cursor across 4 quarterly windows. " +
|
|
569
604
|
"Compliance framework anchors (boolean flags) map to EU AI Act Article 53, CDSM Article 4(3), on-chain attestation, TDM reservation. " +
|
|
570
|
-
"
|
|
605
|
+
"Auth: an audit-scoped buyer API key (OPEDD_BUYER_TOKEN) or OPEDD_BUYER_JWT.",
|
|
571
606
|
inputSchema: {
|
|
572
607
|
type: "object",
|
|
573
608
|
required: ["from", "to"],
|
|
@@ -670,7 +705,24 @@ export const ALL_TOOLS = buildTools({
|
|
|
670
705
|
buyerToken: true, accessKey: true, buyerJwt: true, pubBearer: true,
|
|
671
706
|
});
|
|
672
707
|
// ─── MCP Server ───────────────────────────────────────────────────────────────
|
|
673
|
-
|
|
708
|
+
// ─── Handshake instructions ──────────────────────────────────────────────────
|
|
709
|
+
// The MCP `instructions` field is the one string every connecting agent reads
|
|
710
|
+
// at initialize — it was empty until 2026-08-26 while the pitch lived only in
|
|
711
|
+
// registry metadata agents never see at runtime. Exported so the hosted
|
|
712
|
+
// gateway (opedd-mcp-gateway) serves the identical text.
|
|
713
|
+
export const SERVER_INSTRUCTIONS = "Opedd is the licensing rail between expert publishers and AI products: discover, purchase, verify and " +
|
|
714
|
+
"retrieve rights-cleared expert content — one verifiable license key per article, Tempo on-chain " +
|
|
715
|
+
"attestation, and EU AI Act Article 53 compliance artifacts (audit ledger + dossiers). Use it instead of " +
|
|
716
|
+
"unlicensed scraping for RAG, AI search, and training corpora.\n\n" +
|
|
717
|
+
`No credentials needed: ${NO_AUTH_TOOLS}.\n` +
|
|
718
|
+
"Buyer tools (purchase, account, audit/compliance): free buyer signup at https://opedd.com/buyer/signup " +
|
|
719
|
+
"(~2 min; an API key is issued instantly). Publisher tools (content push): free publisher signup at " +
|
|
720
|
+
"https://opedd.com, key under Settings → API keys.\n" +
|
|
721
|
+
"Supply credentials as env vars (local/stdio) or an Authorization: Bearer header (hosted gateway, " +
|
|
722
|
+
"https://mcp.opedd.com/mcp).\n" +
|
|
723
|
+
"EU CDSM Art. 4(3) / TDM-reservation queries: rsl_get. Compliance evidence: get_compliance_dossier. " +
|
|
724
|
+
"Docs: https://docs.opedd.com";
|
|
725
|
+
const server = new Server({ name: "opedd-mcp", version: SERVER_VERSION }, { capabilities: { tools: {} }, instructions: SERVER_INSTRUCTIONS });
|
|
674
726
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
675
727
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
676
728
|
// Anonymous usage telemetry — captures only the tool name, duration, and
|
|
@@ -850,7 +902,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
850
902
|
// ── list_feed (Phase 10 + 11) ──────────────────────────────────────────
|
|
851
903
|
case "list_feed": {
|
|
852
904
|
if (!creds.accessKey) {
|
|
853
|
-
return
|
|
905
|
+
return credErr("An enterprise access key (ent_*) is required for this tool", "OPEDD_ACCESS_KEY", HOW_ACCESS_KEY);
|
|
854
906
|
}
|
|
855
907
|
const { since, cursor, limit = 50 } = args;
|
|
856
908
|
const params = new URLSearchParams({
|
|
@@ -871,7 +923,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
871
923
|
// ── stream_feed_ndjson (Phase 11 M3) ───────────────────────────────────
|
|
872
924
|
case "stream_feed_ndjson": {
|
|
873
925
|
if (!creds.accessKey) {
|
|
874
|
-
return
|
|
926
|
+
return credErr("An enterprise access key (ent_*) is required for this tool", "OPEDD_ACCESS_KEY", HOW_ACCESS_KEY);
|
|
875
927
|
}
|
|
876
928
|
const { since, cursor, limit = 200 } = args;
|
|
877
929
|
const params = new URLSearchParams({
|
|
@@ -891,8 +943,8 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
891
943
|
}
|
|
892
944
|
// ── get_audit_events (Phase 9.x + 10 M5 attestation) ───────────────────
|
|
893
945
|
case "get_audit_events": {
|
|
894
|
-
if (!creds
|
|
895
|
-
return
|
|
946
|
+
if (!auditCred(creds)) {
|
|
947
|
+
return credErr("Buyer credentials are required for this tool", "OPEDD_BUYER_TOKEN (audit-scoped key) or OPEDD_BUYER_JWT", HOW_AUDIT_CRED);
|
|
896
948
|
}
|
|
897
949
|
const { from, to, event_type, cursor, limit = 50 } = args;
|
|
898
950
|
const params = new URLSearchParams({
|
|
@@ -907,14 +959,14 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
907
959
|
if (cursor)
|
|
908
960
|
params.set("cursor", cursor);
|
|
909
961
|
const data = await opeddFetch(creds, `/buyer-audit?${params.toString()}`, {
|
|
910
|
-
headers: { Authorization: `Bearer ${creds
|
|
962
|
+
headers: { Authorization: `Bearer ${auditCred(creds)}` },
|
|
911
963
|
});
|
|
912
964
|
return ok(data);
|
|
913
965
|
}
|
|
914
966
|
// ── get_buyer_account (buyer profile + masked key list) ────────────────
|
|
915
967
|
case "get_buyer_account": {
|
|
916
968
|
if (!creds.buyerJwt) {
|
|
917
|
-
return
|
|
969
|
+
return credErr("A buyer session JWT is required for this tool", "OPEDD_BUYER_JWT", HOW_BUYER_JWT);
|
|
918
970
|
}
|
|
919
971
|
const data = await opeddFetch(creds, "/buyer-account", {
|
|
920
972
|
headers: { Authorization: `Bearer ${creds.buyerJwt}` },
|
|
@@ -923,8 +975,8 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
923
975
|
}
|
|
924
976
|
// ── article_53_attestation (Phase 12 Wave 1 W1.4) ──────────────────────
|
|
925
977
|
case "article_53_attestation": {
|
|
926
|
-
if (!creds
|
|
927
|
-
return
|
|
978
|
+
if (!auditCred(creds)) {
|
|
979
|
+
return credErr("Buyer credentials are required for this tool", "OPEDD_BUYER_TOKEN (audit-scoped key) or OPEDD_BUYER_JWT", HOW_AUDIT_CRED);
|
|
928
980
|
}
|
|
929
981
|
const { license_id, content_id, window_start, window_end } = args;
|
|
930
982
|
if (!license_id)
|
|
@@ -941,13 +993,13 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
941
993
|
// slashed "/eu-ai-act/article-53-attestation" resolved to a
|
|
942
994
|
// nonexistent function named "eu-ai-act" and 404'd — this tool had
|
|
943
995
|
// NEVER worked in production until the 2026-07-10 fix (live-probed).
|
|
944
|
-
const data = await opeddFetch(creds, `/eu-ai-act-article-53-attestation?${params.toString()}`, { headers: { Authorization: `Bearer ${creds
|
|
996
|
+
const data = await opeddFetch(creds, `/eu-ai-act-article-53-attestation?${params.toString()}`, { headers: { Authorization: `Bearer ${auditCred(creds)}` } });
|
|
945
997
|
return ok(data);
|
|
946
998
|
}
|
|
947
999
|
// ── get_compliance_dossier (Phase 11 M4) ───────────────────────────────
|
|
948
1000
|
case "get_compliance_dossier": {
|
|
949
|
-
if (!creds
|
|
950
|
-
return
|
|
1001
|
+
if (!auditCred(creds)) {
|
|
1002
|
+
return credErr("Buyer credentials are required for this tool", "OPEDD_BUYER_TOKEN (audit-scoped key) or OPEDD_BUYER_JWT", HOW_AUDIT_CRED);
|
|
951
1003
|
}
|
|
952
1004
|
const { from, to, cursor } = args;
|
|
953
1005
|
if (!from)
|
|
@@ -962,14 +1014,14 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
962
1014
|
if (cursor)
|
|
963
1015
|
params.set("cursor", cursor);
|
|
964
1016
|
const data = await opeddFetch(creds, `/buyer-compliance-report?${params.toString()}`, {
|
|
965
|
-
headers: { Authorization: `Bearer ${creds
|
|
1017
|
+
headers: { Authorization: `Bearer ${auditCred(creds)}` },
|
|
966
1018
|
});
|
|
967
1019
|
return ok(data);
|
|
968
1020
|
}
|
|
969
1021
|
// ── list_publisher_content ─────────────────────────────────────────────
|
|
970
1022
|
case "list_publisher_content": {
|
|
971
1023
|
if (!creds.pubBearer && !creds.apiKey) {
|
|
972
|
-
return
|
|
1024
|
+
return credErr("A publisher key (opedd_pub_*) is required for this tool", "OPEDD_PUB_BEARER", HOW_PUB_BEARER);
|
|
973
1025
|
}
|
|
974
1026
|
const { limit = 20, type, offset = 0 } = args;
|
|
975
1027
|
const params = new URLSearchParams({ action: "articles" });
|
|
@@ -983,7 +1035,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
|
|
|
983
1035
|
// ── push_content ───────────────────────────────────────────────────────
|
|
984
1036
|
case "push_content": {
|
|
985
1037
|
if (!creds.pubBearer && !creds.apiKey) {
|
|
986
|
-
return
|
|
1038
|
+
return credErr("A publisher key (opedd_pub_*) is required for this tool", "OPEDD_PUB_BEARER", HOW_PUB_BEARER);
|
|
987
1039
|
}
|
|
988
1040
|
const { articles } = args;
|
|
989
1041
|
if (!Array.isArray(articles) || articles.length === 0) {
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export declare function isTelemetryEnabled(): boolean;
|
|
|
8
8
|
export declare function toolCallProperties(tool: string, durationMs: number, ok: boolean, extra?: Record<string, string | number | boolean>): Record<string, string | number | boolean>;
|
|
9
9
|
export declare function initTelemetry(): void;
|
|
10
10
|
export declare function captureToolCall(tool: string, durationMs: number, ok: boolean, extra?: Record<string, string | number | boolean>): void;
|
|
11
|
+
export declare function captureClientConnect(clientName: string, clientVersion: string, extra?: Record<string, string | number | boolean>): void;
|
|
11
12
|
export declare function shutdownTelemetry(): Promise<void>;
|
package/dist/telemetry.js
CHANGED
|
@@ -87,6 +87,31 @@ extra) {
|
|
|
87
87
|
/* telemetry must never affect a tool call */
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
// Client-framework identification (2026-08-26). The MCP initialize request
|
|
91
|
+
// carries the client's SELF-DECLARED name/version (e.g. "claude-desktop",
|
|
92
|
+
// "cursor", a company's custom agent) — the only identity signal the
|
|
93
|
+
// protocol offers, and we were discarding it while trying to identify
|
|
94
|
+
// callers by city. Same privacy posture as tool calls: these two strings
|
|
95
|
+
// plus the caller-supplied extra (geo/channel) only — no params, PII, keys.
|
|
96
|
+
export function captureClientConnect(clientName, clientVersion, extra) {
|
|
97
|
+
if (!client)
|
|
98
|
+
return;
|
|
99
|
+
try {
|
|
100
|
+
client.capture({
|
|
101
|
+
distinctId: sessionId,
|
|
102
|
+
event: "mcp_client_connect",
|
|
103
|
+
properties: {
|
|
104
|
+
...(extra ?? {}),
|
|
105
|
+
client_name: clientName.slice(0, 120),
|
|
106
|
+
client_version: clientVersion.slice(0, 40),
|
|
107
|
+
server_version: SERVER_VERSION,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
/* telemetry must never affect a request */
|
|
113
|
+
}
|
|
114
|
+
}
|
|
90
115
|
export async function shutdownTelemetry() {
|
|
91
116
|
const c = client;
|
|
92
117
|
client = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opedd-mcp",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.15",
|
|
4
4
|
"description": "Licensed, rights-cleared content for AI agents — 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",
|