agentleFS
nickytonlinenickytonline/beads-mcp/.agents/skills/migrate-mcp-template-to-effect/SKILL.md

migrate-mcp-template-to-effect

Skill3 starsChanged 35 days agoMITView on GitHub

Migrate a project created from the pre-Effect MCP TypeScript template to the Effect-based template while preserving MCP behavior and deployment contracts. Use for this template's Zod/Pino-to-Effect migration, not for generic TypeScript-to-Effect rewrites or native Effect MCP server migrations.

  • Reads credentials

The file

We split this skill into the rules it gives an agent

12 rules. About 0 are common, 4 are distinctive, and 8 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this skill when an existing project was created from the earlier version of this repository and still uses Zod, Pino, direct …

    line 11
  2. Distinctive:

    Keep these behaviors unless the user explicitly requests a separate breaking change:

    line 17
  3. Distinctive:

    Check the working tree first and preserve unrelated user changes.

    line 29
  4. Distinctive:

    Do not mechanically rewrite every Promise.

    line 37
  5. Very specific:

    Keep business logic in an Effect.Effect and cross back to the MCP callback API only with runMcpEffect().

    line 75
  6. Very specific:

    Use yield* to execute Effects in Effect.gen.

    line 76
  7. Very specific:

    Use Effect.tryPromise around SDK, Express, Node, or other Promise APIs.

    line 77
  8. Very specific:

    Use Effect.all with explicit concurrency for independent application effects, such as parallel shutdown cleanup.

    line 78
  9. Very specific:

    Keep genuine tool failures in-band with createErrorResult({ error }).

    line 79
  10. Very specific:

    Use yield* logger.info(...) and yield* logger.error(...) inside workflows.

    line 80
  11. Very specific:

    Run npm run lint, npm run format:check, npm run build, and npm run test:ci.

    line 89
  12. Very specific:

    Update README.md, AGENTS.md, and the create-mcp-tool skill so new tools follow the Effect patterns.

    line 94

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Migrate the MCP TypeScript Template to Effect

Use this skill when an existing project was created from the earlier version of this repository and still uses Zod, Pino, direct environment parsing, and Promise-based tool handlers.

The goal is to adopt Effect for application workflows without changing the MCP protocol or making users learn a different server boundary.

Preserve the external contract

Keep these behaviors unless the user explicitly requests a separate breaking change:

  • @modelcontextprotocol/server remains the MCP implementation
  • Express remains the HTTP server and /mcp remains the MCP endpoint
  • /health remains a plain { "status": "ok" } liveness endpoint
  • PORT, NODE_ENV, SERVER_NAME, SERVER_VERSION, and LOG_LEVEL keep their names. SERVER_NAME and SERVER_VERSION default to package.json name and version; the other defaults stay the same
  • tool names, MCP annotations, structured output, and elicitation behavior remain compatible

Effect should be introduced behind the MCP SDK boundary. Do not replace the official MCP server with Effect's separate native MCP implementation as part of this migration.

Inspect before editing

Check the working tree first and preserve unrelated user changes. Confirm the project has the expected pre-Effect patterns:

  • z.object(...) input/output schemas
  • Pino or pino-pretty logging
  • direct process.env configuration
  • async MCP callbacks with try/catch
  • Promise.all for independent application work

Do not mechanically rewrite every Promise. Identify which code is application workflow and which code is an MCP, Express, Node, or test boundary.

Migration map

Earlier templateEffect-based template
Zod schemasEffect Schema.Struct, adapted with toMcpSchema()
.describe().annotate({ description: "..." })
Pino / pino-prettyEffect JSON logging (Logger.formatStructured) behind the shared logger facade
process.env parsingEffect Config with ConfigProvider.fromEnv()
async tool workflowEffect.gen(function* () { ... })
await an Effectyield* the Effect inside Effect.gen
Promise rejection handlingEffect.tryPromise, typed failures, and Effect.catch
Promise.all for independent effectsEffect.all([...], { concurrency: "unbounded" })
MCP callback returns PromiserunMcpEffect() at the callback boundary

Schema boundary

Define tool contracts with Effect Schema and adapt them at registration time:

const InputSchema = toMcpSchema(
  Schema.Struct({
    message: Schema.String,
  }),
);

server.registerTool(
  "echo",
  { inputSchema: InputSchema },
  (args, ctx) => runMcpEffect(echo(args, ctx)),
);

toMcpSchema() supplies both Standard Schema validation and the JSON Schema converter required by the MCP SDK. It supports the MCP SDK's draft-07 and draft-2020-12 targets. Keep elicitation's restricted requestedSchema as hand-written JSON Schema; it is not interchangeable with a general tool schema.

Effect workflow rules

  • Keep business logic in an Effect.Effect and cross back to the MCP callback API only with runMcpEffect().
  • Use yield* to execute Effects in Effect.gen; merely constructing an Effect does not run it.
  • Use Effect.tryPromise around SDK, Express, Node, or other Promise APIs.
  • Use Effect.all with explicit concurrency for independent application effects, such as parallel shutdown cleanup.
  • Keep genuine tool failures in-band with createErrorResult({ error }); valid outcomes such as elicitation decline/cancel are normal createTextResult results.
  • Use yield* logger.info(...) and yield* logger.error(...) inside workflows. Never log raw tool arguments.

Tests and verification

Preserve the existing integration coverage and add focused tests for migration-sensitive behavior:

  • src/lib/mcp-schema.test.ts validates Effect schemas and both JSON Schema dialects.
  • src/tools.test.ts uses an in-memory MCP client/server to test tool calls, structured output, elicitation outcomes, and modern-era behavior.
  • Assert client.listTools() exposes the expected input/output JSON Schemas when schemas change.
  • Run npm run lint, npm run format:check, npm run build, and npm run test:ci.
  • Manually smoke-test /health and /mcp when the HTTP boundary changes.

Documentation and release

Update README.md, AGENTS.md, and the create-mcp-tool skill so new tools follow the Effect patterns. Explain that the template remains MCP-standard and uses the official MCP SDK.

This migration is breaking for existing template consumers. Use a conventional feat!: commit and let the release workflow calculate the major version; do not manually edit the package version solely for this migration.

Completion checklist

  • Existing user changes were preserved.
  • Zod, Pino, and direct configuration patterns were migrated.
  • MCP registration still uses the official SDK and the existing HTTP boundary.
  • Effect schema adapter and both JSON Schema targets are tested.
  • Tool, elicitation, structured-output, and HTTP behavior are verified.
  • README, AGENTS.md, and tool-authoring guidance are consistent.
  • Required checks pass.
  • The breaking change is recorded with feat!:.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.