
integration-hub
by groeimetai
๐ค AI-powered ServiceNow development with 400+ MCP tools. Works with Claude, GPT, Gemini, Ollama & 75+ providers. Deploy widgets, manage incidents, automate workflows - all through natural language. Open-source Build Agent alternative.
SKILL.md
name: integration-hub description: This skill should be used when the user asks to "IntegrationHub", "spoke", "flow action", "integration", "subflow", "connection alias", "credential alias", "REST step", or any ServiceNow IntegrationHub development. license: Apache-2.0 compatibility: Designed for Snow-Code and ServiceNow development metadata: author: groeimetai version: "1.0.0" category: servicenow tools:
- snow_query_table
- snow_find_artifact
- snow_test_rest_connection
- snow_execute_script_with_output
IntegrationHub for ServiceNow
IntegrationHub provides reusable integration components for Flow Designer and workflows.
IntegrationHub Architecture
Spoke (sn_ih_spoke)
โโโ Actions (sn_ih_action)
โ โโโ Inputs
โ โโโ Steps
โ โโโ Outputs
โโโ Connection Alias
โโโ Credential Alias
Flow Designer
โโโ Uses Spoke Actions
Key Tables
| Table | Purpose |
|---|---|
sn_ih_spoke | Spoke definitions |
sn_ih_action | Spoke actions |
sn_ih_step_config | Action step configuration |
sys_alias | Connection/credential aliases |
Connection & Credential Aliases (ES5)
Create Connection Alias
// Create connection alias (ES5 ONLY!)
var alias = new GlideRecord('sys_alias');
alias.initialize();
alias.setValue('name', 'Jira Connection');
alias.setValue('id', 'x_myapp_jira_connection');
alias.setValue('type', 'connection');
alias.setValue('connection_type', 'http');
// Connection attributes
alias.setValue('attributes', JSON.stringify({
base_url: 'https://mycompany.atlassian.net/rest/api/3',
timeout: 30000
}));
alias.insert();
Create Credential Alias
// Create credential alias (ES5 ONLY!)
var credAlias = new GlideRecord('sys_alias');
credAlias.initialize();
credAlias.setValue('name', 'Jira API Token');
credAlias.setValue('id', 'x_myapp_jira_credential');
credAlias.setValue('type', 'credential');
credAlias.insert();
// Link to actual credential
var credential = new GlideRecord('basic_auth_credentials');
credential.initialize();
credential.setValue('name', 'Jira API Token Credential');
credential.setValue('user_name', 'api-user@company.com');
credential.setValue('password', ''); // Set via secure method
credential.insert();
// Create alias-credential mapping
var mapping = new GlideRecord('sys_alias_credential');
mapping.initialize();
mapping.setValue('alias', credAlias.getUniqueValue());
mapping.setValue('credential', credential.getUniqueValue());
mapping.insert();
Spoke Development (ES5)
Create Custom Spoke
// Create spoke (ES5 ONLY!)
var spoke = new GlideRecord('sn_ih_spoke');
spoke.initialize();
spoke.setValue('name', 'Custom ITSM Connector');
spoke.setValue('label', 'Custom ITSM Connector');
spoke.setValue('description', 'Integration with external ITSM system');
spoke.setValue('vendor', 'My Company');
spoke.setValue('version', '1.0.0');
// Scope
spoke.setValue('scope', 'x_myapp_itsm');
// Logo
spoke.setValue('logo', 'attachment_sys_id');
spoke.insert();
Create Spoke Action
// Create action for spoke (ES5 ONLY!)
var action = new GlideRecord('sn_ih_action');
action.initialize();
action.setValue('name', 'Create External Ticket');
action.setValue('label', 'Create External Ticket');
action.setValue('spoke', spokeSysId);
action.setValue('description', 'Creates a ticket in external ITSM system');
// Category
action.setValue('category', 'record_operations');
// Accessibility
action.setValue('accessible_from', 'flow_designer');
action.insert();
// Add inputs
addActionInput(action.getUniqueValue(), 'summary', 'String', true, 'Ticket summary');
addActionInput(action.getUniqueValue(), 'description', 'String', false, 'Ticket description');
addActionInput(action.getUniqueValue(), 'priority', 'String', false, 'Priority level');
// Add outputs
addActionOutput(action.getUniqueValue(), 'ticket_id', 'String', 'Created ticket ID');
addActionOutput(action.getUniqueValue(), 'ticket_url', 'String', 'URL to ticket');
Action Input/Output Helpers
// Add action input (ES5 ONLY!)
function addActionInput(actionSysId, name, type, mandatory, label) {
var input = new GlideRecord('sn_ih_input');
input.initialize();
input.setValue('action', actionSysId);
input.setValue('name', name);
input.setValue('label', label);
input.setValue('type', type);
input.setValue('mandatory', mandatory);
input.setValue('order', getNextOrder(actionSysId, 'input'));
return input.insert();
}
// Add action output (ES5 ONLY!)
function addActionOutput(actionSysId, name, type, label) {
var output = new GlideRecord('sn_ih_output');
output.initialize();
output.setValue('action', actionSysId);
output.setValue('name', name);
output.setValue('label', label);
output.setValue('type', type);
output.setValue('order', getNextOrder(actionSysId, 'output'));
return output.insert();
}
Action Steps (ES5)
REST Step Configuration
// Create REST step for action (ES5 ONLY!)
var step = new GlideRecord('sn_ih_step_config');
step.initialize();
step.setValue('action', actionSysId);
step.setValue('name', 'Call External API');
step.setValue('order', 100);
step.setValue('step_type', 'rest');
// REST configuration
step.setValue('rest_config', JSON.stringify({
connection_alias: 'x_myapp_jira_connection',
credential_alias: 'x_myapp_jira_credential',
http_method: 'POST',
resource_path: '/issue',
request_body: {
fields: {
project: { key: '${inputs.project_key}' },
summary: '${inputs.summary}',
description: '${inputs.description}',
issuetype: { name: 'Task' }
}
},
headers: {
'Content-Type': 'application/json'
}
}));
step.insert();
Script Step
// Create script step (ES5 ONLY!)
var scriptStep = new GlideRecord('sn_ih_step_config');
scriptStep.initialize();
scriptStep.setValue('action', actionSysId);
scriptStep.setValue('name', 'Process Response');
scriptStep.setValue('order', 200);
scriptStep.setValue('step_type', 'script');
// Script (ES5 ONLY!)
scriptStep.setValue('script',
'(function execute(inputs, outputs) {\n' +
' // Get REST response from previous step\n' +
' var response = inputs.rest_response;\n' +
' \n' +
' if (response.status_code === 201) {\n' +
' var body = JSON.parse(response.body);\n' +
' outputs.ticket_id = body.id;\n' +
' outputs.ticket_url = body.self;\n' +
' outputs.success = true;\n' +
' } else {\n' +
' outputs.success = false;\n' +
' outputs.error_message = "Failed: " + response.status_code;\n' +
' }\n' +
'})(inputs, outputs);'
);
scriptStep.insert();
Subflows for Reuse (ES5)
Create Integration Subflow
// Subflows encapsulate reusable integration logic
// Created via Flow Designer UI, but can be invoked via script
// Invoke subflow from script (ES5 ONLY!)
var inputs = {
ticket_id: 'INC0010001',
action: 'update',
fields: {
status: 'resolved',
resolution: 'Fixed'
}
};
// Start subflow
sn_fd.FlowAPI.startSubflow('x_myapp_update_external_ticket', inputs);
Execute Action from Script
// Execute spoke action from script (ES5 ONLY!)
var actionInputs = {
summary: 'New ticket from ServiceNow',
description: 'Created via integration',
priority: 'Medium'
};
try {
var result = sn_fd.FlowAPI.executeAction(
'x_myapp_itsm.create_external_ticket',
actionInputs
);
if (result.outputs.success) {
gs.info('Created ticket: ' + result.outputs.ticket_id);
} else {
gs.error('Failed: ' + result.outputs.error_message);
}
} catch (e) {
gs.error('Action execution failed: ' + e.message);
}
Error Handling (ES5)
Action Error Handling
// Error handling in action script (ES5 ONLY!)
(function execute(inputs, outputs) {
try {
// Main logic
var response = callExternalAPI(inputs);
if (response.status_code >= 400) {
throw new Error('API error: ' + response.status_code + ' - ' + response.body);
}
outputs.result = JSON.parse(response.body);
outputs.success = true;
} catch (e) {
outputs.success = false;
outputs.error_code = 'INTEGRATION_ERROR';
outputs.error_message = e.message;
// Log for debugging
gs.error('IntegrationHub action failed: ' + e.message);
// Optionally throw to trigger Flow Designer error handling
// throw e;
}
})(inputs, outputs);
Retry Logic
// Retry wrapper for transient failures (ES5 ONLY!)
function executeWithRetry(fn, maxRetries, delayMs) {
var attempts = 0;
var lastError = null;
while (attempts < maxRetries) {
try {
return fn();
} catch (e) {
lastError = e;
attempts++;
if (attempts < maxRetries) {
gs.info('Retry ' + attempts + ' of ' + maxRetries + ' after error: ' + e.message);
gs.sleep(delayMs * attempts); // Exponential backoff
}
}
}
throw new Error('Failed after ' + maxRetries + ' attempts: ' + lastError.message);
}
MCP Tool Integration
Available Tools
| Tool | Purpose |
|---|---|
snow_query_table | Query spokes and actions |
snow_find_artifact | Find integration configs |
snow_test_rest_connection | Test connections |
snow_execute_script_with_output | Test action scripts |
Example Workflow
// 1. Find available spokes
await snow_query_table({
table: 'sn_ih_spoke',
query: 'active=true',
fields: 'name,label,vendor,version'
});
// 2. Get spoke actions
await snow_query_table({
table: 'sn_ih_action',
query: 'spoke.name=Jira Spoke',
fields: 'name,label,description,category'
});
// 3. Test connection
await snow_test_rest_connection({
connection_alias: 'x_myapp_jira_connection',
credential_alias: 'x_myapp_jira_credential'
});
Best Practices
- Connection Aliases - Abstract connection details
- Credential Security - Never hardcode credentials
- Error Handling - Graceful failure handling
- Retry Logic - Handle transient failures
- Logging - Comprehensive debug logging
- Testing - Test with mock data first
- Versioning - Track spoke versions
- ES5 Only - No modern JavaScript syntax
Score
Total Score
Based on repository quality metrics
SKILL.mdใใกใคใซใๅซใพใใฆใใ
ใฉใคใปใณในใ่จญๅฎใใใฆใใ
100ๆๅญไปฅไธใฎ่ชฌๆใใใ
GitHub Stars 100ไปฅไธ
1ใถๆไปฅๅ ใซๆดๆฐ
10ๅไปฅไธใใฉใผใฏใใใฆใใ
ใชใผใใณIssueใ50ๆชๆบ
ใใญใฐใฉใใณใฐ่จ่ชใ่จญๅฎใใใฆใใ
1ใคไปฅไธใฎใฟใฐใ่จญๅฎใใใฆใใ
Reviews
Reviews coming soon


