@north7/entraaware 0.0.1

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/README.md +92 -0
  2. package/build/index.js +109 -0
  3. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # EntraAware MCP Server
2
+
3
+ A simple, lightweight Model Context Protocol (MCP) server for querying Microsoft Entra (Azure AD) data.
4
+
5
+ ## What is EntraAware?
6
+
7
+ EntraAware is an MCP Server allows AI assistants to directly access your Microsoft Entra (Azure AD) tenant data through the Microsoft Graph API. With EntraAware, you can ask natural language questions about your Entra environment.
8
+
9
+ ## Setup
10
+
11
+ ### Prerequisites
12
+
13
+ - Microsoft Entra (Azure AD) tenant
14
+ - Application registration with appropriate Graph API permissions
15
+ - Node.js 18 or higher
16
+
17
+ ### Installation
18
+
19
+ ```bash
20
+ # Install globally
21
+ npm install -g @uniquk/entraaware
22
+
23
+ # Or use with npx (no installation needed)
24
+ npx @uniquk/entraaware
25
+ ```
26
+
27
+ ### Configuration
28
+
29
+ Create a `.mcp.json` file in your VS Code workspace:
30
+
31
+ ```json
32
+ {
33
+ "servers": {
34
+ "EntraAware": {
35
+ "type": "stdio",
36
+ "command": "npx",
37
+ "args": [
38
+ "-y",
39
+ "@uniquk/entraaware@latest"
40
+ ],
41
+ "env": {
42
+ "TENANT_ID": "your-tenant-id",
43
+ "CLIENT_ID": "your-client-id",
44
+ "CLIENT_SECRET": "your-client-secret"
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ Replace the environment variables with your own:
52
+
53
+ - `TENANT_ID` - Your Microsoft Entra tenant ID
54
+ - `CLIENT_ID` - Your Microsoft Entra client ID/application ID
55
+ - `CLIENT_SECRET` - Your Microsoft Entra client secret
56
+
57
+ ## Usage
58
+
59
+ Once configured, you can use EntraAware through VS Code by typing:
60
+
61
+ ```
62
+ ask EntraAware>
63
+ ```
64
+
65
+ The EntraAware MCP tool provides a single function that automatically detects the right Graph API endpoint based on keywords in your question:
66
+
67
+ ```json
68
+ {
69
+ "question": "Show me all conditional access policies"
70
+ }
71
+ ```
72
+
73
+ ### Example Queries
74
+
75
+ ```
76
+ // Get organization details
77
+ Show me details about my organization
78
+
79
+ // Get conditional access policies
80
+ List all conditional access policies
81
+
82
+ // Get information about a specific user
83
+ Find user john.doe@example.com
84
+
85
+ // Get all groups
86
+ Show me all groups
87
+ ```
88
+
89
+ ## References
90
+
91
+ - [Microsoft Graph API Documentation](https://learn.microsoft.com/en-us/graph/api/overview)
92
+ - [EntraAware npm package](https://www.npmjs.com/package/@uniquk/entraaware)
package/build/index.js ADDED
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ import { Client } from "@microsoft/microsoft-graph-client";
6
+ import { ClientSecretCredential } from "@azure/identity";
7
+ import { TokenCredentialAuthenticationProvider } from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials/index.js";
8
+ // Initialize Graph Client
9
+ let graphClient = null;
10
+ // Create server instance
11
+ const server = new McpServer({
12
+ name: "EntraAware",
13
+ version: "0.0.1",
14
+ capabilities: {
15
+ resources: {},
16
+ tools: {},
17
+ },
18
+ });
19
+ // Direct Microsoft Graph API access tool
20
+ server.tool("askEntra", "Ask any question about your Microsoft Entra (Azure AD) tenant in natural language", {
21
+ question: z.string().describe("Your natural language question about Microsoft 365 Entra (Azure AD)")
22
+ }, async ({ question }) => {
23
+ try {
24
+ // Get or initialize Graph client
25
+ if (!graphClient) {
26
+ graphClient = initGraphClient();
27
+ }
28
+ // Default path if we can't determine from the question
29
+ let path = "/organization";
30
+ // Extract any email addresses or GUIDs from the question
31
+ const emailPattern = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/;
32
+ const guidPattern = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
33
+ const emailMatch = question.match(emailPattern);
34
+ const guidMatch = question.match(guidPattern);
35
+ // Check for specific keywords in the question to determine the right path
36
+ const lowerQuestion = question.toLowerCase();
37
+ if (lowerQuestion.includes("conditional access") || lowerQuestion.includes("policies")) {
38
+ path = "/identity/conditionalAccess/policies";
39
+ }
40
+ else if (lowerQuestion.includes("users") || lowerQuestion.includes("user")) {
41
+ path = "/users";
42
+ if (emailMatch) {
43
+ path = `/users/${emailMatch[0]}`;
44
+ }
45
+ }
46
+ else if (lowerQuestion.includes("groups") || lowerQuestion.includes("group")) {
47
+ path = "/groups";
48
+ }
49
+ else if (lowerQuestion.includes("applications") || lowerQuestion.includes("apps")) {
50
+ path = "/applications";
51
+ }
52
+ else if (lowerQuestion.includes("roles") || lowerQuestion.includes("directory roles")) {
53
+ path = "/directoryRoles";
54
+ }
55
+ // If a GUID was found and not already used in the path, append it
56
+ if (guidMatch && !path.includes(guidMatch[0])) {
57
+ path = `${path}/${guidMatch[0]}`;
58
+ }
59
+ // Build and execute the request
60
+ let request = graphClient.api(path);
61
+ // Execute the request
62
+ const result = await request.get();
63
+ // Format the response
64
+ return {
65
+ content: [
66
+ {
67
+ type: "text",
68
+ text: `📊 Entra API Result (${path}):\n\n${JSON.stringify(result, null, 2)}`,
69
+ },
70
+ ],
71
+ };
72
+ }
73
+ catch (err) {
74
+ return {
75
+ content: [
76
+ {
77
+ type: "text",
78
+ text: `Error querying Entra API: ${err instanceof Error ? err.message : String(err)}`,
79
+ },
80
+ ],
81
+ };
82
+ }
83
+ });
84
+ // Helper function to initialize the Microsoft Graph client
85
+ function initGraphClient() {
86
+ const tenantId = process.env.TENANT_ID;
87
+ const clientId = process.env.CLIENT_ID;
88
+ const clientSecret = process.env.CLIENT_SECRET;
89
+ if (!tenantId || !clientId || !clientSecret) {
90
+ throw new Error("Missing required Entra environment variables: TENANT_ID, CLIENT_ID, or CLIENT_SECRET");
91
+ }
92
+ const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
93
+ const authProvider = new TokenCredentialAuthenticationProvider(credential, {
94
+ scopes: ["https://graph.microsoft.com/.default"],
95
+ });
96
+ return Client.initWithMiddleware({
97
+ authProvider: authProvider,
98
+ });
99
+ }
100
+ // Start the server with stdio transport
101
+ async function main() {
102
+ const transport = new StdioServerTransport();
103
+ await server.connect(transport);
104
+ console.error("EntraAware MCP Server running on stdio");
105
+ }
106
+ main().catch((error) => {
107
+ console.error("Fatal error in main():", error);
108
+ process.exit(1);
109
+ });
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@north7/entraaware",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "build/index.js",
6
+ "bin": {
7
+ "entraaware": "build/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc && chmod 755 build/index.js",
11
+ "start": "node build/index.js"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "keywords": ["mcp-server", "entra", "azure-ad", "mcp", "microsoft-graph"],
17
+ "author": "",
18
+ "license": "ISC",
19
+ "description": "MCP server for Microsoft Entra (Azure AD) integration",
20
+ "files": [
21
+ "build"
22
+ ],
23
+ "dependencies": {
24
+ "@azure/identity": "^4.9.0",
25
+ "@microsoft/microsoft-graph-client": "^3.0.7",
26
+ "@modelcontextprotocol/sdk": "^1.10.1",
27
+ "zod": "^3.24.3"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.14.1",
31
+ "typescript": "^5.8.3"
32
+ }
33
+ }