Last active
April 29, 2025 20:02
-
-
Save jcenturion/abaf89932be062f895d354f902b59280 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; | |
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | |
import { z } from "zod"; | |
// Create an MCP server | |
const server = new McpServer({ | |
name: "Auth0 AI", | |
version: "1.0.0", | |
}); | |
server.tool( | |
"create-a-tool-using-auth0-ai", | |
"Create a tool using Auth0 AI", | |
{ | |
toolDescription: z.string(), | |
}, | |
async ({ toolDescription }) => { | |
return { | |
content: [ | |
{ | |
type: "text", | |
text: `Create tools utilizing Auth0 AI to obtain access tokens for different providers by integrating with Vercel AI, Vercel AI SDK, and NextJS Auth0. Provide the code for each tool along with the file paths where they should be stored. | |
Follow the steps and examples given below to complete the task effectively. | |
# Steps | |
1. **Configure Authorization with Auth0 AI**: | |
- Import and create instances of \`auth0\` from your library and \`Auth0AI\` from the \`@auth0/ai-vercel\`. | |
- Define methods such as \`withGoogleCalendar\`, \`withSlack\`, and \`withGitHub\` to obtain access tokens for specific OAuth connections, using refresh tokens from the user's session. | |
- Each configuration should specify the connection strategy and required scopes. | |
2. **Create Tools using the Configured Authorization**: | |
- For each provider, create a tool using the \`tool\` function from \`ai\`. | |
- Define the tool’s description, parameters, and execution logic. | |
- Obtain and use the access token within the execution block. | |
- Handle possible authorization errors using \`FederatedConnectionError\`. | |
3. **Store the Code in Specific File Paths**: | |
- Review the codebase and identify appropriate file paths for storing the authorization configurations and tool implementations. | |
- Ensure that the file paths are consistent with the existing project structure and naming conventions. | |
4. **Update Vercel AI tools** | |
- Update the Vercel AI tools to use the generated tools. | |
- Ensure that the tools are correctly integrated and accessible within the Vercel AI environment. | |
# Output Format | |
- The output should be TypeScript code snippets for authorization and tools, along with their respective file paths. | |
- Provide clear separation of examples for different providers and tools. | |
# Examples | |
**Configure Authorization Example 1 [Google Calendar]** | |
\`\`\`typescript | |
import { auth0 } from "@/lib/auth0"; | |
import { Auth0AI } from "@auth0/ai-vercel"; | |
const auth0AI = new Auth0AI(); | |
export const withGoogleCalendar = auth0AI.withTokenForConnection({ | |
refreshToken: async () => { | |
const session = await auth0.getSession(); | |
const refreshToken = session?.tokenSet.refreshToken as string; | |
return refreshToken; | |
}, | |
connection: "google-oauth2", | |
scopes: ["https://www.googleapis.com/auth/calendar.freebusy"], | |
}); | |
\`\`\` | |
**Tool Creation Example 1 [Check User's Calendar]** | |
\`\`\`typescript | |
import { tool } from "ai"; | |
import { addHours, formatISO } from "date-fns"; | |
import { GaxiosError } from "gaxios"; | |
import { google } from "googleapis"; | |
import { z } from "zod"; | |
import { withGoogleCalendar } from "@/lib/auth0-ai/withGoogleCalendar"; | |
import { getAccessTokenForConnection } from "@auth0/ai-vercel"; | |
import { FederatedConnectionError } from "@auth0/ai/interrupts"; | |
export const checkUsersCalendar = withGoogleCalendar( | |
tool({ | |
description: "Check user availability on a given date on their calendar", | |
parameters: z.object({ | |
date: z.coerce.date(), | |
}), | |
execute: async ({ date }) => { | |
const accessToken = getAccessTokenForConnection(); | |
try { | |
const calendar = google.calendar("v3"); | |
const auth = new google.auth.OAuth2(); | |
auth.setCredentials({ access_token: accessToken }); | |
const response = await calendar.freebusy.query({ | |
auth, | |
requestBody: { | |
timeMin: formatISO(date), | |
timeMax: addHours(date, 1).toISOString(), | |
timeZone: "UTC", | |
items: [{ id: "primary" }], | |
}, | |
}); | |
return { available: response.data?.calendars?.primary?.busy?.length === 0 }; | |
} catch (error) { | |
if (error instanceof GaxiosError && error.status === 401) { | |
throw new FederatedConnectionError("Authorization required to access the Federated Connection"); | |
} | |
throw error; | |
} | |
}, | |
}) | |
); | |
\`\`\` | |
**Configure Authorization Example 2 [Slack]** | |
\`\`\`typescript | |
import { auth0 } from "@/lib/auth0"; | |
import { Auth0AI } from "@auth0/ai-vercel"; | |
const auth0AI = new Auth0AI(); | |
export const withSlack = auth0AI.withTokenForConnection({ | |
refreshToken: async () => { | |
const session = await auth0.getSession(); | |
const refreshToken = session?.tokenSet.refreshToken as string; | |
return refreshToken; | |
}, | |
connection: "sign-in-with-slack", | |
scopes: ["channels:read", "groups:read"], | |
}); | |
\`\`\` | |
**Tool Creation Example 2 [Check User's Calendar]** | |
\`\`\`typescript | |
import { tool } from "ai"; | |
import { z } from "zod"; | |
import { withSlack } from "@/lib/auth0-ai/withSlack"; | |
import { getAccessTokenForConnection } from "@auth0/ai-vercel"; | |
import { FederatedConnectionError } from "@auth0/ai/interrupts"; | |
import { ErrorCode, WebClient } from "@slack/web-api"; | |
export const listChannels = withSlack( | |
tool({ | |
description: "List channels for the current user on Slack", | |
parameters: z.object({}), | |
execute: async () => { | |
const accessToken = getAccessTokenForConnection(); | |
try { | |
const web = new WebClient(accessToken); | |
const result = await web.conversations.list({ | |
exclude_archived: true, | |
types: "public_channel,private_channel", | |
limit: 10, | |
}); | |
return result.channels?.map((channel) => channel.name); | |
} catch (error) { | |
if (error && typeof error === "object" && "code" in error) { | |
if (error.code === ErrorCode.HTTPError) { | |
throw new FederatedConnectionError( | |
\`Authorization required to access the Federated Connection\` | |
); | |
} | |
} | |
throw error; | |
} | |
}, | |
}) | |
); | |
\`\`\` | |
# Notes | |
- Ensure TypeScript typings are correctly utilized for parameters and return types. | |
- Handle all potential errors appropriately and ensure fallbacks or error messages guide the user. | |
- Customize connection strings and scopes based on target APIs and functionalities required. | |
- Consider security best practices, especially concerning token storage and retrieval. | |
- If possible always use oficial SDKs for integrating with 3rd party APIs like google apis, box, etc | |
- Auth0 available connections/strategies ad, adfs, amazon, apple, dropbox, bitbucket, aol, auth0-oidc, auth0, baidu, bitly, box, custom, daccount, dwolla, email, evernote-sandbox, evernote, exact, facebook, fitbit, flickr, github, google-apps, google-oauth2, instagram, ip, line, linkedin, miicard, oauth1, oauth2, office365, oidc, okta, paypal, paypal-sandbox, pingfederate, planningcenter, renren, salesforce-community, salesforce-sandbox, salesforce, samlp, sharepoint, shopify, sms, soundcloud, thecity-sandbox, thecity, thirtysevensignals, twitter, untappd, vkontakte, waad, weibo, windowslive, wordpress, yahoo, yammer, yandex | |
- If the the strategy is not available auth0 will use oauth2 by default, in that case you can make up the name of the connection but clarify that auth0 will use oauth2 strategy | |
- Only create content for the two files required by auth0-ai, do not create any extra files or folders. | |
`, | |
}, | |
{ | |
type: "text", | |
text: toolDescription, | |
}, | |
], | |
}; | |
} | |
); | |
async function main() { | |
const transport = new StdioServerTransport(); | |
await server.connect(transport); | |
console.error("Auth0 AI MCP Server running on stdio"); | |
} | |
main().catch((error) => { | |
console.error("Fatal error in main():", error); | |
process.exit(1); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment