gotoHuman MCP
Official
by gotohuman
Verified
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { GotoHuman } from "gotohuman";
const version = "0.1.0"
// Create an MCP server
const server = new McpServer({
name: "gotohuman-mcp-server",
version: version
},
{
capabilities: {
tools: {},
},
});
// Tool for listing available forms
server.tool(
"list-forms",
"List all available review forms. NOTE: You need to fetch the schema for the form fields first using the get-form-schema tool.",
{},
async () => {
try {
const gotoHuman = new GotoHuman({origin: "mcp-server", originV: version});
const forms = await gotoHuman.fetchReviewForms();
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
forms: forms
})
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: JSON.stringify({
success: false,
error: error instanceof Error ? error.message : "Unknown error occurred"
})
}],
isError: true
};
}
}
);
// Tool for fetching form field schema
server.tool(
"get-form-schema",
"Get the schema to use for the 'fields' property when requesting a human review with a form.",
{
formId: z.string().describe("The form ID to fetch the schema for")
},
async ({ formId }) => {
try {
const gotoHuman = new GotoHuman();
const formFieldsSchema = await gotoHuman.fetchSchemaForFormFields(formId);
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
formId: formId,
fieldsSchema: formFieldsSchema,
})
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: JSON.stringify({
success: false,
error: error instanceof Error ? error.message : "Unknown error occurred"
})
}],
isError: true
};
}
}
);
// Define the tool schema - accepting any valid JSON value for field data
const requestHumanReviewSchema = {
formId: z.string().describe("The form ID to request a human review for"),
fieldData: z.record(z.string(), z.any()).describe("The field data to include in the review request. Note that this is a dynamic schema that you need to fetch first using the get-form-schema tool."),
metadata: z.record(z.string(), z.string()).optional().describe("Optional additional data that will be incl. in the webhook response after form submission. Incl. everything required to proceed with your workflow."),
assignToUsers: z.array(z.string()).optional().describe("Optional list of user emails to assign the review to")
};
// Add the human review request tool
server.tool(
"request-human-review-with-form",
"Request a human review with a form. NOTE: If you don't have a form ID yet, list all available forms using the list-forms tool first. To know what to pass for fieldData, you need to fetch the schema for the form fields using the get-form-schema tool.",
requestHumanReviewSchema,
async ({ formId, fieldData, metadata, assignToUsers }) => {
try {
const gotoHuman = new GotoHuman();
const reviewRequest = gotoHuman.createReview(formId);
// Add all field data dynamically
Object.entries(fieldData).forEach(([key, value]) => {
reviewRequest.addFieldData(key, value);
});
// Add optional metadata if provided
if (metadata) {
Object.entries(metadata).forEach(([key, value]) => {
reviewRequest.addMetaData(key, value);
});
}
// Assign to specific users if provided
if (assignToUsers) {
reviewRequest.assignToUsers(assignToUsers);
}
const response = await reviewRequest.sendRequest();
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
reviewId: response.reviewId,
reviewLink: response.gthLink
})
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: JSON.stringify({
success: false,
error: error instanceof Error ? error.message : "Unknown error occurred"
})
}],
isError: true
};
}
}
);
// Start the server with stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);