Connecting Models to Customer Systems With MCP
Use Model Context Protocol (MCP) to connect AI applications to customer tools and contextual data. Distinguish host, client, and server responsibilities. Enforce authentication and record-level authorization in application and server code, and require appropriate approval before consequential actions. Validate permissions before returning protected information, and treat tool results as untrusted data. Assess third-party servers and data exposure, test unauthorized-access scenarios, and verify that customer access boundaries remain enforced throughout the workflow.
Northstar’s service-status function passes its direct Python test. Put the same function behind a network endpoint, though, and an authenticated client can read another organization’s ticket. The JSON is valid. What the connection exposes is a missing check between the caller and the record. MCP makes that boundary visible, and it gives us a way to test whether an integration keeps the customer’s permissions intact once other clients can reach it.
What problem does MCP solve?
Model Context Protocol (MCP) is an open protocol for connecting AI applications to tools and contextual data. A shared interface reduces the need for a separate integration for every compatible application and server, subject to supported capabilities and access controls. MCP distinguishes the host application, which manages the workflow and exposed capabilities; the client, which maintains a connection, discovers tools, and sends requests; and the server, which exposes capabilities and handles requests. In Northstar’s design, a customer-system adapter behind the server checks business permissions and retrieves records. That adapter is an implementation choice, not a required fourth MCP protocol role.
A real MCP interaction initializes a connection, discovers a tool schema, calls the tool, and receives a protocol result. The direct Python test skipped all of that, which is why it missed the leak.
Our task is a read-only service-status connection. Ticket NS-318 belongs to Northstar: a replacement-pump dispatch between 08:00 and 12:00 UTC, backed by dispatch/NS-318/v3. NS-904 belongs to another organization. The NS-209 callback workflow from the previous lesson stays as it is, and no callback writer goes behind MCP. The server advertises one tool, get_service_status(ticket_id), whose successful result has five fields: ticket_id, status, dispatch_window, source_ref, and customer_note. The model chooses the ticket ID; the server’s authenticated state supplies the caller’s organization and entitlements.
MCP gives us interoperability. Hosting, tenant isolation, and per-record permissions are still our job.
Who connects to the server, and from where?
The same tool can be reached by two routes, and they connect from different machines. Application-side, our Python application runs a Streamable HTTP MCP client against http://127.0.0.1:8765/mcp and owns connection setup and cleanup, which works because server and application share one machine. Responses-hosted, we add an mcp tool to a Responses request, and OpenAI connects to the server itself, handling the whole tool round trip.
A loopback address always means the machine making the connection. When OpenAI connects to 127.0.0.1, it reaches its own host, not your laptop. A hosted server_url must be publicly reachable. For a private or on-premises server, OpenAI’s Secure MCP Tunnel connects it without public exposure, and the tool takes a tunnel_id in place of server_url.
The Python Agents SDK supports both routes. MCPServerStreamableHttp provides an application-side client, opened as an async context manager and connected to an agent. HostedMCPTool accepts a tool_config that mirrors the Responses MCP tool definition. The hosted route changes where the MCP client and ...