opedd-mcp 0.6.13 → 0.6.14

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 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,27 @@ 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
+ const HOW_ACCESS_KEY = "Enterprise access keys (ent_*) are delivered when an enterprise licence is issued — start at https://opedd.com/enterprise " +
140
+ "or purchase programmatically with the purchase_enterprise_license tool.";
141
+ 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
142
  // ─── Tool definitions ─────────────────────────────────────────────────────────
122
143
  function buildTools(has) {
123
144
  const TOOLS = [
@@ -670,7 +691,24 @@ export const ALL_TOOLS = buildTools({
670
691
  buyerToken: true, accessKey: true, buyerJwt: true, pubBearer: true,
671
692
  });
672
693
  // ─── MCP Server ───────────────────────────────────────────────────────────────
673
- const server = new Server({ name: "opedd-mcp", version: SERVER_VERSION }, { capabilities: { tools: {} } });
694
+ // ─── Handshake instructions ──────────────────────────────────────────────────
695
+ // The MCP `instructions` field is the one string every connecting agent reads
696
+ // at initialize — it was empty until 2026-08-26 while the pitch lived only in
697
+ // registry metadata agents never see at runtime. Exported so the hosted
698
+ // gateway (opedd-mcp-gateway) serves the identical text.
699
+ export const SERVER_INSTRUCTIONS = "Opedd is the licensing rail between expert publishers and AI products: discover, purchase, verify and " +
700
+ "retrieve rights-cleared expert content — one verifiable license key per article, Tempo on-chain " +
701
+ "attestation, and EU AI Act Article 53 compliance artifacts (audit ledger + dossiers). Use it instead of " +
702
+ "unlicensed scraping for RAG, AI search, and training corpora.\n\n" +
703
+ `No credentials needed: ${NO_AUTH_TOOLS}.\n` +
704
+ "Buyer tools (purchase, account, audit/compliance): free buyer signup at https://opedd.com/buyer/signup " +
705
+ "(~2 min; an API key is issued instantly). Publisher tools (content push): free publisher signup at " +
706
+ "https://opedd.com, key under Settings → API keys.\n" +
707
+ "Supply credentials as env vars (local/stdio) or an Authorization: Bearer header (hosted gateway, " +
708
+ "https://mcp.opedd.com/mcp).\n" +
709
+ "EU CDSM Art. 4(3) / TDM-reservation queries: rsl_get. Compliance evidence: get_compliance_dossier. " +
710
+ "Docs: https://docs.opedd.com";
711
+ const server = new Server({ name: "opedd-mcp", version: SERVER_VERSION }, { capabilities: { tools: {} }, instructions: SERVER_INSTRUCTIONS });
674
712
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
675
713
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
676
714
  // Anonymous usage telemetry — captures only the tool name, duration, and
@@ -850,7 +888,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
850
888
  // ── list_feed (Phase 10 + 11) ──────────────────────────────────────────
851
889
  case "list_feed": {
852
890
  if (!creds.accessKey) {
853
- return err("OPEDD_ACCESS_KEY env var is required for this tool (ent_* enterprise access key)");
891
+ return credErr("An enterprise access key (ent_*) is required for this tool", "OPEDD_ACCESS_KEY", HOW_ACCESS_KEY);
854
892
  }
855
893
  const { since, cursor, limit = 50 } = args;
856
894
  const params = new URLSearchParams({
@@ -871,7 +909,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
871
909
  // ── stream_feed_ndjson (Phase 11 M3) ───────────────────────────────────
872
910
  case "stream_feed_ndjson": {
873
911
  if (!creds.accessKey) {
874
- return err("OPEDD_ACCESS_KEY env var is required for this tool (ent_* enterprise access key)");
912
+ return credErr("An enterprise access key (ent_*) is required for this tool", "OPEDD_ACCESS_KEY", HOW_ACCESS_KEY);
875
913
  }
876
914
  const { since, cursor, limit = 200 } = args;
877
915
  const params = new URLSearchParams({
@@ -892,7 +930,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
892
930
  // ── get_audit_events (Phase 9.x + 10 M5 attestation) ───────────────────
893
931
  case "get_audit_events": {
894
932
  if (!creds.buyerJwt) {
895
- return err("OPEDD_BUYER_JWT env var is required for this tool (Supabase session JWT)");
933
+ return credErr("A buyer session JWT is required for this tool", "OPEDD_BUYER_JWT", HOW_BUYER_JWT);
896
934
  }
897
935
  const { from, to, event_type, cursor, limit = 50 } = args;
898
936
  const params = new URLSearchParams({
@@ -914,7 +952,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
914
952
  // ── get_buyer_account (buyer profile + masked key list) ────────────────
915
953
  case "get_buyer_account": {
916
954
  if (!creds.buyerJwt) {
917
- return err("OPEDD_BUYER_JWT env var is required for this tool (Supabase session JWT)");
955
+ return credErr("A buyer session JWT is required for this tool", "OPEDD_BUYER_JWT", HOW_BUYER_JWT);
918
956
  }
919
957
  const data = await opeddFetch(creds, "/buyer-account", {
920
958
  headers: { Authorization: `Bearer ${creds.buyerJwt}` },
@@ -924,7 +962,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
924
962
  // ── article_53_attestation (Phase 12 Wave 1 W1.4) ──────────────────────
925
963
  case "article_53_attestation": {
926
964
  if (!creds.buyerJwt) {
927
- return err("OPEDD_BUYER_JWT env var is required for this tool (Supabase session JWT)");
965
+ return credErr("A buyer session JWT is required for this tool", "OPEDD_BUYER_JWT", HOW_BUYER_JWT);
928
966
  }
929
967
  const { license_id, content_id, window_start, window_end } = args;
930
968
  if (!license_id)
@@ -947,7 +985,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
947
985
  // ── get_compliance_dossier (Phase 11 M4) ───────────────────────────────
948
986
  case "get_compliance_dossier": {
949
987
  if (!creds.buyerJwt) {
950
- return err("OPEDD_BUYER_JWT env var is required for this tool (Supabase session JWT)");
988
+ return credErr("A buyer session JWT is required for this tool", "OPEDD_BUYER_JWT", HOW_BUYER_JWT);
951
989
  }
952
990
  const { from, to, cursor } = args;
953
991
  if (!from)
@@ -969,7 +1007,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
969
1007
  // ── list_publisher_content ─────────────────────────────────────────────
970
1008
  case "list_publisher_content": {
971
1009
  if (!creds.pubBearer && !creds.apiKey) {
972
- return err("OPEDD_PUB_BEARER env var is required for this tool (canonical Bearer; legacy OPEDD_API_KEY also accepted during transition)");
1010
+ return credErr("A publisher key (opedd_pub_*) is required for this tool", "OPEDD_PUB_BEARER", HOW_PUB_BEARER);
973
1011
  }
974
1012
  const { limit = 20, type, offset = 0 } = args;
975
1013
  const params = new URLSearchParams({ action: "articles" });
@@ -983,7 +1021,7 @@ export async function dispatchTool(name, args, creds = ENV_CREDS) {
983
1021
  // ── push_content ───────────────────────────────────────────────────────
984
1022
  case "push_content": {
985
1023
  if (!creds.pubBearer && !creds.apiKey) {
986
- return err("OPEDD_PUB_BEARER env var is required for this tool (your opedd_pub_ publisher key).");
1024
+ return credErr("A publisher key (opedd_pub_*) is required for this tool", "OPEDD_PUB_BEARER", HOW_PUB_BEARER);
987
1025
  }
988
1026
  const { articles } = args;
989
1027
  if (!Array.isArray(articles) || articles.length === 0) {
@@ -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.13",
3
+ "version": "0.6.14",
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",