Download server.js from mmty/julesmcp: direct link, hf CLI and curl.
- Browser
- Download file 8.52 kB
-
https://huggingface.co/spaces/mmty/julesmcp/resolve/main/server.js
- Command line
-
hf download hf://spaces/mmty/julesmcp/server.js
-
curl -L -o server.js https://huggingface.co/spaces/mmty/julesmcp/resolve/main/server.js
8.52 kB
| const express = require('express'); | |
| const cors = require('cors'); | |
| // Dynamic import for node-fetch | |
| const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args)); | |
| const app = express(); | |
| const PORT = 7860; | |
| // 1. CONFIGURATION | |
| app.set('trust proxy', 1); | |
| app.use(express.json({ limit: '10mb' })); | |
| app.use(cors({ origin: '*', methods: ['GET', 'POST', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'MCP-Protocol-Version'] })); | |
| // 2. LOGGING | |
| app.use((req, res, next) => { | |
| console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`); | |
| next(); | |
| }); | |
| // --- HELPER: DATA MINIMIZER (Token Saver) --- | |
| const minimizeData = (toolName, data) => { | |
| if (!data) return "No data"; | |
| // A. Optimize Source List (Massive reduction) | |
| if (toolName === "list_sources" && data.sources) { | |
| return data.sources.map(s => ({ | |
| id: s.id, // The only thing the LLM really needs | |
| repo: s.githubRepo?.repo || "unknown" | |
| })); | |
| } | |
| // B. Optimize Activities (The biggest offender) | |
| if (toolName === "get_activities" && data.activities) { | |
| // 1. Take only the last 15 activities (LLM doesn't need history from 3 days ago) | |
| const recent = data.activities.slice(-15); | |
| return recent.map(act => { | |
| let summary = { | |
| type: act.originator, // 'agent' or 'user' | |
| title: act.progressUpdated?.title || "Update", | |
| }; | |
| // Extract Plan | |
| if (act.planGenerated) { | |
| summary.plan = act.planGenerated.plan.steps.map(s => s.title); | |
| } | |
| // Extract PR Link (Crucial for your second question) | |
| if (act.outputs) { | |
| const pr = act.outputs.find(o => o.pullRequest); | |
| if (pr) summary.pr_link = pr.pullRequest.url; | |
| } | |
| // HANDLE ARTIFACTS (CRITICAL OPTIMIZATION) | |
| // We strip massive bash outputs and git diffs | |
| if (act.artifacts) { | |
| summary.artifacts = act.artifacts.map(art => { | |
| if (art.bashOutput) { | |
| return { | |
| type: "bash", | |
| command: art.bashOutput.command?.trim(), | |
| // Truncate output to 200 chars to save tokens | |
| output_preview: (art.bashOutput.output || "").substring(0, 200) + "..." | |
| }; | |
| } | |
| if (art.changeSet) { | |
| return { | |
| type: "code_change", | |
| files: "See PR for details", // Don't dump diffs into context | |
| baseCommit: art.changeSet.gitPatch?.baseCommitId | |
| }; | |
| } | |
| return "Binary/Image Data (Hidden)"; | |
| }); | |
| } | |
| return summary; | |
| }); | |
| } | |
| return data; | |
| }; | |
| // --- AUTH MIDDLEWARE --- | |
| const authMiddleware = (req, res, next) => { | |
| const expected = process.env.MCP_AUTH_TOKEN; | |
| if (!expected) return next(); | |
| const auth = req.headers['authorization']; | |
| if (!auth || !auth.startsWith('Bearer ') || auth.split(' ')[1] !== expected) { | |
| return res.status(401).json({ jsonrpc: "2.0", id: null, error: { code: -32000, message: "Unauthorized" } }); | |
| } | |
| next(); | |
| }; | |
| // 3. MAIN HANDLER | |
| const mcpHandler = async (req, res) => { | |
| try { | |
| const body = req.body; | |
| const { method, params, id } = body; | |
| const requestId = id !== undefined ? id : null; | |
| const send = (result) => res.json({ jsonrpc: "2.0", id: requestId, result }); | |
| const error = (code, msg) => res.json({ jsonrpc: "2.0", id: requestId, error: { code, message: msg } }); | |
| // --- HANDLERS --- | |
| if (method === "initialize") { | |
| return send({ | |
| protocolVersion: "2024-11-05", | |
| capabilities: { tools: {}, prompts: {}, resources: {} }, | |
| serverInfo: { name: "jules-mcp-optimized", version: "1.0.2" } | |
| }); | |
| } | |
| if (method === "notifications/initialized") return send(true); | |
| if (method === "ping") return send({}); | |
| // --- LIST TOOLS --- | |
| if (method === "tools/list") { | |
| return send({ | |
| tools: [ | |
| { | |
| name: "list_sources", | |
| description: "List GitHub repositories. Returns minimized IDs to save context.", | |
| inputSchema: { type: "object", properties: {} } | |
| }, | |
| { | |
| name: "create_session", | |
| description: "Start a new task. If auto_pr is true, Jules will publish a PR automatically.", | |
| inputSchema: { | |
| type: "object", | |
| properties: { | |
| source: { type: "string", description: "Source ID (e.g. 'owner/repo')" }, | |
| prompt: { type: "string", description: "Task description" }, | |
| branch: { type: "string", description: "Branch (default: main)" }, | |
| auto_pr: { type: "boolean", description: "Set true to have Jules create the PR automatically." } | |
| }, | |
| required: ["source", "prompt"] | |
| } | |
| }, | |
| { | |
| name: "get_activities", | |
| description: "Get recent session logs. Returns summarized data (no massive diffs).", | |
| inputSchema: { | |
| type: "object", | |
| properties: { session_id: { type: "string" } }, | |
| required: ["session_id"] | |
| } | |
| }, | |
| { | |
| name: "send_message", | |
| description: "Reply to Jules.", | |
| inputSchema: { | |
| type: "object", | |
| properties: { session_id: { type: "string" }, message: { type: "string" } }, | |
| required: ["session_id", "message"] | |
| } | |
| } | |
| ] | |
| }); | |
| } | |
| // --- CALL TOOL --- | |
| if (method === "tools/call") { | |
| const { name, arguments: args } = params || {}; | |
| const apiKey = process.env.JULES_API_KEY; | |
| if (!apiKey) return error(-32000, "Server Error: JULES_API_KEY missing"); | |
| const callJules = async (ep, m, b) => { | |
| const r = await fetch(`https://jules.googleapis.com/v1alpha/${ep}`, { | |
| method: m, | |
| headers: { "X-Goog-Api-Key": apiKey, "Content-Type": "application/json" }, | |
| body: b ? JSON.stringify(b) : undefined | |
| }); | |
| if (!r.ok) { | |
| const txt = await r.text(); | |
| throw new Error(`${r.status}: ${txt}`); | |
| } | |
| const t = await r.text(); | |
| return t ? JSON.parse(t) : { success: true }; | |
| }; | |
| try { | |
| let data; | |
| if (name === "list_sources") { | |
| data = await callJules("sources", "GET"); | |
| } | |
| else if (name === "create_session") { | |
| // Normalize Source | |
| let sourceInput = args.source; | |
| if (!sourceInput.includes('/')) return error(-32000, "Invalid source. Use 'owner/repo'"); | |
| if (!sourceInput.startsWith('sources/')) { | |
| sourceInput = sourceInput.startsWith('github/') ? `sources/${sourceInput}` : `sources/github/${sourceInput}`; | |
| } | |
| data = await callJules("sessions", "POST", { | |
| prompt: args.prompt, | |
| sourceContext: { | |
| source: sourceInput, | |
| githubRepoContext: { startingBranch: args.branch || "main" } | |
| }, | |
| // THIS handles the PR creation | |
| automationMode: args.auto_pr ? "AUTO_CREATE_PR" : undefined, | |
| title: args.prompt.substring(0, 50) | |
| }); | |
| } | |
| else if (name === "get_activities") { | |
| const sid = args.session_id.replace("sessions/", ""); | |
| data = await callJules(`sessions/${sid}/activities?pageSize=30`, "GET"); | |
| } | |
| else if (name === "send_message") { | |
| const sid = args.session_id.replace("sessions/", ""); | |
| await callJules(`sessions/${sid}:sendMessage`, "POST", { prompt: args.message }); | |
| data = { status: "Message sent." }; | |
| } | |
| else { | |
| return error(-32601, "Tool not found"); | |
| } | |
| // MINIMIZE DATA BEFORE SENDING | |
| const optimizedData = minimizeData(name, data); | |
| return send({ | |
| content: [{ type: "text", text: JSON.stringify(optimizedData, null, 2) }], | |
| isError: false | |
| }); | |
| } catch (err) { | |
| return error(-32000, `Jules API Error: ${err.message}`); | |
| } | |
| } | |
| return error(-32601, "Method not found"); | |
| } catch (err) { | |
| console.error(err); | |
| res.status(500).json({ jsonrpc: "2.0", id: null, error: { code: -32603, message: "Internal Error" } }); | |
| } | |
| }; | |
| app.post('/mcp', authMiddleware, mcpHandler); | |
| app.post('/messages', authMiddleware, mcpHandler); | |
| app.get('/', (req, res) => res.send("Jules MCP Optimized")); | |
| app.listen(PORT, '0.0.0.0', () => console.log(`Server running on ${PORT}`)); |