Buffaly Logo
Reference

Registering MCP services

Register MCP-backed services as explicit per-binding Buffaly services: ProtoScript owns the service boundary and configuration, while C# owns the MCP protocol work.

The model

The intended shape is one generic McpService type, one C# host bridge, and one concrete ProtoScript service instance for each configured MCP server.

Source model

McpService#FeedingFrenzy.ToListServerTools

McpService#GitHub.ToCallTool

Projected tool names

McpService_FeedingFrenzy_ToListServerTools

McpService_GitHub_ToCallTool

The host should initialize the binding before the first projected method call. Service methods should not require authors to call initialization manually.

Why MCP is per-binding

MCP servers usually differ by endpoint, transport, authentication, capability set, intended usage, filesystem roots, and other boundary data. Calling the wrong binding can be materially wrong.

Treat MCP like a Google Workspace account or SQL connection: the instance identity matters. Avoid a singleton unless there is truly one stable server with no meaningful environment or auth variation.

Authoritative split: ProtoScript versus C#

ProtoScript owns

  • Service type and instance names.
  • Binding fields and descriptions.
  • Initialize() and user-facing To* signatures.
  • Friendly wrapper methods once a binding is stable.

C# owns

  • Transport and JSON-RPC session handling.
  • MCP initialize handshake and request correlation.
  • tools/list and tools/call.
  • Connection caching, lifecycle state, and fail-fast binding errors.

Do not reimplement MCP protocol logic in ProtoScript. Keep ProtoScript authoring simple and let the C# bridge handle transport, handshake, and remote calls.

Recommended phase-one service surface

Start small. One real generic service is enough to prove the boundary before investing in generated or hand-authored wrappers.

Initialize()
ToPing()
ToListServerTools()
ToCallTool(string toolName, JsonObject args)
ToCallTextTool(string toolName, JsonObject args)

After a binding is stable, add friendly wrappers such as ToSearchLeads(...), ToReadResource(...), or ToGetPrompt(...) for the remote actions users should rely on.

Binding options

Keep binding identity and credentials explicit. Put server-specific configuration on the service instance rather than passing free-form binding parameters into every method.

OptionPurposeGuidance
BindingKeyStable machine-safe binding identity.Use keys such as feedingfrenzy, github, or filesystem.
DescriptionDomain-specific summary of when to use the binding.Avoid vague names like "Main server"; describe the real purpose.
ServerUrlHTTP MCP endpoint.Keep the URL explicit and authoritative.
BearerTokenEnvironmentVariableEnvironment variable that supplies the bearer token.Never hardcode sensitive tokens in ProtoScript.
TimeoutSecondsRequest timeout.Set a practical timeout for the remote server.
InsecureTLS bypass.Use only for local or controlled test environments.
StreamStream session header pattern.Set true when the server expects stream initialization notifications.

Example: register a stable MCP binding

Declare a partial service instance for each stable server. The projected tools keep the instance identity visible to Buffaly and to operators.

Feeding Frenzy shape

  • BindingKey: feedingfrenzy
  • ServerUrl: remote MCP stream endpoint
  • BearerTokenEnvironmentVariable: FF_MCP_TOKEN
  • Stream: true
McpService_FeedingFrenzy_ToListServerTools
Validate remote tool discovery first.
McpService_FeedingFrenzy_ToCallTool
Call one safe remote tool before adding wrappers.

Once validated, add hand-authored wrappers for important remote tools. Add a generator later only if the server surface becomes large.

Recommended workflow

  1. Create or reuse the generic McpService type.
  2. Declare one partial prototype for the server binding.
  3. Set BindingKey, endpoint, token environment variable, and transport options.
  4. Validate Initialize() and ToListServerTools() first.
  5. Validate ToCallTool(...) or ToCallTextTool(...) against one safe remote tool.
  6. Add friendly wrappers only after the binding is stable and useful.

Avoid hardcoded tokens

Use environment variables or protected secret storage. Do not place API keys in ProtoScript, docs, or examples.

Avoid overexposure

Start with generic calls and a curated wrapper set instead of exposing a large server surface too early.

Build ProtoScript services Review integrations and surfaces Understand tool discovery