AWS re:Invent happy hour: Dec 1, 6 PM PST at MGM Grand RSVP

4 Tips for Developing Model Context Protocol Server

(Updated: )

An MCP server turns an ordinary operation into something a coding assistant can discover and call. The difficult part is making that operation predictable when the client supplies the wrong arguments or a dependency fails. These four practices help you build and test a server without hiding those failures.

1. Start with stdio before HTTP

The MCP transport specification defines stdio and Streamable HTTP. Use stdio when a local client should launch your server as a subprocess. Keep stdout exclusively for protocol messages and send diagnostic logs to stderr. Choose Streamable HTTP for an independently running service that accepts remote clients.

For HTTP deployments, validate the Origin header and use authentication appropriate to the deployment. A local HTTP server should bind to loopback. Streamable HTTP replaces the older HTTP+SSE transport; avoid copying an old SSE example without checking the SDK and protocol version it targets.

Shortcut:

Wrap your server code in a library to make it easy to switch between stdio and HTTP as you gain confidence. Here is an example library for go.

2. Write Verbose Parameter Descriptions

IDEs like Cursor will read the descriptions for each of your parameters and make intelligent guesses to satisfy them. Let’s take an example from the proxymock MCP server written in golang:

	tool := mcp.NewTool("run_mock_server",
		mcp.WithDescription("Runs a mock server that can be used to test the application."),
		mcp.WithString("directory",
			mcp.Required(),
			mcp.Title("Directory containing the mock server configuration (usually proxymock)"),
			mcp.Description("Fully qualified directory path (equivalent to a pwd) on the local filesystem that contains the mock server configuration. Usually the directory ends with 'proxymock' and is contained in the current repository."),
		),
	)
	s.AddTool(tool, handleRunMockServer)

The directory parameter’s description is unnecessarily verbose for a human. However, it causes the LLM to do some work that is pretty valuable. Here’s what happens when we run it:

The directory parameter’s description is unnecessarily verbose for a human.

Cursor saw that the MCP server wanted a fully qualified directory called proxymock. Without prompting, it then found such a directory and filled it in correctly.

Shortcut:

Be verbose, borderline pedantic, when writing your command and parameter descriptions. The more explicit you are, the more the LLM will do work for the user without you asking.

3. Test the protocol and record the dependencies

Test initialization, tool discovery, and tool calls with an MCP client or a protocol test harness. Include invalid arguments and failed dependencies. A saved request can be useful test input, but a raw replay loop must still respect initialization, session state, and the transport it targets.

Shortcut:

Use proxymock to record the supported network dependencies your MCP tool calls. For a Streamable HTTP server launched by python server.py, the recording command is:

proxymock record --out ./mcp-dependencies -- python server.py

Exercise the server with your MCP client, stop the recording, then run the server against those dependency mocks:

proxymock mock --in ./mcp-dependencies --no-passthrough -- python server.py

Follow the language configuration guide if the client library needs explicit proxy or certificate settings. This captures network traffic routed through the proxy. It does not capture the MCP messages exchanged over stdin and stdout, and it does not replace protocol tests. The --no-passthrough flag prevents an unmatched dependency request from being forwarded to the real service.

4. Validate tool arguments before doing work

Different clients can produce missing fields, unexpected types, or values outside the operation’s allowed range. A useful description helps the model choose arguments; server-side validation decides whether those arguments are acceptable.

Shortcut:

Declare an inputSchema and validate tool inputs against it, as required by the MCP tools specification. Then check the caller’s authorization and application constraints before executing the operation. A directory argument, for example, should resolve within an allowed workspace rather than grant access to any path the model supplies.

JSON selection and transformation utilities can help read a document, but they do not replace schema validation or authorization. Decide explicitly whether extra properties are accepted. Test missing required fields, wrong types, path traversal, and arguments that are valid JSON but invalid for the operation.

Summary

Start with the transport your client needs, describe the operation precisely, test the protocol, and validate inputs before acting. Recorded dependency traffic makes those tests repeatable while the MCP client exercises the actual tool interface. The proxymock agent tutorial walks through recording and testing a service with a coding assistant.

Ship AI-generated code with confidence

AI writes fast but doesn't know your production environment. Speedscale captures real traffic and verifies AI code against actual API behavior — before it reaches users.