@blocks-network/mcp-server 0.1.55 → 0.1.64
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 +18 -4
- package/dist/agent-status.d.ts +49 -0
- package/dist/agent-status.js +40 -0
- package/dist/billing.d.ts +50 -0
- package/dist/billing.js +72 -0
- package/dist/index.js +82 -306
- package/dist/protocol-headers.d.ts +11 -0
- package/dist/protocol-headers.js +11 -0
- package/dist/registry-list.d.ts +31 -0
- package/dist/registry-list.js +32 -0
- package/dist/tools.d.ts +197 -0
- package/dist/tools.js +441 -0
- package/package.json +18 -6
- package/src/agent-status.ts +89 -0
- package/src/billing.ts +122 -0
- package/src/index.ts +148 -335
- package/src/protocol-headers.ts +12 -0
- package/src/registry-list.ts +60 -0
- package/src/tools.ts +739 -0
- package/tests/billing.test.ts +203 -0
- package/tests/cancel-task.test.ts +24 -0
- package/tests/connect-task.test.ts +180 -0
- package/tests/download-artifact.test.ts +142 -0
- package/tests/get-agent-card.test.ts +53 -0
- package/tests/get-agent-status.test.ts +108 -0
- package/tests/get-task.test.ts +76 -0
- package/tests/helpers.ts +250 -0
- package/tests/list-agents.test.ts +74 -0
- package/tests/list-tasks.test.ts +58 -0
- package/tests/registry-list.test.ts +120 -0
- package/tests/send-task.test.ts +221 -0
- package/tests/task-lifecycle.test.ts +64 -0
- package/vitest.config.ts +7 -0
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Get API Key: https://app.blocks.ai/manage/api-keys
|
|
|
9
9
|
| Variable | Required | Description |
|
|
10
10
|
|----------|----------|-------------|
|
|
11
11
|
| `BLOCKS_API_KEY` | Yes | Your Blocks Network API key |
|
|
12
|
+
| `BLOCKS_ORG_ID` | For billing tools | Your consumer org ID (required by `check_balance` and `request_topup`). Find it in the dashboard URL or `blocks whoami --json`. |
|
|
12
13
|
| `BLOCKS_MCP_FILE_ROOT` | No | Allowed root directory for file uploads (default: cwd) |
|
|
13
14
|
|
|
14
15
|
All other configuration (keys, endpoints) is resolved automatically from CDM.
|
|
@@ -19,6 +20,8 @@ All other configuration (keys, endpoints) is resolved automatically from CDM.
|
|
|
19
20
|
npm i @blocks-network/mcp-server
|
|
20
21
|
```
|
|
21
22
|
|
|
23
|
+
`BLOCKS_ORG_ID` in the snippets below is only required by the billing tools (`check_balance`, `request_topup`); omit it if you don't plan to use them.
|
|
24
|
+
|
|
22
25
|
### Claude Code (CLI)
|
|
23
26
|
|
|
24
27
|
```bash
|
|
@@ -34,7 +37,8 @@ Or add to your `.claude/settings.json`:
|
|
|
34
37
|
"command": "npx",
|
|
35
38
|
"args": ["@blocks-network/mcp-server"],
|
|
36
39
|
"env": {
|
|
37
|
-
"BLOCKS_API_KEY": "your-api-key"
|
|
40
|
+
"BLOCKS_API_KEY": "your-api-key",
|
|
41
|
+
"BLOCKS_ORG_ID": "your-consumer-org-id"
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
44
|
}
|
|
@@ -52,7 +56,8 @@ Add to your `claude_desktop_config.json`:
|
|
|
52
56
|
"command": "npx",
|
|
53
57
|
"args": ["@blocks-network/mcp-server"],
|
|
54
58
|
"env": {
|
|
55
|
-
"BLOCKS_API_KEY": "your-api-key"
|
|
59
|
+
"BLOCKS_API_KEY": "your-api-key",
|
|
60
|
+
"BLOCKS_ORG_ID": "your-consumer-org-id"
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
}
|
|
@@ -74,7 +79,8 @@ Create an `mcp.json` file:
|
|
|
74
79
|
"command": "npx",
|
|
75
80
|
"args": ["@blocks-network/mcp-server"],
|
|
76
81
|
"env": {
|
|
77
|
-
"BLOCKS_API_KEY": "your-api-key"
|
|
82
|
+
"BLOCKS_API_KEY": "your-api-key",
|
|
83
|
+
"BLOCKS_ORG_ID": "your-consumer-org-id"
|
|
78
84
|
}
|
|
79
85
|
}
|
|
80
86
|
}
|
|
@@ -92,7 +98,8 @@ Add to your `~/.gemini/settings.json`:
|
|
|
92
98
|
"command": "npx",
|
|
93
99
|
"args": ["@blocks-network/mcp-server"],
|
|
94
100
|
"env": {
|
|
95
|
-
"BLOCKS_API_KEY": "your-api-key"
|
|
101
|
+
"BLOCKS_API_KEY": "your-api-key",
|
|
102
|
+
"BLOCKS_ORG_ID": "your-consumer-org-id"
|
|
96
103
|
}
|
|
97
104
|
}
|
|
98
105
|
}
|
|
@@ -107,9 +114,16 @@ Add to your `~/.gemini/settings.json`:
|
|
|
107
114
|
| `get_task` | Get the current status of a task |
|
|
108
115
|
| `list_tasks` | List tasks, optionally filtered by agent or state |
|
|
109
116
|
| `cancel_task` | Cancel a running task |
|
|
117
|
+
| `pause_task` | Pause a running pipe task |
|
|
118
|
+
| `resume_task` | Resume a paused pipe task |
|
|
119
|
+
| `retry_task` | Retry a failed task |
|
|
110
120
|
| `list_agents` | List available agents in the registry |
|
|
111
121
|
| `get_agent_card` | Get the full agent card for a specific agent |
|
|
122
|
+
| `get_agent_status` | Check live availability for agents (online instance count and total task count). Per-instance live activity counters (`activeTasks`, `concurrentTasksPerInstance`, `startedAt`, `totalActiveTasks`) are reserved in the response shape but currently return `0` — the backend does not yet populate them. |
|
|
112
123
|
| `connect_task` | Connect to an existing task and stream events |
|
|
124
|
+
| `download_artifact` | Download a single task artifact by file name (inline content or save to disk) |
|
|
125
|
+
| `check_balance` | Get the consumer billing balance for the configured org |
|
|
126
|
+
| `request_topup` | Create a Stripe Checkout URL to add USD to the consumer balance (user completes payment in a browser). Minimum top-up is `$5` (platform `MIN_BILLING_AMOUNT`). |
|
|
113
127
|
|
|
114
128
|
## Development
|
|
115
129
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent presence/availability helper.
|
|
3
|
+
*
|
|
4
|
+
* Calls GET /api/v1/agent-status with the Blocks-Protocol-Version
|
|
5
|
+
* header. Backend route is optionalAuth so the API key is forwarded
|
|
6
|
+
* when available but not required.
|
|
7
|
+
*
|
|
8
|
+
* Response shape mirrors the service's agent-status types.
|
|
9
|
+
*/
|
|
10
|
+
/** MUST stay in sync with the service's agent-status types. */
|
|
11
|
+
export declare const MAX_AGENT_NAMES = 50;
|
|
12
|
+
export declare const AGENT_NAME_PATTERN: RegExp;
|
|
13
|
+
export interface AgentInstanceStatus {
|
|
14
|
+
instanceId: string;
|
|
15
|
+
uuid: string;
|
|
16
|
+
online: true;
|
|
17
|
+
/**
|
|
18
|
+
* Reserved — backend currently returns 0 (live activity counters are not
|
|
19
|
+
* yet populated by the agent-status service). Do not use for routing or
|
|
20
|
+
* availability decisions.
|
|
21
|
+
*/
|
|
22
|
+
activeTasks: number;
|
|
23
|
+
/** Reserved — backend currently returns 0. See `activeTasks`. */
|
|
24
|
+
concurrentTasksPerInstance: number;
|
|
25
|
+
/** Reserved — backend currently returns 0. See `activeTasks`. */
|
|
26
|
+
startedAt: number;
|
|
27
|
+
sdkVersion: string | null;
|
|
28
|
+
cliVersion: string | null;
|
|
29
|
+
preferredProtocolVersion: string | null;
|
|
30
|
+
protocolVersions: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface AgentStatus {
|
|
33
|
+
agentName: string;
|
|
34
|
+
instances: AgentInstanceStatus[];
|
|
35
|
+
onlineCount: number;
|
|
36
|
+
/** Reserved — backend currently returns 0. See `AgentInstanceStatus.activeTasks`. */
|
|
37
|
+
totalActiveTasks: number;
|
|
38
|
+
taskCount: number;
|
|
39
|
+
}
|
|
40
|
+
export interface AgentStatusResponse {
|
|
41
|
+
agents: Record<string, AgentStatus>;
|
|
42
|
+
}
|
|
43
|
+
export interface FetchAgentStatusOptions {
|
|
44
|
+
baseUrl: string;
|
|
45
|
+
agentNames: string[];
|
|
46
|
+
apiKey?: string;
|
|
47
|
+
fetchImpl?: typeof fetch;
|
|
48
|
+
}
|
|
49
|
+
export declare function fetchAgentStatus(opts: FetchAgentStatusOptions): Promise<AgentStatusResponse>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent presence/availability helper.
|
|
3
|
+
*
|
|
4
|
+
* Calls GET /api/v1/agent-status with the Blocks-Protocol-Version
|
|
5
|
+
* header. Backend route is optionalAuth so the API key is forwarded
|
|
6
|
+
* when available but not required.
|
|
7
|
+
*
|
|
8
|
+
* Response shape mirrors the service's agent-status types.
|
|
9
|
+
*/
|
|
10
|
+
import { PROTOCOL_VERSION_HEADER, CURRENT_PROTOCOL_VERSION, } from './protocol-headers.js';
|
|
11
|
+
/** MUST stay in sync with the service's agent-status types. */
|
|
12
|
+
export const MAX_AGENT_NAMES = 50;
|
|
13
|
+
export const AGENT_NAME_PATTERN = /^[a-zA-Z0-9_]+$/;
|
|
14
|
+
export async function fetchAgentStatus(opts) {
|
|
15
|
+
const names = opts.agentNames.map((n) => n.trim()).filter(Boolean);
|
|
16
|
+
if (names.length === 0) {
|
|
17
|
+
throw new Error('agentNames must contain at least one value');
|
|
18
|
+
}
|
|
19
|
+
if (names.length > MAX_AGENT_NAMES) {
|
|
20
|
+
throw new Error(`agentNames must be at most ${MAX_AGENT_NAMES} values`);
|
|
21
|
+
}
|
|
22
|
+
for (const n of names) {
|
|
23
|
+
if (!AGENT_NAME_PATTERN.test(n)) {
|
|
24
|
+
throw new Error(`Invalid agent name: ${n}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const params = new URLSearchParams({ agentNames: names.join(',') });
|
|
28
|
+
const url = `${opts.baseUrl.replace(/\/+$/, '')}/api/v1/agent-status?${params}`;
|
|
29
|
+
const headers = {
|
|
30
|
+
[PROTOCOL_VERSION_HEADER]: CURRENT_PROTOCOL_VERSION,
|
|
31
|
+
};
|
|
32
|
+
if (opts.apiKey)
|
|
33
|
+
headers['Authorization'] = `Bearer ${opts.apiKey}`;
|
|
34
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
35
|
+
const response = await fetchFn(url, { headers });
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
throw new Error(`Agent status failed: HTTP ${response.status}`);
|
|
38
|
+
}
|
|
39
|
+
return (await response.json());
|
|
40
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Billing helpers — direct HTTP to the routes that accept Bearer
|
|
3
|
+
* API-key auth (`requireAuth` middleware path on the backend).
|
|
4
|
+
*
|
|
5
|
+
* GET /api/v1/billing/:orgId/consumer/balance
|
|
6
|
+
* POST /api/v1/billing/:orgId/consumer/topup
|
|
7
|
+
*
|
|
8
|
+
* Other billing routes (ledger, usage-summary, dashboard-summary,
|
|
9
|
+
* topup-from-earnings) are session-only on the backend and are not
|
|
10
|
+
* callable from an MCP server holding only an API key.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Platform minimum top-up amount in USD. MUST stay in sync with
|
|
14
|
+
* the service's MIN_BILLING_AMOUNT
|
|
15
|
+
* (decimal-dollar string `'5'`). The backend rejects values below this floor
|
|
16
|
+
* via `stripeMoneyAtLeast(MIN_BILLING_AMOUNT, ...)`; we mirror it here so MCP
|
|
17
|
+
* callers get the real contract up front instead of a runtime HTTP 400.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MIN_TOPUP_AMOUNT_USD = 5;
|
|
20
|
+
export interface ConsumerBalance {
|
|
21
|
+
/** Ledger balance as a decimal-dollar string (e.g. "12.34"). */
|
|
22
|
+
balance: string;
|
|
23
|
+
/** Currently reserved (held for in-flight tasks). */
|
|
24
|
+
reservedBalance: string;
|
|
25
|
+
/** balance - reservedBalance. */
|
|
26
|
+
availableBalance: string;
|
|
27
|
+
/** ISO timestamp of when the balance snapshot was taken. */
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
}
|
|
30
|
+
export interface TopUpSession {
|
|
31
|
+
/** Stripe Checkout URL the user opens in a browser to complete payment. */
|
|
32
|
+
checkoutUrl: string;
|
|
33
|
+
/** Stripe Checkout session id. */
|
|
34
|
+
sessionId: string;
|
|
35
|
+
}
|
|
36
|
+
export interface BillingClientBase {
|
|
37
|
+
baseUrl: string;
|
|
38
|
+
orgId: string;
|
|
39
|
+
apiKey: string;
|
|
40
|
+
fetchImpl?: typeof fetch;
|
|
41
|
+
}
|
|
42
|
+
export declare function getConsumerBalance(opts: BillingClientBase): Promise<ConsumerBalance>;
|
|
43
|
+
export interface CreateTopUpOptions extends BillingClientBase {
|
|
44
|
+
/**
|
|
45
|
+
* Whole-dollar (or whole-cent decimal) USD amount, e.g. 25 or 19.99.
|
|
46
|
+
* Must be at least `MIN_TOPUP_AMOUNT_USD` ($5) — backend rejects below this.
|
|
47
|
+
*/
|
|
48
|
+
amountUsd: number;
|
|
49
|
+
}
|
|
50
|
+
export declare function createConsumerTopUp(opts: CreateTopUpOptions): Promise<TopUpSession>;
|
package/dist/billing.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Billing helpers — direct HTTP to the routes that accept Bearer
|
|
3
|
+
* API-key auth (`requireAuth` middleware path on the backend).
|
|
4
|
+
*
|
|
5
|
+
* GET /api/v1/billing/:orgId/consumer/balance
|
|
6
|
+
* POST /api/v1/billing/:orgId/consumer/topup
|
|
7
|
+
*
|
|
8
|
+
* Other billing routes (ledger, usage-summary, dashboard-summary,
|
|
9
|
+
* topup-from-earnings) are session-only on the backend and are not
|
|
10
|
+
* callable from an MCP server holding only an API key.
|
|
11
|
+
*/
|
|
12
|
+
import { PROTOCOL_VERSION_HEADER, CURRENT_PROTOCOL_VERSION, } from './protocol-headers.js';
|
|
13
|
+
/**
|
|
14
|
+
* Platform minimum top-up amount in USD. MUST stay in sync with
|
|
15
|
+
* the service's MIN_BILLING_AMOUNT
|
|
16
|
+
* (decimal-dollar string `'5'`). The backend rejects values below this floor
|
|
17
|
+
* via `stripeMoneyAtLeast(MIN_BILLING_AMOUNT, ...)`; we mirror it here so MCP
|
|
18
|
+
* callers get the real contract up front instead of a runtime HTTP 400.
|
|
19
|
+
*/
|
|
20
|
+
export const MIN_TOPUP_AMOUNT_USD = 5;
|
|
21
|
+
function buildHeaders(apiKey) {
|
|
22
|
+
return {
|
|
23
|
+
[PROTOCOL_VERSION_HEADER]: CURRENT_PROTOCOL_VERSION,
|
|
24
|
+
Authorization: `Bearer ${apiKey}`,
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function billingUrl(baseUrl, orgId, suffix) {
|
|
29
|
+
return `${baseUrl.replace(/\/+$/, '')}/api/v1/billing/${encodeURIComponent(orgId)}${suffix}`;
|
|
30
|
+
}
|
|
31
|
+
export async function getConsumerBalance(opts) {
|
|
32
|
+
const url = billingUrl(opts.baseUrl, opts.orgId, '/consumer/balance');
|
|
33
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
34
|
+
const response = await fetchFn(url, {
|
|
35
|
+
method: 'GET',
|
|
36
|
+
headers: buildHeaders(opts.apiKey),
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(`Balance lookup failed: HTTP ${response.status}`);
|
|
40
|
+
}
|
|
41
|
+
return (await response.json());
|
|
42
|
+
}
|
|
43
|
+
export async function createConsumerTopUp(opts) {
|
|
44
|
+
if (!Number.isFinite(opts.amountUsd) || opts.amountUsd <= 0) {
|
|
45
|
+
throw new Error('amountUsd must be a positive finite number');
|
|
46
|
+
}
|
|
47
|
+
if (Math.round(opts.amountUsd * 100) / 100 !== opts.amountUsd) {
|
|
48
|
+
throw new Error('amountUsd must be a whole-cent value (no sub-cent fractions)');
|
|
49
|
+
}
|
|
50
|
+
if (opts.amountUsd < MIN_TOPUP_AMOUNT_USD) {
|
|
51
|
+
throw new Error(`amountUsd must be at least $${MIN_TOPUP_AMOUNT_USD}.00 (platform minimum)`);
|
|
52
|
+
}
|
|
53
|
+
const amount = opts.amountUsd.toFixed(2);
|
|
54
|
+
const url = billingUrl(opts.baseUrl, opts.orgId, '/consumer/topup');
|
|
55
|
+
const fetchFn = opts.fetchImpl ?? fetch;
|
|
56
|
+
const response = await fetchFn(url, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: buildHeaders(opts.apiKey),
|
|
59
|
+
body: JSON.stringify({ amount }),
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
let detail = '';
|
|
63
|
+
try {
|
|
64
|
+
detail = await response.text();
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// ignore body decode failures
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`Top-up failed: HTTP ${response.status}${detail ? ` — ${detail}` : ''}`);
|
|
70
|
+
}
|
|
71
|
+
return (await response.json());
|
|
72
|
+
}
|