diff --git a/typescript/package-lock.json b/typescript/package-lock.json index 238da22..c48eea4 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mastercard/developers-agent-toolkit", - "version": "0.1.5", + "version": "0.1.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mastercard/developers-agent-toolkit", - "version": "0.1.5", + "version": "0.1.6", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.27.1", diff --git a/typescript/package.json b/typescript/package.json index 5c5c0b7..a4be676 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -1,5 +1,5 @@ { - "version": "0.1.5", + "version": "0.1.6", "name": "@mastercard/developers-agent-toolkit", "homepage": "https://github.com/mastercard/developers-agent-toolkit", "description": "Agent Toolkit for Mastercard Developers Platform", diff --git a/typescript/src/shared/tools/documentation/__tests__/githubReadme.test.ts b/typescript/src/shared/tools/documentation/__tests__/githubReadme.test.ts new file mode 100644 index 0000000..a2b0f53 --- /dev/null +++ b/typescript/src/shared/tools/documentation/__tests__/githubReadme.test.ts @@ -0,0 +1,65 @@ +import { fetchGithubReadme } from '@/shared/tools/documentation/githubReadme'; +import { createMockApi } from '@/tests/mockDevelopersApi'; +import fetch from 'node-fetch'; + +jest.mock('node-fetch'); + +const mockFetch = fetch as jest.MockedFunction; +const mockApi = createMockApi(); + +describe('fetchGithubReadme', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('uses fetchGithubGuide when provided and returns content on success', async () => { + const fetchGithubGuide = jest.fn().mockResolvedValue('github content'); + + const result = await fetchGithubReadme('oauth1-signer-java', { + client: { ...mockApi, fetchGithubGuide }, + }); + + expect(fetchGithubGuide).toHaveBeenCalledWith( + 'https://raw.githubusercontent.com/Mastercard/oauth1-signer-java/refs/heads/main/README.md' + ); + expect(result).toBe('github content'); + }); + + it('returns undefined when fetchGithubGuide is provided but fails', async () => { + const fetchGithubGuide = jest + .fn() + .mockRejectedValue(new Error('network error')); + + const result = await fetchGithubReadme('oauth1-signer-java', { + client: { ...mockApi, fetchGithubGuide }, + }); + + expect(result).toBeUndefined(); + }); + + it('uses plain fetch when fetchGithubGuide is not provided and returns content on success', async () => { + mockFetch.mockResolvedValue({ + ok: true, + text: jest.fn().mockResolvedValue('github content'), + } as any); + + const result = await fetchGithubReadme('oauth1-signer-java', { + client: mockApi, + }); + + expect(mockFetch).toHaveBeenCalledWith( + 'https://raw.githubusercontent.com/Mastercard/oauth1-signer-java/refs/heads/main/README.md' + ); + expect(result).toBe('github content'); + }); + + it('returns undefined when plain fetch response is not ok', async () => { + mockFetch.mockResolvedValue({ ok: false } as any); + + const result = await fetchGithubReadme('oauth1-signer-java', { + client: mockApi, + }); + + expect(result).toBeUndefined(); + }); +}); diff --git a/typescript/src/shared/tools/documentation/getOAuth10aGuide.ts b/typescript/src/shared/tools/documentation/getOAuth10aGuide.ts index c1482c9..e436f02 100644 --- a/typescript/src/shared/tools/documentation/getOAuth10aGuide.ts +++ b/typescript/src/shared/tools/documentation/getOAuth10aGuide.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import fetch from 'node-fetch'; import { Tool, ToolContext } from '@/shared/types'; +import { fetchGithubReadme } from './githubReadme'; const getDescription = (): string => { return `Retrieves the comprehensive OAuth 1.0a integration guide including step-by-step instructions, @@ -58,11 +58,9 @@ export const execute = async ( } if (repositoryName !== undefined) { - const githubUrl = `https://raw.githubusercontent.com/Mastercard/${repositoryName}/refs/heads/main/README.md`; - const response = await fetch(githubUrl); - - if (response.ok) { - return await response.text(); + const content = await fetchGithubReadme(repositoryName, context); + if (content !== undefined) { + return content; } } } diff --git a/typescript/src/shared/tools/documentation/getOAuth20Guide.ts b/typescript/src/shared/tools/documentation/getOAuth20Guide.ts index c5f716e..c925807 100644 --- a/typescript/src/shared/tools/documentation/getOAuth20Guide.ts +++ b/typescript/src/shared/tools/documentation/getOAuth20Guide.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import fetch from 'node-fetch'; import { Tool, ToolContext } from '@/shared/types'; +import { fetchGithubReadme } from './githubReadme'; const getDescription = (): string => { return `Retrieves the comprehensive OAuth 2.0 integration guide including step-by-step instructions, @@ -40,11 +40,9 @@ export const execute = async ( } if (repositoryName !== undefined) { - const githubUrl = `https://raw.githubusercontent.com/Mastercard/${repositoryName}/refs/heads/main/README.md`; - const response = await fetch(githubUrl); - - if (response.ok) { - return await response.text(); + const content = await fetchGithubReadme(repositoryName, context); + if (content !== undefined) { + return content; } } } diff --git a/typescript/src/shared/tools/documentation/githubReadme.ts b/typescript/src/shared/tools/documentation/githubReadme.ts new file mode 100644 index 0000000..33d1cc1 --- /dev/null +++ b/typescript/src/shared/tools/documentation/githubReadme.ts @@ -0,0 +1,14 @@ +import fetch from 'node-fetch'; +import { ToolContext } from '@/shared/types'; + +export async function fetchGithubReadme( + repositoryName: string, + context: ToolContext +): Promise { + const url = `https://raw.githubusercontent.com/Mastercard/${repositoryName}/refs/heads/main/README.md`; + if (context.client.fetchGithubGuide !== undefined) { + return context.client.fetchGithubGuide(url).catch(() => undefined); + } + const response = await fetch(url); + return response.ok ? response.text() : undefined; +} diff --git a/typescript/src/shared/types.ts b/typescript/src/shared/types.ts index 9eca094..3c2a6ba 100644 --- a/typescript/src/shared/types.ts +++ b/typescript/src/shared/types.ts @@ -24,6 +24,7 @@ export interface DevelopersApi { method: string, path: string ): Promise; + fetchGithubGuide?(url: string): Promise; } export interface ToolContext {