shadowjoin 0.3.0 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +14 -1
  2. package/dist/mcp.js +28 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -219,6 +219,19 @@ const key = (value) => normalize(value, rules);
219
219
  toSql("company_name", rules); // the same thing as Postgres SQL
220
220
  ```
221
221
 
222
+ ### Claude Code plugin (easiest)
223
+
224
+ One command installs the skill and the MCP server together, and prompts for your
225
+ config path:
226
+
227
+ ```bash
228
+ claude plugin marketplace add harsh-chandak/shadowjoin
229
+ claude plugin install shadowjoin@harsh-chandak
230
+ ```
231
+
232
+ Also listed in the [official MCP registry](https://registry.modelcontextprotocol.io)
233
+ as `io.github.harsh-chandak/shadowjoin`.
234
+
222
235
  ### MCP server
223
236
 
224
237
  Lets an agent measure a join, look at real examples, propose a fix, and then
@@ -230,7 +243,7 @@ not something it writes.
230
243
  "mcpServers": {
231
244
  "shadowjoin": {
232
245
  "command": "npx",
233
- "args": ["-y", "-p", "shadowjoin", "shadowjoin-mcp"],
246
+ "args": ["-y", "-p", "shadowjoin", "-p", "@modelcontextprotocol/sdk", "shadowjoin-mcp"],
234
247
  "env": { "SHADOWJOIN_CONFIG": "/abs/path/to/shadowjoin.config.json" }
235
248
  }
236
249
  }
package/dist/mcp.js CHANGED
@@ -11,13 +11,36 @@
11
11
  import { readFile } from "node:fs/promises";
12
12
  import { resolve } from "node:path";
13
13
  import { randomUUID } from "node:crypto";
14
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
15
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
16
- import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
14
+ import { createRequire } from "node:module";
17
15
  import { scan } from "./scan.js";
18
16
  import { ALL_RULE_IDS, rulesByIds, toSql } from "./normalize.js";
19
17
  import { rowsFromCsv } from "./adapters/csv.js";
20
18
  import { rowsFromJson } from "./adapters/json.js";
19
+ const VERSION = createRequire(import.meta.url)("../package.json").version;
20
+ /**
21
+ * The SDK is an optional peer, so the core library and CLI stay dependency-free.
22
+ * Import it dynamically to turn a missing install into an instruction rather
23
+ * than a module-resolution stack trace, which is what an MCP client shows the
24
+ * user as nothing more than "Connection closed".
25
+ */
26
+ async function loadSdk() {
27
+ try {
28
+ const [{ Server }, { StdioServerTransport }, types] = await Promise.all([
29
+ import("@modelcontextprotocol/sdk/server/index.js"),
30
+ import("@modelcontextprotocol/sdk/server/stdio.js"),
31
+ import("@modelcontextprotocol/sdk/types.js"),
32
+ ]);
33
+ return { Server, StdioServerTransport, ...types };
34
+ }
35
+ catch {
36
+ process.stderr.write("shadowjoin-mcp needs @modelcontextprotocol/sdk, which is an optional peer dependency.\n" +
37
+ "Run it with the SDK provided:\n" +
38
+ " npx -y -p shadowjoin -p @modelcontextprotocol/sdk shadowjoin-mcp\n" +
39
+ "or install it alongside shadowjoin:\n" +
40
+ " npm i shadowjoin @modelcontextprotocol/sdk\n");
41
+ process.exit(1);
42
+ }
43
+ }
21
44
  const CONFIG_PATH = resolve(process.env.SHADOWJOIN_CONFIG ?? "shadowjoin.config.json");
22
45
  async function loadConfig() {
23
46
  try {
@@ -133,7 +156,8 @@ const TOOLS = [
133
156
  },
134
157
  },
135
158
  ];
136
- const server = new Server({ name: "shadowjoin", version: "0.1.0" }, { capabilities: { tools: {} } });
159
+ const { Server, StdioServerTransport, CallToolRequestSchema, ListToolsRequestSchema } = await loadSdk();
160
+ const server = new Server({ name: "shadowjoin", version: VERSION }, { capabilities: { tools: {} } });
137
161
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
138
162
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
139
163
  const { name } = request.params;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadowjoin",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Measure the matches your exact join is silently dropping. Runs a shadow matcher alongside your real join key and reports a verified floor on lost matches, plus the normalization rule that would recover each one.",
5
5
  "keywords": [
6
6
  "entity-resolution",