feat(API-11): Route API calls through AgilitonAPI gateway

Add gateway-first pattern: when AGILITON_API_KEY is set, route all
external API calls through the gateway with X-API-Key auth. Falls back
to direct API access when gateway is unavailable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Gick
2026-02-11 19:05:19 +02:00
parent 6b53fb9168
commit 77097ac65f
2 changed files with 41 additions and 25 deletions

6
.env
View File

@@ -28,7 +28,11 @@ POSTGRES_PORT=6432
LLM_API_URL=https://api.agiliton.cloud/llm
LLM_API_KEY=sk-c02d41a118ce8330c428100afaa816c8
# Jira Cloud (CF-762 migration)
# AgilitonAPI Gateway (API-11: centralized API access)
AGILITON_API_KEY=gw_92399e154f02730ebadec65ddbde9426c9378ec77093d1c9
AGILITON_API_URL=https://api.agiliton.cloud
# Jira Cloud (fallback if gateway unavailable)
JIRA_URL=https://agiliton.atlassian.net
JIRA_USERNAME=christian.gick@agiliton.eu
JIRA_API_TOKEN=ATATT3xFfGF0tpaJTS4nJklW587McubEw-1SYbLWqfovkxI5320NdbFc-3fgHlw0HGTLOikgV082m9N-SIsYVZveGXa553_1LAyOevV6Qples93xF4hIExWGAvwvXPy_4pW2tH5FNusN5ieMca5_-YUP0i69SIN0RLIMQjfqDmQyhZXbkIvrm-I=A8A2A1FC

View File

@@ -1,8 +1,9 @@
/**
* Jira Cloud REST API client for session-mcp.
* Creates/closes CF issues for sessions and posts session output as comments.
* Jira Cloud REST API client — routes through AgilitonAPI gateway.
* Falls back to direct Jira access if AGILITON_API_KEY is not set.
*
* Uses JIRA_URL, JIRA_USERNAME, JIRA_API_TOKEN env vars.
* Gateway: AGILITON_API_KEY + AGILITON_API_URL
* Direct: JIRA_URL, JIRA_USERNAME, JIRA_API_TOKEN
*/
interface JiraIssue {
@@ -16,35 +17,48 @@ interface JiraTransition {
name: string;
}
const getConfig = () => ({
url: process.env.JIRA_URL || 'https://agiliton.atlassian.net',
username: process.env.JIRA_USERNAME || '',
token: process.env.JIRA_API_TOKEN || '',
});
// Gateway config
const GATEWAY_URL = (process.env.AGILITON_API_URL || 'https://api.agiliton.cloud').replace(/\/$/, '');
const GATEWAY_KEY = process.env.AGILITON_API_KEY || '';
function getAuthHeader(): string {
const { username, token } = getConfig();
return `Basic ${Buffer.from(`${username}:${token}`).toString('base64')}`;
// Direct config (fallback)
const JIRA_URL = process.env.JIRA_URL || 'https://agiliton.atlassian.net';
const JIRA_USERNAME = process.env.JIRA_USERNAME || '';
const JIRA_API_TOKEN = process.env.JIRA_API_TOKEN || '';
function useGateway(): boolean {
return !!GATEWAY_KEY;
}
function isConfigured(): boolean {
const { username, token } = getConfig();
return !!(username && token);
if (useGateway()) return true;
return !!(JIRA_USERNAME && JIRA_API_TOKEN);
}
async function jiraFetch(path: string, options: RequestInit = {}): Promise<Response> {
const { url } = getConfig();
const fullUrl = `${url}/rest/api/3${path}`;
let url: string;
let headers: Record<string, string>;
return fetch(fullUrl, {
...options,
headers: {
'Authorization': getAuthHeader(),
if (useGateway()) {
url = `${GATEWAY_URL}/jira-cloud${path}`;
headers = {
'X-API-Key': GATEWAY_KEY,
'Content-Type': 'application/json',
'Accept': 'application/json',
...options.headers,
},
});
...options.headers as Record<string, string>,
};
} else {
url = `${JIRA_URL}/rest/api/3${path}`;
const auth = Buffer.from(`${JIRA_USERNAME}:${JIRA_API_TOKEN}`).toString('base64');
headers = {
'Authorization': `Basic ${auth}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
...options.headers as Record<string, string>,
};
}
return fetch(url, { ...options, headers });
}
/**
@@ -165,7 +179,6 @@ export async function transitionToDone(issueKey: string): Promise<boolean> {
if (!isConfigured()) return false;
try {
// Get available transitions
const transResponse = await jiraFetch(`/issue/${issueKey}/transitions`);
if (!transResponse.ok) {
console.error(`session-mcp: Jira get transitions failed (${transResponse.status})`);
@@ -182,7 +195,6 @@ export async function transitionToDone(issueKey: string): Promise<boolean> {
return false;
}
// Execute transition
const response = await jiraFetch(`/issue/${issueKey}/transitions`, {
method: 'POST',
body: JSON.stringify({