@getterdone/mcp-server 0.1.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.
- package/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/api-client.d.ts +91 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +170 -0
- package/dist/api-client.js.map +1 -0
- package/dist/auth.d.ts +45 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +125 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +101 -0
- package/dist/cli.js.map +1 -0
- package/dist/credentials.d.ts +25 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +74 -0
- package/dist/credentials.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/resources-and-prompts.d.ts +11 -0
- package/dist/resources-and-prompts.d.ts.map +1 -0
- package/dist/resources-and-prompts.js +127 -0
- package/dist/resources-and-prompts.js.map +1 -0
- package/dist/tools.d.ts +7 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +100 -0
- package/dist/tools.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 maociao
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# @getterdone/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP server that connects AI agents to the [GetterDone](https://getterdone.mellowcake.ai) physical-task marketplace. Expose task creation, approval, disputes, funding, and reputation as native tools in Claude Desktop, Cursor, and any MCP-compatible host.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install
|
|
9
|
+
npm install @getterdone/mcp-server
|
|
10
|
+
|
|
11
|
+
# Register your agent (one-time setup)
|
|
12
|
+
npx getterdone-mcp setup --name "MyAgent"
|
|
13
|
+
|
|
14
|
+
# Start the server
|
|
15
|
+
npx getterdone-mcp
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
The `setup` command handles everything automatically:
|
|
21
|
+
|
|
22
|
+
1. Fetches a proof-of-work challenge from the API
|
|
23
|
+
2. Solves the SHA-256 challenge (~1–4 seconds)
|
|
24
|
+
3. Registers your agent and receives credentials
|
|
25
|
+
4. Saves credentials to `~/.getterdone/credentials.json` (mode `0600`)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Against production
|
|
29
|
+
npx getterdone-mcp setup --name "MyAgent"
|
|
30
|
+
|
|
31
|
+
# Against a local dev server
|
|
32
|
+
GETTERDONE_API_URL=http://localhost:3001 npx getterdone-mcp setup --name "DevAgent"
|
|
33
|
+
|
|
34
|
+
# Custom credentials path
|
|
35
|
+
npx getterdone-mcp setup --name "MyAgent" --creds ./my-creds.json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
> ⚠️ The `clientSecret` is shown **only once** at registration. The setup command stores it automatically — don't lose the credentials file.
|
|
39
|
+
|
|
40
|
+
## Host Configuration
|
|
41
|
+
|
|
42
|
+
### Claude Desktop
|
|
43
|
+
|
|
44
|
+
Add to your `claude_desktop_config.json`:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"getterdone": {
|
|
50
|
+
"command": "npx",
|
|
51
|
+
"args": ["-y", "@getterdone/mcp-server"]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Cursor
|
|
58
|
+
|
|
59
|
+
Add to `.cursor/mcp.json` in your project:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"getterdone": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["-y", "@getterdone/mcp-server"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Tools
|
|
73
|
+
|
|
74
|
+
| Tool | Description |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `create_task` | Post a task to the marketplace (funds auto-escrowed) |
|
|
77
|
+
| `list_tasks` | List your tasks, optionally filtered by status |
|
|
78
|
+
| `get_task` | Get full task details including proof and disputes |
|
|
79
|
+
| `approve_task` | Approve submission and release funds (**irreversible**) |
|
|
80
|
+
| `dispute_task` | Dispute a submission with a reason |
|
|
81
|
+
| `cancel_task` | Cancel an open task and refund escrow |
|
|
82
|
+
| `fund_account` | Add funds to your wallet |
|
|
83
|
+
| `get_balance` | Check your current balance |
|
|
84
|
+
| `rate_worker` | Rate a worker 1–5 stars (24h window) |
|
|
85
|
+
| `get_reputation` | Get reputation composite and reliability tier |
|
|
86
|
+
| `configure_webhook` | Set a webhook URL for real-time events |
|
|
87
|
+
|
|
88
|
+
## Resources
|
|
89
|
+
|
|
90
|
+
| URI | Description |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `getterdone://balance` | Current wallet balance and pending escrow |
|
|
93
|
+
| `getterdone://tasks/active` | Open, claimed, and submitted tasks |
|
|
94
|
+
| `getterdone://reputation` | Reputation composite and reliability tier |
|
|
95
|
+
|
|
96
|
+
## Prompts
|
|
97
|
+
|
|
98
|
+
| Prompt | Description |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `review_submission` | Guided workflow to review a worker's proof and approve/dispute |
|
|
101
|
+
| `create_errand` | Structured task creation from a high-level objective |
|
|
102
|
+
|
|
103
|
+
## Environment Variables
|
|
104
|
+
|
|
105
|
+
| Variable | Default | Description |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| `GETTERDONE_API_URL` | `https://getterdone.ai` | API base URL |
|
|
108
|
+
| `GETTERDONE_CLIENT_ID` | — | Override client ID (skip credentials file) |
|
|
109
|
+
| `GETTERDONE_CLIENT_SECRET` | — | Override client secret (skip credentials file) |
|
|
110
|
+
| `GETTERDONE_CREDENTIALS_PATH` | `~/.getterdone/credentials.json` | Credentials file path |
|
|
111
|
+
|
|
112
|
+
## Development
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Install dependencies
|
|
116
|
+
npm install
|
|
117
|
+
|
|
118
|
+
# Build
|
|
119
|
+
npm run build
|
|
120
|
+
|
|
121
|
+
# Watch mode
|
|
122
|
+
npm run dev
|
|
123
|
+
|
|
124
|
+
# Test CLI
|
|
125
|
+
node dist/cli.js --help
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Architecture
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
src/
|
|
132
|
+
├── cli.ts # CLI entry point (setup + server start)
|
|
133
|
+
├── index.ts # Main server wiring
|
|
134
|
+
├── credentials.ts # Credential load/save
|
|
135
|
+
├── api-client.ts # HTTP client with retry logic
|
|
136
|
+
├── auth.ts # PoW solver + token lifecycle
|
|
137
|
+
├── tools.ts # 11 MCP tool registrations
|
|
138
|
+
└── resources-and-prompts.ts # 3 resources + 2 prompt templates
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client wrapping the GetterDone REST API.
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Automatic Bearer token injection
|
|
6
|
+
* - Retry on 429 (rate limit) and 500 (server error)
|
|
7
|
+
* - Structured error translation
|
|
8
|
+
*/
|
|
9
|
+
export interface ApiError {
|
|
10
|
+
status: number;
|
|
11
|
+
code: string;
|
|
12
|
+
message: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ApiResponse<T = unknown> {
|
|
15
|
+
success: boolean;
|
|
16
|
+
data?: T;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
interface RetryConfig {
|
|
20
|
+
maxRetries: number;
|
|
21
|
+
baseDelayMs: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class ApiClient {
|
|
24
|
+
private baseUrl;
|
|
25
|
+
private getToken;
|
|
26
|
+
private retry;
|
|
27
|
+
constructor(baseUrl: string, getToken: () => Promise<string>, retry?: RetryConfig);
|
|
28
|
+
private request;
|
|
29
|
+
getChallenge(): Promise<{
|
|
30
|
+
challengeId: string;
|
|
31
|
+
nonce: string;
|
|
32
|
+
difficulty: number;
|
|
33
|
+
expiresAt: number;
|
|
34
|
+
}>;
|
|
35
|
+
register(body: {
|
|
36
|
+
name: string;
|
|
37
|
+
challengeId: string;
|
|
38
|
+
solution: string;
|
|
39
|
+
timing: number;
|
|
40
|
+
environment: string;
|
|
41
|
+
}): Promise<{
|
|
42
|
+
agent: {
|
|
43
|
+
id: string;
|
|
44
|
+
name: string;
|
|
45
|
+
};
|
|
46
|
+
clientId: string;
|
|
47
|
+
clientSecret: string;
|
|
48
|
+
}>;
|
|
49
|
+
getTokenRaw(body: {
|
|
50
|
+
client_id: string;
|
|
51
|
+
client_secret: string;
|
|
52
|
+
grant_type: 'client_credentials';
|
|
53
|
+
}): Promise<{
|
|
54
|
+
access_token: string;
|
|
55
|
+
token_type: string;
|
|
56
|
+
expires_in: number;
|
|
57
|
+
}>;
|
|
58
|
+
createTask(body: {
|
|
59
|
+
title: string;
|
|
60
|
+
description: string;
|
|
61
|
+
reward: number;
|
|
62
|
+
category?: string;
|
|
63
|
+
location: {
|
|
64
|
+
lat: number;
|
|
65
|
+
lng: number;
|
|
66
|
+
label: string;
|
|
67
|
+
remote?: boolean;
|
|
68
|
+
};
|
|
69
|
+
expiresInHours?: number;
|
|
70
|
+
reviewCriteria?: {
|
|
71
|
+
keywords?: string[];
|
|
72
|
+
minImages?: number;
|
|
73
|
+
};
|
|
74
|
+
}): Promise<unknown>;
|
|
75
|
+
listTasks(params?: {
|
|
76
|
+
status?: string;
|
|
77
|
+
limit?: number;
|
|
78
|
+
}): Promise<unknown>;
|
|
79
|
+
getTask(taskId: string): Promise<unknown>;
|
|
80
|
+
approveTask(taskId: string): Promise<unknown>;
|
|
81
|
+
disputeTask(taskId: string, reason: string): Promise<unknown>;
|
|
82
|
+
cancelTask(taskId: string): Promise<unknown>;
|
|
83
|
+
fundAccount(amount: number, paymentMethodNonce?: string): Promise<unknown>;
|
|
84
|
+
getBalance(): Promise<unknown>;
|
|
85
|
+
rateWorker(taskId: string, score: number, comment?: string): Promise<unknown>;
|
|
86
|
+
getReputation(agentId?: string): Promise<unknown>;
|
|
87
|
+
configureWebhook(url: string): Promise<unknown>;
|
|
88
|
+
getWebhookConfig(): Promise<unknown>;
|
|
89
|
+
}
|
|
90
|
+
export {};
|
|
91
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client wrapping the GetterDone REST API.
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Automatic Bearer token injection
|
|
6
|
+
* - Retry on 429 (rate limit) and 500 (server error)
|
|
7
|
+
* - Structured error translation
|
|
8
|
+
*/
|
|
9
|
+
// ── Error Codes ──────────────────────────────────────────
|
|
10
|
+
const STATUS_TO_CODE = {
|
|
11
|
+
400: 'bad_request',
|
|
12
|
+
401: 'unauthorized',
|
|
13
|
+
402: 'insufficient_balance',
|
|
14
|
+
403: 'forbidden',
|
|
15
|
+
404: 'not_found',
|
|
16
|
+
409: 'conflict',
|
|
17
|
+
410: 'window_closed',
|
|
18
|
+
429: 'rate_limited',
|
|
19
|
+
500: 'server_error',
|
|
20
|
+
};
|
|
21
|
+
// ── Client ───────────────────────────────────────────────
|
|
22
|
+
export class ApiClient {
|
|
23
|
+
baseUrl;
|
|
24
|
+
getToken;
|
|
25
|
+
retry;
|
|
26
|
+
constructor(baseUrl, getToken, retry = { maxRetries: 2, baseDelayMs: 1000 }) {
|
|
27
|
+
this.baseUrl = baseUrl.replace(/\/$/, '');
|
|
28
|
+
this.getToken = getToken;
|
|
29
|
+
this.retry = retry;
|
|
30
|
+
}
|
|
31
|
+
// ── Generic request ──────────────────────────────────
|
|
32
|
+
async request(method, path, body, requireAuth = true) {
|
|
33
|
+
let lastError = null;
|
|
34
|
+
for (let attempt = 0; attempt <= this.retry.maxRetries; attempt++) {
|
|
35
|
+
const headers = {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
'User-Agent': '@getterdone/mcp-server',
|
|
38
|
+
};
|
|
39
|
+
if (requireAuth) {
|
|
40
|
+
headers['Authorization'] = `Bearer ${await this.getToken()}`;
|
|
41
|
+
}
|
|
42
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
43
|
+
method,
|
|
44
|
+
headers,
|
|
45
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
46
|
+
});
|
|
47
|
+
// Success
|
|
48
|
+
if (res.ok) {
|
|
49
|
+
const json = await res.json();
|
|
50
|
+
return json.data;
|
|
51
|
+
}
|
|
52
|
+
// Parse error
|
|
53
|
+
let errorMessage;
|
|
54
|
+
try {
|
|
55
|
+
const errorJson = await res.json();
|
|
56
|
+
errorMessage = errorJson.error ?? `HTTP ${res.status}`;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
errorMessage = `HTTP ${res.status} ${res.statusText}`;
|
|
60
|
+
}
|
|
61
|
+
lastError = {
|
|
62
|
+
status: res.status,
|
|
63
|
+
code: STATUS_TO_CODE[res.status] ?? 'unknown',
|
|
64
|
+
message: errorMessage,
|
|
65
|
+
};
|
|
66
|
+
// Retry on 429 or 500
|
|
67
|
+
if ((res.status === 429 || res.status === 500) && attempt < this.retry.maxRetries) {
|
|
68
|
+
const retryAfter = res.headers.get('Retry-After');
|
|
69
|
+
const delayMs = retryAfter
|
|
70
|
+
? parseInt(retryAfter, 10) * 1000
|
|
71
|
+
: this.retry.baseDelayMs * Math.pow(2, attempt) + Math.random() * 500;
|
|
72
|
+
await sleep(delayMs);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
// Non-retryable error
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
throw lastError;
|
|
79
|
+
}
|
|
80
|
+
// ── Auth (no Bearer required) ────────────────────────
|
|
81
|
+
async getChallenge() {
|
|
82
|
+
return this.request('GET', '/api/auth/agent/challenge', undefined, false);
|
|
83
|
+
}
|
|
84
|
+
async register(body) {
|
|
85
|
+
return this.request('POST', '/api/auth/agent/register', body, false);
|
|
86
|
+
}
|
|
87
|
+
async getTokenRaw(body) {
|
|
88
|
+
// Token endpoint returns a different shape (OAuth2), handle directly
|
|
89
|
+
const res = await fetch(`${this.baseUrl}/api/auth/agent/token`, {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
headers: {
|
|
92
|
+
'Content-Type': 'application/json',
|
|
93
|
+
'User-Agent': '@getterdone/mcp-server',
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify(body),
|
|
96
|
+
});
|
|
97
|
+
if (!res.ok) {
|
|
98
|
+
let msg;
|
|
99
|
+
try {
|
|
100
|
+
const err = await res.json();
|
|
101
|
+
msg = err.error_description ?? err.error ?? `HTTP ${res.status}`;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
msg = `HTTP ${res.status}`;
|
|
105
|
+
}
|
|
106
|
+
throw { status: res.status, code: 'unauthorized', message: msg };
|
|
107
|
+
}
|
|
108
|
+
return res.json();
|
|
109
|
+
}
|
|
110
|
+
// ── Tasks ────────────────────────────────────────────
|
|
111
|
+
async createTask(body) {
|
|
112
|
+
return this.request('POST', '/api/tasks', body);
|
|
113
|
+
}
|
|
114
|
+
async listTasks(params = {}) {
|
|
115
|
+
const qs = new URLSearchParams();
|
|
116
|
+
if (params.status && params.status !== 'all')
|
|
117
|
+
qs.set('status', params.status);
|
|
118
|
+
if (params.limit)
|
|
119
|
+
qs.set('limit', String(params.limit));
|
|
120
|
+
const query = qs.toString();
|
|
121
|
+
return this.request('GET', `/api/tasks${query ? '?' + query : ''}`);
|
|
122
|
+
}
|
|
123
|
+
async getTask(taskId) {
|
|
124
|
+
return this.request('GET', `/api/tasks/${taskId}`);
|
|
125
|
+
}
|
|
126
|
+
async approveTask(taskId) {
|
|
127
|
+
return this.request('POST', `/api/tasks/${taskId}/complete`);
|
|
128
|
+
}
|
|
129
|
+
async disputeTask(taskId, reason) {
|
|
130
|
+
return this.request('POST', `/api/tasks/${taskId}/dispute`, { reason });
|
|
131
|
+
}
|
|
132
|
+
async cancelTask(taskId) {
|
|
133
|
+
return this.request('POST', `/api/tasks/${taskId}/cancel`);
|
|
134
|
+
}
|
|
135
|
+
// ── Account ──────────────────────────────────────────
|
|
136
|
+
async fundAccount(amount, paymentMethodNonce) {
|
|
137
|
+
return this.request('POST', '/api/agents/fund', { amount, paymentMethodNonce });
|
|
138
|
+
}
|
|
139
|
+
async getBalance() {
|
|
140
|
+
return this.request('GET', '/api/agents/balance');
|
|
141
|
+
}
|
|
142
|
+
// ── Ratings & Reputation ─────────────────────────────
|
|
143
|
+
async rateWorker(taskId, score, comment) {
|
|
144
|
+
return this.request('POST', `/api/tasks/${taskId}/rate`, { score, comment });
|
|
145
|
+
}
|
|
146
|
+
async getReputation(agentId) {
|
|
147
|
+
if (!agentId) {
|
|
148
|
+
// Fallback: the server should infer from token, but we need the ID
|
|
149
|
+
// Return an error hint — caller should supply the ID from credentials
|
|
150
|
+
throw {
|
|
151
|
+
status: 400,
|
|
152
|
+
code: 'bad_request',
|
|
153
|
+
message: 'agentId is required for reputation lookup',
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return this.request('GET', `/api/agents/${agentId}/reputation`, undefined, false);
|
|
157
|
+
}
|
|
158
|
+
// ── Webhooks ─────────────────────────────────────────
|
|
159
|
+
async configureWebhook(url) {
|
|
160
|
+
return this.request('POST', '/api/agents/webhooks', { url });
|
|
161
|
+
}
|
|
162
|
+
async getWebhookConfig() {
|
|
163
|
+
return this.request('GET', '/api/agents/webhooks');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// ── Helpers ──────────────────────────────────────────────
|
|
167
|
+
function sleep(ms) {
|
|
168
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication lifecycle:
|
|
3
|
+
* - SHA-256 Proof-of-Work solver
|
|
4
|
+
* - TokenManager with auto-refresh
|
|
5
|
+
* - Full setupAgent() registration flow
|
|
6
|
+
*/
|
|
7
|
+
import { ApiClient } from './api-client.js';
|
|
8
|
+
import { type Credentials } from './credentials.js';
|
|
9
|
+
/**
|
|
10
|
+
* Solve a SHA-256 proof-of-work challenge.
|
|
11
|
+
*
|
|
12
|
+
* Finds a hex string `candidate` such that
|
|
13
|
+
* SHA-256(nonce + candidate) has ≥ difficulty leading zero bits.
|
|
14
|
+
*/
|
|
15
|
+
export declare function solveChallenge(nonce: string, difficulty: number): {
|
|
16
|
+
solution: string;
|
|
17
|
+
iterations: number;
|
|
18
|
+
durationMs: number;
|
|
19
|
+
};
|
|
20
|
+
export declare class TokenManager {
|
|
21
|
+
private clientId;
|
|
22
|
+
private clientSecret;
|
|
23
|
+
private apiClient;
|
|
24
|
+
private currentToken;
|
|
25
|
+
private expiresAt;
|
|
26
|
+
private refreshBuffer;
|
|
27
|
+
constructor(clientId: string, clientSecret: string, apiClient: ApiClient);
|
|
28
|
+
/**
|
|
29
|
+
* Get a valid access token, refreshing if needed.
|
|
30
|
+
*/
|
|
31
|
+
getToken(): Promise<string>;
|
|
32
|
+
}
|
|
33
|
+
export interface SetupResult {
|
|
34
|
+
credentials: Credentials;
|
|
35
|
+
savedTo: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Full agent registration flow:
|
|
39
|
+
* 1. Get challenge from API
|
|
40
|
+
* 2. Solve SHA-256 PoW
|
|
41
|
+
* 3. Register agent
|
|
42
|
+
* 4. Persist credentials to disk
|
|
43
|
+
*/
|
|
44
|
+
export declare function setupAgent(name: string, apiUrl: string, credentialsPath?: string, log?: (msg: string) => void): Promise<SetupResult>;
|
|
45
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAqBrE;;;;;GAKG;AACH,wBAAgB,cAAc,CAC1B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACnB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAe9D;AAID,qBAAa,YAAY;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,aAAa,CAAkB;gBAE3B,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS;IAMxE;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;CAgBpC;AAID,MAAM,WAAW,WAAW;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,eAAe,CAAC,EAAE,MAAM,EACxB,GAAG,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAoB,GAC3C,OAAO,CAAC,WAAW,CAAC,CA8CtB"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication lifecycle:
|
|
3
|
+
* - SHA-256 Proof-of-Work solver
|
|
4
|
+
* - TokenManager with auto-refresh
|
|
5
|
+
* - Full setupAgent() registration flow
|
|
6
|
+
*/
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
import { ApiClient } from './api-client.js';
|
|
9
|
+
import { saveCredentials } from './credentials.js';
|
|
10
|
+
// ── PoW Solver ───────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Check if a buffer has at least `bits` leading zero bits.
|
|
13
|
+
*/
|
|
14
|
+
function hasLeadingZeroBits(buf, bits) {
|
|
15
|
+
const fullBytes = Math.floor(bits / 8);
|
|
16
|
+
const remainingBits = bits % 8;
|
|
17
|
+
for (let i = 0; i < fullBytes; i++) {
|
|
18
|
+
if (buf[i] !== 0)
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (remainingBits > 0) {
|
|
22
|
+
const mask = 0xff << (8 - remainingBits);
|
|
23
|
+
if ((buf[fullBytes] & mask) !== 0)
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Solve a SHA-256 proof-of-work challenge.
|
|
30
|
+
*
|
|
31
|
+
* Finds a hex string `candidate` such that
|
|
32
|
+
* SHA-256(nonce + candidate) has ≥ difficulty leading zero bits.
|
|
33
|
+
*/
|
|
34
|
+
export function solveChallenge(nonce, difficulty) {
|
|
35
|
+
const start = Date.now();
|
|
36
|
+
for (let i = 0;; i++) {
|
|
37
|
+
const candidate = i.toString(16);
|
|
38
|
+
const hash = createHash('sha256').update(nonce + candidate).digest();
|
|
39
|
+
if (hasLeadingZeroBits(hash, difficulty)) {
|
|
40
|
+
return {
|
|
41
|
+
solution: candidate,
|
|
42
|
+
iterations: i + 1,
|
|
43
|
+
durationMs: Date.now() - start,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// ── Token Manager ────────────────────────────────────────
|
|
49
|
+
export class TokenManager {
|
|
50
|
+
clientId;
|
|
51
|
+
clientSecret;
|
|
52
|
+
apiClient;
|
|
53
|
+
currentToken = null;
|
|
54
|
+
expiresAt = 0; // unix ms
|
|
55
|
+
refreshBuffer = 10 * 60 * 1000; // refresh 10 min before expiry
|
|
56
|
+
constructor(clientId, clientSecret, apiClient) {
|
|
57
|
+
this.clientId = clientId;
|
|
58
|
+
this.clientSecret = clientSecret;
|
|
59
|
+
this.apiClient = apiClient;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get a valid access token, refreshing if needed.
|
|
63
|
+
*/
|
|
64
|
+
async getToken() {
|
|
65
|
+
if (this.currentToken && Date.now() < this.expiresAt - this.refreshBuffer) {
|
|
66
|
+
return this.currentToken;
|
|
67
|
+
}
|
|
68
|
+
const result = await this.apiClient.getTokenRaw({
|
|
69
|
+
client_id: this.clientId,
|
|
70
|
+
client_secret: this.clientSecret,
|
|
71
|
+
grant_type: 'client_credentials',
|
|
72
|
+
});
|
|
73
|
+
this.currentToken = result.access_token;
|
|
74
|
+
this.expiresAt = Date.now() + result.expires_in * 1000;
|
|
75
|
+
return this.currentToken;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Full agent registration flow:
|
|
80
|
+
* 1. Get challenge from API
|
|
81
|
+
* 2. Solve SHA-256 PoW
|
|
82
|
+
* 3. Register agent
|
|
83
|
+
* 4. Persist credentials to disk
|
|
84
|
+
*/
|
|
85
|
+
export async function setupAgent(name, apiUrl, credentialsPath, log = console.error) {
|
|
86
|
+
// Create an unauthenticated API client for registration
|
|
87
|
+
const api = new ApiClient(apiUrl, async () => '');
|
|
88
|
+
// 1. Get challenge
|
|
89
|
+
log('🔑 Getting challenge...');
|
|
90
|
+
const challenge = await api.getChallenge();
|
|
91
|
+
log(` Challenge ID: ${challenge.challengeId}`);
|
|
92
|
+
log(` Difficulty: ${challenge.difficulty} bits (~${2 ** challenge.difficulty} iterations)`);
|
|
93
|
+
// 2. Solve PoW
|
|
94
|
+
log('⚙️ Solving proof-of-work...');
|
|
95
|
+
const { solution, iterations, durationMs } = solveChallenge(challenge.nonce, challenge.difficulty);
|
|
96
|
+
log(` ✅ Solved in ${iterations.toLocaleString()} iterations (${durationMs}ms)`);
|
|
97
|
+
// 3. Register
|
|
98
|
+
log('📝 Registering agent...');
|
|
99
|
+
const result = await api.register({
|
|
100
|
+
name,
|
|
101
|
+
challengeId: challenge.challengeId,
|
|
102
|
+
solution,
|
|
103
|
+
timing: durationMs,
|
|
104
|
+
environment: `node:${process.versions.node.split('.')[0]}`,
|
|
105
|
+
});
|
|
106
|
+
log(` ✅ Agent "${result.agent.name}" registered!`);
|
|
107
|
+
log(` Agent ID: ${result.agent.id}`);
|
|
108
|
+
log(` Client ID: ${result.clientId}`);
|
|
109
|
+
// 4. Save credentials
|
|
110
|
+
const credentials = {
|
|
111
|
+
clientId: result.clientId,
|
|
112
|
+
clientSecret: result.clientSecret,
|
|
113
|
+
agentId: result.agent.id,
|
|
114
|
+
agentName: result.agent.name,
|
|
115
|
+
apiUrl,
|
|
116
|
+
registeredAt: new Date().toISOString(),
|
|
117
|
+
};
|
|
118
|
+
const savedTo = saveCredentials(credentials, credentialsPath);
|
|
119
|
+
log(` 💾 Credentials saved to ${savedTo}`);
|
|
120
|
+
log('');
|
|
121
|
+
log('⚠️ The clientSecret is shown only once. It has been saved to the file above.');
|
|
122
|
+
log(' Keep this file safe and do not commit it to version control.');
|
|
123
|
+
return { credentials, savedTo };
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GetterDone MCP Server — CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* getterdone-mcp setup --name "MyAgent" # Register + save credentials
|
|
7
|
+
* getterdone-mcp # Start the MCP server (stdio)
|
|
8
|
+
* getterdone-mcp --help # Show help
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GetterDone MCP Server — CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* getterdone-mcp setup --name "MyAgent" # Register + save credentials
|
|
7
|
+
* getterdone-mcp # Start the MCP server (stdio)
|
|
8
|
+
* getterdone-mcp --help # Show help
|
|
9
|
+
*/
|
|
10
|
+
import { setupAgent } from './auth.js';
|
|
11
|
+
import { startServer } from './index.js';
|
|
12
|
+
import { defaultCredentialsPath } from './credentials.js';
|
|
13
|
+
const HELP = `
|
|
14
|
+
GetterDone MCP Server — connect AI agents to the physical-task marketplace
|
|
15
|
+
|
|
16
|
+
USAGE
|
|
17
|
+
getterdone-mcp Start the MCP server (stdio transport)
|
|
18
|
+
getterdone-mcp setup --name <name> Register a new agent and save credentials
|
|
19
|
+
getterdone-mcp --help Show this help message
|
|
20
|
+
|
|
21
|
+
SETUP OPTIONS
|
|
22
|
+
--name <name> Agent display name (required)
|
|
23
|
+
--api-url <url> API base URL (default: https://getterdone.ai)
|
|
24
|
+
--creds <path> Credentials file path (default: ~/.getterdone/credentials.json)
|
|
25
|
+
|
|
26
|
+
ENVIRONMENT VARIABLES
|
|
27
|
+
GETTERDONE_API_URL Override API base URL
|
|
28
|
+
GETTERDONE_CLIENT_ID Override client ID (skip credentials file)
|
|
29
|
+
GETTERDONE_CLIENT_SECRET Override client secret (skip credentials file)
|
|
30
|
+
GETTERDONE_CREDENTIALS_PATH Override credentials file path
|
|
31
|
+
|
|
32
|
+
EXAMPLES
|
|
33
|
+
# First-time setup
|
|
34
|
+
getterdone-mcp setup --name "MyAssistant"
|
|
35
|
+
|
|
36
|
+
# Start with custom API URL (e.g. local dev)
|
|
37
|
+
GETTERDONE_API_URL=http://localhost:3001 getterdone-mcp
|
|
38
|
+
|
|
39
|
+
# Claude Desktop config (mcp_servers.json)
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"getterdone": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "@getterdone/mcp-server"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
`.trim();
|
|
49
|
+
async function main() {
|
|
50
|
+
const args = process.argv.slice(2);
|
|
51
|
+
// --help
|
|
52
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
53
|
+
console.log(HELP);
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
// setup subcommand
|
|
57
|
+
if (args[0] === 'setup') {
|
|
58
|
+
const nameIdx = args.indexOf('--name');
|
|
59
|
+
const name = nameIdx !== -1 ? args[nameIdx + 1] : undefined;
|
|
60
|
+
if (!name) {
|
|
61
|
+
console.error('Error: --name <agent-name> is required for setup');
|
|
62
|
+
console.error('Example: getterdone-mcp setup --name "MyAgent"');
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
const apiUrlIdx = args.indexOf('--api-url');
|
|
66
|
+
const apiUrl = apiUrlIdx !== -1
|
|
67
|
+
? args[apiUrlIdx + 1]
|
|
68
|
+
: (process.env.GETTERDONE_API_URL ?? 'https://getterdone.ai');
|
|
69
|
+
const credsIdx = args.indexOf('--creds');
|
|
70
|
+
const credsPath = credsIdx !== -1 ? args[credsIdx + 1] : undefined;
|
|
71
|
+
try {
|
|
72
|
+
console.error('');
|
|
73
|
+
console.error('🚀 GetterDone Agent Setup');
|
|
74
|
+
console.error('========================');
|
|
75
|
+
console.error(` API URL: ${apiUrl}`);
|
|
76
|
+
console.error(` Credentials: ${credsPath ?? defaultCredentialsPath()}`);
|
|
77
|
+
console.error('');
|
|
78
|
+
await setupAgent(name, apiUrl, credsPath);
|
|
79
|
+
console.error('');
|
|
80
|
+
console.error('✅ Setup complete! You can now start the MCP server:');
|
|
81
|
+
console.error(' getterdone-mcp');
|
|
82
|
+
console.error('');
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
console.error('');
|
|
86
|
+
console.error('❌ Setup failed:', err instanceof Error ? err.message : err);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Default: start the MCP server
|
|
92
|
+
try {
|
|
93
|
+
await startServer();
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
console.error('Fatal error:', err instanceof Error ? err.message : err);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
main();
|
|
101
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential persistence — load / save agent credentials to disk.
|
|
3
|
+
*
|
|
4
|
+
* Default path: ~/.getterdone/credentials.json
|
|
5
|
+
* Env-var overrides: GETTERDONE_CLIENT_ID, GETTERDONE_CLIENT_SECRET
|
|
6
|
+
*/
|
|
7
|
+
export interface Credentials {
|
|
8
|
+
clientId: string;
|
|
9
|
+
clientSecret: string;
|
|
10
|
+
agentId: string;
|
|
11
|
+
agentName: string;
|
|
12
|
+
apiUrl: string;
|
|
13
|
+
registeredAt: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function defaultCredentialsPath(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Load credentials from env vars first, then fall back to disk.
|
|
18
|
+
* Throws if neither source provides valid credentials.
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadCredentials(path?: string): Credentials;
|
|
21
|
+
/**
|
|
22
|
+
* Persist credentials to disk with restrictive permissions (0600).
|
|
23
|
+
*/
|
|
24
|
+
export declare function saveCredentials(creds: Credentials, path?: string): string;
|
|
25
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,MAAM,WAAW,WAAW;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACxB;AAID,wBAAgB,sBAAsB,IAAI,MAAM,CAG/C;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CA6C1D;AAID;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAazE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential persistence — load / save agent credentials to disk.
|
|
3
|
+
*
|
|
4
|
+
* Default path: ~/.getterdone/credentials.json
|
|
5
|
+
* Env-var overrides: GETTERDONE_CLIENT_ID, GETTERDONE_CLIENT_SECRET
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync } from 'node:fs';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
// ── Paths ────────────────────────────────────────────────
|
|
11
|
+
export function defaultCredentialsPath() {
|
|
12
|
+
return process.env.GETTERDONE_CREDENTIALS_PATH
|
|
13
|
+
?? join(homedir(), '.getterdone', 'credentials.json');
|
|
14
|
+
}
|
|
15
|
+
// ── Load ─────────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Load credentials from env vars first, then fall back to disk.
|
|
18
|
+
* Throws if neither source provides valid credentials.
|
|
19
|
+
*/
|
|
20
|
+
export function loadCredentials(path) {
|
|
21
|
+
// 1. Try env vars
|
|
22
|
+
const envId = process.env.GETTERDONE_CLIENT_ID;
|
|
23
|
+
const envSecret = process.env.GETTERDONE_CLIENT_SECRET;
|
|
24
|
+
if (envId && envSecret) {
|
|
25
|
+
return {
|
|
26
|
+
clientId: envId,
|
|
27
|
+
clientSecret: envSecret,
|
|
28
|
+
agentId: '',
|
|
29
|
+
agentName: '',
|
|
30
|
+
apiUrl: process.env.GETTERDONE_API_URL ?? 'https://getterdone.ai',
|
|
31
|
+
registeredAt: '',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// 2. Try credentials file
|
|
35
|
+
const filePath = path ?? defaultCredentialsPath();
|
|
36
|
+
if (!existsSync(filePath)) {
|
|
37
|
+
throw new Error(`No credentials found. Run "getterdone-mcp setup --name <agent>" first, ` +
|
|
38
|
+
`or set GETTERDONE_CLIENT_ID and GETTERDONE_CLIENT_SECRET env vars.`);
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
42
|
+
const creds = JSON.parse(raw);
|
|
43
|
+
if (!creds.clientId || !creds.clientSecret) {
|
|
44
|
+
throw new Error('Credentials file is missing clientId or clientSecret');
|
|
45
|
+
}
|
|
46
|
+
// Allow env override of API URL even when reading from file
|
|
47
|
+
if (process.env.GETTERDONE_API_URL) {
|
|
48
|
+
creds.apiUrl = process.env.GETTERDONE_API_URL;
|
|
49
|
+
}
|
|
50
|
+
return creds;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
if (err instanceof SyntaxError) {
|
|
54
|
+
throw new Error(`Invalid credentials file at ${filePath}: ${err.message}`);
|
|
55
|
+
}
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// ── Save ─────────────────────────────────────────────────
|
|
60
|
+
/**
|
|
61
|
+
* Persist credentials to disk with restrictive permissions (0600).
|
|
62
|
+
*/
|
|
63
|
+
export function saveCredentials(creds, path) {
|
|
64
|
+
const filePath = path ?? defaultCredentialsPath();
|
|
65
|
+
const dir = dirname(filePath);
|
|
66
|
+
// Create directory if needed
|
|
67
|
+
if (!existsSync(dir)) {
|
|
68
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
69
|
+
}
|
|
70
|
+
writeFileSync(filePath, JSON.stringify(creds, null, 2) + '\n', 'utf-8');
|
|
71
|
+
chmodSync(filePath, 0o600);
|
|
72
|
+
return filePath;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAa1C,4DAA4D;AAE5D,MAAM,UAAU,sBAAsB;IAClC,OAAO,OAAO,CAAC,GAAG,CAAC,2BAA2B;WACvC,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,kBAAkB,CAAC,CAAC;AAC9D,CAAC;AAED,4DAA4D;AAE5D;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAa;IACzC,kBAAkB;IAClB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAEvD,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;QACrB,OAAO;YACH,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,SAAS;YACvB,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,EAAE;YACb,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,uBAAuB;YACjE,YAAY,EAAE,EAAE;SACnB,CAAC;IACN,CAAC;IAED,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,IAAI,IAAI,sBAAsB,EAAE,CAAC;IAClD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACX,yEAAyE;YACzE,oEAAoE,CACvE,CAAC;IACN,CAAC;IAED,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;QAE7C,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC5E,CAAC;QAED,4DAA4D;QAC5D,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;YACjC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAClD,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,MAAM,GAAG,CAAC;IACd,CAAC;AACL,CAAC;AAED,4DAA4D;AAE5D;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAkB,EAAE,IAAa;IAC7D,MAAM,QAAQ,GAAG,IAAI,IAAI,sBAAsB,EAAE,CAAC;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE9B,6BAA6B;IAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IACxE,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAE3B,OAAO,QAAQ,CAAC;AACpB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAmCjD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GetterDone MCP Server — main entry point.
|
|
3
|
+
*
|
|
4
|
+
* Wires credentials → auth → API client → tools/resources/prompts,
|
|
5
|
+
* then connects via stdio transport.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
9
|
+
import { loadCredentials } from './credentials.js';
|
|
10
|
+
import { ApiClient } from './api-client.js';
|
|
11
|
+
import { TokenManager } from './auth.js';
|
|
12
|
+
import { registerTools } from './tools.js';
|
|
13
|
+
import { registerResources, registerPrompts } from './resources-and-prompts.js';
|
|
14
|
+
export async function startServer() {
|
|
15
|
+
// 1. Load credentials
|
|
16
|
+
const creds = loadCredentials();
|
|
17
|
+
// 2. Create server
|
|
18
|
+
const server = new McpServer({
|
|
19
|
+
name: 'getterdone',
|
|
20
|
+
version: '0.1.0',
|
|
21
|
+
});
|
|
22
|
+
// 3. Create API client with token manager
|
|
23
|
+
// We need a circular dependency: ApiClient needs getToken, TokenManager needs ApiClient.
|
|
24
|
+
// Solve by creating ApiClient first with a placeholder, then wiring up.
|
|
25
|
+
let tokenManager;
|
|
26
|
+
const api = new ApiClient(creds.apiUrl, async () => tokenManager.getToken());
|
|
27
|
+
tokenManager = new TokenManager(creds.clientId, creds.clientSecret, api);
|
|
28
|
+
// 4. Register tools, resources, and prompts
|
|
29
|
+
registerTools(server, api, creds.agentId);
|
|
30
|
+
registerResources(server, api, creds.agentId);
|
|
31
|
+
registerPrompts(server);
|
|
32
|
+
// 5. Connect via stdio
|
|
33
|
+
const transport = new StdioServerTransport();
|
|
34
|
+
await server.connect(transport);
|
|
35
|
+
// Log to stderr (stdout is reserved for MCP protocol)
|
|
36
|
+
console.error('🚀 GetterDone MCP Server running on stdio');
|
|
37
|
+
console.error(` Agent: ${creds.agentName || creds.clientId}`);
|
|
38
|
+
console.error(` API: ${creds.apiUrl}`);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAEhF,MAAM,CAAC,KAAK,UAAU,WAAW;IAC7B,sBAAsB;IACtB,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAEhC,mBAAmB;IACnB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QACzB,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACnB,CAAC,CAAC;IAEH,0CAA0C;IAC1C,4FAA4F;IAC5F,2EAA2E;IAC3E,IAAI,YAA0B,CAAC;IAE/B,MAAM,GAAG,GAAG,IAAI,SAAS,CACrB,KAAK,CAAC,MAAM,EACZ,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,CACtC,CAAC;IAEF,YAAY,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;IAEzE,4CAA4C;IAC5C,aAAa,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1C,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9C,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,uBAAuB;IACvB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,sDAAsD;IACtD,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC3D,OAAO,CAAC,KAAK,CAAC,aAAa,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAChE,OAAO,CAAC,KAAK,CAAC,aAAa,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP resources and prompt templates.
|
|
3
|
+
*
|
|
4
|
+
* Resources: getterdone://balance, getterdone://tasks/active, getterdone://reputation
|
|
5
|
+
* Prompts: review_submission, create_errand
|
|
6
|
+
*/
|
|
7
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
import type { ApiClient } from './api-client.js';
|
|
9
|
+
export declare function registerResources(server: McpServer, api: ApiClient, agentId: string): void;
|
|
10
|
+
export declare function registerPrompts(server: McpServer): void;
|
|
11
|
+
//# sourceMappingURL=resources-and-prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources-and-prompts.d.ts","sourceRoot":"","sources":["../src/resources-and-prompts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAKjD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAkF1F;AAID,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4DvD"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP resources and prompt templates.
|
|
3
|
+
*
|
|
4
|
+
* Resources: getterdone://balance, getterdone://tasks/active, getterdone://reputation
|
|
5
|
+
* Prompts: review_submission, create_errand
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
// ── Resources ────────────────────────────────────────────
|
|
9
|
+
export function registerResources(server, api, agentId) {
|
|
10
|
+
// Balance
|
|
11
|
+
server.resource('balance', 'getterdone://balance', { description: "Agent's current wallet balance and pending escrow" }, async () => {
|
|
12
|
+
try {
|
|
13
|
+
const data = await api.getBalance();
|
|
14
|
+
return {
|
|
15
|
+
contents: [{
|
|
16
|
+
uri: 'getterdone://balance',
|
|
17
|
+
mimeType: 'application/json',
|
|
18
|
+
text: JSON.stringify(data, null, 2),
|
|
19
|
+
}],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return {
|
|
24
|
+
contents: [{
|
|
25
|
+
uri: 'getterdone://balance',
|
|
26
|
+
mimeType: 'application/json',
|
|
27
|
+
text: '{"error": "Failed to fetch balance"}',
|
|
28
|
+
}],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
// Active tasks
|
|
33
|
+
server.resource('active_tasks', 'getterdone://tasks/active', { description: "Agent's currently open, claimed, or submitted tasks" }, async () => {
|
|
34
|
+
try {
|
|
35
|
+
const data = await api.listTasks({ status: 'open,claimed,submitted' });
|
|
36
|
+
return {
|
|
37
|
+
contents: [{
|
|
38
|
+
uri: 'getterdone://tasks/active',
|
|
39
|
+
mimeType: 'application/json',
|
|
40
|
+
text: JSON.stringify(data, null, 2),
|
|
41
|
+
}],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return {
|
|
46
|
+
contents: [{
|
|
47
|
+
uri: 'getterdone://tasks/active',
|
|
48
|
+
mimeType: 'application/json',
|
|
49
|
+
text: '{"error": "Failed to fetch active tasks"}',
|
|
50
|
+
}],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// Reputation
|
|
55
|
+
server.resource('reputation', 'getterdone://reputation', { description: "Agent's reputation composite and reliability tier" }, async () => {
|
|
56
|
+
try {
|
|
57
|
+
const data = await api.getReputation(agentId);
|
|
58
|
+
return {
|
|
59
|
+
contents: [{
|
|
60
|
+
uri: 'getterdone://reputation',
|
|
61
|
+
mimeType: 'application/json',
|
|
62
|
+
text: JSON.stringify(data, null, 2),
|
|
63
|
+
}],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return {
|
|
68
|
+
contents: [{
|
|
69
|
+
uri: 'getterdone://reputation',
|
|
70
|
+
mimeType: 'application/json',
|
|
71
|
+
text: '{"error": "Failed to fetch reputation"}',
|
|
72
|
+
}],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// ── Prompts ──────────────────────────────────────────────
|
|
78
|
+
export function registerPrompts(server) {
|
|
79
|
+
// review_submission — guide agent through reviewing a worker's proof
|
|
80
|
+
server.prompt('review_submission', 'Review a worker submission and decide whether to approve or dispute', { taskId: z.string().describe('The task ID to review') }, async ({ taskId }) => ({
|
|
81
|
+
messages: [{
|
|
82
|
+
role: 'user',
|
|
83
|
+
content: {
|
|
84
|
+
type: 'text',
|
|
85
|
+
text: [
|
|
86
|
+
`Please review the submission for task ${taskId}.`,
|
|
87
|
+
'',
|
|
88
|
+
'Steps:',
|
|
89
|
+
`1. First, call the \`get_task\` tool with taskId "${taskId}" to fetch the full task details.`,
|
|
90
|
+
'2. Compare the worker\'s proof-of-work against the original task requirements.',
|
|
91
|
+
'3. Check if any review criteria (keywords, minimum images) are satisfied.',
|
|
92
|
+
'4. Make a decision:',
|
|
93
|
+
` - If the proof satisfies the requirements → call \`approve_task\` with taskId "${taskId}"`,
|
|
94
|
+
` - If the proof is insufficient → call \`dispute_task\` with taskId "${taskId}" and a detailed reason (min 10 chars)`,
|
|
95
|
+
'',
|
|
96
|
+
'Important: Approving is IRREVERSIBLE and releases the escrowed funds to the worker.',
|
|
97
|
+
'When in doubt, ask me for clarification before approving.',
|
|
98
|
+
].join('\n'),
|
|
99
|
+
},
|
|
100
|
+
}],
|
|
101
|
+
}));
|
|
102
|
+
// create_errand — guide agent through structured task creation
|
|
103
|
+
server.prompt('create_errand', 'Create a well-structured physical errand from a high-level objective', { objective: z.string().describe("What the agent wants accomplished (e.g., 'verify business hours of Joe's Pizza')") }, async ({ objective }) => ({
|
|
104
|
+
messages: [{
|
|
105
|
+
role: 'user',
|
|
106
|
+
content: {
|
|
107
|
+
type: 'text',
|
|
108
|
+
text: [
|
|
109
|
+
`I want to create a GetterDone task from this objective: "${objective}"`,
|
|
110
|
+
'',
|
|
111
|
+
'Please help me structure this into a well-defined task:',
|
|
112
|
+
'',
|
|
113
|
+
'1. **Title** — A short, clear summary (< 80 chars)',
|
|
114
|
+
'2. **Description** — Step-by-step instructions for the worker',
|
|
115
|
+
'3. **Location** — Where the task needs to happen (lat, lng, label)',
|
|
116
|
+
'4. **Reward** — Fair compensation ($1–$100)',
|
|
117
|
+
'5. **Category** — General, Delivery, Photography, Research, or Physical Task',
|
|
118
|
+
'6. **Review Criteria** — Keywords and minimum images to verify completion',
|
|
119
|
+
'',
|
|
120
|
+
'Once you have all the details, call `create_task` with the structured payload.',
|
|
121
|
+
'If the objective is location-independent, set remote to true.',
|
|
122
|
+
].join('\n'),
|
|
123
|
+
},
|
|
124
|
+
}],
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=resources-and-prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources-and-prompts.js","sourceRoot":"","sources":["../src/resources-and-prompts.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register all 11 MCP tools on the server instance.
|
|
3
|
+
*/
|
|
4
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
|
+
import type { ApiClient } from './api-client.js';
|
|
6
|
+
export declare function registerTools(server: McpServer, api: ApiClient, agentId: string): void;
|
|
7
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,iBAAiB,CAAC;AAuC3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAsItF"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register all 11 MCP tools on the server instance.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
// ── Helpers ──────────────────────────────────────────────
|
|
6
|
+
function success(data) {
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function error(err) {
|
|
12
|
+
const apiErr = err;
|
|
13
|
+
const message = apiErr?.message
|
|
14
|
+
? `[${apiErr.code ?? 'error'}] ${apiErr.message}`
|
|
15
|
+
: String(err);
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: 'text', text: message }],
|
|
18
|
+
isError: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async function wrap(fn) {
|
|
22
|
+
try {
|
|
23
|
+
const data = await fn();
|
|
24
|
+
return success(data);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
return error(err);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// ── Registration ─────────────────────────────────────────
|
|
31
|
+
export function registerTools(server, api, agentId) {
|
|
32
|
+
// 1. create_task
|
|
33
|
+
server.tool('create_task', "Post a new task to the GetterDone marketplace. Funds are automatically escrowed from the agent's balance.", {
|
|
34
|
+
title: z.string().describe("Short title (e.g., 'Buy coffee at Starbucks on 5th Ave')"),
|
|
35
|
+
description: z.string().describe('Detailed instructions for the worker'),
|
|
36
|
+
reward: z.number().min(1).max(100).describe('USD amount to pay the worker ($1–$100)'),
|
|
37
|
+
category: z.enum(['General', 'Delivery', 'Photography', 'Research', 'Physical Task']).default('General').describe('Task category'),
|
|
38
|
+
lat: z.number().describe('Location latitude'),
|
|
39
|
+
lng: z.number().describe('Location longitude'),
|
|
40
|
+
locationLabel: z.string().describe('Human-readable address'),
|
|
41
|
+
remote: z.boolean().default(false).describe('Set true for location-independent tasks'),
|
|
42
|
+
expiresInHours: z.number().default(24).describe('Hours until auto-expiry if unclaimed'),
|
|
43
|
+
keywords: z.array(z.string()).optional().describe('Keywords required in worker proof'),
|
|
44
|
+
minImages: z.number().optional().describe('Minimum images required in worker proof'),
|
|
45
|
+
}, async (args) => wrap(() => api.createTask({
|
|
46
|
+
title: args.title,
|
|
47
|
+
description: args.description,
|
|
48
|
+
reward: args.reward,
|
|
49
|
+
category: args.category,
|
|
50
|
+
location: { lat: args.lat, lng: args.lng, label: args.locationLabel, remote: args.remote },
|
|
51
|
+
expiresInHours: args.expiresInHours,
|
|
52
|
+
reviewCriteria: (args.keywords || args.minImages)
|
|
53
|
+
? { keywords: args.keywords, minImages: args.minImages }
|
|
54
|
+
: undefined,
|
|
55
|
+
})));
|
|
56
|
+
// 2. list_tasks
|
|
57
|
+
server.tool('list_tasks', "List the agent's own tasks, optionally filtered by status.", {
|
|
58
|
+
status: z.enum(['open', 'claimed', 'submitted', 'completed', 'disputed', 'contested', 'expired', 'all']).default('all').describe('Filter by status'),
|
|
59
|
+
limit: z.number().min(1).max(50).default(20).describe('Max results'),
|
|
60
|
+
}, async (args) => wrap(() => api.listTasks({ status: args.status, limit: args.limit })));
|
|
61
|
+
// 3. get_task
|
|
62
|
+
server.tool('get_task', 'Get full details for a specific task, including proof-of-work submissions and dispute history.', {
|
|
63
|
+
taskId: z.string().describe('The unique task ID'),
|
|
64
|
+
}, async (args) => wrap(() => api.getTask(args.taskId)));
|
|
65
|
+
// 4. approve_task
|
|
66
|
+
server.tool('approve_task', 'Approve a submitted task, release escrowed funds to the worker. This is IRREVERSIBLE.', {
|
|
67
|
+
taskId: z.string().describe('The task ID to approve'),
|
|
68
|
+
}, async (args) => wrap(() => api.approveTask(args.taskId)));
|
|
69
|
+
// 5. dispute_task
|
|
70
|
+
server.tool('dispute_task', "Dispute a submitted task's proof-of-work. The worker will be notified and may contest.", {
|
|
71
|
+
taskId: z.string().describe('The task ID to dispute'),
|
|
72
|
+
reason: z.string().min(10).describe('Detailed reason why the proof is insufficient (min 10 chars)'),
|
|
73
|
+
}, async (args) => wrap(() => api.disputeTask(args.taskId, args.reason)));
|
|
74
|
+
// 6. cancel_task
|
|
75
|
+
server.tool('cancel_task', 'Cancel an open task and refund escrowed funds. Cannot cancel claimed or submitted tasks.', {
|
|
76
|
+
taskId: z.string().describe('The task ID to cancel'),
|
|
77
|
+
}, async (args) => wrap(() => api.cancelTask(args.taskId)));
|
|
78
|
+
// 7. fund_account
|
|
79
|
+
server.tool('fund_account', "Add funds to the agent's wallet.", {
|
|
80
|
+
amount: z.number().min(1).describe('USD amount to add (minimum $1.00)'),
|
|
81
|
+
paymentMethodNonce: z.string().optional().describe('Braintree nonce (optional in sandbox)'),
|
|
82
|
+
}, async (args) => wrap(() => api.fundAccount(args.amount, args.paymentMethodNonce)));
|
|
83
|
+
// 8. get_balance
|
|
84
|
+
server.tool('get_balance', "Get the agent's current wallet balance.", {}, async () => wrap(() => api.getBalance()));
|
|
85
|
+
// 9. rate_worker
|
|
86
|
+
server.tool('rate_worker', 'Leave a 1–5 star rating for a worker after task completion. Must be within the 24-hour window.', {
|
|
87
|
+
taskId: z.string().describe('The completed task ID'),
|
|
88
|
+
score: z.number().int().min(1).max(5).describe('Star rating (1 = poor, 5 = excellent)'),
|
|
89
|
+
comment: z.string().optional().describe('Optional text feedback'),
|
|
90
|
+
}, async (args) => wrap(() => api.rateWorker(args.taskId, args.score, args.comment)));
|
|
91
|
+
// 10. get_reputation
|
|
92
|
+
server.tool('get_reputation', "Get an agent's reputation composite including completion rate, dispute history, and reliability tier.", {
|
|
93
|
+
agentId: z.string().optional().describe('Agent ID. Omit to get your own reputation.'),
|
|
94
|
+
}, async (args) => wrap(() => api.getReputation(args.agentId ?? agentId)));
|
|
95
|
+
// 11. configure_webhook
|
|
96
|
+
server.tool('configure_webhook', 'Register or update a webhook URL for real-time event notifications.', {
|
|
97
|
+
url: z.string().url().describe('HTTPS URL to receive webhook POST requests'),
|
|
98
|
+
}, async (args) => wrap(() => api.configureWebhook(args.url)));
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@getterdone/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for GetterDone — connect AI agents to the physical-task marketplace",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"getterdone-mcp": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"start": "node dist/index.js",
|
|
20
|
+
"setup": "node dist/cli.js setup",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"mcp",
|
|
25
|
+
"model-context-protocol",
|
|
26
|
+
"getterdone",
|
|
27
|
+
"ai-agent",
|
|
28
|
+
"marketplace",
|
|
29
|
+
"claude",
|
|
30
|
+
"cursor",
|
|
31
|
+
"llm"
|
|
32
|
+
],
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/maociao/getterdone-mcp.git"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://getterdone.mellowcake.ai",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/maociao/getterdone-mcp/issues"
|
|
40
|
+
},
|
|
41
|
+
"author": "maociao",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
45
|
+
"zod": "^3.24.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^20",
|
|
49
|
+
"typescript": "^5"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18"
|
|
53
|
+
}
|
|
54
|
+
}
|