fix(mcp): add shared operations and secure scene APIs
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import type { SceneBridge } from '../bridge/scene-bridge'
|
||||
import type { SceneOperations } from '../operations'
|
||||
|
||||
export const AGENT_GUIDE = [
|
||||
'# Pascal MCP agent guide',
|
||||
@@ -46,7 +46,7 @@ export const AGENT_GUIDE = [
|
||||
'- Use `apply_patch` for bulk exact edits after semantic tools have established the main structure.',
|
||||
].join('\n')
|
||||
|
||||
export function registerAgentGuide(server: McpServer, _bridge: SceneBridge): void {
|
||||
export function registerAgentGuide(server: McpServer, _bridge: SceneOperations): void {
|
||||
server.registerResource(
|
||||
'agent-guide',
|
||||
'pascal://agent/guide',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import type { SceneBridge } from '../bridge/scene-bridge'
|
||||
import type { SceneOperations } from '../operations'
|
||||
import { MCP_CATALOG_ITEMS } from '../tools/asset-catalog'
|
||||
|
||||
/**
|
||||
@@ -8,7 +8,7 @@ import { MCP_CATALOG_ITEMS } from '../tools/asset-catalog'
|
||||
* The editor UI owns the full catalog. MCP intentionally keeps a dependency-free
|
||||
* subset so headless agents can still place realistic furniture and fixtures.
|
||||
*/
|
||||
export function registerCatalogItems(server: McpServer, _bridge: SceneBridge): void {
|
||||
export function registerCatalogItems(server: McpServer, _bridge: SceneOperations): void {
|
||||
server.registerResource(
|
||||
'catalog-items',
|
||||
'pascal://catalog/items',
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import type { AnyNode, SlabNode, WallNode } from '@pascal-app/core/schema'
|
||||
import { getWallPlanFootprint } from '@pascal-app/core/wall'
|
||||
import type { SceneBridge } from '../bridge/scene-bridge'
|
||||
import type { SceneOperations } from '../operations'
|
||||
|
||||
type WallFootprint = {
|
||||
wallId: string
|
||||
@@ -36,7 +36,10 @@ const EMPTY_MITER_DATA: Parameters<typeof getWallPlanFootprint>[1] = {
|
||||
junctions: new Map(),
|
||||
}
|
||||
|
||||
function buildPayload(bridge: SceneBridge, levelId: string): ConstraintsPayload | ConstraintsError {
|
||||
function buildPayload(
|
||||
bridge: SceneOperations,
|
||||
levelId: string,
|
||||
): ConstraintsPayload | ConstraintsError {
|
||||
const level = bridge.getNode(levelId as never)
|
||||
if (!level || level.type !== 'level') {
|
||||
return {
|
||||
@@ -72,7 +75,7 @@ function buildPayload(bridge: SceneBridge, levelId: string): ConstraintsPayload
|
||||
* input hints for agents: slab nodes (with polygons/holes/elevation) + each
|
||||
* wall's plan-view footprint polygon.
|
||||
*/
|
||||
export function registerConstraints(server: McpServer, bridge: SceneBridge): void {
|
||||
export function registerConstraints(server: McpServer, bridge: SceneOperations): void {
|
||||
server.registerResource(
|
||||
'constraints',
|
||||
new ResourceTemplate('pascal://constraints/{levelId}', { list: undefined }),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import type { SceneBridge } from '../bridge/scene-bridge'
|
||||
import type { SceneOperations } from '../operations'
|
||||
import { registerAgentGuide } from './agent-guide'
|
||||
import { registerCatalogItems } from './catalog-items'
|
||||
import { registerConstraints } from './constraints'
|
||||
@@ -16,10 +16,10 @@ import { registerSceneSummary } from './scene-summary'
|
||||
* - `pascal://constraints/{levelId}` — application/json, per-level constraints
|
||||
* - `pascal://agent/guide` — text/markdown, MCP-first construction guide
|
||||
*/
|
||||
export function registerResources(server: McpServer, bridge: SceneBridge): void {
|
||||
registerAgentGuide(server, bridge)
|
||||
registerSceneCurrent(server, bridge)
|
||||
registerSceneSummary(server, bridge)
|
||||
registerCatalogItems(server, bridge)
|
||||
registerConstraints(server, bridge)
|
||||
export function registerResources(server: McpServer, operations: SceneOperations): void {
|
||||
registerAgentGuide(server, operations)
|
||||
registerSceneCurrent(server, operations)
|
||||
registerSceneSummary(server, operations)
|
||||
registerCatalogItems(server, operations)
|
||||
registerConstraints(server, operations)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import type { SceneBridge } from '../bridge/scene-bridge'
|
||||
import type { SceneOperations } from '../operations'
|
||||
|
||||
/**
|
||||
* `pascal://scene/current` — full `{ nodes, rootNodeIds, collections }` snapshot.
|
||||
*
|
||||
* Static URI (not a template). MIME `application/json`.
|
||||
*/
|
||||
export function registerSceneCurrent(server: McpServer, bridge: SceneBridge): void {
|
||||
export function registerSceneCurrent(server: McpServer, bridge: SceneOperations): void {
|
||||
server.registerResource(
|
||||
'scene-current',
|
||||
'pascal://scene/current',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import type { AnyNode, AnyNodeType } from '@pascal-app/core/schema'
|
||||
import type { SceneBridge } from '../bridge/scene-bridge'
|
||||
import type { SceneOperations } from '../operations'
|
||||
|
||||
type Poly2D = ReadonlyArray<readonly [number, number]>
|
||||
|
||||
@@ -77,7 +77,9 @@ function countByType(nodes: AnyNode[]): Record<string, number> {
|
||||
}
|
||||
|
||||
/** Build the markdown summary. Pure over the SceneGraph snapshot. */
|
||||
export function buildSceneSummaryMarkdown(snapshot: ReturnType<SceneBridge['exportJSON']>): string {
|
||||
export function buildSceneSummaryMarkdown(
|
||||
snapshot: ReturnType<SceneOperations['exportJSON']>,
|
||||
): string {
|
||||
const { nodes, rootNodeIds } = snapshot
|
||||
const allNodes = Object.values(nodes) as AnyNode[]
|
||||
|
||||
@@ -193,7 +195,7 @@ function walkToLevel(node: AnyNode, nodes: Record<string, AnyNode>): string | nu
|
||||
* `pascal://scene/current/summary` — human-readable scene overview.
|
||||
* MIME `text/markdown`.
|
||||
*/
|
||||
export function registerSceneSummary(server: McpServer, bridge: SceneBridge): void {
|
||||
export function registerSceneSummary(server: McpServer, bridge: SceneOperations): void {
|
||||
server.registerResource(
|
||||
'scene-summary',
|
||||
'pascal://scene/current/summary',
|
||||
|
||||
Reference in New Issue
Block a user