@hapticpaper/mcp-server 1.0.8 → 1.0.9
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/dist/client/hapticPaperClient.js +107 -0
- package/dist/index.js +8 -8
- package/dist/resources/index.js +1 -1
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/server.json +8 -4
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
export class HapticPaperClient {
|
|
3
|
+
client;
|
|
4
|
+
tokenProvider;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.client = axios.create({
|
|
7
|
+
baseURL: config.baseUrl,
|
|
8
|
+
headers: {
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
this.tokenProvider = config.tokenProvider;
|
|
13
|
+
// Request interceptor to add auth token
|
|
14
|
+
this.client.interceptors.request.use(async (config) => {
|
|
15
|
+
if (this.tokenProvider) {
|
|
16
|
+
const token = await this.tokenProvider();
|
|
17
|
+
if (token) {
|
|
18
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return config;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async authHeaders(accessToken) {
|
|
25
|
+
if (accessToken) {
|
|
26
|
+
return { Authorization: `Bearer ${accessToken}` };
|
|
27
|
+
}
|
|
28
|
+
if (!this.tokenProvider) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
const token = await this.tokenProvider();
|
|
32
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
33
|
+
}
|
|
34
|
+
// Account Methods
|
|
35
|
+
async getAccount(accessToken) {
|
|
36
|
+
const response = await this.client.get('/gpt/account', { headers: await this.authHeaders(accessToken) });
|
|
37
|
+
return response.data;
|
|
38
|
+
}
|
|
39
|
+
// Task Methods
|
|
40
|
+
async createTask(data, accessToken) {
|
|
41
|
+
const response = await this.client.post('/gpt/tasks', data, { headers: await this.authHeaders(accessToken) });
|
|
42
|
+
return response.data;
|
|
43
|
+
}
|
|
44
|
+
async getTask(taskId, accessToken) {
|
|
45
|
+
const response = await this.client.get(`/gpt/tasks/${taskId}`, { headers: await this.authHeaders(accessToken) });
|
|
46
|
+
return response.data;
|
|
47
|
+
}
|
|
48
|
+
async listTasks(params, accessToken) {
|
|
49
|
+
const response = await this.client.get('/gpt/tasks', { params, headers: await this.authHeaders(accessToken) });
|
|
50
|
+
return response.data;
|
|
51
|
+
}
|
|
52
|
+
async cancelTask(taskId, reason, accessToken) {
|
|
53
|
+
const response = await this.client.post(`/gpt/tasks/${taskId}/cancel`, { reason }, { headers: await this.authHeaders(accessToken) });
|
|
54
|
+
return response.data;
|
|
55
|
+
}
|
|
56
|
+
// Worker Methods
|
|
57
|
+
async searchWorkers(params, accessToken) {
|
|
58
|
+
const response = await this.client.post('/gpt/workers/search', params, { headers: await this.authHeaders(accessToken) });
|
|
59
|
+
return response.data;
|
|
60
|
+
}
|
|
61
|
+
async getWorkerProfile(workerId, accessToken) {
|
|
62
|
+
// This endpoint might not exist in gptRoutes yet, assuming it maps to backend logic
|
|
63
|
+
// If not in GPT routes, we might need to add it or use a different route
|
|
64
|
+
// For now assuming it exists based on plan
|
|
65
|
+
const response = await this.client.get(`/gpt/workers/${workerId}`, { headers: await this.authHeaders(accessToken) });
|
|
66
|
+
return response.data;
|
|
67
|
+
}
|
|
68
|
+
// Estimate Methods
|
|
69
|
+
async getEstimate(params, accessToken) {
|
|
70
|
+
const response = await this.client.post('/gpt/estimate', params, { headers: await this.authHeaders(accessToken) });
|
|
71
|
+
return response.data;
|
|
72
|
+
}
|
|
73
|
+
async getSkillCategories() {
|
|
74
|
+
// Placeholder or real endpoint
|
|
75
|
+
return [
|
|
76
|
+
{
|
|
77
|
+
name: "Delivery",
|
|
78
|
+
description: "Physical delivery of items",
|
|
79
|
+
examples: ["Food delivery", "Package courier"],
|
|
80
|
+
priceRange: { min: 15, max: 50 }
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "General Help",
|
|
84
|
+
description: "Moving, cleaning, organizing",
|
|
85
|
+
examples: ["Help moving boxes", "Garage cleanup"],
|
|
86
|
+
priceRange: { min: 30, max: 100 }
|
|
87
|
+
}
|
|
88
|
+
];
|
|
89
|
+
}
|
|
90
|
+
// Qualification Methods
|
|
91
|
+
async discoverEarningOpportunity(params) {
|
|
92
|
+
const response = await this.client.post('/gpt/qualification/discover', params);
|
|
93
|
+
return response.data;
|
|
94
|
+
}
|
|
95
|
+
async continueQualification(sessionId, userResponse) {
|
|
96
|
+
const response = await this.client.post(`/gpt/qualification/${sessionId}/respond`, { userResponse });
|
|
97
|
+
return response.data;
|
|
98
|
+
}
|
|
99
|
+
async getQualificationStatus(sessionId) {
|
|
100
|
+
const response = await this.client.get(`/gpt/qualification/${sessionId}`);
|
|
101
|
+
return response.data;
|
|
102
|
+
}
|
|
103
|
+
async completeQualification(sessionId) {
|
|
104
|
+
const response = await this.client.post(`/gpt/qualification/${sessionId}/complete`, {});
|
|
105
|
+
return response.data;
|
|
106
|
+
}
|
|
107
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import crypto from 'node:crypto';
|
|
|
11
11
|
import fs from 'node:fs';
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import jwt from 'jsonwebtoken';
|
|
14
|
-
import {
|
|
14
|
+
import { HapticPaperClient } from "./client/hapticPaperClient.js";
|
|
15
15
|
import { registerAllTools } from "./tools/index.js";
|
|
16
16
|
import { registerAllResources } from "./resources/index.js";
|
|
17
17
|
import { TokenManager, MCPOAuthHandler } from "./auth/oauth.js";
|
|
@@ -49,10 +49,10 @@ async function main() {
|
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
const widgetJs = fs.readFileSync(widgetBundlePath, 'utf8');
|
|
52
|
-
server.registerResource('hirehuman-widget', 'ui://widget/
|
|
52
|
+
server.registerResource('hirehuman-widget', 'ui://widget/hapticpaper.html', {}, async () => ({
|
|
53
53
|
contents: [
|
|
54
54
|
{
|
|
55
|
-
uri: 'ui://widget/
|
|
55
|
+
uri: 'ui://widget/hapticpaper.html',
|
|
56
56
|
mimeType: 'text/html+skybridge',
|
|
57
57
|
text: `
|
|
58
58
|
<div id="hirehuman-root"></div>
|
|
@@ -76,7 +76,7 @@ ${widgetJs}
|
|
|
76
76
|
_meta: {
|
|
77
77
|
'openai/widgetPrefersBorder': true,
|
|
78
78
|
'openai/widgetDomain': 'https://chatgpt.com',
|
|
79
|
-
'openai/widgetDescription': 'Shows interactive task and worker results for
|
|
79
|
+
'openai/widgetDescription': 'Shows interactive task and worker results for Haptic-Paper tools.',
|
|
80
80
|
'openai/widgetCSP': {
|
|
81
81
|
connect_domains: ['https://chatgpt.com'],
|
|
82
82
|
resource_domains: ['https://*.oaistatic.com'],
|
|
@@ -88,7 +88,7 @@ ${widgetJs}
|
|
|
88
88
|
}
|
|
89
89
|
function createMcpServer(client) {
|
|
90
90
|
const server = new McpServer({
|
|
91
|
-
name: "
|
|
91
|
+
name: "haptic-paper",
|
|
92
92
|
version: "1.0.0"
|
|
93
93
|
});
|
|
94
94
|
registerWidgetTemplate(server);
|
|
@@ -112,7 +112,7 @@ ${widgetJs}
|
|
|
112
112
|
return tokens.access_token;
|
|
113
113
|
};
|
|
114
114
|
// Initialize Client with auto-auth tokenProvider
|
|
115
|
-
const client = new
|
|
115
|
+
const client = new HapticPaperClient({
|
|
116
116
|
baseUrl: process.env.API_URL || 'https://hapticpaper.com/api/v1',
|
|
117
117
|
tokenProvider: async () => {
|
|
118
118
|
// 1. Check for API key (CI/headless mode)
|
|
@@ -209,7 +209,7 @@ ${widgetJs}
|
|
|
209
209
|
resource: resourceServerUrl.toString(),
|
|
210
210
|
authorization_servers: [issuer],
|
|
211
211
|
scopes_supported: scopesSupported,
|
|
212
|
-
resource_name: '
|
|
212
|
+
resource_name: 'Haptic-Paper MCP',
|
|
213
213
|
});
|
|
214
214
|
});
|
|
215
215
|
if (shouldAdvertiseAuthMetadata) {
|
|
@@ -218,7 +218,7 @@ ${widgetJs}
|
|
|
218
218
|
oauthMetadata,
|
|
219
219
|
resourceServerUrl,
|
|
220
220
|
scopesSupported,
|
|
221
|
-
resourceName: '
|
|
221
|
+
resourceName: 'Haptic-Paper MCP',
|
|
222
222
|
}));
|
|
223
223
|
}
|
|
224
224
|
else if (!authMetadataDisabled) {
|
package/dist/resources/index.js
CHANGED
|
@@ -15,7 +15,7 @@ const templates = [
|
|
|
15
15
|
typicalDuration: "3-5 hours"
|
|
16
16
|
}
|
|
17
17
|
];
|
|
18
|
-
export function registerAllResources(server,
|
|
18
|
+
export function registerAllResources(server, client) {
|
|
19
19
|
server.registerResource('task-templates', TEMPLATES_URI, {
|
|
20
20
|
title: 'Task Templates',
|
|
21
21
|
description: 'List of common task templates with pricing guidance',
|
package/gemini-extension.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hapticpaper/mcp-server",
|
|
3
3
|
"mcpName": "com.hapticpaper/mcp",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.9",
|
|
5
5
|
"description": "Official MCP Server for Haptic Paper - Connect your account to create human tasks from agentic pipelines.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
package/server.json
CHANGED
|
@@ -6,12 +6,16 @@
|
|
|
6
6
|
"icons": [
|
|
7
7
|
{
|
|
8
8
|
"mimeType": "image/png",
|
|
9
|
-
"sizes": [
|
|
9
|
+
"sizes": [
|
|
10
|
+
"32x32"
|
|
11
|
+
],
|
|
10
12
|
"src": "https://hapticpaper.com/favicon-32x32.png"
|
|
11
13
|
},
|
|
12
14
|
{
|
|
13
15
|
"mimeType": "image/png",
|
|
14
|
-
"sizes": [
|
|
16
|
+
"sizes": [
|
|
17
|
+
"192x192"
|
|
18
|
+
],
|
|
15
19
|
"src": "https://hapticpaper.com/android-chrome-192x192.png"
|
|
16
20
|
}
|
|
17
21
|
],
|
|
@@ -21,7 +25,7 @@
|
|
|
21
25
|
"subfolder": "packages/mcp-server"
|
|
22
26
|
},
|
|
23
27
|
"websiteUrl": "https://hapticpaper.com/developer",
|
|
24
|
-
"version": "1.0.
|
|
28
|
+
"version": "1.0.9",
|
|
25
29
|
"remotes": [
|
|
26
30
|
{
|
|
27
31
|
"type": "streamable-http",
|
|
@@ -33,7 +37,7 @@
|
|
|
33
37
|
"registryType": "npm",
|
|
34
38
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
35
39
|
"identifier": "@hapticpaper/mcp-server",
|
|
36
|
-
"version": "1.0.
|
|
40
|
+
"version": "1.0.9",
|
|
37
41
|
"transport": {
|
|
38
42
|
"type": "stdio"
|
|
39
43
|
},
|