McpActions.Core 0.2.0

dotnet add package McpActions.Core --version 0.2.0
                    
NuGet\Install-Package McpActions.Core -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="McpActions.Core" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="McpActions.Core" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="McpActions.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add McpActions.Core --version 0.2.0
                    
#r "nuget: McpActions.Core, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package McpActions.Core@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=McpActions.Core&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=McpActions.Core&version=0.2.0
                    
Install as a Cake Tool

MCP Toolbox for Actions

MCP Toolbox for Actions (mcp-actions) turns configured actions into MCP tools. Users compose their own toolbox with mcp-actions.yml, then run mcp-actions.exe -c mcp-actions.yml to serve MCP over stdio.

The project separates low-level providers from product plugins:

  • HTTP requests
  • CLI commands (can invoke PowerShell / Python / Node without a shell wrapper)
  • Built-in script providers for PowerShell (pwsh), Node.js (node), and Python (python)
  • Providers such as SQLite (shipped as a NuGet package, loaded dynamically)
  • Product plugins such as PocketBase, GitHub, SQL Server, Kubernetes (shipped as NuGet packages, loaded dynamically)

See REGISTRY.md for the list of available providers and plugins and instructions on how to register new ones. See docs/architecture.md for the runtime contract (external ActionRequest/ActionResponse and internal InternalRequest/InternalResponse protocols, Primitive type set, broker model, and SQLite row/column result conventions).

mcp-actions.exe is a framework-dependent single-file executable. Providers and plugins are .nupkg packages loaded at runtime via AssemblyLoadContext, so AOT is intentionally not used.

Project layout

src/
  core/
    McpActions.Core/                  Shared contracts (IActionProvider / IActionPlugin) + discovery attributes
  runtime/
    McpActions/                       Framework-dependent single-file console app
    McpActions.Runtime/               Runtime: config, template, dispatcher, package loader, MCP bridge
    McpActions.Provider.Http/         Built-in HTTP provider (compiled into host)
    McpActions.Provider.Cli/          Built-in local process provider (compiled into host)
  providers/
    McpActions.Provider.Sqlite/       SQLite provider; packs a nupkg
  plugins/
    McpActions.Plugin.PocketBase/     PocketBase plugin; packs a nupkg
examples/
  mcp-actions.yml
  pocketbase-mcp-actions.yml
  pwsh-mcp-actions.yml
test/
  McpActions.Tests/                   In-process unit tests
  McpActions.IntegrationTests/        End-to-end tests that drive dist/mcp-actions[.exe]

Built-in providers (http, cli, pwsh, node, python) are compiled into the host. Any other provider or plugin is a .nupkg dropped into dist/providers/ or dist/plugins/.

Commands

dotnet build .\McpActions.slnx
dotnet pack .\McpActions.slnx -c Release
dotnet publish .\src\runtime\McpActions -c Release -r win-x64 --self-contained false -p:PublishSingleFile=true
dotnet run --project .\src\runtime\McpActions -- --help
dotnet run --project .\src\runtime\McpActions -- -c .\examples\mcp-actions.yml
dotnet run --project .\src\runtime\McpActions -- -c .\examples\pocketbase-mcp-actions.yml

Debugging with MCP Inspector

Run the command from the dist directory:

npx @modelcontextprotocol/inspector ./mcp-actions.exe -c ./examples/pocketbase-mcp-actions.yml

On Windows, use / in paths passed through Inspector. Inspector treats \ as an argument escape character, so a value such as .\examples\pocketbase-mcp-actions.yml is parsed incorrectly.

Testing

Tests live under test/ and are split into two layers:

  • test/McpActions.Tests — in-process unit tests for the runtime (TemplateEngine, YamlConfigLoader, PackageRef, InputSchemaBuilder, …).
  • test/McpActions.IntegrationTests — end-to-end tests that spawn the packaged mcp-actions executable and drive it as an MCP client over stdio against every YAML file in examples/.

Both layers use xUnit and FluentAssertions. Integration tests read from dist/, so build it first:

./tools/build.ps1 -Clean
dotnet test ./McpActions.slnx

To run just one layer:

dotnet test ./test/McpActions.Tests
dotnet test ./test/McpActions.IntegrationTests

Dist layout

dist/
  mcp-actions.exe
  providers/
    McpActions.Provider.Sqlite.0.1.0.nupkg
  plugins/
    McpActions.Plugin.PocketBase.0.1.0.nupkg
  examples/
    mcp-actions.yml
    pocketbase-mcp-actions.yml

Provider and plugin loading

Package entry-point types are marked with attributes so the loader can discover them without full assembly scans:

[McpActionsProvider(Name = "sqlite")]
public sealed class SqliteProvider : IActionProvider { ... }

[McpActionsPlugin(Name = "pocketbase", RequiredProviders = new[] { "sqlite" })]
public sealed class PocketBasePlugin : IActionPlugin { ... }

Each package is loaded into its own AssemblyLoadContext named {id}@{version} (via PackageLoader in McpActions.Runtime). Because contexts are keyed on both id and version, two configurations can pull different versions of the same package side by side without conflict. The contract assembly McpActions.Core is pinned to the host's default load context so plugins and the host see the same Type identities for IActionProvider, IActionPlugin, etc.

Package extraction rejects paths outside the package cache directory. Package providers may include managed and native runtime dependencies in the nupkg; the SQLite package is self-contained this way.

Package references

Third-party providers and plugins are declared with a pinned {Id}@{Version} reference:

providers:
  - name: sqlite
    package: McpActions.Provider.Sqlite@0.1.0

plugins:
  - name: pocketbase
    package: McpActions.Plugin.PocketBase@0.1.0
    providers: [sqlite]

Built-in providers (http, cli, pwsh, node, python) ship with the host and never carry a package: field. They also do not need to be declared under providers: — the runtime auto-registers any built-in provider referenced by an action. Only add an explicit providers: entry for a built-in when you need to pass it per-instance config (currently unused by the shipped built-ins).

Package resolution order

For each {id}@{version}, PackageLoader looks for {id}.{version}.nupkg in this order:

  1. <config-dir>/providers/ or <config-dir>/plugins/
  2. <exe-dir>/providers/ or <exe-dir>/plugins/
  3. Local user cache %LocalAppData%\mcp-actions\packages\{id}\{version}\{id}.{version}.nupkg — only when nuget.command is configured
  4. Invoke <nuget-command> install {id} -Version {version} -OutputDirectory <cache> — only when nuget.command is configured

Steps 3 and 4 are gated on the nuget.command value in the yml:

nuget:
  command: nuget            # or an absolute path like C:\tools\nuget.exe

Use an absolute path when the CLI is not on PATH. The command is invoked with install <id> -Version <version> -OutputDirectory <cache> -DirectDownload -PackageSaveMode nupkg -DependencyVersion Ignore -NonInteractive; feed selection, credentials, and proxy settings are inherited from the user's nuget.config.

Configuration

Templates support tool arguments, variables, and environment variables:

{{name}}          MCP tool call parameter (bare, no namespace)
{{vars.name}}     value from the top-level vars mapping
{{envs.NAME}}     environment variable

If a complete YAML scalar is one template expression, its resolved type is preserved. Templates embedded in longer strings are rendered as text.

Relative database paths and CLI working directories are resolved from the directory containing mcp-actions.yml.

Action anatomy

Each action's YAML has two halves that serve different purposes:

Section Fields Role
① MCP tool facet (outward) name / description / parameters Populates the tool metadata returned by tools/list — the name, description, and inputSchema that MCP clients see.
② Execution facet (inward) provider + its execution fields (script / scriptFile / args / env / command / request / sql / mode / timeoutSeconds / ...) Describes how the tool actually runs when a tools/call arrives — spawn a process, make an HTTP request, run a SQLite query, etc.

Templates are the bridge: {{name}} binds a parameter declared in ① into a concrete position of the execution fields in ②.

- name: download_desktop_images_to_target_dry_run     # ① tool name
  description: Preview copying...                     # ① tool description
  parameters:                                         # ① tool inputSchema
    targetPath:
      type: string
      required: true
      description: Target folder path.
  # ---------- boundary ----------
  provider: pwsh                                      # ② which provider
  scriptFile: '{{vars.toolsDir}}\...ps1'              # ② execution detail
  args: ["-TargetPath", "{{targetPath}}", "-DryRun"]  # ② + template bridge
  timeoutSeconds: 30                                  # ② execution detail

Parameters

Each action declares its MCP tool inputs under parameters:. Two shapes are accepted:

parameters:
  # Shorthand: just the JSON schema type. Implies required=true.
  limit: integer

  # Full form: any JSON schema keywords plus the extra `required` flag.
  targetPath:
    type: string
    required: true          # optional, defaults to true
    description: Target folder path.

Any extra keys (description, enum, minimum, pattern, ...) pass through verbatim into the tool's inputSchema.

HTTP

- name: get_issue
  provider: http
  request:
    method: GET
    url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues/{{number}}"
    timeoutSeconds: 30
  headers:
    Accept: application/vnd.github+json
  response:
    parse: json # json | text | binary

CLI

command.args is passed through ProcessStartInfo.ArgumentList; it is not concatenated into a shell command.

- name: dotnet_info
  provider: cli
  command:
    file: dotnet
    args: ["--info"]
    workingDirectory: .
    timeoutSeconds: 30
    successExitCodes: [0]
    env:
      DOTNET_CLI_UI_LANGUAGE: en-US

Built-in script providers

The pwsh, node, and python providers run either inline script content or a script file. Use exactly one of:

  • script: inline script content.
  • scriptFile: script path relative to the directory containing mcp-actions.yml, or an absolute path.

Invocation arguments are exposed to the script as environment variables:

  • MCP_ARGS_JSON: JSON object containing all tool arguments.
  • MCP_ARG_<NAME>: one variable per argument, with the name upper-cased and non-alphanumeric characters replaced with _.

Common options are args, workingDirectory, env, timeoutSeconds, successExitCodes, and executable. args are appended after the generated script-file argument.

Default working directory (when workingDirectory: is not set):

  • scriptFile: — the directory of the script file (so the script can reference sibling files by relative path).
  • inline script: — the directory of the yml file (the temp file's location is not meaningful).
- name: pwsh_echo
  description: Echo text with PowerShell.
  parameters:
    text: string
  provider: pwsh
  script: |
    Write-Output "PowerShell: $env:MCP_ARG_TEXT"

- name: node_echo
  description: Echo text with Node.js.
  parameters:
    text: string
  provider: node
  script: |
    console.log(`Node.js: ${process.env.MCP_ARG_TEXT}`);

- name: python_echo
  description: Echo text with Python.
  parameters:
    text: string
  provider: python
  script: |
    import os
    print(f"Python: {os.environ['MCP_ARG_TEXT']}")

- name: run_existing_script
  description: Run a script file with extra arguments.
  provider: pwsh
  scriptFile: ./scripts/report.ps1
  args: ["--format", "json"]
  timeoutSeconds: 60

SQLite

providers:
  - name: sqlite
    package: McpActions.Provider.Sqlite@0.1.0

actions:
  - name: list_messages
    description: List messages, optionally capped by a limit.
    parameters:
      limit: integer
    provider: sqlite
    database: ./messages.db
    sql: SELECT * FROM messages LIMIT @limit
    mode: query # query | scalar | nonQuery

SQLite binds tool arguments referenced as @name, :name, or $name. When mode is omitted, SELECT, WITH, and PRAGMA are treated as queries.

PocketBase

The PocketBase plugin requires the SQLite provider and implements listCollections, describeCollection, and listRecords. See examples/pocketbase-mcp-actions.yml.

Implemented

  • YAML loading and structural validation
  • Recursive template rendering with type preservation
  • Dynamic nupkg loading in isolated AssemblyLoadContext instances
  • MCP stdio tools/list and tools/call
  • HTTP and CLI built-in providers
  • SQLite package provider
  • PocketBase package plugin
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 130 7/16/2026
0.1.0 140 7/14/2026