@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 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
@@ -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
@@ -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"}
@@ -0,0 +1,8 @@
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
+ export declare function startServer(): Promise<void>;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -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":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,4DAA4D;AAE5D,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,GAAc,EAAE,OAAe;IAEhF,UAAU;IACV,MAAM,CAAC,QAAQ,CACX,SAAS,EACT,sBAAsB,EACtB,EAAE,WAAW,EAAE,mDAAmD,EAAE,EACpE,KAAK,IAAI,EAAE;QACP,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,UAAU,EAAE,CAAC;YACpC,OAAO;gBACH,QAAQ,EAAE,CAAC;wBACP,GAAG,EAAE,sBAAsB;wBAC3B,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;qBACtC,CAAC;aACL,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACL,OAAO;gBACH,QAAQ,EAAE,CAAC;wBACP,GAAG,EAAE,sBAAsB;wBAC3B,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,sCAAsC;qBAC/C,CAAC;aACL,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;IAEF,eAAe;IACf,MAAM,CAAC,QAAQ,CACX,cAAc,EACd,2BAA2B,EAC3B,EAAE,WAAW,EAAE,qDAAqD,EAAE,EACtE,KAAK,IAAI,EAAE;QACP,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC,CAAC;YACvE,OAAO;gBACH,QAAQ,EAAE,CAAC;wBACP,GAAG,EAAE,2BAA2B;wBAChC,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;qBACtC,CAAC;aACL,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACL,OAAO;gBACH,QAAQ,EAAE,CAAC;wBACP,GAAG,EAAE,2BAA2B;wBAChC,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,2CAA2C;qBACpD,CAAC;aACL,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;IAEF,aAAa;IACb,MAAM,CAAC,QAAQ,CACX,YAAY,EACZ,yBAAyB,EACzB,EAAE,WAAW,EAAE,mDAAmD,EAAE,EACpE,KAAK,IAAI,EAAE;QACP,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC9C,OAAO;gBACH,QAAQ,EAAE,CAAC;wBACP,GAAG,EAAE,yBAAyB;wBAC9B,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;qBACtC,CAAC;aACL,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACL,OAAO;gBACH,QAAQ,EAAE,CAAC;wBACP,GAAG,EAAE,yBAAyB;wBAC9B,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,yCAAyC;qBAClD,CAAC;aACL,CAAC;QACN,CAAC;IACL,CAAC,CACJ,CAAC;AACN,CAAC;AAED,4DAA4D;AAE5D,MAAM,UAAU,eAAe,CAAC,MAAiB;IAE7C,qEAAqE;IACrE,MAAM,CAAC,MAAM,CACT,mBAAmB,EACnB,qEAAqE,EACrE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,EACxD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QACnB,QAAQ,EAAE,CAAC;gBACP,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACL,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;wBACF,yCAAyC,MAAM,GAAG;wBAClD,EAAE;wBACF,QAAQ;wBACR,qDAAqD,MAAM,mCAAmC;wBAC9F,gFAAgF;wBAChF,2EAA2E;wBAC3E,qBAAqB;wBACrB,qFAAqF,MAAM,GAAG;wBAC9F,0EAA0E,MAAM,wCAAwC;wBACxH,EAAE;wBACF,qFAAqF;wBACrF,2DAA2D;qBAC9D,CAAC,IAAI,CAAC,IAAI,CAAC;iBACf;aACJ,CAAC;KACL,CAAC,CACL,CAAC;IAEF,+DAA+D;IAC/D,MAAM,CAAC,MAAM,CACT,eAAe,EACf,sEAAsE,EACtE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kFAAkF,CAAC,EAAE,EACtH,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QACtB,QAAQ,EAAE,CAAC;gBACP,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACL,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;wBACF,4DAA4D,SAAS,GAAG;wBACxE,EAAE;wBACF,yDAAyD;wBACzD,EAAE;wBACF,oDAAoD;wBACpD,+DAA+D;wBAC/D,oEAAoE;wBACpE,6CAA6C;wBAC7C,8EAA8E;wBAC9E,2EAA2E;wBAC3E,EAAE;wBACF,gFAAgF;wBAChF,+DAA+D;qBAClE,CAAC,IAAI,CAAC,IAAI,CAAC;iBACf;aACJ,CAAC;KACL,CAAC,CACL,CAAC;AACN,CAAC"}
@@ -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
+ }