@inkeep/agents-manage-api 0.9.0 → 0.10.2
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/index.cjs +372 -341
- package/dist/index.js +373 -342
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loadEnvironmentFiles, getLogger, createDatabaseClient, commonGetErrorResponses, TenantProjectGraphParamsSchema, ArtifactComponentApiSelectSchema, getArtifactComponentsForAgent, getAgentsUsingArtifactComponent, ErrorResponseSchema, SingleResponseSchema, AgentArtifactComponentApiInsertSchema, AgentArtifactComponentApiSelectSchema, getAgentById, getArtifactComponentById, createApiError, isArtifactComponentAssociatedWithAgent, associateArtifactComponentWithAgent, RemovedResponseSchema, removeArtifactComponentFromAgent, ExistsResponseSchema, DataComponentApiSelectSchema, getDataComponentsForAgent, getAgentsUsingDataComponent, AgentDataComponentApiInsertSchema, AgentDataComponentApiSelectSchema, getDataComponent, isDataComponentAssociatedWithAgent, associateDataComponentWithAgent, removeDataComponentFromAgent, ListResponseSchema, PaginationQueryParamsSchema, TenantProjectParamsSchema, AgentGraphApiSelectSchema, listAgentGraphs, IdParamsSchema, getAgentGraphById, getGraphAgentInfos, FullGraphDefinitionSchema, getFullGraphDefinition, AgentGraphApiInsertSchema, createAgentGraph, AgentGraphApiUpdateSchema, updateAgentGraph, deleteAgentGraph, AgentRelationApiSelectSchema, AgentRelationQuerySchema, getAgentRelationsBySource, getAgentRelationsByTarget, getExternalAgentRelations, listAgentRelations, TenantProjectGraphIdParamsSchema, getAgentRelationById, AgentRelationApiInsertSchema, validateExternalAgent, validateInternalAgent, createAgentRelation, AgentRelationApiUpdateSchema, updateAgentRelation, deleteAgentRelation, AgentApiSelectSchema, listAgentsPaginated, AgentApiInsertSchema, createAgent, AgentApiUpdateSchema, updateAgent, deleteAgent, AgentToolRelationApiSelectSchema, getAgentToolRelationByAgent, getAgentToolRelationByTool, listAgentToolRelations, getAgentToolRelationById, getAgentsForTool, AgentToolRelationApiInsertSchema, createAgentToolRelation, AgentToolRelationApiUpdateSchema, updateAgentToolRelation, deleteAgentToolRelation, ApiKeyApiSelectSchema, listApiKeysPaginated, getApiKeyById, ApiKeyApiCreationResponseSchema, ApiKeyApiInsertSchema, generateApiKey, createApiKey, ApiKeyApiUpdateSchema, updateApiKey, deleteApiKey, listArtifactComponentsPaginated, ArtifactComponentApiInsertSchema, createArtifactComponent, ArtifactComponentApiUpdateSchema, updateArtifactComponent, deleteArtifactComponent, ContextConfigApiSelectSchema, listContextConfigsPaginated, getContextConfigById, ContextConfigApiInsertSchema, createContextConfig, commonUpdateErrorResponses, ContextConfigApiUpdateSchema, updateContextConfig, commonDeleteErrorResponses, deleteContextConfig, CredentialReferenceApiSelectSchema, listCredentialReferencesPaginated, getCredentialReferenceWithTools, CredentialReferenceApiInsertSchema, createCredentialReference, CredentialReferenceApiUpdateSchema, updateCredentialReference, getCredentialReferenceById, getCredentialStoreLookupKeyFromRetrievalParams, deleteCredentialReference, listDataComponentsPaginated, DataComponentApiInsertSchema, createDataComponent, DataComponentApiUpdateSchema, updateDataComponent, deleteDataComponent, ExternalAgentApiSelectSchema, listExternalAgentsPaginated, getExternalAgent, ExternalAgentApiInsertSchema, createExternalAgent, ExternalAgentApiUpdateSchema, updateExternalAgent, deleteExternalAgent, createFullGraphServerSide, getFullGraph, updateFullGraphServerSide, deleteFullGraph, TenantParamsSchema, ProjectApiSelectSchema, listProjectsPaginated, TenantIdParamsSchema, getProject, ProjectApiInsertSchema, createProject, ProjectApiUpdateSchema, updateProject, deleteProject, McpToolSchema, ToolStatusSchema, listTools, dbResultToMcpTool, getToolById, ToolApiInsertSchema, createTool, ToolApiUpdateSchema, updateTool, deleteTool,
|
|
1
|
+
import { loadEnvironmentFiles, getLogger, createDatabaseClient, commonGetErrorResponses, TenantProjectGraphParamsSchema, ArtifactComponentApiSelectSchema, getArtifactComponentsForAgent, getAgentsUsingArtifactComponent, ErrorResponseSchema, SingleResponseSchema, AgentArtifactComponentApiInsertSchema, AgentArtifactComponentApiSelectSchema, getAgentById, getArtifactComponentById, createApiError, isArtifactComponentAssociatedWithAgent, associateArtifactComponentWithAgent, RemovedResponseSchema, removeArtifactComponentFromAgent, ExistsResponseSchema, DataComponentApiSelectSchema, getDataComponentsForAgent, getAgentsUsingDataComponent, AgentDataComponentApiInsertSchema, AgentDataComponentApiSelectSchema, getDataComponent, isDataComponentAssociatedWithAgent, associateDataComponentWithAgent, removeDataComponentFromAgent, ListResponseSchema, PaginationQueryParamsSchema, TenantProjectParamsSchema, AgentGraphApiSelectSchema, listAgentGraphs, IdParamsSchema, getAgentGraphById, getGraphAgentInfos, FullGraphDefinitionSchema, getFullGraphDefinition, AgentGraphApiInsertSchema, createAgentGraph, AgentGraphApiUpdateSchema, updateAgentGraph, deleteAgentGraph, AgentRelationApiSelectSchema, AgentRelationQuerySchema, getAgentRelationsBySource, getAgentRelationsByTarget, getExternalAgentRelations, listAgentRelations, TenantProjectGraphIdParamsSchema, getAgentRelationById, AgentRelationApiInsertSchema, validateExternalAgent, validateInternalAgent, createAgentRelation, AgentRelationApiUpdateSchema, updateAgentRelation, deleteAgentRelation, AgentApiSelectSchema, listAgentsPaginated, AgentApiInsertSchema, createAgent, AgentApiUpdateSchema, updateAgent, deleteAgent, AgentToolRelationApiSelectSchema, getAgentToolRelationByAgent, getAgentToolRelationByTool, listAgentToolRelations, getAgentToolRelationById, getAgentsForTool, AgentToolRelationApiInsertSchema, createAgentToolRelation, AgentToolRelationApiUpdateSchema, updateAgentToolRelation, deleteAgentToolRelation, ApiKeyApiSelectSchema, listApiKeysPaginated, getApiKeyById, ApiKeyApiCreationResponseSchema, ApiKeyApiInsertSchema, generateApiKey, createApiKey, ApiKeyApiUpdateSchema, updateApiKey, deleteApiKey, listArtifactComponentsPaginated, ArtifactComponentApiInsertSchema, createArtifactComponent, ArtifactComponentApiUpdateSchema, updateArtifactComponent, deleteArtifactComponent, ContextConfigApiSelectSchema, listContextConfigsPaginated, getContextConfigById, ContextConfigApiInsertSchema, createContextConfig, commonUpdateErrorResponses, ContextConfigApiUpdateSchema, updateContextConfig, commonDeleteErrorResponses, deleteContextConfig, CredentialReferenceApiSelectSchema, listCredentialReferencesPaginated, getCredentialReferenceWithTools, CredentialReferenceApiInsertSchema, createCredentialReference, CredentialReferenceApiUpdateSchema, updateCredentialReference, getCredentialReferenceById, getCredentialStoreLookupKeyFromRetrievalParams, deleteCredentialReference, listDataComponentsPaginated, DataComponentApiInsertSchema, createDataComponent, DataComponentApiUpdateSchema, updateDataComponent, deleteDataComponent, ExternalAgentApiSelectSchema, listExternalAgentsPaginated, getExternalAgent, ExternalAgentApiInsertSchema, createExternalAgent, ExternalAgentApiUpdateSchema, updateExternalAgent, deleteExternalAgent, createFullGraphServerSide, getFullGraph, updateFullGraphServerSide, deleteFullGraph, TenantParamsSchema, ProjectApiSelectSchema, listProjectsPaginated, TenantIdParamsSchema, getProject, ProjectApiInsertSchema, createProject, ProjectApiUpdateSchema, updateProject, deleteProject, McpToolSchema, ToolStatusSchema, listTools, dbResultToMcpTool, getToolById, ToolApiInsertSchema, createTool, ToolApiUpdateSchema, updateTool, deleteTool, CredentialStoreType, FullProjectDefinitionSchema, createFullProjectServerSide, getFullProject, updateFullProjectServerSide, deleteFullProject, createDefaultCredentialStores, CredentialStoreRegistry, discoverOAuthEndpoints, handleApiError } from '@inkeep/agents-core';
|
|
2
2
|
import { OpenAPIHono, createRoute, z as z$1 } from '@hono/zod-openapi';
|
|
3
3
|
import { Hono } from 'hono';
|
|
4
4
|
import { cors } from 'hono/cors';
|
|
@@ -3476,245 +3476,7 @@ app14.openapi(
|
|
|
3476
3476
|
}
|
|
3477
3477
|
);
|
|
3478
3478
|
var projects_default = app14;
|
|
3479
|
-
var logger3 = getLogger("
|
|
3480
|
-
var pkceStore = /* @__PURE__ */ new Map();
|
|
3481
|
-
function storePKCEVerifier(state, codeVerifier, toolId, tenantId, projectId, clientId) {
|
|
3482
|
-
pkceStore.set(state, { codeVerifier, toolId, tenantId, projectId, clientId });
|
|
3483
|
-
setTimeout(
|
|
3484
|
-
() => {
|
|
3485
|
-
pkceStore.delete(state);
|
|
3486
|
-
},
|
|
3487
|
-
10 * 60 * 1e3
|
|
3488
|
-
);
|
|
3489
|
-
}
|
|
3490
|
-
function retrievePKCEVerifier(state) {
|
|
3491
|
-
const data = pkceStore.get(state);
|
|
3492
|
-
if (data) {
|
|
3493
|
-
pkceStore.delete(state);
|
|
3494
|
-
return data;
|
|
3495
|
-
}
|
|
3496
|
-
return null;
|
|
3497
|
-
}
|
|
3498
|
-
var OAuthService = class {
|
|
3499
|
-
constructor(config = {}) {
|
|
3500
|
-
__publicField(this, "defaultConfig");
|
|
3501
|
-
this.defaultConfig = {
|
|
3502
|
-
defaultClientId: config.defaultClientId || process.env.DEFAULT_OAUTH_CLIENT_ID || "mcp-client",
|
|
3503
|
-
clientName: config.clientName || process.env.OAUTH_CLIENT_NAME || "Inkeep Agent Framework",
|
|
3504
|
-
clientUri: config.clientUri || process.env.OAUTH_CLIENT_URI || "https://inkeep.com",
|
|
3505
|
-
logoUri: config.logoUri || process.env.OAUTH_CLIENT_LOGO_URI || "https://inkeep.com/images/logos/inkeep-logo-blue.svg",
|
|
3506
|
-
redirectBaseUrl: config.redirectBaseUrl || process.env.OAUTH_REDIRECT_BASE_URL || "http://localhost:3002"
|
|
3507
|
-
};
|
|
3508
|
-
}
|
|
3509
|
-
/**
|
|
3510
|
-
* Initiate OAuth flow for an MCP tool
|
|
3511
|
-
*/
|
|
3512
|
-
async initiateOAuthFlow(params) {
|
|
3513
|
-
const { tool, tenantId, projectId, toolId } = params;
|
|
3514
|
-
const oAuthConfig = await discoverOAuthEndpoints(tool.config.mcp.server.url, logger3);
|
|
3515
|
-
if (!oAuthConfig) {
|
|
3516
|
-
throw new Error("OAuth not supported by this server");
|
|
3517
|
-
}
|
|
3518
|
-
const { codeVerifier, codeChallenge } = await this.generatePKCEInternal();
|
|
3519
|
-
const redirectUri = `${this.defaultConfig.redirectBaseUrl}/oauth/callback`;
|
|
3520
|
-
let clientId = this.defaultConfig.defaultClientId;
|
|
3521
|
-
if (oAuthConfig.supportsDynamicRegistration && oAuthConfig.registrationUrl) {
|
|
3522
|
-
clientId = await this.performDynamicClientRegistration(
|
|
3523
|
-
oAuthConfig.registrationUrl,
|
|
3524
|
-
redirectUri
|
|
3525
|
-
);
|
|
3526
|
-
}
|
|
3527
|
-
const state = `tool_${toolId}`;
|
|
3528
|
-
const authUrl = this.buildAuthorizationUrl({
|
|
3529
|
-
oAuthConfig,
|
|
3530
|
-
clientId,
|
|
3531
|
-
redirectUri,
|
|
3532
|
-
state,
|
|
3533
|
-
codeChallenge,
|
|
3534
|
-
resource: tool.config.mcp.server.url
|
|
3535
|
-
});
|
|
3536
|
-
storePKCEVerifier(state, codeVerifier, toolId, tenantId, projectId, clientId);
|
|
3537
|
-
logger3.info({ toolId, oAuthConfig, tenantId, projectId }, "OAuth flow initiated successfully");
|
|
3538
|
-
return {
|
|
3539
|
-
redirectUrl: authUrl,
|
|
3540
|
-
state
|
|
3541
|
-
};
|
|
3542
|
-
}
|
|
3543
|
-
/**
|
|
3544
|
-
* Exchange authorization code for access tokens
|
|
3545
|
-
*/
|
|
3546
|
-
async exchangeCodeForTokens(params) {
|
|
3547
|
-
const { code, codeVerifier, clientId, tool } = params;
|
|
3548
|
-
const oAuthConfig = await discoverOAuthEndpoints(tool.config.mcp.server.url, logger3);
|
|
3549
|
-
if (!oAuthConfig?.tokenUrl) {
|
|
3550
|
-
throw new Error("Could not discover OAuth token endpoint");
|
|
3551
|
-
}
|
|
3552
|
-
const redirectUri = `${this.defaultConfig.redirectBaseUrl}/oauth/callback`;
|
|
3553
|
-
let tokens;
|
|
3554
|
-
try {
|
|
3555
|
-
tokens = await this.exchangeWithOpenIdClient({
|
|
3556
|
-
oAuthConfig,
|
|
3557
|
-
clientId,
|
|
3558
|
-
code,
|
|
3559
|
-
codeVerifier,
|
|
3560
|
-
redirectUri
|
|
3561
|
-
});
|
|
3562
|
-
logger3.info({ tokenType: tokens.token_type }, "Token exchange successful with openid-client");
|
|
3563
|
-
} catch (error) {
|
|
3564
|
-
logger3.warn(
|
|
3565
|
-
{ error: error instanceof Error ? error.message : error },
|
|
3566
|
-
"openid-client failed, falling back to manual token exchange"
|
|
3567
|
-
);
|
|
3568
|
-
tokens = await this.exchangeManually({
|
|
3569
|
-
oAuthConfig,
|
|
3570
|
-
clientId,
|
|
3571
|
-
code,
|
|
3572
|
-
codeVerifier,
|
|
3573
|
-
redirectUri
|
|
3574
|
-
});
|
|
3575
|
-
logger3.info({ tokenType: tokens.token_type }, "Manual token exchange successful");
|
|
3576
|
-
}
|
|
3577
|
-
return { tokens, oAuthConfig };
|
|
3578
|
-
}
|
|
3579
|
-
/**
|
|
3580
|
-
* Perform dynamic client registration
|
|
3581
|
-
*/
|
|
3582
|
-
async performDynamicClientRegistration(registrationUrl, redirectUri) {
|
|
3583
|
-
logger3.info({ registrationUrl }, "Attempting dynamic client registration");
|
|
3584
|
-
try {
|
|
3585
|
-
const registrationResponse = await fetch(registrationUrl, {
|
|
3586
|
-
method: "POST",
|
|
3587
|
-
headers: {
|
|
3588
|
-
"Content-Type": "application/json",
|
|
3589
|
-
Accept: "application/json"
|
|
3590
|
-
},
|
|
3591
|
-
body: JSON.stringify({
|
|
3592
|
-
client_name: this.defaultConfig.clientName,
|
|
3593
|
-
client_uri: this.defaultConfig.clientUri,
|
|
3594
|
-
logo_uri: this.defaultConfig.logoUri,
|
|
3595
|
-
redirect_uris: [redirectUri],
|
|
3596
|
-
grant_types: ["authorization_code"],
|
|
3597
|
-
response_types: ["code"],
|
|
3598
|
-
token_endpoint_auth_method: "none",
|
|
3599
|
-
// PKCE only, no client secret
|
|
3600
|
-
application_type: "native"
|
|
3601
|
-
// For PKCE flows
|
|
3602
|
-
})
|
|
3603
|
-
});
|
|
3604
|
-
if (registrationResponse.ok) {
|
|
3605
|
-
const registration = await registrationResponse.json();
|
|
3606
|
-
logger3.info({ clientId: registration.client_id }, "Dynamic client registration successful");
|
|
3607
|
-
return registration.client_id;
|
|
3608
|
-
} else {
|
|
3609
|
-
const errorText = await registrationResponse.text();
|
|
3610
|
-
logger3.warn(
|
|
3611
|
-
{
|
|
3612
|
-
status: registrationResponse.status,
|
|
3613
|
-
errorText
|
|
3614
|
-
},
|
|
3615
|
-
"Dynamic client registration failed, using default client_id"
|
|
3616
|
-
);
|
|
3617
|
-
}
|
|
3618
|
-
} catch (regError) {
|
|
3619
|
-
logger3.warn(
|
|
3620
|
-
{ error: regError },
|
|
3621
|
-
"Dynamic client registration error, using default client_id"
|
|
3622
|
-
);
|
|
3623
|
-
}
|
|
3624
|
-
return this.defaultConfig.defaultClientId;
|
|
3625
|
-
}
|
|
3626
|
-
/**
|
|
3627
|
-
* Build authorization URL
|
|
3628
|
-
*/
|
|
3629
|
-
buildAuthorizationUrl(params) {
|
|
3630
|
-
const { oAuthConfig, clientId, redirectUri, state, codeChallenge, resource } = params;
|
|
3631
|
-
const authUrl = new URL(oAuthConfig.authorizationUrl);
|
|
3632
|
-
authUrl.searchParams.set("response_type", "code");
|
|
3633
|
-
authUrl.searchParams.set("client_id", clientId);
|
|
3634
|
-
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
3635
|
-
authUrl.searchParams.set("state", state);
|
|
3636
|
-
authUrl.searchParams.set("code_challenge", codeChallenge);
|
|
3637
|
-
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
3638
|
-
authUrl.searchParams.set("resource", resource);
|
|
3639
|
-
return authUrl.toString();
|
|
3640
|
-
}
|
|
3641
|
-
/**
|
|
3642
|
-
* Exchange code using openid-client library
|
|
3643
|
-
*/
|
|
3644
|
-
async exchangeWithOpenIdClient(params) {
|
|
3645
|
-
const { oAuthConfig, clientId, code, codeVerifier, redirectUri } = params;
|
|
3646
|
-
const oauth = await import('openid-client');
|
|
3647
|
-
const tokenUrl = new URL(oAuthConfig.tokenUrl);
|
|
3648
|
-
const oauthServerUrl = `${tokenUrl.protocol}//${tokenUrl.host}`;
|
|
3649
|
-
logger3.info({ oauthServerUrl, clientId }, "Attempting openid-client discovery");
|
|
3650
|
-
const config = await oauth.discovery(
|
|
3651
|
-
new URL(oauthServerUrl),
|
|
3652
|
-
clientId,
|
|
3653
|
-
void 0
|
|
3654
|
-
// No client secret for PKCE
|
|
3655
|
-
);
|
|
3656
|
-
const callbackUrl = new URL(
|
|
3657
|
-
`${redirectUri}?${new URLSearchParams({ code, state: "unused" }).toString()}`
|
|
3658
|
-
);
|
|
3659
|
-
return await oauth.authorizationCodeGrant(config, callbackUrl, {
|
|
3660
|
-
pkceCodeVerifier: codeVerifier
|
|
3661
|
-
});
|
|
3662
|
-
}
|
|
3663
|
-
/**
|
|
3664
|
-
* Internal PKCE generation
|
|
3665
|
-
*/
|
|
3666
|
-
async generatePKCEInternal() {
|
|
3667
|
-
const codeVerifier = Buffer.from(
|
|
3668
|
-
Array.from(crypto.getRandomValues(new Uint8Array(32)))
|
|
3669
|
-
).toString("base64url");
|
|
3670
|
-
const encoder = new TextEncoder();
|
|
3671
|
-
const data = encoder.encode(codeVerifier);
|
|
3672
|
-
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
3673
|
-
const codeChallenge = Buffer.from(hash).toString("base64url");
|
|
3674
|
-
return { codeVerifier, codeChallenge };
|
|
3675
|
-
}
|
|
3676
|
-
/**
|
|
3677
|
-
* Manual token exchange fallback
|
|
3678
|
-
*/
|
|
3679
|
-
async exchangeManually(params) {
|
|
3680
|
-
const { oAuthConfig, clientId, code, codeVerifier, redirectUri } = params;
|
|
3681
|
-
logger3.info({ tokenUrl: oAuthConfig.tokenUrl }, "Attempting manual token exchange");
|
|
3682
|
-
const tokenResponse = await fetch(oAuthConfig.tokenUrl, {
|
|
3683
|
-
method: "POST",
|
|
3684
|
-
headers: {
|
|
3685
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
3686
|
-
Accept: "application/json"
|
|
3687
|
-
},
|
|
3688
|
-
body: new URLSearchParams({
|
|
3689
|
-
grant_type: "authorization_code",
|
|
3690
|
-
code,
|
|
3691
|
-
redirect_uri: redirectUri,
|
|
3692
|
-
client_id: clientId,
|
|
3693
|
-
code_verifier: codeVerifier
|
|
3694
|
-
// PKCE verification
|
|
3695
|
-
})
|
|
3696
|
-
});
|
|
3697
|
-
if (!tokenResponse.ok) {
|
|
3698
|
-
const errorText = await tokenResponse.text();
|
|
3699
|
-
logger3.error(
|
|
3700
|
-
{
|
|
3701
|
-
status: tokenResponse.status,
|
|
3702
|
-
statusText: tokenResponse.statusText,
|
|
3703
|
-
...process.env.NODE_ENV === "development" && { errorText },
|
|
3704
|
-
clientId,
|
|
3705
|
-
tokenUrl: oAuthConfig.tokenUrl
|
|
3706
|
-
},
|
|
3707
|
-
"Token exchange failed"
|
|
3708
|
-
);
|
|
3709
|
-
throw new Error("Authentication failed. Please try again or contact support.");
|
|
3710
|
-
}
|
|
3711
|
-
return await tokenResponse.json();
|
|
3712
|
-
}
|
|
3713
|
-
};
|
|
3714
|
-
var oauthService = new OAuthService();
|
|
3715
|
-
|
|
3716
|
-
// src/routes/tools.ts
|
|
3717
|
-
var logger4 = getLogger("tools");
|
|
3479
|
+
var logger3 = getLogger("tools");
|
|
3718
3480
|
var app15 = new OpenAPIHono();
|
|
3719
3481
|
app15.openapi(
|
|
3720
3482
|
createRoute({
|
|
@@ -3846,7 +3608,7 @@ app15.openapi(
|
|
|
3846
3608
|
const { tenantId, projectId } = c.req.valid("param");
|
|
3847
3609
|
const body = c.req.valid("json");
|
|
3848
3610
|
const credentialStores = c.get("credentialStores");
|
|
3849
|
-
|
|
3611
|
+
logger3.info({ body }, "body");
|
|
3850
3612
|
const id = body.id || nanoid();
|
|
3851
3613
|
const tool = await createTool(dbClient_default)({
|
|
3852
3614
|
tenantId,
|
|
@@ -3963,109 +3725,375 @@ app15.openapi(
|
|
|
3963
3725
|
return c.body(null, 204);
|
|
3964
3726
|
}
|
|
3965
3727
|
);
|
|
3966
|
-
app15
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3728
|
+
var tools_default = app15;
|
|
3729
|
+
|
|
3730
|
+
// src/routes/index.ts
|
|
3731
|
+
var app16 = new OpenAPIHono();
|
|
3732
|
+
app16.route("/projects", projects_default);
|
|
3733
|
+
app16.route("/projects/:projectId/graphs/:graphId/agents", agents_default);
|
|
3734
|
+
app16.route("/projects/:projectId/graphs/:graphId/agent-relations", agentRelations_default);
|
|
3735
|
+
app16.route("/projects/:projectId/agent-graphs", agentGraph_default);
|
|
3736
|
+
app16.route("/projects/:projectId/graphs/:graphId/agent-tool-relations", agentToolRelations_default);
|
|
3737
|
+
app16.route("/projects/:projectId/graphs/:graphId/agent-artifact-components", agentArtifactComponents_default);
|
|
3738
|
+
app16.route("/projects/:projectId/graphs/:graphId/agent-data-components", agentDataComponents_default);
|
|
3739
|
+
app16.route("/projects/:projectId/artifact-components", artifactComponents_default);
|
|
3740
|
+
app16.route("/projects/:projectId/context-configs", contextConfigs_default);
|
|
3741
|
+
app16.route("/projects/:projectId/credentials", credentials_default);
|
|
3742
|
+
app16.route("/projects/:projectId/data-components", dataComponents_default);
|
|
3743
|
+
app16.route("/projects/:projectId/graphs/:graphId/external-agents", externalAgents_default);
|
|
3744
|
+
app16.route("/projects/:projectId/tools", tools_default);
|
|
3745
|
+
app16.route("/projects/:projectId/api-keys", apiKeys_default);
|
|
3746
|
+
app16.route("/projects/:projectId/graph", graphFull_default);
|
|
3747
|
+
var routes_default = app16;
|
|
3748
|
+
var logger4 = getLogger("oauth-service");
|
|
3749
|
+
var pkceStore = /* @__PURE__ */ new Map();
|
|
3750
|
+
function storePKCEVerifier(state, codeVerifier, toolId, tenantId, projectId, clientId) {
|
|
3751
|
+
pkceStore.set(state, { codeVerifier, toolId, tenantId, projectId, clientId });
|
|
3752
|
+
setTimeout(
|
|
3753
|
+
() => {
|
|
3754
|
+
pkceStore.delete(state);
|
|
3976
3755
|
},
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3756
|
+
10 * 60 * 1e3
|
|
3757
|
+
);
|
|
3758
|
+
}
|
|
3759
|
+
function retrievePKCEVerifier(state) {
|
|
3760
|
+
const data = pkceStore.get(state);
|
|
3761
|
+
if (data) {
|
|
3762
|
+
pkceStore.delete(state);
|
|
3763
|
+
return data;
|
|
3764
|
+
}
|
|
3765
|
+
return null;
|
|
3766
|
+
}
|
|
3767
|
+
var OAuthService = class {
|
|
3768
|
+
constructor(config = {}) {
|
|
3769
|
+
__publicField(this, "defaultConfig");
|
|
3770
|
+
this.defaultConfig = {
|
|
3771
|
+
defaultClientId: config.defaultClientId || process.env.DEFAULT_OAUTH_CLIENT_ID || "mcp-client",
|
|
3772
|
+
clientName: config.clientName || process.env.OAUTH_CLIENT_NAME || "Inkeep Agent Framework",
|
|
3773
|
+
clientUri: config.clientUri || process.env.OAUTH_CLIENT_URI || "https://inkeep.com",
|
|
3774
|
+
logoUri: config.logoUri || process.env.OAUTH_CLIENT_LOGO_URI || "https://inkeep.com/images/logos/inkeep-logo-blue.svg",
|
|
3775
|
+
redirectBaseUrl: config.redirectBaseUrl || env.AGENTS_MANAGE_API_URL
|
|
3776
|
+
};
|
|
3777
|
+
}
|
|
3778
|
+
/**
|
|
3779
|
+
* Initiate OAuth flow for an MCP tool
|
|
3780
|
+
*/
|
|
3781
|
+
async initiateOAuthFlow(params) {
|
|
3782
|
+
const { tool, tenantId, projectId, toolId, baseUrl } = params;
|
|
3783
|
+
const oAuthConfig = await discoverOAuthEndpoints(tool.config.mcp.server.url, logger4);
|
|
3784
|
+
if (!oAuthConfig) {
|
|
3785
|
+
throw new Error("OAuth not supported by this server");
|
|
3786
|
+
}
|
|
3787
|
+
const { codeVerifier, codeChallenge } = await this.generatePKCEInternal();
|
|
3788
|
+
const redirectBaseUrl = baseUrl || this.defaultConfig.redirectBaseUrl;
|
|
3789
|
+
const redirectUri = `${redirectBaseUrl}/oauth/callback`;
|
|
3790
|
+
let clientId = this.defaultConfig.defaultClientId;
|
|
3791
|
+
if (oAuthConfig.supportsDynamicRegistration && oAuthConfig.registrationUrl) {
|
|
3792
|
+
clientId = await this.performDynamicClientRegistration(
|
|
3793
|
+
oAuthConfig.registrationUrl,
|
|
3794
|
+
redirectUri
|
|
3795
|
+
);
|
|
3796
|
+
}
|
|
3797
|
+
const state = `tool_${toolId}`;
|
|
3798
|
+
const authUrl = this.buildAuthorizationUrl({
|
|
3799
|
+
oAuthConfig,
|
|
3800
|
+
clientId,
|
|
3801
|
+
redirectUri,
|
|
3802
|
+
state,
|
|
3803
|
+
codeChallenge,
|
|
3804
|
+
resource: tool.config.mcp.server.url
|
|
3805
|
+
});
|
|
3806
|
+
storePKCEVerifier(state, codeVerifier, toolId, tenantId, projectId, clientId);
|
|
3807
|
+
logger4.info({ toolId, oAuthConfig, tenantId, projectId }, "OAuth flow initiated successfully");
|
|
3808
|
+
return {
|
|
3809
|
+
redirectUrl: authUrl,
|
|
3810
|
+
state
|
|
3811
|
+
};
|
|
3812
|
+
}
|
|
3813
|
+
/**
|
|
3814
|
+
* Exchange authorization code for access tokens
|
|
3815
|
+
*/
|
|
3816
|
+
async exchangeCodeForTokens(params) {
|
|
3817
|
+
const { code, codeVerifier, clientId, tool, baseUrl } = params;
|
|
3818
|
+
const oAuthConfig = await discoverOAuthEndpoints(tool.config.mcp.server.url, logger4);
|
|
3819
|
+
if (!oAuthConfig?.tokenUrl) {
|
|
3820
|
+
throw new Error("Could not discover OAuth token endpoint");
|
|
3821
|
+
}
|
|
3822
|
+
const redirectBaseUrl = baseUrl || this.defaultConfig.redirectBaseUrl;
|
|
3823
|
+
const redirectUri = `${redirectBaseUrl}/oauth/callback`;
|
|
3824
|
+
let tokens;
|
|
3825
|
+
try {
|
|
3826
|
+
tokens = await this.exchangeWithOpenIdClient({
|
|
3827
|
+
oAuthConfig,
|
|
3828
|
+
clientId,
|
|
3829
|
+
code,
|
|
3830
|
+
codeVerifier,
|
|
3831
|
+
redirectUri
|
|
3832
|
+
});
|
|
3833
|
+
logger4.info({ tokenType: tokens.token_type }, "Token exchange successful with openid-client");
|
|
3834
|
+
} catch (error) {
|
|
3835
|
+
logger4.warn(
|
|
3836
|
+
{ error: error instanceof Error ? error.message : error },
|
|
3837
|
+
"openid-client failed, falling back to manual token exchange"
|
|
3838
|
+
);
|
|
3839
|
+
tokens = await this.exchangeManually({
|
|
3840
|
+
oAuthConfig,
|
|
3841
|
+
clientId,
|
|
3842
|
+
code,
|
|
3843
|
+
codeVerifier,
|
|
3844
|
+
redirectUri
|
|
3845
|
+
});
|
|
3846
|
+
logger4.info({ tokenType: tokens.token_type }, "Manual token exchange successful");
|
|
3847
|
+
}
|
|
3848
|
+
return { tokens, oAuthConfig };
|
|
3849
|
+
}
|
|
3850
|
+
/**
|
|
3851
|
+
* Perform dynamic client registration
|
|
3852
|
+
*/
|
|
3853
|
+
async performDynamicClientRegistration(registrationUrl, redirectUri) {
|
|
3854
|
+
logger4.info({ registrationUrl }, "Attempting dynamic client registration");
|
|
3855
|
+
try {
|
|
3856
|
+
const registrationResponse = await fetch(registrationUrl, {
|
|
3857
|
+
method: "POST",
|
|
3858
|
+
headers: {
|
|
3859
|
+
"Content-Type": "application/json",
|
|
3860
|
+
Accept: "application/json"
|
|
3861
|
+
},
|
|
3862
|
+
body: JSON.stringify({
|
|
3863
|
+
client_name: this.defaultConfig.clientName,
|
|
3864
|
+
client_uri: this.defaultConfig.clientUri,
|
|
3865
|
+
logo_uri: this.defaultConfig.logoUri,
|
|
3866
|
+
redirect_uris: [redirectUri],
|
|
3867
|
+
grant_types: ["authorization_code"],
|
|
3868
|
+
response_types: ["code"],
|
|
3869
|
+
token_endpoint_auth_method: "none",
|
|
3870
|
+
// PKCE only, no client secret
|
|
3871
|
+
application_type: "native"
|
|
3872
|
+
// For PKCE flows
|
|
3873
|
+
})
|
|
3874
|
+
});
|
|
3875
|
+
if (registrationResponse.ok) {
|
|
3876
|
+
const registration = await registrationResponse.json();
|
|
3877
|
+
logger4.info({ clientId: registration.client_id }, "Dynamic client registration successful");
|
|
3878
|
+
return registration.client_id;
|
|
3879
|
+
} else {
|
|
3880
|
+
const errorText = await registrationResponse.text();
|
|
3881
|
+
logger4.warn(
|
|
3882
|
+
{
|
|
3883
|
+
status: registrationResponse.status,
|
|
3884
|
+
errorText
|
|
3885
|
+
},
|
|
3886
|
+
"Dynamic client registration failed, using default client_id"
|
|
3887
|
+
);
|
|
3888
|
+
}
|
|
3889
|
+
} catch (regError) {
|
|
3890
|
+
logger4.warn(
|
|
3891
|
+
{ error: regError },
|
|
3892
|
+
"Dynamic client registration error, using default client_id"
|
|
3893
|
+
);
|
|
3894
|
+
}
|
|
3895
|
+
return this.defaultConfig.defaultClientId;
|
|
3896
|
+
}
|
|
3897
|
+
/**
|
|
3898
|
+
* Build authorization URL
|
|
3899
|
+
*/
|
|
3900
|
+
buildAuthorizationUrl(params) {
|
|
3901
|
+
const { oAuthConfig, clientId, redirectUri, state, codeChallenge, resource } = params;
|
|
3902
|
+
const authUrl = new URL(oAuthConfig.authorizationUrl);
|
|
3903
|
+
authUrl.searchParams.set("response_type", "code");
|
|
3904
|
+
authUrl.searchParams.set("client_id", clientId);
|
|
3905
|
+
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
3906
|
+
authUrl.searchParams.set("state", state);
|
|
3907
|
+
authUrl.searchParams.set("code_challenge", codeChallenge);
|
|
3908
|
+
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
3909
|
+
authUrl.searchParams.set("resource", resource);
|
|
3910
|
+
return authUrl.toString();
|
|
3911
|
+
}
|
|
3912
|
+
/**
|
|
3913
|
+
* Exchange code using openid-client library
|
|
3914
|
+
*/
|
|
3915
|
+
async exchangeWithOpenIdClient(params) {
|
|
3916
|
+
const { oAuthConfig, clientId, code, codeVerifier, redirectUri } = params;
|
|
3917
|
+
const oauth = await import('openid-client');
|
|
3918
|
+
const tokenUrl = new URL(oAuthConfig.tokenUrl);
|
|
3919
|
+
const oauthServerUrl = `${tokenUrl.protocol}//${tokenUrl.host}`;
|
|
3920
|
+
logger4.info({ oauthServerUrl, clientId }, "Attempting openid-client discovery");
|
|
3921
|
+
const config = await oauth.discovery(
|
|
3922
|
+
new URL(oauthServerUrl),
|
|
3923
|
+
clientId,
|
|
3924
|
+
void 0
|
|
3925
|
+
// No client secret for PKCE
|
|
3926
|
+
);
|
|
3927
|
+
const callbackUrl = new URL(
|
|
3928
|
+
`${redirectUri}?${new URLSearchParams({ code, state: "unused" }).toString()}`
|
|
3929
|
+
);
|
|
3930
|
+
return await oauth.authorizationCodeGrant(config, callbackUrl, {
|
|
3931
|
+
pkceCodeVerifier: codeVerifier
|
|
3932
|
+
});
|
|
3933
|
+
}
|
|
3934
|
+
/**
|
|
3935
|
+
* Internal PKCE generation
|
|
3936
|
+
*/
|
|
3937
|
+
async generatePKCEInternal() {
|
|
3938
|
+
const codeVerifier = Buffer.from(
|
|
3939
|
+
Array.from(crypto.getRandomValues(new Uint8Array(32)))
|
|
3940
|
+
).toString("base64url");
|
|
3941
|
+
const encoder = new TextEncoder();
|
|
3942
|
+
const data = encoder.encode(codeVerifier);
|
|
3943
|
+
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
3944
|
+
const codeChallenge = Buffer.from(hash).toString("base64url");
|
|
3945
|
+
return { codeVerifier, codeChallenge };
|
|
3946
|
+
}
|
|
3947
|
+
/**
|
|
3948
|
+
* Manual token exchange fallback
|
|
3949
|
+
*/
|
|
3950
|
+
async exchangeManually(params) {
|
|
3951
|
+
const { oAuthConfig, clientId, code, codeVerifier, redirectUri } = params;
|
|
3952
|
+
logger4.info({ tokenUrl: oAuthConfig.tokenUrl }, "Attempting manual token exchange");
|
|
3953
|
+
const tokenResponse = await fetch(oAuthConfig.tokenUrl, {
|
|
3954
|
+
method: "POST",
|
|
3955
|
+
headers: {
|
|
3956
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
3957
|
+
Accept: "application/json"
|
|
3958
|
+
},
|
|
3959
|
+
body: new URLSearchParams({
|
|
3960
|
+
grant_type: "authorization_code",
|
|
3961
|
+
code,
|
|
3962
|
+
redirect_uri: redirectUri,
|
|
3963
|
+
client_id: clientId,
|
|
3964
|
+
code_verifier: codeVerifier
|
|
3965
|
+
// PKCE verification
|
|
3966
|
+
})
|
|
3967
|
+
});
|
|
3968
|
+
if (!tokenResponse.ok) {
|
|
3969
|
+
const errorText = await tokenResponse.text();
|
|
3970
|
+
logger4.error(
|
|
3971
|
+
{
|
|
3972
|
+
status: tokenResponse.status,
|
|
3973
|
+
statusText: tokenResponse.statusText,
|
|
3974
|
+
...process.env.NODE_ENV === "development" && { errorText },
|
|
3975
|
+
clientId,
|
|
3976
|
+
tokenUrl: oAuthConfig.tokenUrl
|
|
3977
|
+
},
|
|
3978
|
+
"Token exchange failed"
|
|
3979
|
+
);
|
|
3980
|
+
throw new Error("Authentication failed. Please try again or contact support.");
|
|
3981
|
+
}
|
|
3982
|
+
return await tokenResponse.json();
|
|
3983
|
+
}
|
|
3984
|
+
};
|
|
3985
|
+
var oauthService = new OAuthService();
|
|
3986
|
+
|
|
3987
|
+
// src/routes/oauth.ts
|
|
3988
|
+
async function findOrCreateCredential(tenantId, projectId, credentialData) {
|
|
3989
|
+
try {
|
|
3990
|
+
const existingCredential = await getCredentialReferenceWithTools(dbClient_default)({
|
|
3991
|
+
scopes: { tenantId, projectId },
|
|
3992
|
+
id: credentialData.id
|
|
3993
|
+
});
|
|
3994
|
+
if (existingCredential) {
|
|
3995
|
+
const validatedCredential = CredentialReferenceApiSelectSchema.parse(existingCredential);
|
|
3996
|
+
return validatedCredential;
|
|
3997
|
+
}
|
|
3998
|
+
} catch {
|
|
3999
|
+
}
|
|
4000
|
+
try {
|
|
4001
|
+
const credential = await createCredentialReference(dbClient_default)({
|
|
4002
|
+
...credentialData,
|
|
4003
|
+
tenantId,
|
|
4004
|
+
projectId
|
|
4005
|
+
});
|
|
4006
|
+
const validatedCredential = CredentialReferenceApiSelectSchema.parse(credential);
|
|
4007
|
+
return validatedCredential;
|
|
4008
|
+
} catch (error) {
|
|
4009
|
+
console.error("Failed to save credential to database:", error);
|
|
4010
|
+
throw new Error(`Failed to save credential '${credentialData.id}' to database`);
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
var app17 = new OpenAPIHono();
|
|
4014
|
+
var logger5 = getLogger("oauth-callback");
|
|
4015
|
+
function getBaseUrlFromRequest(c) {
|
|
4016
|
+
const url = new URL(c.req.url);
|
|
4017
|
+
return `${url.protocol}//${url.host}`;
|
|
4018
|
+
}
|
|
4019
|
+
var OAuthLoginQuerySchema = z$1.object({
|
|
4020
|
+
tenantId: z$1.string().min(1, "Tenant ID is required"),
|
|
4021
|
+
projectId: z$1.string().min(1, "Project ID is required"),
|
|
4022
|
+
toolId: z$1.string().min(1, "Tool ID is required")
|
|
4023
|
+
});
|
|
4024
|
+
var OAuthCallbackQuerySchema = z$1.object({
|
|
4025
|
+
code: z$1.string().min(1, "Authorization code is required"),
|
|
4026
|
+
state: z$1.string().min(1, "State parameter is required"),
|
|
4027
|
+
error: z$1.string().optional(),
|
|
4028
|
+
error_description: z$1.string().optional()
|
|
4029
|
+
});
|
|
4030
|
+
app17.openapi(
|
|
4031
|
+
createRoute({
|
|
4032
|
+
method: "get",
|
|
4033
|
+
path: "/login",
|
|
4034
|
+
summary: "Initiate OAuth login for MCP tool",
|
|
4035
|
+
description: "Detects OAuth requirements and redirects to authorization server (public endpoint)",
|
|
4036
|
+
operationId: "initiate-oauth-login-public",
|
|
4037
|
+
tags: ["OAuth"],
|
|
4038
|
+
request: {
|
|
4039
|
+
query: OAuthLoginQuerySchema
|
|
4040
|
+
},
|
|
4041
|
+
responses: {
|
|
4042
|
+
302: {
|
|
4043
|
+
description: "Redirect to OAuth authorization server"
|
|
4044
|
+
},
|
|
4045
|
+
400: {
|
|
3982
4046
|
description: "OAuth not supported or configuration error",
|
|
3983
4047
|
content: {
|
|
3984
|
-
"
|
|
3985
|
-
schema:
|
|
4048
|
+
"text/html": {
|
|
4049
|
+
schema: z$1.string()
|
|
3986
4050
|
}
|
|
3987
4051
|
}
|
|
3988
4052
|
},
|
|
3989
4053
|
404: {
|
|
3990
4054
|
description: "Tool not found",
|
|
3991
4055
|
content: {
|
|
3992
|
-
"
|
|
3993
|
-
schema:
|
|
4056
|
+
"text/html": {
|
|
4057
|
+
schema: z$1.string()
|
|
3994
4058
|
}
|
|
3995
4059
|
}
|
|
3996
4060
|
},
|
|
3997
4061
|
500: {
|
|
3998
4062
|
description: "Internal server error",
|
|
3999
4063
|
content: {
|
|
4000
|
-
"
|
|
4001
|
-
schema:
|
|
4064
|
+
"text/html": {
|
|
4065
|
+
schema: z$1.string()
|
|
4002
4066
|
}
|
|
4003
4067
|
}
|
|
4004
4068
|
}
|
|
4005
4069
|
}
|
|
4006
4070
|
}),
|
|
4007
4071
|
async (c) => {
|
|
4008
|
-
const { tenantId, projectId,
|
|
4072
|
+
const { tenantId, projectId, toolId } = c.req.valid("query");
|
|
4009
4073
|
try {
|
|
4010
|
-
const tool = await getToolById(dbClient_default)({ scopes: { tenantId, projectId }, toolId
|
|
4074
|
+
const tool = await getToolById(dbClient_default)({ scopes: { tenantId, projectId }, toolId });
|
|
4011
4075
|
if (!tool) {
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
message: "Tool not found"
|
|
4015
|
-
});
|
|
4076
|
+
logger5.error({ toolId, tenantId, projectId }, "Tool not found for OAuth login");
|
|
4077
|
+
return c.text("Tool not found", 404);
|
|
4016
4078
|
}
|
|
4017
4079
|
const credentialStores = c.get("credentialStores");
|
|
4018
4080
|
const mcpTool = await dbResultToMcpTool(tool, dbClient_default, credentialStores);
|
|
4081
|
+
const baseUrl = getBaseUrlFromRequest(c);
|
|
4019
4082
|
const { redirectUrl } = await oauthService.initiateOAuthFlow({
|
|
4020
4083
|
tool: mcpTool,
|
|
4021
4084
|
tenantId,
|
|
4022
4085
|
projectId,
|
|
4023
|
-
toolId
|
|
4086
|
+
toolId,
|
|
4087
|
+
baseUrl
|
|
4024
4088
|
});
|
|
4025
4089
|
return c.redirect(redirectUrl, 302);
|
|
4026
4090
|
} catch (error) {
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
return c.json({ error: apiError.message }, apiError.code === "not_found" ? 404 : 400);
|
|
4031
|
-
}
|
|
4032
|
-
return c.json(
|
|
4033
|
-
{
|
|
4034
|
-
error: "Failed to initiate OAuth login"
|
|
4035
|
-
},
|
|
4036
|
-
500
|
|
4037
|
-
);
|
|
4091
|
+
logger5.error({ toolId, tenantId, projectId, error }, "OAuth login failed");
|
|
4092
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to initiate OAuth login";
|
|
4093
|
+
return c.text(`OAuth Error: ${errorMessage}`, 500);
|
|
4038
4094
|
}
|
|
4039
4095
|
}
|
|
4040
4096
|
);
|
|
4041
|
-
var tools_default = app15;
|
|
4042
|
-
|
|
4043
|
-
// src/routes/index.ts
|
|
4044
|
-
var app16 = new OpenAPIHono();
|
|
4045
|
-
app16.route("/projects", projects_default);
|
|
4046
|
-
app16.route("/projects/:projectId/graphs/:graphId/agents", agents_default);
|
|
4047
|
-
app16.route("/projects/:projectId/graphs/:graphId/agent-relations", agentRelations_default);
|
|
4048
|
-
app16.route("/projects/:projectId/agent-graphs", agentGraph_default);
|
|
4049
|
-
app16.route("/projects/:projectId/graphs/:graphId/agent-tool-relations", agentToolRelations_default);
|
|
4050
|
-
app16.route("/projects/:projectId/graphs/:graphId/agent-artifact-components", agentArtifactComponents_default);
|
|
4051
|
-
app16.route("/projects/:projectId/graphs/:graphId/agent-data-components", agentDataComponents_default);
|
|
4052
|
-
app16.route("/projects/:projectId/artifact-components", artifactComponents_default);
|
|
4053
|
-
app16.route("/projects/:projectId/context-configs", contextConfigs_default);
|
|
4054
|
-
app16.route("/projects/:projectId/credentials", credentials_default);
|
|
4055
|
-
app16.route("/projects/:projectId/data-components", dataComponents_default);
|
|
4056
|
-
app16.route("/projects/:projectId/graphs/:graphId/external-agents", externalAgents_default);
|
|
4057
|
-
app16.route("/projects/:projectId/tools", tools_default);
|
|
4058
|
-
app16.route("/projects/:projectId/api-keys", apiKeys_default);
|
|
4059
|
-
app16.route("/projects/:projectId/graph", graphFull_default);
|
|
4060
|
-
var routes_default = app16;
|
|
4061
|
-
var app17 = new OpenAPIHono();
|
|
4062
|
-
var logger5 = getLogger("oauth-callback");
|
|
4063
|
-
var OAuthCallbackQuerySchema = z$1.object({
|
|
4064
|
-
code: z$1.string().min(1, "Authorization code is required"),
|
|
4065
|
-
state: z$1.string().min(1, "State parameter is required"),
|
|
4066
|
-
error: z$1.string().optional(),
|
|
4067
|
-
error_description: z$1.string().optional()
|
|
4068
|
-
});
|
|
4069
4097
|
app17.openapi(
|
|
4070
4098
|
createRoute({
|
|
4071
4099
|
method: "get",
|
|
@@ -4128,59 +4156,62 @@ app17.openapi(
|
|
|
4128
4156
|
logger5.info({ toolId }, "Exchanging authorization code for access token");
|
|
4129
4157
|
const credentialStores = c.get("credentialStores");
|
|
4130
4158
|
const mcpTool = await dbResultToMcpTool(tool, dbClient_default, credentialStores);
|
|
4159
|
+
const baseUrl = getBaseUrlFromRequest(c);
|
|
4131
4160
|
const { tokens } = await oauthService.exchangeCodeForTokens({
|
|
4132
4161
|
code,
|
|
4133
4162
|
codeVerifier,
|
|
4134
4163
|
clientId,
|
|
4135
|
-
tool: mcpTool
|
|
4164
|
+
tool: mcpTool,
|
|
4165
|
+
baseUrl
|
|
4136
4166
|
});
|
|
4137
4167
|
logger5.info(
|
|
4138
4168
|
{ toolId, tokenType: tokens.token_type, hasRefresh: !!tokens.refresh_token },
|
|
4139
4169
|
"Token exchange successful"
|
|
4140
4170
|
);
|
|
4171
|
+
const credentialTokenKey = `oauth_token_${toolId}`;
|
|
4172
|
+
let newCredentialData;
|
|
4141
4173
|
const keychainStore = credentialStores.get("keychain-default");
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4174
|
+
if (keychainStore) {
|
|
4175
|
+
try {
|
|
4176
|
+
await keychainStore.set(credentialTokenKey, JSON.stringify(tokens));
|
|
4177
|
+
newCredentialData = {
|
|
4178
|
+
id: mcpTool.name,
|
|
4179
|
+
type: CredentialStoreType.keychain,
|
|
4180
|
+
credentialStoreId: "keychain-default",
|
|
4181
|
+
retrievalParams: {
|
|
4182
|
+
key: credentialTokenKey
|
|
4183
|
+
}
|
|
4184
|
+
};
|
|
4185
|
+
} catch {
|
|
4154
4186
|
}
|
|
4155
|
-
};
|
|
4156
|
-
let credential;
|
|
4157
|
-
if (existingCredential) {
|
|
4158
|
-
logger5.info({ credentialId: existingCredential.id }, "Updating existing credential");
|
|
4159
|
-
credential = await updateCredentialReference(dbClient_default)({
|
|
4160
|
-
scopes: { tenantId, projectId },
|
|
4161
|
-
id: existingCredential.id,
|
|
4162
|
-
data: credentialData
|
|
4163
|
-
});
|
|
4164
|
-
} else {
|
|
4165
|
-
logger5.info({ credentialId }, "Creating new credential");
|
|
4166
|
-
credential = await createCredentialReference(dbClient_default)({
|
|
4167
|
-
tenantId,
|
|
4168
|
-
projectId,
|
|
4169
|
-
id: credentialId,
|
|
4170
|
-
...credentialData
|
|
4171
|
-
});
|
|
4172
4187
|
}
|
|
4173
|
-
if (!
|
|
4174
|
-
|
|
4188
|
+
if (!newCredentialData && process.env.NANGO_SECRET_KEY) {
|
|
4189
|
+
const nangoStore = credentialStores.get("nango-default");
|
|
4190
|
+
await nangoStore?.set(credentialTokenKey, JSON.stringify(tokens));
|
|
4191
|
+
newCredentialData = {
|
|
4192
|
+
id: mcpTool.name,
|
|
4193
|
+
type: CredentialStoreType.nango,
|
|
4194
|
+
credentialStoreId: "nango-default",
|
|
4195
|
+
retrievalParams: {
|
|
4196
|
+
connectionId: credentialTokenKey,
|
|
4197
|
+
providerConfigKey: credentialTokenKey,
|
|
4198
|
+
provider: "private-api-bearer",
|
|
4199
|
+
authMode: "API_KEY"
|
|
4200
|
+
}
|
|
4201
|
+
};
|
|
4202
|
+
}
|
|
4203
|
+
if (!newCredentialData) {
|
|
4204
|
+
throw new Error("No credential store found");
|
|
4175
4205
|
}
|
|
4206
|
+
const newCredential = await findOrCreateCredential(tenantId, projectId, newCredentialData);
|
|
4176
4207
|
await updateTool(dbClient_default)({
|
|
4177
4208
|
scopes: { tenantId, projectId },
|
|
4178
4209
|
toolId,
|
|
4179
4210
|
data: {
|
|
4180
|
-
credentialReferenceId:
|
|
4211
|
+
credentialReferenceId: newCredential.id
|
|
4181
4212
|
}
|
|
4182
4213
|
});
|
|
4183
|
-
logger5.info({ toolId, credentialId:
|
|
4214
|
+
logger5.info({ toolId, credentialId: newCredential.id }, "OAuth flow completed successfully");
|
|
4184
4215
|
const successPage = `
|
|
4185
4216
|
<!DOCTYPE html>
|
|
4186
4217
|
<html>
|