Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
456 changes: 0 additions & 456 deletions backend/app/mcp/mcp_bridge/index.ts

This file was deleted.

16 changes: 0 additions & 16 deletions backend/app/mcp/mcp_bridge/package.json

This file was deleted.

125 changes: 125 additions & 0 deletions backend/app/mcp/udos_mcp/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/server";
import { serveStdio } from "@modelcontextprotocol/server/stdio";
import * as z from "zod/v4";

const UCORE_BASE = process.env.UCORE_URL || "http://localhost:8484";

async function apiGet(path: string): Promise<unknown> {
const response = await fetch(`${UCORE_BASE}${path}`, {
signal: AbortSignal.timeout(15_000),
});
if (!response.ok) {
const detail = (await response.text()).slice(0, 200);
throw new Error(`uCore GET ${path} -> ${response.status}: ${detail}`);
}
return response.json();
}

function result(data: unknown) {
return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] };
}

function failure(error: unknown) {
const message = error instanceof Error ? error.message : String(error);
return {
content: [{ type: "text" as const, text: `uDOS MCP error: ${message}` }],
isError: true,
};
}

async function read(path: string) {
try {
return result(await apiGet(path));
} catch (error) {
return failure(error);
}
}

export function createServer(): McpServer {
const server = new McpServer({ name: "udos-mcp", version: "2.0.0" });

server.registerTool(
"system.health.get",
{ description: "Read the current uCore system health report.", inputSchema: z.object({}) },
async () => read("/api/health/full"),
);

server.registerTool(
"developer.repositories.list",
{
description: "List repositories visible to the uCore Developer surface.",
inputSchema: z.object({
scope: z.enum(["code", "ecosystem"]).optional(),
excludeSystem: z.boolean().optional(),
}),
},
async ({ scope, excludeSystem }) => {
const query = new URLSearchParams();
if (scope) query.set("scope", scope);
if (excludeSystem !== undefined) query.set("exclude_system", String(excludeSystem));
return read(`/api/developer/repos${query.size ? `?${query}` : ""}`);
},
);

server.registerTool(
"developer.repository.status",
{
description: "Read staged and unstaged status for one named repository.",
inputSchema: z.object({ repository: z.string().min(1).max(100) }),
},
async ({ repository }) => read(`/api/developer/repos/${encodeURIComponent(repository)}/status`),
);

server.registerTool(
"flow.tasks.list",
{
description: "List workflow tasks using the canonical uFlow-backed task store.",
inputSchema: z.object({
scope: z.enum(["user", "all"]).optional(),
board: z.string().max(100).optional(),
tag: z.string().max(100).optional(),
}),
},
async ({ scope, board, tag }) => {
const query = new URLSearchParams();
if (scope) query.set("scope", scope);
if (board) query.set("board", board);
if (tag) query.set("tag", tag);
return read(`/api/workflow/tasks${query.size ? `?${query}` : ""}`);
},
);

server.registerTool(
"knowledge.search",
{
description: "Search indexed Markdown through the canonical uKnowledge route.",
inputSchema: z.object({
query: z.string().min(1).max(500),
workspaceId: z.string().max(100).optional(),
limit: z.number().int().min(1).max(50).optional(),
}),
},
async ({ query: term, workspaceId, limit }) => {
const query = new URLSearchParams({ q: term });
if (workspaceId) query.set("workspace_id", workspaceId);
if (limit !== undefined) query.set("limit", String(limit));
return read(`/api/knowledge/search?${query}`);
},
);

server.registerTool(
"code.grid.tools.list",
{ description: "List the read-only GridSmith tool catalogue exposed by uCode.", inputSchema: z.object({}) },
async () => read("/api/gridsmith/tools"),
);

return server;
}

const handle = serveStdio(createServer);
console.error("udos-mcp server running on stdio");

for (const signal of ["SIGINT", "SIGTERM"] as const) {
process.on(signal, () => void handle.close());
}
219 changes: 219 additions & 0 deletions backend/app/mcp/udos_mcp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions backend/app/mcp/udos_mcp/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "udos-mcp",
"version": "2.0.0",
"description": "Canonical read-only uDOS MCP gateway over local stdio",
"type": "module",
"scripts": {
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
"test": "npm run build && node --test test/*.test.mjs"
},
"dependencies": {
"@modelcontextprotocol/server": "^2.0.0",
"zod": "^4.0.0"
},
"devDependencies": {
"@modelcontextprotocol/client": "^2.0.0",
"@types/node": "^20.0.0",
"typescript": "^5.0.0"
}
}
Loading
Loading