openfactory-mcp 0.3.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.
Files changed (3) hide show
  1. package/README.md +54 -0
  2. package/bin/start.js +188 -0
  3. package/package.json +22 -0
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # openfactory-mcp
2
+
3
+ > Manufacturing as a function call. Connect Claude (or any MCP agent) to verified GBA factories.
4
+
5
+ ```bash
6
+ npx openfactory-mcp
7
+ ```
8
+
9
+ ## Claude Desktop setup
10
+
11
+ Add to `~/.claude/claude_desktop_config.json`:
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "openfactory": {
17
+ "command": "npx",
18
+ "args": ["openfactory-mcp"],
19
+ "env": {
20
+ "OPENFACTORY_URL": "http://localhost:3000"
21
+ }
22
+ }
23
+ }
24
+ }
25
+ ```
26
+
27
+ Then ask Claude:
28
+ > *"Find me a verified PCB factory in Shenzhen with MOQ under 500, get a quote for 2000 units of an IoT sensor board, and place the order."*
29
+
30
+ ## Tools
31
+
32
+ | Tool | What it does |
33
+ |------|-------------|
34
+ | `search_factories` | Filter 10+ verified GBA factories by category, MOQ, tier |
35
+ | `get_quote` | Request price quote → unit price, total, lead time |
36
+ | `place_order` | Place escrow-protected order |
37
+ | `track_order` | Get production status + full event history |
38
+ | `update_order_status` | Advance production milestone (factory-side) |
39
+ | `get_analytics` | Platform GMV, quote volume, factory stats |
40
+
41
+ ## Environment
42
+
43
+ | Variable | Default | Description |
44
+ |----------|---------|-------------|
45
+ | `OPENFACTORY_URL` | `http://localhost:3000` | OpenFactory API base URL |
46
+
47
+ ## Run the API server
48
+
49
+ ```bash
50
+ git clone https://github.com/fengweit/OpenFactory
51
+ cd OpenFactory && npm install && npm run api
52
+ ```
53
+
54
+ Server starts at `http://localhost:3000` with 10 seeded GBA factories.
package/bin/start.js ADDED
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * openfactory-mcp v0.3.0 — factory-side API for AI procurement agents
4
+ *
5
+ * Connects to the OpenFactory REST API and exposes 8 manufacturing tools
6
+ * to any MCP-compatible AI agent (Claude, GPT-4o, Lio, Didero, etc.)
7
+ *
8
+ * Usage:
9
+ * npx openfactory-mcp # connects to localhost:3000
10
+ * OPENFACTORY_URL=https://api.openfactory.com npx openfactory-mcp
11
+ *
12
+ * Claude Desktop config (~/.claude/claude_desktop_config.json):
13
+ * {
14
+ * "mcpServers": {
15
+ * "openfactory": {
16
+ * "command": "npx",
17
+ * "args": ["openfactory-mcp"],
18
+ * "env": { "OPENFACTORY_URL": "http://localhost:3000" }
19
+ * }
20
+ * }
21
+ * }
22
+ *
23
+ * Tools:
24
+ * search_factories — find verified GBA factories by category/MOQ/rating
25
+ * get_instant_quote ⚡ — sub-100ms quote from pre-declared factory pricing
26
+ * query_live_capacity ⚡ — factories available to start production RIGHT NOW
27
+ * get_quote — async RFQ (factory responds within 2h via WeChat)
28
+ * place_order — place order with USD escrow protection
29
+ * track_order — production milestone tracking
30
+ * update_order_status — factory advances order status
31
+ * get_analytics — platform GMV, response rates, top categories
32
+ */
33
+
34
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
35
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
36
+ import { z } from "zod";
37
+
38
+ const BASE_URL = process.env.OPENFACTORY_URL || "http://localhost:3000";
39
+
40
+ const server = new McpServer({
41
+ name: "openfactory",
42
+ version: "0.3.0",
43
+ description: "Factory-side API for AI procurement agents. Call verified GBA factories — instant quotes in <100ms, live capacity, orders, escrow.",
44
+ });
45
+
46
+ async function api(path, options = {}) {
47
+ const res = await fetch(`${BASE_URL}${path}`, {
48
+ headers: { "Content-Type": "application/json", ...options.headers },
49
+ ...options,
50
+ });
51
+ if (!res.ok) throw new Error(`API error ${res.status}: ${await res.text()}`);
52
+ return res.json();
53
+ }
54
+
55
+ function ok(data) {
56
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
57
+ }
58
+ function err(e) {
59
+ return { content: [{ type: "text", text: `Error: ${e instanceof Error ? e.message : String(e)}` }], isError: true };
60
+ }
61
+
62
+ // ── get_instant_quote ⚡ ──────────────────────────────────────────
63
+ server.tool("get_instant_quote",
64
+ "⚡ Get a binding quote in <100ms from a factory's pre-declared pricing rules. No async wait. Returns unit price, total, lead time, and confidence score. Use this first — fall back to get_quote for complex or custom requirements.",
65
+ {
66
+ factory_id: z.string().describe("Factory ID (e.g. sz-006). Use search_factories or query_live_capacity to find IDs."),
67
+ category: z.string().describe("Product category: pcb_assembly | electronics_accessories | cable_assembly | plastic_injection | metal_enclosure | furniture"),
68
+ quantity: z.number().int().positive().describe("Number of units to manufacture"),
69
+ },
70
+ async ({ factory_id, category, quantity }) => {
71
+ try {
72
+ const qs = new URLSearchParams({ category, qty: String(quantity) });
73
+ return ok(await api(`/factories/${factory_id}/instant-quote?${qs}`));
74
+ } catch(e) { return err(e); }
75
+ }
76
+ );
77
+
78
+ // ── query_live_capacity ⚡ ────────────────────────────────────────
79
+ server.tool("query_live_capacity",
80
+ "⚡ Find factories that can START PRODUCTION RIGHT NOW for a given category and quantity. Returns live availability, unit price, and earliest start date. Analogous to AWS spot instances — real-time manufacturing capacity.",
81
+ {
82
+ category: z.string().describe("Product category: pcb_assembly | electronics_accessories | cable_assembly | plastic_injection | metal_enclosure | furniture"),
83
+ quantity: z.number().int().positive().describe("Required production quantity"),
84
+ city: z.string().optional().describe("Filter by city: shenzhen | guangzhou | dongguan | foshan | huizhou | zhongshan | jiangmen | zhuhai | zhuhai"),
85
+ },
86
+ async ({ category, quantity, city }) => {
87
+ try {
88
+ const qs = new URLSearchParams({ category, qty: String(quantity) });
89
+ if (city) qs.set("city", city);
90
+ return ok(await api(`/capacity?${qs}`));
91
+ } catch(e) { return err(e); }
92
+ }
93
+ );
94
+
95
+ // ── search_factories ─────────────────────────────────────────────
96
+ server.tool("search_factories",
97
+ "Search verified GBA factories (Shenzhen · Guangzhou · Dongguan · Foshan) by category, MOQ, and price tier. Returns ranked matches with capabilities and WeChat contact.",
98
+ {
99
+ category: z.string().optional().describe("electronics_accessories | pcb_assembly | plastic_injection | metal_enclosure | cable_assembly | furniture"),
100
+ max_moq: z.number().optional().describe("Maximum minimum order quantity"),
101
+ price_tier: z.string().optional().describe("budget | mid | premium"),
102
+ min_rating: z.number().optional().describe("Minimum rating 0–5"),
103
+ verified_only: z.boolean().optional().describe("Only return physically verified factories (recommended)"),
104
+ },
105
+ async (params) => {
106
+ try {
107
+ const qs = new URLSearchParams();
108
+ if (params.category) qs.set("category", params.category);
109
+ if (params.max_moq) qs.set("max_moq", String(params.max_moq));
110
+ if (params.price_tier) qs.set("price_tier", params.price_tier);
111
+ if (params.min_rating) qs.set("min_rating", String(params.min_rating));
112
+ if (params.verified_only !== undefined) qs.set("verified_only", String(params.verified_only));
113
+ return ok(await api(`/factories?${qs}`));
114
+ } catch(e) { return err(e); }
115
+ }
116
+ );
117
+
118
+ // ── get_quote ────────────────────────────────────────────────────
119
+ server.tool("get_quote",
120
+ "Request a price quote from a factory. Factory responds via WeChat within 2h. Returns a quote_id valid for 7 days. For instant pricing, use get_instant_quote instead.",
121
+ {
122
+ factory_id: z.string().describe("Factory ID from search_factories (e.g. sz-001)"),
123
+ product_description: z.string().describe("Plain-language description of what to manufacture"),
124
+ quantity: z.number().int().positive().describe("Number of units"),
125
+ buyer_id: z.string().optional().describe("Your buyer ID"),
126
+ target_price_usd: z.number().optional().describe("Target unit price in USD"),
127
+ deadline_days: z.number().optional().describe("Days until delivery needed"),
128
+ },
129
+ async (params) => {
130
+ try { return ok(await api("/quotes", { method: "POST", body: JSON.stringify(params) })); }
131
+ catch(e) { return err(e); }
132
+ }
133
+ );
134
+
135
+ // ── place_order ──────────────────────────────────────────────────
136
+ server.tool("place_order",
137
+ "Place a manufacturing order from an accepted quote. Payment held in USD escrow until buyer confirms receipt.",
138
+ {
139
+ quote_id: z.string().describe("quote_id from get_quote or get_instant_quote"),
140
+ buyer_id: z.string().describe("Your buyer ID"),
141
+ },
142
+ async (params) => {
143
+ try { return ok(await api("/orders", { method: "POST", body: JSON.stringify(params) })); }
144
+ catch(e) { return err(e); }
145
+ }
146
+ );
147
+
148
+ // ── track_order ──────────────────────────────────────────────────
149
+ server.tool("track_order",
150
+ "Get current production status and full event history for an order.",
151
+ { order_id: z.string().describe("order_id from place_order") },
152
+ async ({ order_id }) => {
153
+ try { return ok(await api(`/orders/${order_id}`)); }
154
+ catch(e) { return err(e); }
155
+ }
156
+ );
157
+
158
+ // ── update_order_status ───────────────────────────────────────────
159
+ server.tool("update_order_status",
160
+ "Update the production milestone of an order (factory-side). Status: confirmed | in_production | qc | shipped | delivered.",
161
+ {
162
+ order_id: z.string(),
163
+ status: z.enum(["confirmed", "in_production", "qc", "shipped", "delivered"]),
164
+ note: z.string().optional().describe("Optional note (e.g. tracking number)"),
165
+ },
166
+ async (params) => {
167
+ try {
168
+ return ok(await api(`/orders/${params.order_id}/status`, {
169
+ method: "PATCH", body: JSON.stringify({ status: params.status, note: params.note })
170
+ }));
171
+ } catch(e) { return err(e); }
172
+ }
173
+ );
174
+
175
+ // ── get_analytics ─────────────────────────────────────────────────
176
+ server.tool("get_analytics",
177
+ "Get platform analytics: factory count, quote volume, GMV, response rates, top categories.",
178
+ {},
179
+ async () => {
180
+ try { return ok(await api("/analytics")); }
181
+ catch(e) { return err(e); }
182
+ }
183
+ );
184
+
185
+ // ── start ─────────────────────────────────────────────────────────
186
+ const transport = new StdioServerTransport();
187
+ await server.connect(transport);
188
+ console.error(`✅ openfactory-mcp v0.3.0 connected to ${BASE_URL} (8 tools: search_factories, get_instant_quote ⚡, query_live_capacity ⚡, get_quote, place_order, track_order, update_order_status, get_analytics)`);
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "openfactory-mcp",
3
+ "version": "0.3.0",
4
+ "description": "Factory-side API for AI procurement agents. Call verified GBA factories via MCP — instant quotes in 36ms, live capacity, orders, tracking.",
5
+ "type": "module",
6
+ "bin": {
7
+ "openfactory-mcp": "./bin/start.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node bin/start.js"
11
+ },
12
+ "dependencies": {
13
+ "@modelcontextprotocol/sdk": "^1.0.0",
14
+ "zod": "^3.22.0"
15
+ },
16
+ "engines": { "node": ">=18" },
17
+ "keywords": ["mcp", "manufacturing", "shenzhen", "factory", "gba", "sourcing", "claude", "procurement", "instant-quote", "ai-agent", "greater-bay-area"],
18
+ "author": "Fengwei Tian <fengweit@gmail.com>",
19
+ "license": "MIT",
20
+ "homepage": "https://github.com/fengweit/OpenFactory",
21
+ "repository": { "type": "git", "url": "https://github.com/fengweit/OpenFactory.git" }
22
+ }