pi-mcp-extension 1.3.0 → 1.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.
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
- # pi-mcp
1
+ # pi-mcp-extension
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/pi-mcp.svg)](https://www.npmjs.com/package/pi-mcp)
4
- [![license](https://img.shields.io/npm/l/pi-mcp.svg)](https://github.com/irahardianto/pi-mcp/blob/main/LICENSE)
3
+ [![npm version](https://img.shields.io/npm/v/pi-mcp-extension.svg)](https://www.npmjs.com/package/pi-mcp-extension)
4
+ [![license](https://img.shields.io/npm/l/pi-mcp-extension.svg)](https://github.com/irahardianto/pi-mcp-extension/blob/main/LICENSE)
5
5
 
6
6
  **Connect [Pi](https://pi.dev) to any MCP server.** Supabase, DeepSource, Playwright, Context7, filesystem, databases — if it speaks [MCP](https://modelcontextprotocol.io), Pi can use it.
7
7
 
8
- `pi-mcp` is a production-ready [Model Context Protocol](https://modelcontextprotocol.io/) client extension for the [Pi coding agent](https://pi.dev). It manages server connections, discovers tools, and bridges them into Pi so the LLM can call them directly.
8
+ `pi-mcp-extension` is a production-ready [Model Context Protocol](https://modelcontextprotocol.io/) client extension for the [Pi coding agent](https://pi.dev). It manages server connections, discovers tools, and bridges them into Pi so the LLM can call them directly.
9
9
 
10
10
  ## Features
11
11
 
@@ -25,20 +25,20 @@
25
25
  ## Installation
26
26
 
27
27
  ```bash
28
- pi install npm:pi-mcp
28
+ pi install npm:pi-mcp-extension
29
29
  ```
30
30
 
31
31
  Or try without installing:
32
32
 
33
33
  ```bash
34
- pi -e npm:pi-mcp
34
+ pi -e npm:pi-mcp-extension
35
35
  ```
36
36
 
37
37
  ## Quick Start
38
38
 
39
39
  1. Install the extension:
40
40
  ```bash
41
- pi install npm:pi-mcp
41
+ pi install npm:pi-mcp-extension
42
42
  ```
43
43
 
44
44
  2. Create a config file at `~/.pi/agent/mcp.json` (global) or `.pi/mcp.json` (project-level):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mcp-extension",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "MCP (Model Context Protocol) client extension for the Pi coding agent — connect Pi to any MCP server",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -16,11 +16,11 @@
16
16
  "license": "MIT",
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "git+https://github.com/irahardianto/pi-mcp.git"
19
+ "url": "git+https://github.com/irahardianto/pi-mcp-extension.git"
20
20
  },
21
- "homepage": "https://github.com/irahardianto/pi-mcp",
21
+ "homepage": "https://github.com/irahardianto/pi-mcp-extension",
22
22
  "bugs": {
23
- "url": "https://github.com/irahardianto/pi-mcp/issues"
23
+ "url": "https://github.com/irahardianto/pi-mcp-extension/issues"
24
24
  },
25
25
  "files": [
26
26
  "src/",
@@ -30,13 +30,20 @@ export type PiExtensionAPI = Pick<ExtensionAPI, "registerTool" | "getActiveTools
30
30
 
31
31
  /**
32
32
  * Convert a JSON Schema object to a TypeBox schema.
33
- * Handles the common subset used by real-world MCP servers.
34
- * Falls back to Type.Any() for unsupported constructs ($ref, oneOf, etc.)
35
- * and logs a warning so users can report gaps.
33
+ * Handles the common subset used by real-world MCP servers:
34
+ * - Primitives (string, number, integer, boolean, null)
35
+ * - Arrays, objects (with required/optional/additionalProperties)
36
+ * - Enums (string enums → Union of Literals)
37
+ * - Nullable types ("type": ["string", "null"])
38
+ * - $ref (local #/$defs/ and #/definitions/ references)
39
+ * - oneOf / anyOf → TypeBox Union
40
+ * - allOf → TypeBox Intersect
41
+ * Falls back to Type.Any() for unresolvable $ref or missing type.
36
42
  */
37
43
  export function convertJsonSchemaToTypebox(
38
44
  schema: unknown,
39
45
  depth = 0,
46
+ defs?: Record<string, unknown>,
40
47
  ): TSchema {
41
48
  // Guard against infinite recursion and malformed schemas
42
49
  if (!schema || typeof schema !== "object" || Array.isArray(schema) || depth > 10) {
@@ -47,6 +54,71 @@ export function convertJsonSchemaToTypebox(
47
54
  const description = typeof s["description"] === "string" ? s["description"] : undefined;
48
55
  const opts = description ? { description } : {};
49
56
 
57
+ // Extract $defs / definitions for $ref resolution (carried through recursive calls)
58
+ const resolvedDefs: Record<string, unknown> = {
59
+ ...((s["$defs"] ?? s["definitions"]) as Record<string, unknown> | undefined),
60
+ ...defs,
61
+ };
62
+
63
+ // ── Handle $ref ──────────────────────────────────────────────────────────
64
+ if (typeof s["$ref"] === "string") {
65
+ const ref = s["$ref"] as string;
66
+ let resolved: unknown;
67
+
68
+ // Local references: #/$defs/Foo, #/definitions/Foo
69
+ if (ref.startsWith("#/")) {
70
+ const parts = ref.slice(2).split("/");
71
+ if (parts[0] === "$defs" || parts[0] === "definitions") {
72
+ const key = parts.slice(1).join("/");
73
+ resolved = resolvedDefs[key];
74
+ } else {
75
+ // Fallback: try walking the defs map by the last part
76
+ const key = parts[parts.length - 1]!;
77
+ resolved = resolvedDefs[key];
78
+ }
79
+ } else {
80
+ // External $ref — cannot resolve, fall back
81
+ console.warn(
82
+ `[pi-mcp] Cannot resolve external $ref "${ref}", using Type.Any()`,
83
+ );
84
+ return Type.Any(opts);
85
+ }
86
+
87
+ if (!resolved) {
88
+ console.warn(
89
+ `[pi-mcp] Could not resolve $ref "${ref}", using Type.Any()`,
90
+ );
91
+ return Type.Any(opts);
92
+ }
93
+
94
+ // Merge description from referencing schema into resolved schema
95
+ const merged = { ...(resolved as Record<string, unknown>) };
96
+ if (description && !merged["description"]) {
97
+ merged["description"] = description;
98
+ }
99
+ return convertJsonSchemaToTypebox(merged, depth + 1, resolvedDefs);
100
+ }
101
+
102
+ // ── Handle oneOf / anyOf → TypeBox Union ─────────────────────────────────
103
+ if (Array.isArray(s["oneOf"])) {
104
+ const members = (s["oneOf"] as unknown[])
105
+ .map((sub) => convertJsonSchemaToTypebox(sub, depth + 1, resolvedDefs));
106
+ return members.length === 1 ? members[0]! : Type.Union(members, opts);
107
+ }
108
+
109
+ if (Array.isArray(s["anyOf"])) {
110
+ const members = (s["anyOf"] as unknown[])
111
+ .map((sub) => convertJsonSchemaToTypebox(sub, depth + 1, resolvedDefs));
112
+ return members.length === 1 ? members[0]! : Type.Union(members, opts);
113
+ }
114
+
115
+ // ── Handle allOf → TypeBox Intersect ─────────────────────────────────────
116
+ if (Array.isArray(s["allOf"])) {
117
+ const members = (s["allOf"] as unknown[])
118
+ .map((sub) => convertJsonSchemaToTypebox(sub, depth + 1, resolvedDefs));
119
+ return members.length === 1 ? members[0]! : Type.Intersect(members, opts);
120
+ }
121
+
50
122
  // Handle nullable types: { "type": ["string", "null"] }
51
123
  const rawType = s["type"];
52
124
  const type = Array.isArray(rawType)
@@ -84,7 +156,7 @@ export function convertJsonSchemaToTypebox(
84
156
  case "array": {
85
157
  const items = s["items"];
86
158
  base = Type.Array(
87
- items ? convertJsonSchemaToTypebox(items, depth + 1) : Type.Unknown(),
159
+ items ? convertJsonSchemaToTypebox(items, depth + 1, resolvedDefs) : Type.Unknown(),
88
160
  opts,
89
161
  );
90
162
  break;
@@ -104,7 +176,7 @@ export function convertJsonSchemaToTypebox(
104
176
 
105
177
  const props: Record<string, TSchema> = {};
106
178
  for (const [key, value] of Object.entries(properties)) {
107
- const converted = convertJsonSchemaToTypebox(value, depth + 1);
179
+ const converted = convertJsonSchemaToTypebox(value, depth + 1, resolvedDefs);
108
180
  props[key] = required.has(key) ? converted : Type.Optional(converted);
109
181
  }
110
182
 
@@ -117,12 +189,7 @@ export function convertJsonSchemaToTypebox(
117
189
  break;
118
190
  }
119
191
  default: {
120
- // Unsupported: $ref, oneOf, anyOf, allOf, or missing type field
121
- if (s["oneOf"] || s["anyOf"] || s["allOf"] || s["$ref"]) {
122
- console.error(
123
- `[pi-mcp] Unsupported JSON Schema construct (oneOf/anyOf/allOf/$ref), using Type.Any(). Schema: ${JSON.stringify(s).slice(0, 200)}`,
124
- );
125
- }
192
+ // Truly unsupported or missing type field
126
193
  base = Type.Any(opts);
127
194
  break;
128
195
  }