@inkeep/agents-manage-api 0.0.0-dev-20250930131913 → 0.0.0-dev-20250930181023

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