Skip to content

Commit a6e1330

Browse files
committed
feat(pluggable-widgets-mcp): update readme and agents.md, add security.md, clarify notifications
1 parent d91f78b commit a6e1330

7 files changed

Lines changed: 281 additions & 227 deletions

File tree

Lines changed: 62 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -1,257 +1,113 @@
1-
# Pluggable Widgets MCP Server - AI Agent Guide
1+
# Pluggable Widgets MCP Server
22

3-
This document provides context for AI development assistants working on the MCP (Model Context Protocol) server for Mendix pluggable widgets.
3+
MCP server enabling AI assistants to scaffold and manage Mendix pluggable widgets via STDIO (default) or HTTP transport.
44

5-
## Overview
5+
## Quick Reference
66

7-
This package implements an MCP server that enables AI assistants to scaffold and manage Mendix pluggable widgets programmatically. It supports both HTTP and STDIO transports for flexible integration with various MCP clients.
8-
9-
### Key Characteristics
10-
11-
- **MCP SDK**: Built on `@modelcontextprotocol/sdk` for standardized AI tool integration
12-
- **Dual Transport**: HTTP (Express) for web clients, STDIO for CLI clients (Claude Desktop, etc.)
13-
- **TypeScript**: Fully typed with Zod schemas for runtime validation
14-
- **Widget Generator**: Wraps `@mendix/generator-widget` via PTY for interactive scaffolding
7+
```bash
8+
pnpm dev # Development with hot reload
9+
pnpm build # TypeScript compilation + path alias resolution
10+
pnpm start # Build and run (STDIO mode, default)
11+
pnpm start:http # Build and run (HTTP mode, port 3100)
12+
pnpm lint # ESLint check
13+
```
1514

1615
## Project Structure
1716

1817
```
1918
src/
20-
├── index.ts # Entry point - transport mode selection
21-
├── config.ts # Server configuration and constants
22-
├── security/
23-
│ ├── guardrails.ts # Security validation (path traversal, extension whitelist)
24-
│ └── index.ts # Security module exports
25-
├── server/
26-
│ ├── server.ts # MCP server factory and tool/resource registration
27-
│ ├── http.ts # HTTP transport setup (Express)
28-
│ ├── stdio.ts # STDIO transport setup
29-
│ ├── routes.ts # Express route handlers
30-
│ └── session.ts # HTTP session management
31-
├── resources/
32-
│ ├── index.ts # Resource registration
33-
│ └── guidelines.ts # Widget development guidelines
34-
└── tools/
35-
├── index.ts # Tool registration aggregation
36-
├── types.ts # MCP tool type definitions
37-
├── scaffolding.tools.ts # Widget creation (create-widget)
38-
├── file-operations.tools.ts # File read/write/list operations
39-
├── build.tools.ts # Widget building and validation
40-
└── utils/
41-
├── generator.ts # Widget generator PTY wrapper
42-
├── progress-tracker.ts # Progress/logging helper
43-
├── notifications.ts # MCP notification utilities
44-
└── response.ts # Tool response helpers
45-
```
46-
47-
## Architecture
48-
49-
### Transport Layer
50-
51-
The server supports two transport modes selected via CLI argument:
52-
53-
- **STDIO** (default): Single-session stdin/stdout for CLI integration (Claude Code, Claude Desktop)
54-
- **HTTP**: Multi-session Express server on port 3100 for web clients and testing
55-
56-
### Tool Registration
57-
58-
Tools are registered directly with the MCP server using the SDK's `server.tool()` method. The current architecture uses category-based registration functions:
59-
60-
```typescript
61-
// src/tools/index.ts
62-
export function registerAllTools(server: McpServer): void {
63-
registerScaffoldingTools(server); // Widget creation
64-
registerFileOperationTools(server); // File operations
65-
registerBuildTools(server); // Building & validation
66-
}
67-
```
68-
69-
**Available Tools**:
70-
71-
- **Scaffolding**: `create-widget` - Scaffolds new widgets via PTY interaction
72-
- **File Operations**:
73-
- `list-widget-files` - Lists files in widget directory
74-
- `read-widget-file` - Reads widget file contents
75-
- `write-widget-file` - Writes single file
76-
- `batch-write-widget-files` - Writes multiple files atomically
77-
- **Build**: `build-widget` - Compiles widget and parses errors (TypeScript, XML, dependencies)
78-
79-
### Resources
80-
81-
MCP resources provide read-only documentation that clients can fetch on-demand:
82-
83-
```typescript
84-
// src/resources/index.ts
85-
export function registerResources(server: McpServer): void {
86-
registerGuidelineResources(server); // Widget development guidelines
87-
}
88-
```
89-
90-
Resources are loaded from `docs/` directory and exposed via URIs like `resource://guidelines/property-types`.
91-
92-
### Widget Generator Integration
93-
94-
The `create-widget` tool uses `node-pty` to interact with the Mendix widget generator CLI. Key implementation details:
95-
96-
- **PTY Simulation**: Required because the generator uses interactive prompts
97-
- **Prompt Detection**: Matches expected prompts in terminal output
98-
- **Answer Automation**: Sends pre-configured answers based on user input
99-
- **Progress Tracking**: Reports progress via MCP notifications
100-
101-
## Development Commands
102-
103-
```bash
104-
pnpm dev # Development mode with hot reload (tsx watch)
105-
pnpm build # TypeScript compilation + path alias resolution (preserves shebang)
106-
pnpm start # Build and run (HTTP mode on port 3100)
107-
pnpm start:stdio # Build and run (STDIO mode)
108-
pnpm lint # ESLint check
19+
├── index.ts # Entry point - transport mode selection
20+
├── config.ts # Server configuration and constants
21+
├── security/ # Path traversal & extension validation
22+
├── server/ # HTTP and STDIO transport setup
23+
├── resources/ # MCP resources (guidelines)
24+
├── generators/ # XML and TSX code generators
25+
└── tools/ # MCP tool implementations
10926
```
11027

111-
## Adding New Tools
28+
## Adding Tools
11229

113-
1. **Create tool file**: `src/tools/my-feature.tools.ts`
30+
1. Create `src/tools/my-feature.tools.ts`:
11431

11532
```typescript
11633
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
11734
import { z } from "zod";
11835

119-
const myToolSchema = z.object({
120-
param: z.string().describe("Parameter description for LLM")
121-
});
122-
12336
export function registerMyTools(server: McpServer): void {
12437
server.tool(
125-
"my-tool", // Tool name
126-
"Description shown to LLM", // Tool description
127-
myToolSchema, // Input validation schema
128-
async ({ param }) => {
129-
// Handler with typed args
130-
// Implementation
131-
return {
132-
content: [
133-
{
134-
type: "text",
135-
text: "Success message"
136-
}
137-
]
138-
};
139-
}
38+
"my-tool",
39+
"Description shown to LLM",
40+
z.object({ param: z.string().describe("Parameter description") }),
41+
async ({ param }) => ({
42+
content: [{ type: "text", text: "Success" }]
43+
})
14044
);
141-
142-
console.error("[my-feature] Registered 1 tool");
14345
}
14446
```
14547

146-
2. **Register in index**: Update `src/tools/index.ts`
48+
2. Register in `src/tools/index.ts`:
14749

14850
```typescript
14951
import { registerMyTools } from "./my-feature.tools";
15052

15153
export function registerAllTools(server: McpServer): void {
152-
registerScaffoldingTools(server);
153-
registerFileOperationTools(server);
154-
registerBuildTools(server);
155-
registerMyTools(server); // Add here
54+
// ... existing registrations
55+
registerMyTools(server);
15656
}
15757
```
15858

159-
## Code Conventions
59+
## Code Patterns
16060

161-
### Imports
61+
- **Imports**: Use `@/` path alias for absolute imports from `src/`
62+
- **Schemas**: All tool inputs require Zod schemas
63+
- **Errors**: Use `createErrorResponse()` from `@/tools/utils/response`
64+
- **Long operations**: Use `ProgressTracker` from `@/tools/utils/progress-tracker`
16265

163-
- Use `@/` path alias for absolute imports from `src/`
164-
- Prefer specific file imports over barrel exports when dealing with circular dependencies
165-
- Group imports: node builtins → external packages → internal modules
66+
## Notification Behavior (Important for AI Agents)
16667

167-
### Error Handling
68+
When using this MCP server, understand where different types of output appear:
16869

169-
- Use `createErrorResponse()` for user-facing errors
170-
- Log to `console.error` (not stdout) in STDIO mode
171-
- Use `ProgressTracker` for long-running operations
70+
| Output Type | Visibility | Purpose |
71+
| -------------------------- | -------------------------- | ------------------------------------------------------- |
72+
| **Tool Results** | ✅ Visible in conversation | Final outcomes, structured data, success/error messages |
73+
| **Progress Notifications** | ❌ Not in conversation | Client UI indicators only (spinners, progress bars) |
74+
| **Log Messages** | ❌ Not in conversation | Debug console/MCP Inspector only |
17275

173-
### Type Safety
76+
**Key Implications for AI Agents:**
17477

175-
- All tool inputs must have Zod schemas
176-
- Tool handlers receive fully typed arguments via Zod inference
177-
- Use `McpServer` methods directly for type-safe tool registration
78+
1. **Don't expect intermediate progress in chat**: Long operations (scaffolding, building) will show results only when complete. The conversation won't contain step-by-step progress updates.
17879

179-
## Testing
80+
2. **Tool results are authoritative**: Only tool result content appears in the conversation history. Use this for:
18081

181-
Use MCP Inspector for interactive testing:
82+
- Success confirmations with file paths
83+
- Structured error messages with suggestions
84+
- Any information the AI needs to continue the workflow
18285

183-
```bash
184-
# STDIO mode
185-
npx @modelcontextprotocol/inspector node dist/index.js stdio
86+
3. **Progress tracking is for humans**: `sendProgress()` and `sendLogMessage()` are for human observers using MCP Inspector or UI indicators, not for AI decision-making.
18687

187-
# HTTP mode
188-
pnpm start
189-
npx @modelcontextprotocol/inspector
190-
# Connect to http://localhost:3100/mcp
191-
```
88+
4. **When debugging**:
89+
- If operations seem to "hang", check MCP Inspector's Notifications/Logs panels
90+
- Progress notifications confirm the server is working, even if the chat is quiet
91+
- This is per MCP specification, not a bug
19292

193-
## Security
194-
195-
All security validation is centralized in `src/security/guardrails.ts` for easy auditing:
93+
**Example Workflow:**
19694

19795
```typescript
198-
import { validateFilePath, ALLOWED_EXTENSIONS } from "@/security";
96+
// ❌ This progress won't appear in AI's context
97+
await sendProgress(context, 50, "Scaffolding widget...");
19998

200-
// Validates path traversal and extension whitelist
201-
validateFilePath(widgetPath, filePath, true); // true = check extension
99+
// ✅ This result WILL appear in AI's context
100+
return createToolResponse(`Widget created at ${widgetPath}`);
202101
```
203102

204-
### Security Measures
205-
206-
| Protection | Function | Description |
207-
| ------------------- | ------------------------- | ------------------------------------------------------------------- |
208-
| Path Traversal | `validateFilePath()` | Blocks `..` sequences and resolved path escapes |
209-
| Extension Whitelist | `isExtensionAllowed()` | Only allows: `.tsx`, `.ts`, `.xml`, `.scss`, `.css`, `.json`, `.md` |
210-
| Directory Boundary | `isPathWithinDirectory()` | Ensures files stay within widget directory |
211-
212-
When adding file operation tools, always use `validateFilePath()` from the security module.
213-
214-
## Key Files Reference
215-
216-
| File | Purpose |
217-
| -------------------------- | ------------------------------------------------ |
218-
| `config.ts` | Server constants (ports, timeouts, paths) |
219-
| `security/guardrails.ts` | Security validation (path traversal, extensions) |
220-
| `tools/index.ts` | Tool registration aggregation |
221-
| `tools/utils/generator.ts` | Widget generator PTY prompts and defaults |
222-
| `resources/guidelines.ts` | Widget development guideline resources |
223-
| `server/session.ts` | HTTP session lifecycle management |
224-
| `server/server.ts` | MCP server factory and registration entry point |
225-
226-
## Common Patterns
227-
228-
### Progress Notifications
229-
230-
```typescript
231-
const tracker = new ProgressTracker({
232-
context,
233-
logger: "my-tool",
234-
totalSteps: 5
235-
});
103+
## Testing
236104

237-
tracker.start("initializing");
238-
await tracker.progress(25, "Step 1 complete");
239-
await tracker.info("Detailed log message", { key: "value" });
240-
tracker.stop();
105+
```bash
106+
npx @modelcontextprotocol/inspector node dist/index.js
241107
```
242108

243-
### Long-Running Operations
244-
245-
- Use `ProgressTracker` for heartbeat and stuck detection
246-
- Set appropriate timeouts (see `SCAFFOLD_TIMEOUT_MS`)
247-
- Call `tracker.markComplete()` before expected long waits (e.g., npm install)
248-
249-
## Roadmap Context
250-
251-
Current focus is widget scaffolding. Planned additions:
109+
## Security
252110

253-
- Widget property editing
254-
- XML configuration management
255-
- Build and deployment automation
111+
**Read before implementing file operations**: [docs/agent/security.md](docs/agent/security.md)
256112

257-
When adding features, maintain the existing patterns for tool registration, progress tracking, and transport-agnostic design.
113+
All file operation tools must use `validateFilePath()` from `@/security` to prevent path traversal attacks.

packages/pluggable-widgets-mcp/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,59 @@ npx @modelcontextprotocol/inspector
197197

198198
This is useful for verifying tool behavior without needing a full AI client integration.
199199

200+
## Understanding Feedback and Notifications
201+
202+
This server uses MCP's notification system to provide progress updates and logging. However, **different types of feedback appear in different places**—not all feedback shows up in your chat conversation.
203+
204+
### Where Different Types of Feedback Appear
205+
206+
| Feedback Type | Where It Appears | Example |
207+
| -------------------------- | -------------------------------------- | ----------------------------------------------------------------- |
208+
| **Tool Results** | ✅ Chat conversation | Widget created at `/path/to/widget`, Build completed successfully |
209+
| **Progress Notifications** | ⚙️ Client UI (spinners, progress bars) | "Scaffolding widget...", "Building widget..." |
210+
| **Log Messages** | 🔍 Debug console (MCP Inspector) | Detailed operation logs, debug info |
211+
212+
### Why Progress Doesn't Show in Chat
213+
214+
**This is by design per the MCP specification**, not a bug. The MCP architecture separates concerns:
215+
216+
- **`notifications/progress`** → Routed to client UI indicators (loading spinners, status bars)
217+
- **`notifications/message`** → Routed to debug/inspector consoles for developers
218+
- **Tool results** → Returned to the conversation when operations complete
219+
220+
This means:
221+
222+
- Long operations (scaffolding, building) will show **results** when complete
223+
- You won't see intermediate progress steps in the chat history
224+
- MCP Inspector shows all notifications in real-time (bottom-right panel)
225+
226+
### Viewing Debug Output
227+
228+
**With MCP Inspector:**
229+
230+
1. Run: `npx @modelcontextprotocol/inspector node dist/index.js stdio`
231+
2. Execute a tool (e.g., `create-widget`)
232+
3. Watch the **Notifications panel** (bottom-right) for progress updates
233+
4. Check the **Logs panel** for detailed debug output
234+
235+
**With Claude Desktop:**
236+
237+
- Progress notifications may appear as UI indicators (client-dependent)
238+
- Check Claude Desktop's developer console for log messages (if available)
239+
- Tool results will always appear in the conversation
240+
241+
### Expected Behavior Examples
242+
243+
**During widget scaffolding:**
244+
245+
- Chat shows: "Starting scaffolding..." → (wait) → "Widget created at `/path`"
246+
- Inspector shows: Step-by-step progress notifications for all 14 prompts
247+
248+
**During widget building:**
249+
250+
- Chat shows: "Building..." → (wait) → "Build successful" or structured error
251+
- Inspector shows: TypeScript compilation progress, dependency resolution
252+
200253
## Roadmap
201254

202255
- [x] Widget scaffolding (`create-widget`)

0 commit comments

Comments
 (0)