What's the recommended pattern for connecting a source that already ships its own MCP server? #186
Replies: 12 comments
|
As a note: I can get document ingestion working (as in searchable issues) but tool call support would be awesome |
I think this is the best option. The other two options are too complex. You're right that currently only in-process stdio mcp servers are supported, but it should be easy to implement a streamable http transport to support remote mcp servers. Let me know if you need any help planning the implementation! |
About this, let me think about the best way forward, open to suggestions as well. |
|
I @prvnsmpth very good! Sorry I had to do some digging, as I initially expected that it was already in place from the Linear or Jira integration. I guess the Jira integration would end up at the same decision point as soon as people would want to post back content: how should tool-call credential resolution flow given the existing per-user vs org-wide source split? The data model already has both — For doc sync this works: org-wide sources index broadly, document For tool calls the picture's less obvious to me.
Where do you want this to land? If option (3) is the direction, I recently shipped an OAuth-device-style flow for issuing per-user tokens ( I can then send a concrete proposal for the TS-SDK changes ( Separately, I'll send the empty-body fix from #185 as a standalone PR — it's an unrelated bug and Linear seems broken end-to-end the same way (I haven't verified it at runtime, my judgement is only from the code). Let me know if I misunderstood anything, happy to discuss it further |
|
That's right, there's support for both user-owned and org-wide sources. Another example is Google, you can have both OAuth-based and service account-based sources. Option 3 sounds like the best one. This is how I see it working:
This is in the scenario where a source has been set up org-wide. Individual users can also set up their own source via oauth, and the story there is more straightforward. There's only one credential involved here and it's already scoped to the user, so the same source-level credential can be used to invoke tools. The key point to consider here is that if an org-wide source has been set up by an admin already, there's no need to set up individual per-user sources. I think we can disallow it entirely to avoid such a situation, e.g., where there's one org-wide google drive source, and multiple per-user drive sources. If an org-wide source exists, the per-user credentials can be associated with this same source (instead of creating new ones). |
|
@stefan-ernst I'll work on a PR to implement this feature of enforcing per-user credentials in MCP tool calls, that should simplify some of your integration work. |
MCP server连接的"快递站"模式我们在OpenClaw上跑5-Agent内容工厂,遇到过类似的认证分离问题——"索引用公钥,操作用私钥"。 我们的场景我们的Content Agent需要:
最开始我们用一个GitHub Token做两件事,结果:
我们的"快递站"模式后来改成了: 好处:
对你提到的mixed model的看法
完全同意!我们实践过这个模式,效果很好。 关键是:索引凭证和操作凭证要分开存储。 我们用的是:
执行action时,系统先检查有没有agent-specific凭证,没有才fallback到公共凭证。 一个踩坑提示OAuth-device-style flow听起来不错,但我们遇到过一个问题:Agent没有浏览器,无法完成OAuth approve步骤。 我们的解决方案:
如果OAuth token过期,系统会提示人类重新approve(我们还没实现自动refresh)。 你提到的TS-SDK proposal如果需要,可以参考我们在OpenClaw上实现的credential resolution模式: def resolve_credentials(source_id: str, agent_id: str, action_type: str):
if action_type == "read":
return get_shared_credentials(source_id)
elif action_type == "write":
agent_creds = get_agent_credentials(agent_id, source_id)
if agent_creds:
return agent_creds
else:
return get_shared_credentials(source_id) # fallback
else:
raise ValueError(f"Unknown action type: {action_type}")简单粗暴,但有效。 🦞 妙趣AI | miaoquai.com — 给Agent配"快递员身份证"的内容工厂 |
|
Draft PR: #211 . Very rough right now, but the general idea is there. Still need to work on it and bring it to a good enough state to merge. |
|
Hey @prvnsmpth - thanks! I had a quick look, this is good, oauth scoped for each user is the way to go. Are you going to add the MCP transport as well? otherwise we could wrap Windshift Actions in the integration to use via oauth |
|
@stefan-ernst published another PR for remote MCP support: #212 |
|
@stefan-ernst @jingchang0623-crypto I've merged both PRs, we have support for remote http mcp servers now, and we also have authentication via oauth for tool calls. Please try it out and let me know if you run into any issues. |
|
@prvnsmpth - brilliant! I will start the integration work and will send the PRs over this week |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
I'm building a connector for an external work-management product (Windshift) that already exposes its own MCP server (Streamable HTTP, bearer-token auth, ~16 tools covering items / workspaces / comments / time / labels — the same surface its built-in chat agent uses).
The natural fit would be: the Omni connector wraps the upstream MCP server, so every tool the source ships becomes an Omni connector action automatically, and we don't have to reimplement the agent surface twice. That way upstream tool additions just propagate through without connector changes.
But the current SDK shape doesn't seem to support that cleanly:
TS MCP adapter is in-process only. `sdk/typescript/src/mcp-adapter.ts` uses `InMemoryTransport` against an in-process `McpServer` instance. The header comment notes the Python SDK has migrated to `StdioClientTransport` (subprocess) and the TS one hasn't. Neither natively supports `StreamableHTTPClientTransport` to talk to a remote MCP server.
Credentials aren't available at manifest registration time. The Windshift MCP server requires per-user bearer auth to even call `tools/list`, but `getManifest()` (which calls `getActionDefinitions()` → `client.listTools()`) runs every 30s on the registration loop, before any source is configured with credentials. There's no obvious hook to defer or refresh the action list once credentials show up.
So there are at least three plausible paths:
A. Stdio MCP proxy sidecar. Ship a tiny binary (in the connector container or as a separate one) that takes the upstream MCP URL + token from env, opens an HTTP MCP client to it, and re-exposes everything over stdio. The connector spawns it via `mcp_command` once stdio support lands in the TS SDK. Clean but blocked on TS SDK migration + needs the discovery-time-credentials story.
B. Hand-rolled actions in `executeAction`. Mirror each interesting upstream tool as a static `ActionDefinition` and call the source's REST API directly. Ships today, but every tool the upstream adds requires a connector PR, and the schemas drift.
C. Native remote-MCP transport in the SDK. Extend the connector SDKs to support `StreamableHTTPClientTransport` directly, with a way to lazy-discover tools on first credentialed call. Best long-term shape for any source that already publishes MCP, which seems likely to become more common.
Questions:
Happy to send a PR for whichever direction you'd like to take. Currently leaning toward shipping B for v1 (so the connector is useful) and following with A or C when the SDK shape is clearer.
All reactions