pi-cloudflare 0.5.5 → 0.6.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,7 +1,8 @@
1
1
  # pi-cloudflare
2
2
 
3
- One install for Cloudflare-driven agent work: **skills + MCP tools + setup
4
- helper** in a single pi package.
3
+ One package for Cloudflare-driven agent work: **skills + MCP tools + setup
4
+ helper**, distributed both as a native Pi package and an
5
+ [Agent Plugins 1.0](https://agent-plugins.org/) package.
5
6
 
6
7
  - **Skills** (12 vendored from the official
7
8
  [cloudflare/skills](https://github.com/cloudflare/skills) repo: `cloudflare`,
@@ -21,26 +22,45 @@ helper** in a single pi package.
21
22
  | `cf_builds_*` | Workers Builds insights |
22
23
  | `cf_obs_*` | Workers logs/metrics/traces |
23
24
 
24
- Requires pi with package support, Node 20.19+ (or 22.12+), and network
25
- access. No browser, wrangler CLI, or API token needed to install; the docs
26
- tools work immediately after install.
25
+ Requires Node 20.19+ (or 22.12+) and network access. Native Pi installation
26
+ also requires Pi package support. No browser, wrangler CLI, or API token is
27
+ needed to install; the docs tools work immediately after install.
27
28
 
28
29
  ![Architecture](https://raw.githubusercontent.com/0xPlayerOne/pi-cloudflare/main/docs/assets/architecture.svg)
29
30
 
30
31
  ## Install
31
32
 
33
+ ### Pi
34
+
32
35
  ```bash
33
36
  pi install npm:pi-cloudflare
34
37
  ```
35
38
 
36
- Tools and skills register on the **next** session start. (`web-perf` is
37
- intentionally not vendored: keep a local customized copy instead, since the
38
- upstream version would clobber environment-specific rules.)
39
+ Tools and skills register on the **next** session start.
40
+
41
+ ### Agent Plugins 1.0
42
+
43
+ The published npm package is also a self-contained Agent Plugin. Its root
44
+ `plugin.json` discovers `skills/`, while `mcp.json` launches the portable
45
+ stdio gateway in `dist/mcp-server.js`.
46
+
47
+ Agent Plugins deliberately leaves installation sources to each client. Install
48
+ or unpack the npm package using the client-specific plugin flow, with the
49
+ package root as `PLUGIN_ROOT`. A raw Git checkout must be built first with
50
+ `npm ci && npm run build`; npm releases already contain `dist/`.
51
+
52
+ The portable gateway exposes the same `cf_api_*`, `cf_docs_*`,
53
+ `cf_bindings_*`, `cf_builds_*`, and `cf_obs_*` tool names as the native Pi
54
+ adapter. OAuth state is stored under the client-managed `${PLUGIN_DATA}`
55
+ directory rather than `~/.pi`.
56
+
57
+ (`web-perf` is intentionally not vendored: keep a local customized copy
58
+ instead, since the upstream version would clobber environment-specific rules.)
39
59
 
40
60
  ## Authenticate (one-time browser OAuth)
41
61
 
42
62
  ```bash
43
- npx -p pi-cloudflare pi-cloudflare-setup # authorize missing servers
63
+ npx -p pi-cloudflare pi-cloudflare-setup # authorize missing servers
44
64
  npx -p pi-cloudflare pi-cloudflare-setup --only builds # re-auth specific servers
45
65
  ```
46
66
 
@@ -50,9 +70,14 @@ you approve, and tokens (with refresh) are stored owner-only in
50
70
  `~/.pi/cloudflare-tokens.json`. The extension refreshes them silently
51
71
  before expiry, and setup skips servers that are still fresh. If a server
52
72
  later rejects its token, rerun setup (with `--only` for just that one).
73
+
74
+ Agent Plugins clients use their own token file under `${PLUGIN_DATA}`. When
75
+ authentication is missing or rejected, call the generated
76
+ `cf_<server>_reauthenticate` tool and run the exact command it returns; that
77
+ command includes the plugin-local setup script and the correct data path.
53
78
  Nothing is ever logged or committed.
54
79
 
55
- ## Configure (optional)
80
+ ## Configure Pi (optional)
56
81
 
57
82
  In `~/.pi/agent/settings.json`:
58
83
 
@@ -67,12 +92,11 @@ In `~/.pi/agent/settings.json`:
67
92
 
68
93
  ## Persistent auth (a month and beyond)
69
94
 
70
- Browser OAuth access tokens live about an hour; the extension refreshes
71
- them silently on every session start and before every tool call, so daily
72
- use never re-authenticates. When refresh itself is rejected (revoked,
73
- rotated away by a parallel login, or expired), agents get an exact
74
- recovery command instead of a dead end — and a `cf_<server>_reauthenticate`
75
- tool appears with the same instructions.
95
+ Browser OAuth access tokens live about an hour; both adapters refresh them
96
+ silently before tool calls, so daily use normally does not re-authenticate.
97
+ When refresh itself is rejected (revoked, rotated away by a parallel login,
98
+ or expired), agents get an exact recovery command instead of a dead end — and
99
+ a `cf_<server>_reauthenticate` tool appears with the same instructions.
76
100
 
77
101
  Two levers for longer-lived credentials:
78
102
 
@@ -83,11 +107,15 @@ Two levers for longer-lived credentials:
83
107
  ```jsonc
84
108
  {
85
109
  "pi-cloudflare": {
86
- "apiToken": "${CLOUDFLARE_API_TOKEN}", // env expansion supported
110
+ "apiToken": "${CLOUDFLARE_API_TOKEN}", // native Pi
87
111
  },
88
112
  }
89
113
  ```
90
114
 
115
+ Agent Plugin hosts can supply `CLOUDFLARE_API_TOKEN` to the MCP subprocess
116
+ through their client-specific environment/secret mechanism. Agent Plugins
117
+ 1.0 intentionally does not define a portable secret-reference field.
118
+
91
119
  Create one at dash.cloudflare.com → Manage Account → API Tokens with
92
120
  the scopes your agents need (exact template, additions, and account
93
121
  scoping in `docs/api-token.md`). Other servers stay on browser OAuth.
@@ -124,9 +152,9 @@ closed on scope). They complement; neither replaces the other.
124
152
  | Symptom | Likely cause | Fix |
125
153
  | -------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
126
154
  | `Browser connection failed` on session start | A server is down or its token expired | The extension skips it with a warning and continues; rerun `pi-cloudflare-setup --only <server>` for the failing one |
127
- | OAuth tab never opens | Headless environment or blocked popup | Copy the printed URL into any browser; tokens land in `~/.pi/cloudflare-tokens.json` either way |
128
- | `401` from one server only | That server's refresh token was revoked | `npx -p pi-cloudflare pi-cloudflare-setup --only <server>` |
129
- | Tools missing for a server | Disabled via `servers: { <id>: false }` | Re-enable in settings; tools register on next session start |
155
+ | OAuth tab never opens | Headless environment or blocked popup | Copy the printed URL into any browser; native Pi tokens land in `~/.pi/cloudflare-tokens.json` |
156
+ | `401` from one server only | That server's refresh token was revoked | Call `cf_<server>_reauthenticate` for the host-correct recovery command |
157
+ | Tools missing for a server | Disabled in native Pi settings | Re-enable it; tools register on next session start |
130
158
  | Rate-limited API calls | Too many write calls in a loop | Back off and batch; prefer one `cf_api_execute` with a precise query over paginated scans |
131
159
 
132
160
  ## Development
package/bin/setup.mjs CHANGED
@@ -2,20 +2,30 @@
2
2
  /**
3
3
  * pi-cloudflare setup: one-time browser OAuth for every Cloudflare MCP
4
4
  * server. Each server is its own OAuth issuer, so approval happens once per
5
- * server (docs needs none). Tokens (with refresh) are stored owner-only in
6
- * ~/.pi/cloudflare-tokens.json and refreshed automatically afterwards.
5
+ * server (docs needs none).
6
+ *
7
+ * Native Pi defaults to ~/.pi/cloudflare-tokens.json. Agent Plugins clients
8
+ * pass --token-file with their ${PLUGIN_DATA} path so credentials remain
9
+ * client-local and do not require Pi to be installed.
7
10
  *
8
11
  * Usage:
9
- * pi-cloudflare-setup # authorize missing/expired servers
10
- * pi-cloudflare-setup --only builds # re-auth specific servers
12
+ * pi-cloudflare-setup
13
+ * pi-cloudflare-setup --only builds
11
14
  * pi-cloudflare-setup --only api,observability
15
+ * pi-cloudflare-setup --token-file /path/to/cloudflare-tokens.json --only api
12
16
  *
13
17
  * Nothing secret is ever logged or written anywhere else.
14
18
  */
15
19
  import { connectAll } from '../dist/client.js'
16
20
  import { CLOUDFLARE_SERVERS } from '../dist/servers.js'
17
21
  import { runOAuthFlow } from '../dist/auth-flow.js'
18
- import { partitionServers, readTokenFile, writeTokenFile } from '../dist/token-store.js'
22
+ import {
23
+ partitionServers,
24
+ readTokenFile,
25
+ readTokenFileAt,
26
+ writeTokenFile,
27
+ writeTokenFileAt,
28
+ } from '../dist/token-store.js'
19
29
 
20
30
  const AUTHED_IDS = ['api', 'bindings', 'builds', 'observability']
21
31
 
@@ -39,9 +49,14 @@ function parseOnly() {
39
49
  return ids
40
50
  }
41
51
 
52
+ const tokenFile = argValue('--token-file')
53
+ const readStore = () => (tokenFile ? readTokenFileAt(tokenFile) : readTokenFile())
54
+ const writeStore = (servers) =>
55
+ tokenFile ? writeTokenFileAt(servers, tokenFile) : writeTokenFile(servers)
56
+
42
57
  const only = parseOnly()
43
58
  const wanted = only ?? AUTHED_IDS
44
- const file = readTokenFile() ?? { version: 1, servers: {} }
59
+ const file = readStore() ?? { version: 1, servers: {} }
45
60
  const { fresh, needed } = partitionServers(wanted, file.servers)
46
61
 
47
62
  if (fresh.length > 0) {
@@ -62,7 +77,7 @@ if (needed.length === 0) {
62
77
  try {
63
78
  const { tokens, clientId, tokenEndpoint } = await runOAuthFlow(definition)
64
79
  file.servers[id] = { ...tokens, clientId, tokenEndpoint }
65
- writeTokenFile(file.servers)
80
+ writeStore(file.servers)
66
81
  console.log(`[${index}/${needed.length}] ${id}: authorized and stored\n`)
67
82
  } catch (error) {
68
83
  console.log(
@@ -73,7 +88,7 @@ if (needed.length === 0) {
73
88
  }
74
89
 
75
90
  console.log('Verifying all servers...\n')
76
- const stored = readTokenFile()
91
+ const stored = readStore()
77
92
  let okCount = 0
78
93
  const failed = []
79
94
  for (const definition of CLOUDFLARE_SERVERS) {
@@ -98,6 +113,7 @@ for (const definition of CLOUDFLARE_SERVERS) {
98
113
 
99
114
  console.log(`\n${okCount}/5 servers working.`)
100
115
  if (failed.length > 0) {
101
- console.log(`Re-authenticate with: pi-cloudflare-setup --only ${failed.join(',')}`)
116
+ const tokenArg = tokenFile ? ` --token-file ${JSON.stringify(tokenFile)}` : ''
117
+ console.log(`Re-authenticate with: pi-cloudflare-setup${tokenArg} --only ${failed.join(',')}`)
102
118
  process.exit(1)
103
119
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- import { type ServerConnection } from './client.js';
2
- import { type CloudflareServerDefinition } from './servers.js';
3
- import { type StoredServerTokens } from './token-store.js';
1
+ export { isAuthFailure, reauthHint, syncFromFile } from './runtime.js';
4
2
  interface PiToolDefinition {
5
3
  name: string;
6
4
  label?: string;
@@ -12,36 +10,13 @@ interface PiHost {
12
10
  registerTool: (definition: PiToolDefinition) => void;
13
11
  on: (event: 'session_start' | 'session_shutdown', handler: (...args: never[]) => unknown) => void;
14
12
  }
15
- interface ServerEntry {
16
- definition: CloudflareServerDefinition;
17
- connection?: ServerConnection;
18
- stored?: StoredServerTokens;
19
- /** Static bearer token (api server only): never expires, never refreshes. */
20
- staticToken?: string;
21
- timeoutMs: number;
22
- /** Access token the live connection was built with; drift triggers reconnect. */
23
- connectedToken?: string;
24
- }
25
- /** Exact command that re-authorizes one server; shown to agents, never guessed. */
26
- export declare function reauthHint(serverId: string): string;
27
- /** True when a failure smells like rejected credentials rather than a broken server. */
28
- export declare function isAuthFailure(error: unknown): boolean;
29
- /**
30
- * Adopt rotations performed by sibling sessions: parallel Pi processes
31
- * share one token file, and refresh grants are single-use. If the file
32
- * holds a different grant than memory, the file wins without network I/O.
33
- */
34
- export declare function syncFromFile(entry: ServerEntry, home?: string): void;
35
13
  /**
36
- * pi-coding-agent extension entry point.
14
+ * Native pi-coding-agent adapter.
37
15
  *
38
- * Credentials come only from per-server browser OAuth (pi-cloudflare-setup
39
- * --oauth), stored owner-only in ~/.pi/cloudflare-tokens.json. The docs
40
- * server needs no credential. On session_start every enabled server is
41
- * connected independently and its tools registered with a `cf_<server>_`
42
- * prefix; unreachable servers are skipped with a re-auth hint instead of
43
- * failing the session. On session_shutdown all connections close.
16
+ * The Cloudflare runtime is host-independent; Pi contributes only settings,
17
+ * lifecycle hooks, and tool registration. This preserves the existing
18
+ * `pi install npm:pi-cloudflare` behavior while Agent Plugins clients use the
19
+ * stdio adapter in mcp.json.
44
20
  */
45
21
  export default function piCloudflareExtension(pi: PiHost): void;
46
- export {};
47
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAIlE,OAAO,EAAsB,KAAK,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAClF,OAAO,EAA4C,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAEpG,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,EAAE,CACP,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,OAAO,CAAC,CAAA;CACtB;AAED,UAAU,MAAM;IACd,YAAY,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACpD,EAAE,EAAE,CAAC,KAAK,EAAE,eAAe,GAAG,kBAAkB,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,KAAK,IAAI,CAAA;CAClG;AAMD,UAAU,WAAW;IACnB,UAAU,EAAE,0BAA0B,CAAA;IACtC,UAAU,CAAC,EAAE,gBAAgB,CAAA;IAC7B,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AA4CD,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQnD;AAED,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKrD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAKpE;AAmCD;;;;;;;;;GASG;AACH,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAwF9D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEtE,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,EAAE,CACP,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,OAAO,CAAC,CAAA;CACtB;AAED,UAAU,MAAM;IACd,YAAY,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACpD,EAAE,EAAE,CAAC,KAAK,EAAE,eAAe,GAAG,kBAAkB,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,KAAK,IAAI,CAAA;CAClG;AAsCD;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAgB9D"}
package/dist/index.js CHANGED
@@ -1,22 +1,8 @@
1
+ import { readFileSync } from 'node:fs';
1
2
  import { homedir } from 'node:os';
2
3
  import { join } from 'node:path';
3
- import { readFileSync } from 'node:fs';
4
- import { Type } from 'typebox';
5
- import { connectServer } from './client.js';
6
- import { refreshAccessToken } from './oauth.js';
7
- import { resolveConfig } from './config.js';
8
- import { buildAllRegistrations } from './proxy.js';
9
- import { CLOUDFLARE_SERVERS } from './servers.js';
10
- import { isExpired, readTokenFile, writeTokenFile } from './token-store.js';
11
- async function reconnect(entry) {
12
- await entry.connection?.close().catch(() => undefined);
13
- const token = entry.staticToken ?? entry.stored?.accessToken;
14
- entry.connection = await connectServer(entry.definition, {
15
- apiToken: token,
16
- timeoutMs: entry.timeoutMs,
17
- });
18
- entry.connectedToken = token;
19
- }
4
+ import { CloudflareRuntime } from './runtime.js';
5
+ export { isAuthFailure, reauthHint, syncFromFile } from './runtime.js';
20
6
  function expandEnvVars(value) {
21
7
  if (typeof value === 'string') {
22
8
  return value.replace(/\$\{([^}]+)\}/g, (_match, expr) => {
@@ -47,158 +33,27 @@ function loadUserConfig() {
47
33
  function warn(message) {
48
34
  console.warn(`[pi-cloudflare] ${message}`);
49
35
  }
50
- /** Exact command that re-authorizes one server; shown to agents, never guessed. */
51
- export function reauthHint(serverId) {
52
- return (`${serverId} needs re-authentication (token expired, revoked, or never granted). ` +
53
- `For temporary access, run in a terminal (approve in the browser when it opens): ` +
54
- `npx -p pi-cloudflare pi-cloudflare-setup --only ${serverId}. ` +
55
- `For persistent access across sessions, create an API token instead — ` +
56
- `see the cloudflare-auth-setup skill (it asks once, then sets up either path).`);
57
- }
58
- /** True when a failure smells like rejected credentials rather than a broken server. */
59
- export function isAuthFailure(error) {
60
- const message = error instanceof Error ? error.message : String(error);
61
- return /\b401\b|\b403\b|unauthorized|invalid_token|invalid_grant|token refresh failed|expired|forbidden|authenticate/i.test(message);
62
- }
63
36
  /**
64
- * Adopt rotations performed by sibling sessions: parallel Pi processes
65
- * share one token file, and refresh grants are single-use. If the file
66
- * holds a different grant than memory, the file wins without network I/O.
67
- */
68
- export function syncFromFile(entry, home) {
69
- const latest = readTokenFile(home)?.servers[entry.definition.id];
70
- if (latest && latest.refreshToken !== entry.stored?.refreshToken) {
71
- entry.stored = latest;
72
- }
73
- }
74
- /** Refresh unconditionally (caller decided the token is rejected). Persists and reconnects. */
75
- async function refreshNow(entry) {
76
- syncFromFile(entry);
77
- const stored = entry.stored;
78
- if (!stored?.refreshToken)
79
- throw new Error(`${entry.definition.id}: no refresh token stored`);
80
- const fresh = await refreshAccessToken({
81
- tokenEndpoint: stored.tokenEndpoint,
82
- clientId: stored.clientId,
83
- refreshToken: stored.refreshToken,
84
- });
85
- entry.stored = { ...stored, ...fresh };
86
- const file = readTokenFile() ?? { version: 1, servers: {} };
87
- file.servers[entry.definition.id] = entry.stored;
88
- writeTokenFile(file.servers);
89
- await reconnect(entry);
90
- }
91
- /** Refresh an OAuth token that is expired (or nearly so), persisting the result. Static tokens skip refresh. */
92
- async function ensureFreshToken(entry) {
93
- if (entry.staticToken)
94
- return entry.staticToken;
95
- syncFromFile(entry);
96
- const stored = entry.stored;
97
- if (!stored)
98
- return undefined;
99
- if (!isExpired(stored) || !stored.refreshToken) {
100
- if (!entry.connection || entry.connectedToken !== stored.accessToken) {
101
- await reconnect(entry);
102
- }
103
- return stored.accessToken;
104
- }
105
- await refreshNow(entry);
106
- return entry.stored?.accessToken;
107
- }
108
- /**
109
- * pi-coding-agent extension entry point.
37
+ * Native pi-coding-agent adapter.
110
38
  *
111
- * Credentials come only from per-server browser OAuth (pi-cloudflare-setup
112
- * --oauth), stored owner-only in ~/.pi/cloudflare-tokens.json. The docs
113
- * server needs no credential. On session_start every enabled server is
114
- * connected independently and its tools registered with a `cf_<server>_`
115
- * prefix; unreachable servers are skipped with a re-auth hint instead of
116
- * failing the session. On session_shutdown all connections close.
39
+ * The Cloudflare runtime is host-independent; Pi contributes only settings,
40
+ * lifecycle hooks, and tool registration. This preserves the existing
41
+ * `pi install npm:pi-cloudflare` behavior while Agent Plugins clients use the
42
+ * stdio adapter in mcp.json.
117
43
  */
118
44
  export default function piCloudflareExtension(pi) {
119
- let entries = [];
45
+ let runtime;
120
46
  pi.on('session_start', async () => {
121
- for (const entry of entries) {
122
- await entry.connection?.close().catch(() => undefined);
123
- }
124
- entries = [];
125
- const userConfig = loadUserConfig() ?? {};
126
- const config = resolveConfig(userConfig);
127
- const file = readTokenFile();
128
- const definitions = CLOUDFLARE_SERVERS.filter((server) => config.enabledServerIds.includes(server.id));
129
- for (const definition of definitions) {
130
- const entry = {
131
- definition,
132
- timeoutMs: config.connectTimeoutMs,
133
- staticToken: definition.id === 'api' ? userConfig.apiToken : undefined,
134
- };
135
- try {
136
- entry.stored = file?.servers[definition.id];
137
- await ensureFreshToken(entry);
138
- if (!entry.connection)
139
- await reconnect(entry);
140
- const tools = (await entry.connection?.listTools()) ?? [];
141
- const registrations = buildAllRegistrations([
142
- {
143
- prefix: definition.prefix,
144
- tools,
145
- callTool: async (name, params) => {
146
- if (!entry.connection)
147
- throw new Error(`${definition.id}: not connected`);
148
- return entry.connection.callTool(name, params);
149
- },
150
- },
151
- ]);
152
- for (const registration of registrations) {
153
- pi.registerTool({
154
- ...registration,
155
- execute: async (toolCallId, params, signal) => {
156
- await ensureFreshToken(entry);
157
- try {
158
- return await registration.execute(toolCallId, params, signal);
159
- }
160
- catch (error) {
161
- // Clock-fresh but server-rejected: one forced refresh plus
162
- // reconnect and retry before giving the agent a dead end.
163
- if (!isAuthFailure(error) || entry.staticToken || !entry.stored?.refreshToken) {
164
- throw error;
165
- }
166
- try {
167
- await refreshNow(entry);
168
- return await registration.execute(toolCallId, params, signal);
169
- }
170
- catch {
171
- const detail = error instanceof Error ? error.message : String(error);
172
- throw new Error(`${definition.id}: request rejected (${detail}). ${reauthHint(definition.id)}`);
173
- }
174
- }
175
- },
176
- });
177
- }
178
- entries.push(entry);
179
- }
180
- catch (error) {
181
- warn(`${definition.id}: unavailable (${error instanceof Error ? error.message : String(error)}).`);
182
- if (isAuthFailure(error)) {
183
- // Agents rarely see process logs: register a stub they will find.
184
- pi.registerTool({
185
- name: `${definition.prefix}reauthenticate`,
186
- label: `${definition.prefix}reauthenticate`,
187
- description: `${definition.id} is not authenticated. Call this tool for exact re-authentication instructions.`,
188
- parameters: Type.Object({}),
189
- execute: async () => ({
190
- content: [{ type: 'text', text: reauthHint(definition.id) }],
191
- }),
192
- });
193
- warn(reauthHint(definition.id));
194
- }
195
- await entry.connection?.close().catch(() => undefined);
196
- }
47
+ await runtime?.stop();
48
+ runtime = new CloudflareRuntime({ config: loadUserConfig() ?? {}, warn });
49
+ const registrations = await runtime.start();
50
+ for (const registration of registrations) {
51
+ pi.registerTool(registration);
197
52
  }
198
53
  });
199
54
  pi.on('session_shutdown', async () => {
200
- await Promise.all(entries.map((entry) => entry.connection?.close().catch(() => undefined)));
201
- entries = [];
55
+ await runtime?.stop();
56
+ runtime = undefined;
202
57
  });
203
58
  }
204
59
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAEhD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAuBtE,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE;YAC9D,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACxC,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7C,CAAC,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IACzD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CACzE,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,CAAA;QAClF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAA;QAChD,MAAM,OAAO,GAAG,MAAM,CAAC,eAAe,CAAC,CAAA;QACvC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAA;QAC7D,OAAO,aAAa,CAAC,OAAO,CAAuB,CAAA;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,OAAe;IAC3B,OAAO,CAAC,IAAI,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAA;AAC5C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAU;IACtD,IAAI,OAAsC,CAAA;IAE1C,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;QAChC,MAAM,OAAO,EAAE,IAAI,EAAE,CAAA;QACrB,OAAO,GAAG,IAAI,iBAAiB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;QACzE,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAA;QAC3C,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;YACzC,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,OAAO,EAAE,IAAI,EAAE,CAAA;QACrB,OAAO,GAAG,SAAS,CAAA;IACrB,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":""}
@@ -0,0 +1,106 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
6
+ import { CloudflareRuntime } from './runtime.js';
7
+ import { tokenFilePath } from './token-store.js';
8
+ function packageVersion() {
9
+ try {
10
+ const raw = readFileSync(new URL('../package.json', import.meta.url), 'utf8');
11
+ const parsed = JSON.parse(raw);
12
+ return typeof parsed.version === 'string' ? parsed.version : '0.0.0';
13
+ }
14
+ catch {
15
+ return '0.0.0';
16
+ }
17
+ }
18
+ function positiveInteger(value) {
19
+ if (!value)
20
+ return undefined;
21
+ const parsed = Number(value);
22
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
23
+ }
24
+ function runtimeConfig() {
25
+ const timeout = positiveInteger(process.env.PI_CLOUDFLARE_CONNECT_TIMEOUT_MS);
26
+ return {
27
+ apiToken: process.env.CLOUDFLARE_API_TOKEN,
28
+ connectTimeoutMs: timeout,
29
+ };
30
+ }
31
+ function portableTokenFile() {
32
+ if (process.env.PI_CLOUDFLARE_TOKEN_FILE)
33
+ return process.env.PI_CLOUDFLARE_TOKEN_FILE;
34
+ if (process.env.PLUGIN_DATA)
35
+ return join(process.env.PLUGIN_DATA, 'cloudflare-tokens.json');
36
+ return tokenFilePath();
37
+ }
38
+ function portableSetupScript() {
39
+ const root = process.env.PI_CLOUDFLARE_PLUGIN_ROOT ?? process.env.PLUGIN_ROOT;
40
+ return root ? join(root, 'bin', 'setup.mjs') : undefined;
41
+ }
42
+ async function main() {
43
+ const runtime = new CloudflareRuntime({
44
+ config: runtimeConfig(),
45
+ tokenFile: portableTokenFile(),
46
+ setupScript: portableSetupScript(),
47
+ warn: (message) => console.error(`[pi-cloudflare] ${message}`),
48
+ });
49
+ let registrationsPromise;
50
+ const registrations = () => {
51
+ registrationsPromise ??= runtime.start();
52
+ return registrationsPromise;
53
+ };
54
+ const server = new Server({ name: 'pi-cloudflare', version: packageVersion() }, { capabilities: { tools: {} } });
55
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
56
+ const tools = await registrations();
57
+ return {
58
+ tools: tools.map((tool) => ({
59
+ name: tool.name,
60
+ description: tool.description,
61
+ inputSchema: tool.inputSchema,
62
+ })),
63
+ };
64
+ });
65
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
66
+ const tools = await registrations();
67
+ const tool = tools.find((candidate) => candidate.name === request.params.name);
68
+ if (!tool) {
69
+ return {
70
+ content: [{ type: 'text', text: `Unknown tool: ${request.params.name}` }],
71
+ isError: true,
72
+ };
73
+ }
74
+ try {
75
+ return await tool.execute('agent-plugin', request.params.arguments ?? {}, undefined);
76
+ }
77
+ catch (error) {
78
+ return {
79
+ content: [
80
+ {
81
+ type: 'text',
82
+ text: error instanceof Error ? error.message : String(error),
83
+ },
84
+ ],
85
+ isError: true,
86
+ };
87
+ }
88
+ });
89
+ const transport = new StdioServerTransport();
90
+ await server.connect(transport);
91
+ const shutdown = async () => {
92
+ await runtime.stop();
93
+ await server.close();
94
+ };
95
+ process.once('SIGINT', () => {
96
+ void shutdown().finally(() => process.exit(0));
97
+ });
98
+ process.once('SIGTERM', () => {
99
+ void shutdown().finally(() => process.exit(0));
100
+ });
101
+ }
102
+ main().catch((error) => {
103
+ console.error(`[pi-cloudflare] MCP server failed: ${error instanceof Error ? error.message : String(error)}`);
104
+ process.exitCode = 1;
105
+ });
106
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
package/dist/proxy.d.ts CHANGED
@@ -1,13 +1,14 @@
1
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
1
2
  import type { ServerConnection } from './client.js';
2
3
  export interface ToolRegistration {
3
4
  name: string;
4
5
  label: string;
5
6
  description: string;
7
+ /** Raw JSON Schema for MCP clients. */
8
+ inputSchema: Record<string, unknown>;
9
+ /** TypeBox view of inputSchema for the native Pi host. */
6
10
  parameters: unknown;
7
- execute: (toolCallId: string, params: Record<string, unknown>, signal: AbortSignal | undefined) => Promise<{
8
- content: unknown[];
9
- isError?: boolean;
10
- }>;
11
+ execute: (toolCallId: string, params: Record<string, unknown>, signal?: AbortSignal) => Promise<CallToolResult>;
11
12
  }
12
13
  interface UpstreamTool {
13
14
  name: string;
@@ -15,8 +16,8 @@ interface UpstreamTool {
15
16
  inputSchema: Record<string, unknown>;
16
17
  }
17
18
  /**
18
- * Build pi tool registrations for one upstream server. Pure function over
19
- * injected dependencies so it unit tests without network or a pi session.
19
+ * Build host-neutral tool registrations for one upstream server. The raw
20
+ * schema is retained for MCP while Pi receives the TypeBox representation.
20
21
  */
21
22
  export declare function buildToolRegistrations(prefix: string, tools: UpstreamTool[], callUpstream: (name: string, params: Record<string, unknown>) => Promise<unknown>): ToolRegistration[];
22
23
  /** Prefix every tool of every connected server; names stay unique per server. */