Compare commits

...

1 Commits

Author SHA1 Message Date
Benjamin S. Leveritt
9df50ee7c2 Adds an MCP project 2025-05-12 08:27:04 +01:00
7 changed files with 1895 additions and 55 deletions

View File

@@ -0,0 +1,4 @@
# Provide Jazz Account and secret for the MCP server to load CoValues from
JAZZ_ACCOUNT_ID=co_z123
JAZZ_ACCOUNT_SECRET=sealerSecret_z123

2
packages/jazz-mcp-server/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.env
build

View File

@@ -0,0 +1,13 @@
# Jazz MCP Server
An MCP server for interacting with Jazz.
An early experiment into offering easier understandability for Jazz for LLMs.
## Installation
`pnpm build`
## Running
`pnpm inspect`

View File

@@ -0,0 +1,28 @@
{
"name": "jazz-mcp-server",
"version": "0.0.1",
"type": "module",
"main": "./src/index.js",
"bin": {
"jazz": "./build/index.js"
},
"scripts": {
"build": "tsc && chmod 755 build/index.js",
"inspect": "pnpx @modelcontextprotocol/inspector node build/index.js"
},
"files": [
"build"
],
"dependencies": {
"@modelcontextprotocol/sdk": "^1.11.1",
"cojson": "workspace:*",
"dotenv": "^16.5.0",
"jazz-tools": "workspace:*",
"zod": "^3.24.4"
},
"devDependencies": {
"@modelcontextprotocol/inspector": "^0.11.0",
"@types/node": "^22.5.1",
"typescript": "^5.8.3"
}
}

View File

@@ -0,0 +1,114 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
import {
Account,
AnonymousJazzAgent,
ID,
createAnonymousJazzContext,
createJazzContextFromExistingCredentials,
randomSessionProvider,
} from "jazz-tools";
import { z } from "zod";
const accountID = process.env.JAZZ_ACCOUNT_ID;
const accountSecret = process.env.JAZZ_ACCOUNT_SECRET;
let accountContext: { agent: Account | AnonymousJazzAgent | undefined } = {
agent: undefined,
};
async function setupAccountContext() {
const crypto = await WasmCrypto.create();
if (accountID && accountSecret) {
// Owner mode: ensure the secret is the correct type (cast if necessary)
const ctx = await createJazzContextFromExistingCredentials({
credentials: {
accountID: accountID as ID<Account>,
secret: accountSecret as any, // Ensure this is the actual agent secret string
},
peersToLoadFrom: [], // TODO: Do we need to load peers?
crypto,
sessionProvider: randomSessionProvider,
});
accountContext.agent = ctx.account;
} else {
// Guest mode: use the proper guest context
const guestCtx = await createAnonymousJazzContext({
peersToLoadFrom: [],
crypto,
});
accountContext.agent = guestCtx.agent;
}
}
// Create server instance
const server = new McpServer({
name: "jazz",
version: "0.0.1",
capabilities: {
resources: {},
tools: {},
},
});
server.tool(
"load-account",
"Load a Jazz account",
{
accountID: z.string(),
},
async ({ accountID }) => {
// Wait for context to be ready if not already
if (!accountContext.agent) {
await setupAccountContext();
}
let account;
try {
account = await Account.load(accountID as ID<Account>, {
loadAs: accountContext.agent,
});
if (!account) {
return {
isError: true,
content: [
{
type: "text",
text: `Account with ID ${accountID} not found or not accessible.`,
},
],
};
}
} catch (err) {
return {
isError: true,
content: [
{
type: "text",
text: `Error loading account: ${err instanceof Error ? err.message : String(err)}`,
},
],
};
}
return {
content: [
{
type: "text",
text: `Account loaded: ${JSON.stringify(account.toJSON())}`,
},
],
};
},
);
async function main() {
await setupAccountContext();
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Jazz MCP Server running on stdio");
}
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

1774
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff