Skip to content

Commit a2853bf

Browse files
committed
chore: move atlas projects and clusters into resources
1 parent 9edf3ca commit a2853bf

File tree

17 files changed

+212
-212
lines changed

17 files changed

+212
-212
lines changed

package-lock.json

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"description": "MongoDB Model Context Protocol Server",
44
"version": "0.0.0",
55
"main": "dist/index.js",
6+
"type": "module",
67
"author": "MongoDB <[email protected]>",
78
"homepage": "https://github.com/mongodb-js/mongodb-mcp-server",
89
"repository": {

src/common/atlas/auth.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ApiClient } from "../../client.js";
2+
import { State } from "../../state.js";
3+
4+
export async function ensureAuthenticated(state: State, apiClient: ApiClient): Promise<void> {
5+
if (!(await isAuthenticated(state, apiClient))) {
6+
throw new Error("Not authenticated");
7+
}
8+
}
9+
10+
export async function isAuthenticated(state: State, apiClient: ApiClient): Promise<boolean> {
11+
switch (state.auth.status) {
12+
case "not_auth":
13+
return false;
14+
case "requested":
15+
try {
16+
if (!state.auth.code) {
17+
return false;
18+
}
19+
await apiClient.retrieveToken(state.auth.code.device_code);
20+
return !!state.auth.token;
21+
} catch {
22+
return false;
23+
}
24+
case "issued":
25+
if (!state.auth.token) {
26+
return false;
27+
}
28+
return await apiClient.validateToken();
29+
default:
30+
throw new Error("Unknown authentication status");
31+
}
32+
}

src/config.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import path from "path";
22
import fs from "fs";
33

4-
const packageMetadata = fs.readFileSync(path.resolve("./package.json"), "utf8");
4+
import { fileURLToPath } from 'url';
5+
import { dirname } from 'path';
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const dir = path.resolve(path.join(dirname(__filename), ".."));
9+
10+
const packageMetadata = fs.readFileSync(path.join(dir, "package.json"), "utf8");
511
const packageJson = JSON.parse(packageMetadata);
612

713
export const config = {
814
version: packageJson.version,
915
apiBaseURL: process.env.API_BASE_URL || "https://cloud.mongodb.com/",
1016
clientID: process.env.CLIENT_ID || "0oabtxactgS3gHIR0297",
11-
stateFile: process.env.STATE_FILE || path.resolve("./state.json"),
17+
stateFile: process.env.STATE_FILE || path.join(dir, "state.json"),
1218
projectID: process.env.PROJECT_ID,
1319
userAgent: `AtlasMCP/${packageJson.version} (${process.platform}; ${process.arch}; ${process.env.HOSTNAME || "unknown"})`,
1420
};

src/resources/atlas/clusters.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";;
2+
import { ResourceTemplateBase } from "../base.js";
3+
import { ensureAuthenticated } from "../../common/atlas/auth.js";
4+
5+
export class ClustersResource extends ResourceTemplateBase {
6+
name = "clusters";
7+
metadata = {
8+
description: "MongoDB Atlas clusters"
9+
};
10+
template = new ResourceTemplate("atlas://clusters", { list: undefined });
11+
12+
async execute(uri: URL, { projectId }: { projectId: string }) {
13+
await ensureAuthenticated(this.state, this.apiClient);
14+
15+
const clusters = await this.apiClient.listProjectClusters(projectId);
16+
17+
if (!clusters || clusters.results.length === 0) {
18+
return {
19+
contents: [],
20+
};
21+
}
22+
23+
return {
24+
contents: [
25+
{
26+
uri: uri.href,
27+
mimeType: "application/json",
28+
text: JSON.stringify(clusters.results),
29+
},
30+
],
31+
};
32+
}
33+
};

src/resources/atlas/projects.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { ensureAuthenticated } from "../../common/atlas/auth.js";
2+
import { ResourceUriBase } from "../base.js";
3+
4+
export class ProjectsResource extends ResourceUriBase {
5+
name = "projects";
6+
metadata = {
7+
description: "MongoDB Atlas projects"
8+
};
9+
uri = "atlas://projects";
10+
11+
async execute(uri: URL) {
12+
await ensureAuthenticated(this.state, this.apiClient);
13+
14+
const projects = await this.apiClient.listProjects();
15+
16+
if (!projects) {
17+
return {
18+
contents: [],
19+
};
20+
}
21+
22+
const projectList = projects.results.map((project) => ({
23+
id: project.id,
24+
name: project.name,
25+
}));
26+
27+
return {
28+
contents: [
29+
{
30+
uri: uri.href,
31+
mimeType: "application/json",
32+
text: JSON.stringify(projectList),
33+
},
34+
],
35+
};
36+
}
37+
};

src/resources/base.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { McpServer, ResourceMetadata, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";;
2+
import { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";;
3+
import { State } from "../state.js";
4+
import { ApiClient } from "../client.js";
5+
import { ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";;
6+
import { Variables } from "@modelcontextprotocol/sdk/shared/uriTemplate.js";;
7+
8+
abstract class ResourceCommonBase {
9+
protected abstract name: string;
10+
protected abstract metadata?: ResourceMetadata;
11+
12+
constructor(protected state: State, protected apiClient: ApiClient) { }
13+
}
14+
15+
export abstract class ResourceUriBase extends ResourceCommonBase {
16+
protected abstract uri: string;
17+
18+
abstract execute(uri: URL, extra: RequestHandlerExtra): ReadResourceResult | Promise<ReadResourceResult>;
19+
20+
register(server: McpServer) {
21+
server.resource(
22+
this.name,
23+
this.uri,
24+
this.metadata || {},
25+
(uri: URL, extra: RequestHandlerExtra) => {
26+
return this.execute(uri, extra);
27+
}
28+
);
29+
}
30+
}
31+
32+
export abstract class ResourceTemplateBase extends ResourceCommonBase {
33+
protected abstract template: ResourceTemplate;
34+
35+
abstract execute(uri: URL, variables: Variables, extra: RequestHandlerExtra): ReadResourceResult | Promise<ReadResourceResult>;
36+
37+
register(server: McpServer) {
38+
server.resource(
39+
this.name,
40+
this.template,
41+
this.metadata || {},
42+
(uri: URL, variables: Variables, extra: RequestHandlerExtra) => {
43+
return this.execute(uri, variables, extra);
44+
}
45+
);
46+
}
47+
}
48+
49+
export type ResourceBase = ResourceTemplateBase | ResourceUriBase;

src/resources/register.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2+
import { ApiClient } from '../client';
3+
import { State } from '../state';
4+
import { ProjectsResource } from './atlas/projects.js';
5+
import { ClustersResource } from './atlas/clusters.js';
6+
7+
export function registerResources(server: McpServer, state: State, apiClient: ApiClient) {
8+
const projectsResource = new ProjectsResource(state, apiClient);
9+
const clustersResource = new ClustersResource(state, apiClient);
10+
11+
projectsResource.register(server);
12+
clustersResource.register(server);
13+
}
14+

src/server.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";;
22
import { ApiClient } from "./client.js";
33
import { State, saveState, loadState } from "./state.js";
4-
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
5-
import { registerAtlasTools } from "./tools/atlas/tools.js";
6-
import { registerMongoDBTools } from "./tools/mongodb/index.js";
4+
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";;
75
import { config } from "./config.js";
6+
import { registerResources } from "./resources/register.js";
7+
import { registerTools } from "./tools/register.js";
88

99
export class Server {
1010
state: State | undefined = undefined;
@@ -39,9 +39,10 @@ export class Server {
3939
version: config.version,
4040
});
4141

42-
registerAtlasTools(server, this.state!, this.apiClient!);
43-
registerMongoDBTools(server, this.state!);
42+
registerResources(server, this.state!, this.apiClient!);
43+
registerTools(server, this.state!, this.apiClient!);
4444

45+
4546
return server;
4647
}
4748

src/tools/atlas/atlasTool.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)