Skip to main content
Glama
williamzujkowski

Strudel MCP Server

write

Write TidalCycles/Strudel music patterns to the editor with options for auto-playback and validation to control browser-based music generation.

Instructions

Write pattern to editor with optional auto-play and validation

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
patternYesPattern code
auto_playNoStart playback immediately after writing (default: false)
validateNoValidate pattern before writing (default: true)

Implementation Reference

  • Tool registration and schema definition for 'write' tool, including input schema with pattern (required), auto_play, and validate options.
    {
      name: 'write',
      description: 'Write pattern to editor with optional auto-play and validation',
      inputSchema: {
        type: 'object',
        properties: {
          pattern: { type: 'string', description: 'Pattern code' },
          auto_play: { type: 'boolean', description: 'Start playback immediately after writing (default: false)' },
          validate: { type: 'boolean', description: 'Validate pattern before writing (default: true)' }
        },
        required: ['pattern']
      }
    },
  • MCP tool handler for 'write': validates input, optionally validates pattern, writes via writePatternSafe, optionally auto-plays.
    case 'write':
      InputValidator.validateStringLength(args.pattern, 'pattern', 10000, true);
    
      // Validate pattern if requested (default: true) - Issue #40
      if (args.validate !== false && this.isInitialized && typeof this.controller.validatePattern === 'function') {
        try {
          const validation = await this.controller.validatePattern(args.pattern);
          if (validation && !validation.valid) {
            return {
              success: false,
              errors: validation.errors,
              warnings: validation.warnings,
              suggestions: validation.suggestions,
              message: `Pattern validation failed: ${validation.errors.join('; ')}`
            };
          }
        } catch (e) {
          // Validation failed, but we can still try to write
          this.logger.warn('Pattern validation threw error, continuing with write');
        }
      }
    
      const writeResult = await this.writePatternSafe(args.pattern);
    
      // Auto-play if requested - Issue #38
      if (args.auto_play && this.isInitialized) {
        await this.controller.play();
        return `${writeResult}. Playing.`;
      }
    
      return writeResult;
  • Helper method writePatternSafe: handles uninitialized state by caching pattern, otherwise delegates to controller.writePattern.
    private async writePatternSafe(pattern: string): Promise<string> {
      if (!this.isInitialized) {
        // Store the pattern for later use
        const id = `pattern_${Date.now()}`;
        this.generatedPatterns.set(id, pattern);
        return `Pattern generated (initialize Strudel to use it): ${pattern.substring(0, 50)}...`;
      }
      
      return await this.controller.writePattern(pattern);
    }
  • Core implementation of writePattern: uses Playwright to manipulate CodeMirror editor in strudel.cc browser page, verifies write, updates cache.
    async writePattern(pattern: string): Promise<string> {
      if (!this._page) throw new Error('Browser not initialized. Run init tool first.');
    
      // Invalidate cache before write to prevent stale reads
      this.invalidateCache();
    
      // Use evaluate for faster direct manipulation
      const success = await this._page.evaluate((newPattern) => {
        const editor = document.querySelector('.cm-content') as HTMLElement;
        if (editor) {
          const view = (editor as any).__view;
          if (view) {
            view.dispatch({
              changes: { from: 0, to: view.state.doc.length, insert: newPattern }
            });
            return true;
          }
        }
        return false;
      }, pattern);
    
      if (!success) {
        throw new Error('Failed to write pattern - editor not found or view unavailable');
      }
    
      // Verify the write by reading back from browser (fixes cache sync issues)
      const verified = await this._page.evaluate(() => {
        const editor = document.querySelector('.cm-content') as HTMLElement;
        if (editor) {
          const view = (editor as any).__view;
          if (view && view.state && view.state.doc) {
            return view.state.doc.toString();
          }
        }
        return null;
      });
    
      // Update cache with verified content
      this.editorCache = verified || pattern;
      this.cacheTimestamp = Date.now();
    
      // Log warning if verification failed
      if (verified === null) {
        this.logger.warn('Pattern write verification failed - using input pattern for cache');
      }
    
      return `Pattern written (${pattern.length} chars)`;
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/williamzujkowski/strudel-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server